diff --git a/buildpack.go b/buildpack.go index e1c2d5c..ed5f675 100644 --- a/buildpack.go +++ b/buildpack.go @@ -18,8 +18,10 @@ package libpak import ( "fmt" + "net/url" "os" "reflect" + "runtime" "sort" "strconv" "strings" @@ -506,6 +508,15 @@ func (d *DependencyResolver) Resolve(id string, version string) (BuildpackDepend return BuildpackDependency{}, fmt.Errorf("unable to parse version %s\n%w", c.Version, err) } + // filter out deps that do not match the current running architecture + arch, err := archFromPURL(c.PURL) + if err != nil { + return BuildpackDependency{}, fmt.Errorf("unable to compare arch\n%w", err) + } + if arch != archFromSystem() { + continue + } + if c.ID == id && vc.Check(v) && d.contains(c.Stacks, d.StackID) { candidates = append(candidates, c) } @@ -534,6 +545,33 @@ func (d *DependencyResolver) Resolve(id string, version string) (BuildpackDepend return candidate, nil } +func archFromPURL(rawPURL string) (string, error) { + if len(strings.TrimSpace(rawPURL)) == 0 { + return "amd64", nil + } + + purl, err := url.Parse(rawPURL) + if err != nil { + return "", fmt.Errorf("unable to parse PURL\n%w", err) + } + + queryParams := purl.Query() + if arch, ok := queryParams["arch"]; ok { + return arch[0], nil + } + + return "amd64", nil +} + +func archFromSystem() string { + archFromEnv, ok := os.LookupEnv("BP_ARCH") + if !ok { + archFromEnv = runtime.GOARCH + } + + return archFromEnv +} + func (DependencyResolver) contains(candidates []string, value string) bool { if len(candidates) == 0 { return true diff --git a/buildpack_test.go b/buildpack_test.go index ee3bdda..a881752 100644 --- a/buildpack_test.go +++ b/buildpack_test.go @@ -282,6 +282,10 @@ func testBuildpack(t *testing.T, context spec.G, it spec.S) { resolver libpak.DependencyResolver ) + it.Before(func() { + t.Setenv("BP_ARCH", "amd64") // force for test consistency + }) + context("Resolve", func() { it("filters by id", func() { @@ -315,6 +319,42 @@ func testBuildpack(t *testing.T, context spec.G, it spec.S) { })) }) + it("filters by arch", func() { + resolver.Dependencies = []libpak.BuildpackDependency{ + { + ID: "test-id-1", + Name: "test-name", + Version: "1.0", + URI: "test-uri-amd64", + SHA256: "test-sha256", + Stacks: []string{"test-stack-1", "test-stack-2"}, + PURL: "pkg:generic/bellsoft-jdk@8.0.382?arch=amd64", + }, + { + ID: "test-id-1", + Name: "test-name", + Version: "1.0", + URI: "test-uri-arm64", + SHA256: "test-sha256", + Stacks: []string{"test-stack-1", "test-stack-2"}, + PURL: "pkg:generic/bellsoft-jdk@8.0.382?arch=arm64", + }, + } + resolver.StackID = "test-stack-1" + + t.Setenv("BP_ARCH", "arm64") + + Expect(resolver.Resolve("test-id-1", "1.0")).To(Equal(libpak.BuildpackDependency{ + ID: "test-id-1", + Name: "test-name", + Version: "1.0", + URI: "test-uri-arm64", + SHA256: "test-sha256", + Stacks: []string{"test-stack-1", "test-stack-2"}, + PURL: "pkg:generic/bellsoft-jdk@8.0.382?arch=arm64", + })) + }) + it("filters by version constraint", func() { resolver.Dependencies = []libpak.BuildpackDependency{ { diff --git a/carton/package.go b/carton/package.go index 1a2267f..f6251b7 100644 --- a/carton/package.go +++ b/carton/package.go @@ -89,7 +89,7 @@ func (p Package) Create(options ...Option) { config.exitHandler.Error(fmt.Errorf("unable to decode buildpack %s\n%w", file, err)) return } - logger.Debug("Buildpack: %+v", buildpack) + logger.Debugf("Buildpack: %+v", buildpack) metadata, err := libpak.NewBuildpackMetadata(buildpack.Metadata) if err != nil { @@ -102,7 +102,7 @@ func (p Package) Create(options ...Option) { for _, i := range metadata.IncludeFiles { entries[i] = filepath.Join(p.Source, i) } - logger.Debug("Include files: %+v", entries) + logger.Debugf("Include files: %+v", entries) if p.Version != "" { buildpack.Info.Version = p.Version