]> go.fuhry.dev Git - runtime.git/commitdiff
[pkg] support rename rules and multiple bazel-bin directories
authorDan Fuhry <dan@fuhry.com>
Wed, 3 Jun 2026 04:50:47 +0000 (00:50 -0400)
committerDan Fuhry <dan@fuhry.com>
Wed, 3 Jun 2026 04:51:29 +0000 (00:51 -0400)
I am not proud of this code, but at least it works.

```
bazel build //pkg:runtime_utils_deb_nfpm_pkg //pkg:runtime_utils_archlinux_nfpm_pkg
```

pkg/nfpmgen/BUILD.bazel
pkg/nfpmgen/config_generator.go
pkg/nfpmgen/main.go
pkg/runtime-utils.yaml

index 7532737381a804301f2235a6d9dd49d06800d3c7..1037a743a611901344bbe9ba689215ce044b6188 100644 (file)
@@ -10,6 +10,7 @@ go_multi_library(
     visibility = ["//visibility:private"],
     deps = [
         "//constants",
+        "//utils/hashset",
         "//utils/subst",
         "@com_github_goreleaser_nfpm_v2//:nfpm",
         "@com_github_goreleaser_nfpm_v2//files",
index d91fc642b10c659b1b2b987ecde2deb7bc3dd208..e3c8396209c74fd5ce7b68c943ca6e4c9bcdc6a6 100644 (file)
@@ -13,6 +13,7 @@ import (
        "gopkg.in/yaml.v3"
 
        "go.fuhry.dev/runtime/constants"
+       "go.fuhry.dev/runtime/utils/hashset"
        "go.fuhry.dev/runtime/utils/subst"
 )
 
@@ -26,10 +27,16 @@ func debug(fmtstr string, args ...any) {
        fmt.Fprintf(os.Stderr, fmtstr+"\n", args...)
 }
 
+type RenameRule struct {
+       Source      string `yaml:"src" json:"src" jsonschema:"title=source path"`
+       Destination string `yaml:"dst" json:"dst" jsonschema:"title=destination path"`
+}
+
 type NfpmConfig struct {
        *nfpm.Config
 
-       Vars subst.KV `yaml:"vars" json:"vars" jsonschema:"title=map of context vars to inject into subst"`
+       Vars        subst.KV      `yaml:"vars" json:"vars" jsonschema:"title=map of context vars to inject into subst"`
+       RenameRules []*RenameRule `yaml:"rename_rules" json:"rename_rules" jsonschema:"title=dictionary of files to rename as source: target"`
 
        files map[string]struct{} `yaml:"-" json:"-"`
 }
@@ -97,28 +104,43 @@ func LoadNfpmConfig(yamlPath string, fileAllowlist []string, varOverrides subst.
        return out, nil
 }
 
-func (c *NfpmConfig) DiscoverBinaries(bazelBinDir string) error {
+func (c *NfpmConfig) DiscoverBinaries(bazelBinDirs []string) error {
        wd, err := os.Getwd()
        if err != nil {
                return err
        }
 
-       cmdDir, err := os.ReadDir(path.Join(wd, bazelBinDir, "cmd"))
-       if err != nil {
-               return err
+       var entries []os.DirEntry
+       dedup := hashset.NewHashSet[string]()
+
+       for _, dir := range bazelBinDirs {
+               if dirEntries, err := os.ReadDir(path.Join(wd, dir, "cmd")); err == nil {
+                       entries = append(entries, dirEntries...)
+               }
        }
 
-       for _, entry := range cmdDir {
+       for _, entry := range entries {
                if entry.Name() == "." || entry.Name() == ".." || !entry.IsDir() {
                        continue
                }
 
                exe := executable(entry.Name())
+               if dedup.Contains(exe.pkgPath(c.Vars)) {
+                       continue
+               }
 
-               exePath := exe.buildPath(bazelBinDir)
+               var exePath string
+               for _, bazelBinDir := range bazelBinDirs {
+                       checkPath := exe.buildPath(bazelBinDir)
 
-               if _, ok := c.files[exePath]; !ok {
-                       debug("exe not allowlisted in includes: %s", exePath)
+                       if _, ok := c.files[checkPath]; ok {
+                               exePath = checkPath
+                               break
+                       }
+               }
+
+               if exePath == "" {
+                       debug("exe not allowlisted in includes: %s", entry.Name())
                        continue
                }
 
@@ -148,9 +170,12 @@ func (c *NfpmConfig) DiscoverBinaries(bazelBinDir string) error {
                        continue
                }
 
+               pkgPath := exe.pkgPath(c.Vars)
+               dedup.Add(pkgPath)
+
                c.Config.Contents = append(c.Config.Contents, &files.Content{
                        Source:      exePath,
-                       Destination: exe.pkgPath(c.Vars),
+                       Destination: pkgPath,
                        FileInfo: &files.ContentFileInfo{
                                Owner: "root",
                                Group: "root",
@@ -187,19 +212,23 @@ func recursiveDirectoryScan(baseDir string, match func(e os.DirEntry) bool) ([]s
        return out, nil
 }
 
-func (c *NfpmConfig) DiscoverSystemdUnits(bazelBinDir string) error {
-       unitFiles, err := recursiveDirectoryScan(
-               bazelBinDir,
-               func(e os.DirEntry) bool {
-                       if e.IsDir() {
-                               return false
-                       }
+func (c *NfpmConfig) DiscoverSystemdUnits(bazelBinDirs []string) error {
+       var unitFiles []string
 
-                       return systemdUnitFilename.MatchString(e.Name())
-               },
-       )
-       if err != nil {
-               return err
+       for _, bazelBinDir := range bazelBinDirs {
+               files, err := recursiveDirectoryScan(
+                       bazelBinDir,
+                       func(e os.DirEntry) bool {
+                               if e.IsDir() {
+                                       return false
+                               }
+
+                               return systemdUnitFilename.MatchString(e.Name())
+                       },
+               )
+               if err == nil {
+                       unitFiles = append(unitFiles, files...)
+               }
        }
 
        for _, f := range unitFiles {
@@ -235,6 +264,35 @@ func (c *NfpmConfig) DiscoverSystemdUnits(bazelBinDir string) error {
        return nil
 }
 
+func (c *NfpmConfig) ProcessRenameRules() error {
+       for _, r := range c.RenameRules {
+               found := false
+               src, err := subst.Eval(c.Vars, r.Source)
+               if err != nil {
+                       return err
+               }
+               dst, err := subst.Eval(c.Vars, r.Destination)
+               if err != nil {
+                       return err
+               }
+
+               for _, file := range c.Config.Contents {
+                       if file.Destination == src {
+                               found = true
+                               file.Destination = dst
+                               break
+                       }
+
+                       debug("destination: %s", file.Destination)
+               }
+
+               if !found {
+                       return fmt.Errorf("src %q not found among contents", src)
+               }
+       }
+       return nil
+}
+
 func (c *NfpmConfig) Generate() (string, error) {
        out, err := yaml.Marshal(c.Config)
        if err != nil {
index 6fa7be7241d76d81857392ff46ba1ccefd5b2314..55c72fe2114b8c44ee6579e96f78c21aed1647c5 100644 (file)
@@ -5,6 +5,7 @@ import (
        "flag"
        "fmt"
        "os"
+       "slices"
        "strings"
 
        "go.fuhry.dev/runtime/utils/subst"
@@ -49,23 +50,38 @@ func main() {
                panic(err)
        }
 
-       bazelBinDir := ""
+       var bazelBinDirs []string
        if outFile != nil && *outFile != "" {
                // pushd to the bazel-bin dir `bazel-bin/[arch]/bin` directory
                parts := strings.Split(*outFile, "/")
                if len(parts) >= 3 {
-                       bazelBinDir = strings.Join(parts[:3], "/")
+                       bazelBinDirs = append(bazelBinDirs, strings.Join(parts[:3], "/"))
                }
        }
+       for _, incl := range includes {
+               if strings.HasPrefix(incl, "bazel-out/") {
+                       parts := strings.Split(incl, "/")
+                       if len(parts) >= 3 {
+                               candidate := strings.Join(parts[:3], "/")
+                               if !slices.Contains(bazelBinDirs, candidate) {
+                                       bazelBinDirs = append(bazelBinDirs, candidate)
+                               }
+                       }
+               }
+       }
+
+       debug("loaded nfpm config template: %s\ncwd: %s\nout: %s\nbazelBinDirs: %+v\n",
+               *yamlFile, wd, *outFile, bazelBinDirs)
 
-       debug("loaded nfpm config template: %s\ncwd: %s\nout: %s\n",
-               *yamlFile, wd, *outFile)
+       if err := c.DiscoverBinaries(bazelBinDirs); err != nil {
+               panic(err)
+       }
 
-       if err := c.DiscoverBinaries(bazelBinDir); err != nil {
+       if err := c.DiscoverSystemdUnits(bazelBinDirs); err != nil {
                panic(err)
        }
 
-       if err := c.DiscoverSystemdUnits(bazelBinDir); err != nil {
+       if err := c.ProcessRenameRules(); err != nil {
                panic(err)
        }
 
index 6e87438c93c592b810f366c163cda7aa1397ed6e..763ca202ee720fe91056e971dcc80b8ea1770762 100644 (file)
@@ -6,8 +6,7 @@ section: "net"
 priority: "extra"
 replaces:
   - ${const:OrgSlug}-service-discovery
-depends:
-  - glibc
+depends: []
 conflicts:
   - ${const:OrgSlug}-service-discovery
 maintainer: "Bazel Build Service <bazelbuild@${const:RootDomain}>"
@@ -15,4 +14,18 @@ description: Tools needed by virtually all ${const:OrgName} systems for service
 vendor: "${const:OrgName}"
 homepage: "https://go.fuhry.dev/runtime"
 license: "Proprietary"
-contents: []
\ No newline at end of file
+contents: []
+rename_rules:
+  - src: "/usr/bin/${const:ExePrefix}ephs-client"
+    dst: "/usr/bin/ephs"
+
+overrides:
+  archlinux:
+    depends:
+      - glibc
+  deb:
+    depends:
+      - libc6
+  rpm:
+    depends:
+      - glibc