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  }