Skip to content

Commit

Permalink
Merge pull request #2010 from carolynvs/fix-build-on-arm
Browse files Browse the repository at this point in the history
Fallback to amd64 on M1 when installing binaries
  • Loading branch information
carolynvs authored Apr 7, 2022
2 parents 39a5cbe + b7e76e8 commit 5ca26b5
Show file tree
Hide file tree
Showing 16 changed files with 199 additions and 91 deletions.
2 changes: 1 addition & 1 deletion cmd/porter/mixins.go
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ By default mixins are downloaded from the official Porter mixin feed at https://
return opts.Validate(args)
},
RunE: func(cmd *cobra.Command, args []string) error {
return p.InstallMixin(opts)
return p.InstallMixin(cmd.Context(), opts)
},
}

Expand Down
2 changes: 1 addition & 1 deletion cmd/porter/plugins.go
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ By default plugins are downloaded from the official Porter plugin feed at https:
return opts.Validate(args)
},
RunE: func(cmd *cobra.Command, args []string) error {
return p.InstallPlugin(opts)
return p.InstallPlugin(cmd.Context(), opts)
},
}

Expand Down
2 changes: 1 addition & 1 deletion docs/content/cli/build.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ porter build [flags]
-f, --file porter.yaml Path to the Porter manifest. Defaults to porter.yaml in the current directory.
-h, --help help for build
--name string Override the bundle name
--no-cache Do not use cache when building the image.
--no-cache Do not use the Docker cache when building the bundle's invocation image.
--no-lint Do not run the linter
--secret stringArray Secret file to expose to the build (format: id=mysecret,src=/local/secret). May be specified multiple times.
--ssh stringArray SSH agent socket or keys to expose to the build (format: default|<id>[=<socket>|<key>[,<key>]]). May be specified multiple times.
Expand Down
2 changes: 1 addition & 1 deletion docs/content/cli/bundles_build.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ porter bundles build [flags]
-f, --file porter.yaml Path to the Porter manifest. Defaults to porter.yaml in the current directory.
-h, --help help for build
--name string Override the bundle name
--no-cache Do not use cache when building the image.
--no-cache Do not use the Docker cache when building the bundle's invocation image.
--no-lint Do not run the linter
--secret stringArray Secret file to expose to the build (format: id=mysecret,src=/local/secret). May be specified multiple times.
--ssh stringArray SSH agent socket or keys to expose to the build (format: default|<id>[=<socket>|<key>[,<key>]]). May be specified multiple times.
Expand Down
4 changes: 2 additions & 2 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,12 @@ replace (
)

require (
get.porter.sh/magefiles v0.1.2
get.porter.sh/magefiles v0.1.3
github.com/Masterminds/semver/v3 v3.1.1
github.com/PaesslerAG/jsonpath v0.1.1
github.com/carolynvs/aferox v0.3.0
github.com/carolynvs/datetime-printer v0.2.0
github.com/carolynvs/magex v0.7.0
github.com/carolynvs/magex v0.7.2
github.com/cbroglie/mustache v1.0.1
github.com/cnabio/cnab-go v0.23.1
github.com/cnabio/cnab-to-oci v0.3.3
Expand Down
8 changes: 4 additions & 4 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -53,8 +53,8 @@ contrib.go.opencensus.io/exporter/stackdriver v0.12.1/go.mod h1:iwB6wGarfphGGe/e
contrib.go.opencensus.io/integrations/ocsql v0.1.4/go.mod h1:8DsSdjz3F+APR+0z0WkU1aRorQCFfRxvqjUUPMbF3fE=
contrib.go.opencensus.io/resource v0.1.1/go.mod h1:F361eGI91LCmW1I/Saf+rX0+OFcigGlFvXwEGEnkRLA=
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
get.porter.sh/magefiles v0.1.2 h1:9AybljWeUDGKhMwwHYa8wnvtZ1VDPv5i3uHZTwnIysI=
get.porter.sh/magefiles v0.1.2/go.mod h1:wtCIGWp79ARl8Agt1JE4Wchtb0Pn9fea/7LbkOnFbEc=
get.porter.sh/magefiles v0.1.3 h1:91Y7vFDHGmMBbRfHQqEcIlqpp/RfDCMhyHGVusTYlmE=
get.porter.sh/magefiles v0.1.3/go.mod h1:Whw/DSX8dcgn7dUPb6csbY6PtuTy1wujwFR2G6ONf20=
git.apache.org/thrift.git v0.0.0-20180902110319-2566ecd5d999/go.mod h1:fPE2ZNJGynbRyZ4dJvy6G277gSllfV2HJqblrnkyeyg=
git.apache.org/thrift.git v0.12.0/go.mod h1:fPE2ZNJGynbRyZ4dJvy6G277gSllfV2HJqblrnkyeyg=
github.com/AdaLogics/go-fuzz-headers v0.0.0-20210715213245-6c3934b029d8/go.mod h1:CzsSbkDixRphAF5hS6wbMKq0eI6ccJRb7/A0M6JBnwg=
Expand Down Expand Up @@ -276,8 +276,8 @@ github.com/carolynvs/aferox v0.3.0 h1:CMT50zX88amTMbFfFIWSTKRVRaOw6sejUMbbKiCD4z
github.com/carolynvs/aferox v0.3.0/go.mod h1:eb7CHGIO33CCZS//xtnblvPZbuuZMv0p1VbhiSwZnH4=
github.com/carolynvs/datetime-printer v0.2.0 h1:Td3FU4YGzx0OogCMhCmLBTUTDPQcq0xlgCeMhAKZmMc=
github.com/carolynvs/datetime-printer v0.2.0/go.mod h1:p9W8ZUhmQUOVD5kiDuGXwRG65/nTkZWlLylY7s+Qw2k=
github.com/carolynvs/magex v0.7.0 h1:z5PaWogvA/kOHMYueXqlQBobXt32N/a7kZXPvK9V728=
github.com/carolynvs/magex v0.7.0/go.mod h1:vZB3BkRfkd5ZMtkxJkCGbdFyWGoZiuNPKhx6uEQARmY=
github.com/carolynvs/magex v0.7.2 h1:6IpoxUorSDOXtZmd72ExPCzQBxkeUj09JwJfnzf+9y8=
github.com/carolynvs/magex v0.7.2/go.mod h1:vZB3BkRfkd5ZMtkxJkCGbdFyWGoZiuNPKhx6uEQARmY=
github.com/casbin/casbin/v2 v2.1.2/go.mod h1:YcPU1XXisHhLzuxH9coDNf2FbKpjGlbCg3n9yuLkIJQ=
github.com/cavaliercoder/go-cpio v0.0.0-20180626203310-925f9528c45e/go.mod h1:oDpT4efm8tSYHXV5tHSdRvBet/b/QzxZ+XyyPehvm3A=
github.com/cbroglie/mustache v1.0.1 h1:ivMg8MguXq/rrz2eu3tw6g3b16+PQhoTn6EZAhst2mw=
Expand Down
3 changes: 2 additions & 1 deletion pkg/pkgmgmt/client/helpers.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package client

import (
"context"
"fmt"
"path"
"testing"
Expand Down Expand Up @@ -40,7 +41,7 @@ func (p *TestPackageManager) GetMetadata(name string) (pkgmgmt.PackageMetadata,
return nil, fmt.Errorf("%s %s not installed", p.PkgType, name)
}

func (p *TestPackageManager) Install(o pkgmgmt.InstallOptions) error {
func (p *TestPackageManager) Install(ctx context.Context, opts pkgmgmt.InstallOptions) error {
// do nothing
return nil
}
Expand Down
95 changes: 57 additions & 38 deletions pkg/pkgmgmt/client/install.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package client

import (
"context"
"encoding/json"
"fmt"
"io"
Expand All @@ -13,45 +14,47 @@ import (
"get.porter.sh/porter/pkg"
"get.porter.sh/porter/pkg/pkgmgmt"
"get.porter.sh/porter/pkg/pkgmgmt/feed"
"github.com/pkg/errors"
"get.porter.sh/porter/pkg/tracing"
)

const PackageCacheJSON string = "cache.json"

func (fs *FileSystem) Install(opts pkgmgmt.InstallOptions) error {
func (fs *FileSystem) Install(ctx context.Context, opts pkgmgmt.InstallOptions) error {
var err error
if opts.FeedURL != "" {
err = fs.InstallFromFeedURL(opts)
err = fs.InstallFromFeedURL(ctx, opts)
} else {
err = fs.InstallFromURL(opts)
err = fs.InstallFromURL(ctx, opts)
}
if err != nil {
return err
}
return fs.savePackageInfo(opts)
return fs.savePackageInfo(ctx, opts)
}

func (fs *FileSystem) savePackageInfo(opts pkgmgmt.InstallOptions) error {
func (fs *FileSystem) savePackageInfo(ctx context.Context, opts pkgmgmt.InstallOptions) error {
log := tracing.LoggerFromContext(ctx)

parentDir, _ := fs.GetPackagesDir()
cacheJSONPath := filepath.Join(parentDir, "/", PackageCacheJSON)
exists, _ := fs.FileSystem.Exists(cacheJSONPath)
if !exists {
_, err := fs.FileSystem.Create(cacheJSONPath)
if err != nil {
return errors.Wrapf(err, "error creating %s package cache.json", fs.PackageType)
return log.Errorf("error creating %s package cache.json: %w", fs.PackageType, err)
}
}

cacheContentsB, err := fs.FileSystem.ReadFile(cacheJSONPath)
if err != nil {
return errors.Wrapf(err, "error reading package %s cache.json", fs.PackageType)
return log.Errorf("error reading package %s cache.json: %w", fs.PackageType, err)
}

pkgDataJSON := &packages{}
if len(cacheContentsB) > 0 {
err = json.Unmarshal(cacheContentsB, &pkgDataJSON)
if err != nil {
return errors.Wrapf(err, "error unmarshalling from %s package cache.json", fs.PackageType)
return log.Errorf("error unmarshalling from %s package cache.json: %w", fs.PackageType, err)
}
}
//if a package exists, skip.
Expand All @@ -64,12 +67,12 @@ func (fs *FileSystem) savePackageInfo(opts pkgmgmt.InstallOptions) error {
pkgDataJSON.Packages = updatedPkgList
updatedPkgInfo, err := json.MarshalIndent(&pkgDataJSON, "", " ")
if err != nil {
return errors.Wrapf(err, "error marshalling to %s package cache.json", fs.PackageType)
return log.Errorf("error marshalling to %s package cache.json: %w", fs.PackageType, err)
}
err = fs.FileSystem.WriteFile(cacheJSONPath, updatedPkgInfo, pkg.FileModeWritable)

if err != nil {
return errors.Wrapf(err, "error adding package info to %s cache.json", fs.PackageType)
return log.Errorf("error adding package info to %s cache.json: %w", fs.PackageType, err)
}
return nil
}
Expand All @@ -84,26 +87,41 @@ type packages struct {
Packages []PackageInfo `json:"packages"`
}

func (fs *FileSystem) InstallFromURL(opts pkgmgmt.InstallOptions) error {
func (fs *FileSystem) InstallFromURL(ctx context.Context, opts pkgmgmt.InstallOptions) error {
return fs.installFromURLFor(ctx, opts, runtime.GOOS, runtime.GOARCH)
}

func (fs *FileSystem) installFromURLFor(ctx context.Context, opts pkgmgmt.InstallOptions, os string, arch string) error {
log := tracing.LoggerFromContext(ctx)

clientUrl := opts.GetParsedURL()
clientUrl.Path = path.Join(clientUrl.Path, opts.Version, fmt.Sprintf("%s-%s-%s%s", opts.Name, runtime.GOOS, runtime.GOARCH, pkgmgmt.FileExt))
clientUrl.Path = path.Join(clientUrl.Path, opts.Version, fmt.Sprintf("%s-%s-%s%s", opts.Name, os, arch, pkgmgmt.FileExt))

runtimeUrl := opts.GetParsedURL()
runtimeUrl.Path = path.Join(runtimeUrl.Path, opts.Version, fmt.Sprintf("%s-linux-amd64", opts.Name))

return fs.downloadPackage(opts.Name, clientUrl, runtimeUrl)
err := fs.downloadPackage(ctx, opts.Name, clientUrl, runtimeUrl)
if err != nil && os == "darwin" && arch == "arm64" {
// Until we have full support for M1 chipsets, rely on rossetta functionality in macos and use the amd64 binary
log.Debugf("%s @ %s did not publish a download for darwin/amd64, falling back to darwin/amd64", opts.Name, opts.Version)
return fs.installFromURLFor(ctx, opts, "darwin", "amd64")
}

return err
}

func (fs *FileSystem) InstallFromFeedURL(opts pkgmgmt.InstallOptions) error {
func (fs *FileSystem) InstallFromFeedURL(ctx context.Context, opts pkgmgmt.InstallOptions) error {
log := tracing.LoggerFromContext(ctx)

feedUrl := opts.GetParsedFeedURL()
tmpDir, err := fs.FileSystem.TempDir("", "porter")
if err != nil {
return errors.Wrap(err, "error creating temp directory")
return log.Errorf("error creating temp directory: %w", err)
}
defer fs.FileSystem.RemoveAll(tmpDir)
feedPath := filepath.Join(tmpDir, "atom.xml")

err = fs.downloadFile(feedUrl, feedPath, false)
err = fs.downloadFile(ctx, feedUrl, feedPath, false)
if err != nil {
return err
}
Expand All @@ -116,37 +134,37 @@ func (fs *FileSystem) InstallFromFeedURL(opts pkgmgmt.InstallOptions) error {

result := searchFeed.Search(opts.Name, opts.Version)
if result == nil {
return errors.Errorf("the feed at %s does not contain an entry for %s @ %s", opts.FeedURL, opts.Name, opts.Version)
return log.Errorf("the feed at %s does not contain an entry for %s @ %s", opts.FeedURL, opts.Name, opts.Version)
}

clientUrl := result.FindDownloadURL(runtime.GOOS, runtime.GOARCH)
clientUrl := result.FindDownloadURL(ctx, runtime.GOOS, runtime.GOARCH)
if clientUrl == nil {
return errors.Errorf("%s @ %s did not publish a download for %s/%s", opts.Name, opts.Version, runtime.GOOS, runtime.GOARCH)
return log.Errorf("%s @ %s did not publish a download for %s/%s", opts.Name, opts.Version, runtime.GOOS, runtime.GOARCH)
}

runtimeUrl := result.FindDownloadURL("linux", "amd64")
runtimeUrl := result.FindDownloadURL(ctx, "linux", "amd64")
if runtimeUrl == nil {
return errors.Errorf("%s @ %s did not publish a download for linux/amd64", opts.Name, opts.Version)
return log.Errorf("%s @ %s did not publish a download for linux/amd64", opts.Name, opts.Version)
}

return fs.downloadPackage(opts.Name, *clientUrl, *runtimeUrl)
return fs.downloadPackage(ctx, opts.Name, *clientUrl, *runtimeUrl)
}

func (fs *FileSystem) downloadPackage(name string, clientUrl url.URL, runtimeUrl url.URL) error {
func (fs *FileSystem) downloadPackage(ctx context.Context, name string, clientUrl url.URL, runtimeUrl url.URL) error {
parentDir, err := fs.GetPackagesDir()
if err != nil {
return err
}
pkgDir := filepath.Join(parentDir, name)

clientPath := fs.BuildClientPath(pkgDir, name)
err = fs.downloadFile(clientUrl, clientPath, true)
err = fs.downloadFile(ctx, clientUrl, clientPath, true)
if err != nil {
return err
}

runtimePath := filepath.Join(pkgDir, "runtimes", name+"-runtime")
err = fs.downloadFile(runtimeUrl, runtimePath, true)
err = fs.downloadFile(ctx, runtimeUrl, runtimePath, true)
if err != nil {
fs.FileSystem.RemoveAll(pkgDir) // If the runtime download fails, cleanup the package so it's not half installed
return err
Expand All @@ -155,37 +173,38 @@ func (fs *FileSystem) downloadPackage(name string, clientUrl url.URL, runtimeUrl
return nil
}

func (fs *FileSystem) downloadFile(url url.URL, destPath string, executable bool) error {
if fs.Debug {
fmt.Fprintf(fs.Err, "Downloading %s to %s\n", url.String(), destPath)
}
func (fs *FileSystem) downloadFile(ctx context.Context, url url.URL, destPath string, executable bool) error {
log := tracing.LoggerFromContext(ctx)
log.Debugf("Downloading %s to %s\n", url.String(), destPath)

req, err := http.NewRequest(http.MethodGet, url.String(), nil)
if err != nil {
return errors.Wrapf(err, "error creating web request to %s", url.String())
return log.Errorf("error creating web request to %s: %w", url.String(), err)
}

resp, err := http.DefaultClient.Do(req)
if err != nil {
return errors.Wrapf(err, "error downloading %s", url.String())
return log.Errorf("error downloading %s: %w", url.String(), err)
}
if resp.StatusCode != 200 {
return errors.Errorf("bad status returned when downloading %s (%d) %s", url.String(), resp.StatusCode, resp.Status)
err := fmt.Errorf("bad status returned when downloading %s (%d) %s", url.String(), resp.StatusCode, resp.Status)
log.Debugf(err.Error()) // Only debug log this since higher up on the stack we may handle this error
return err
}
defer resp.Body.Close()

// Ensure the parent directories exist
parentDir := filepath.Dir(destPath)
parentDirExists, err := fs.FileSystem.DirExists(parentDir)
if err != nil {
return errors.Wrapf(err, "unable to check if directory exists %s", parentDir)
return log.Errorf("unable to check if directory exists %s: %w", parentDir, err)
}

cleanup := func() {}
if !parentDirExists {
err = fs.FileSystem.MkdirAll(parentDir, pkg.FileModeDirectory)
if err != nil {
errors.Wrapf(err, "unable to create parent directory %s", parentDir)
return log.Errorf("unable to create parent directory %s: %w", parentDir, err)
}
cleanup = func() {
fs.FileSystem.RemoveAll(parentDir) // If we can't download the file, don't leave traces of it
Expand All @@ -195,22 +214,22 @@ func (fs *FileSystem) downloadFile(url url.URL, destPath string, executable bool
destFile, err := fs.FileSystem.Create(destPath)
if err != nil {
cleanup()
return errors.Wrapf(err, "could not create the file at %s", destPath)
return log.Errorf("could not create the file at %s: %w", destPath, err)
}
defer destFile.Close()

if executable {
err = fs.FileSystem.Chmod(destPath, pkg.FileModeExecutable)
if err != nil {
cleanup()
return errors.Wrapf(err, "could not set the file as executable at %s", destPath)
return log.Errorf("could not set the file as executable at %s: %w", destPath, err)
}
}

_, err = io.Copy(destFile, resp.Body)
if err != nil {
cleanup()
return errors.Wrapf(err, "error writing the file to %s", destPath)
return log.Errorf("error writing the file to %s: %w", destPath, err)
}
return nil
}
Loading

0 comments on commit 5ca26b5

Please sign in to comment.