From 763ed5b9bc47e144e6a5fab47adc2a8de6b7a20b Mon Sep 17 00:00:00 2001 From: Daniel Mikusa Date: Sun, 29 Oct 2023 00:28:59 -0400 Subject: [PATCH] Add support for ARM64 support in DependencyResolver This commit adds support to DependencyResolver.Resolve to pick a Dependency and consider the architecture. It looks at either `BP_ARCH` (if set) or `runtime.GOARCH` otherwise. It then compares this to the `arch=` value that is set in PURL. We are using the PURL because it exists already and already contains the arch info. This is opposed to adding a new property to the dependency metadata. We *may* end up doing that still, but this just gets things working more quickly now and we can change this in the future. Signed-off-by: Daniel Mikusa --- buildpack.go | 38 ++++++++++++++++++++++++++++++++++++++ buildpack_test.go | 40 ++++++++++++++++++++++++++++++++++++++++ carton/package.go | 4 ++-- 3 files changed, 80 insertions(+), 2 deletions(-) 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