package mkdeb import ( "fmt" "log/slog" "os" "path/filepath" "runtime" "github.com/Masterminds/semver/v3" "github.com/TecharoHQ/yeet/internal" "github.com/TecharoHQ/yeet/internal/pkgmeta" "github.com/goreleaser/nfpm/v2" _ "github.com/goreleaser/nfpm/v2/deb" "github.com/goreleaser/nfpm/v2/files" ) func Build(p pkgmeta.Package) (foutpath string, err error) { defer func() { if r := recover(); r != nil { if err, ok := r.(error); ok { slog.Error("mkdeb: error while building", "err", err) } else { err = fmt.Errorf("%v", r) slog.Error("mkdeb: error while building", "err", err) } } }() os.MkdirAll(*internal.PackageDestDir, 0755) os.WriteFile(filepath.Join(*internal.PackageDestDir, ".gitignore"), []byte("*\n!.gitignore"), 0644) if p.Version == "" { p.Version = internal.GitVersion() } if _, err := semver.NewVersion(p.Version); err != nil { return "", fmt.Errorf("invalid version %q: %w", p.Version, err) } dir, err := os.MkdirTemp("", "yeet-mkdeb") if err != nil { return "", fmt.Errorf("mkdeb: can't make temporary directory") } defer os.RemoveAll(dir) os.MkdirAll(dir, 0755) cgoEnabled := os.Getenv("CGO_ENABLED") defer func() { os.Setenv("GOARCH", runtime.GOARCH) os.Setenv("GOOS", runtime.GOOS) os.Setenv("CGO_ENABLED", cgoEnabled) }() os.Setenv("GOARCH", p.Goarch) os.Setenv("GOOS", "linux") os.Setenv("CGO_ENABLED", "0") p.Build(pkgmeta.BuildInput{ Output: dir, Bin: filepath.Join(dir, "usr", "bin"), Doc: filepath.Join(dir, "usr", "share", "doc", p.Name), Etc: filepath.Join(dir, "etc", p.Name), Man: filepath.Join(dir, "usr", "share", "man"), Systemd: filepath.Join(dir, "usr", "lib", "systemd", "system"), }) var contents files.Contents for _, d := range p.EmptyDirs { if d == "" { continue } contents = append(contents, &files.Content{ Type: files.TypeDir, Destination: d, FileInfo: &files.ContentFileInfo{ MTime: internal.SourceEpoch(), Mode: os.FileMode(0600), }, }) } for repoPath, osPath := range p.ConfigFiles { contents = append(contents, &files.Content{ Type: files.TypeConfig, Source: repoPath, Destination: osPath, FileInfo: &files.ContentFileInfo{ Mode: os.FileMode(0600), MTime: internal.SourceEpoch(), }, }) } for repoPath, rpmPath := range p.Documentation { contents = append(contents, &files.Content{ Type: files.TypeFile, Source: repoPath, Destination: filepath.Join("/usr/share/doc", p.Name, rpmPath), FileInfo: &files.ContentFileInfo{ MTime: internal.SourceEpoch(), }, }) } for repoPath, rpmPath := range p.Files { contents = append(contents, &files.Content{ Type: files.TypeFile, Source: repoPath, Destination: rpmPath, FileInfo: &files.ContentFileInfo{ MTime: internal.SourceEpoch(), }, }) } if err := filepath.Walk(dir, func(path string, stat os.FileInfo, err error) error { if err != nil { return err } if stat.IsDir() { return nil } contents = append(contents, &files.Content{ Type: files.TypeFile, Source: path, Destination: path[len(dir)+1:], FileInfo: &files.ContentFileInfo{ MTime: internal.SourceEpoch(), }, }) return nil }); err != nil { return "", fmt.Errorf("mkdeb: can't walk output directory: %w", err) } contents, err = files.PrepareForPackager(contents, 0o002, "deb", true, internal.SourceEpoch()) if err != nil { return "", fmt.Errorf("mkdeb: can't prepare for packager: %w", err) } for _, content := range contents { content.FileInfo.MTime = internal.SourceEpoch() } info := nfpm.WithDefaults(&nfpm.Info{ Name: p.Name, Version: p.Version, Arch: p.Goarch, Platform: "linux", Description: p.Description, Maintainer: fmt.Sprintf("%s <%s>", *internal.UserName, *internal.UserEmail), Homepage: p.Homepage, License: p.License, MTime: internal.SourceEpoch(), Overridables: nfpm.Overridables{ Contents: contents, Depends: p.Depends, Recommends: p.Recommends, Replaces: p.Replaces, Conflicts: p.Replaces, }, }) info.Overridables.RPM.Group = p.Group if *internal.GPGKeyID != "" { slog.Debug("using GPG key", "file", *internal.GPGKeyFile, "id", *internal.GPGKeyID) info.Overridables.Deb.Signature.KeyFile = *internal.GPGKeyFile info.Overridables.Deb.Signature.KeyID = internal.GPGKeyID info.Overridables.Deb.Signature.KeyPassphrase = *internal.GPGKeyPassword } pkg, err := nfpm.Get("deb") if err != nil { return "", fmt.Errorf("mkdeb: can't get RPM packager: %w", err) } foutpath = pkg.ConventionalFileName(info) fout, err := os.Create(filepath.Join(*internal.PackageDestDir, foutpath)) if err != nil { return "", fmt.Errorf("mkdeb: can't create output file: %w", err) } defer fout.Close() if err := pkg.Package(info, fout); err != nil { return "", fmt.Errorf("mkdeb: can't build package: %w", err) } slog.Info("built package", "name", p.Name, "arch", p.Goarch, "version", p.Version, "path", fout.Name()) return fout.Name(), err }