github.com/docker/app@v0.9.1-beta3.0.20210611140623-a48f773ab002/internal/packager/bundle.go (about) 1 package packager 2 3 import ( 4 "bytes" 5 "context" 6 "fmt" 7 "io/ioutil" 8 9 "github.com/docker/app/internal/image" 10 11 "github.com/deislabs/cnab-go/bundle" 12 "github.com/docker/app/internal/store" 13 "github.com/docker/app/types" 14 "github.com/docker/app/types/metadata" 15 "github.com/docker/cli/cli/command" 16 "github.com/docker/cli/cli/config" 17 "github.com/docker/distribution/reference" 18 dockertypes "github.com/docker/docker/api/types" 19 "github.com/docker/docker/pkg/jsonmessage" 20 "github.com/pkg/errors" 21 "github.com/sirupsen/logrus" 22 ) 23 24 func MakeBundleFromApp(dockerCli command.Cli, app *types.App, refOverride reference.NamedTagged) (*bundle.Bundle, error) { 25 logrus.Debug("Making app bundle") 26 meta := app.Metadata() 27 invocationImageName, err := MakeInvocationImageName(meta, refOverride) 28 if err != nil { 29 return nil, err 30 } 31 32 buildContext := bytes.NewBuffer(nil) 33 if err := PackInvocationImageContext(dockerCli, app, buildContext); err != nil { 34 return nil, err 35 } 36 37 logrus.Debugf("Building invocation image %s", invocationImageName) 38 buildResp, err := dockerCli.Client().ImageBuild(context.TODO(), buildContext, dockertypes.ImageBuildOptions{ 39 Dockerfile: "Dockerfile", 40 Tags: []string{invocationImageName}, 41 BuildArgs: map[string]*string{}, 42 }) 43 if err != nil { 44 return nil, err 45 } 46 defer buildResp.Body.Close() 47 48 if err := jsonmessage.DisplayJSONMessagesStream(buildResp.Body, ioutil.Discard, 0, false, func(jsonmessage.JSONMessage) {}); err != nil { 49 // If the invocation image can't be found we will get an error of the form: 50 // manifest for docker/cnab-app-base:v0.6.0-202-gbaf0b246c7 not found 51 if err.Error() == fmt.Sprintf("manifest for %s not found", BaseInvocationImage(dockerCli)) { 52 return nil, fmt.Errorf("unable to resolve Docker App base image: %s", BaseInvocationImage(dockerCli)) 53 } 54 return nil, err 55 } 56 57 return ToCNAB(app, invocationImageName) 58 } 59 60 func MakeInvocationImageName(meta metadata.AppMetadata, refOverride reference.NamedTagged) (string, error) { 61 if refOverride != nil { 62 return MakeCNABImageName(reference.FamiliarName(refOverride), refOverride.Tag(), "-invoc") 63 } 64 return MakeCNABImageName(meta.Name, meta.Version, "-invoc") 65 } 66 67 func MakeCNABImageName(appName, appVersion, suffix string) (string, error) { 68 name := fmt.Sprintf("%s:%s%s", appName, appVersion, suffix) 69 if _, err := reference.ParseNormalizedNamed(name); err != nil { 70 return "", errors.Wrapf(err, "image name %q is invalid, please check name and version fields", name) 71 } 72 return name, nil 73 } 74 75 // PersistInImageStore do store a bundle with optional reference and return it's ID 76 func PersistInImageStore(ref reference.Reference, bndl *bundle.Bundle) (reference.Digested, error) { 77 appstore, err := store.NewApplicationStore(config.Dir()) 78 if err != nil { 79 return nil, err 80 } 81 imageStore, err := appstore.ImageStore() 82 if err != nil { 83 return nil, err 84 } 85 return imageStore.Store(image.FromBundle(bndl), ref) 86 } 87 88 func GetNamedTagged(tag string) (reference.NamedTagged, error) { 89 if tag == "" { 90 return nil, nil 91 } 92 namedRef, err := reference.ParseNormalizedNamed(tag) 93 if err != nil { 94 return nil, err 95 } 96 ref, ok := reference.TagNameOnly(namedRef).(reference.NamedTagged) 97 if !ok { 98 return nil, fmt.Errorf("tag %q must be name with a tag in the 'name:tag' format", tag) 99 } 100 return ref, nil 101 }