Skip to content
This repository has been archived by the owner on Jun 13, 2021. It is now read-only.

Introduce --iidfile option #705

Merged
merged 1 commit into from
Oct 22, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
18 changes: 17 additions & 1 deletion e2e/build_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,15 @@ package e2e
import (
"encoding/json"
"io/ioutil"
"os"
"path"
"strings"
"testing"

"gotest.tools/fs"

"github.com/docker/app/internal/store"

"github.com/deislabs/cnab-go/bundle"
"gotest.tools/assert"
"gotest.tools/icmd"
Expand All @@ -15,9 +20,11 @@ import (
func TestBuild(t *testing.T) {
runWithDindSwarmAndRegistry(t, func(info dindSwarmAndRegistryInfo) {
cmd := info.configuredCmd
tmp := fs.NewDir(t, "TestBuild")

testDir := path.Join("testdata", "build")
cmd.Command = dockerCli.Command("app", "build", "--tag", "single:1.0.0", "-f", path.Join(testDir, "single.dockerapp"), testDir)
iidfile := tmp.Join("iidfile")
cmd.Command = dockerCli.Command("app", "build", "--tag", "single:1.0.0", "--iidfile", iidfile, "-f", path.Join(testDir, "single.dockerapp"), testDir)
icmd.RunCmd(cmd).Assert(t, icmd.Success)

cfg := getDockerConfigDir(t, cmd)
Expand All @@ -34,6 +41,15 @@ func TestBuild(t *testing.T) {
cmd.Command = dockerCli.Command("inspect", ref)
icmd.RunCmd(cmd).Assert(t, icmd.Success)
}

_, err = os.Stat(iidfile)
assert.NilError(t, err)
bytes, err := ioutil.ReadFile(iidfile)
assert.NilError(t, err)
iid := string(bytes)
actualID, err := store.FromBundle(&bndl)
assert.NilError(t, err)
assert.Equal(t, iid, actualID.String())
})
}

Expand Down
79 changes: 51 additions & 28 deletions internal/commands/build/build.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,12 +32,13 @@ import (
)

type buildOptions struct {
noCache bool
progress string
pull bool
tag string
folder string
args []string
noCache bool
progress string
pull bool
tag string
folder string
imageIDFile string
args []string
}

func Cmd(dockerCli command.Cli) *cobra.Command {
Expand All @@ -48,11 +49,7 @@ func Cmd(dockerCli command.Cli) *cobra.Command {
Example: `$ docker app build --tag my/app:1.0.0 .`,
Args: cli.ExactArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
ref, err := runBuild(dockerCli, args[0], opts)
if err == nil {
fmt.Printf("Successfully build %s\n", ref.String())
}
return err
return runBuild(dockerCli, args[0], opts)
},
}

Expand All @@ -63,49 +60,78 @@ func Cmd(dockerCli command.Cli) *cobra.Command {
flags.StringVarP(&opts.folder, "folder", "f", "", "Docker app folder containing application definition")
flags.BoolVar(&opts.pull, "pull", false, "Always attempt to pull a newer version of the image")
flags.StringArrayVar(&opts.args, "build-arg", []string{}, "Set build-time variables")
flags.StringVar(&opts.imageIDFile, "iidfile", "", "Write the app image ID to the file")

return cmd
}

func runBuild(dockerCli command.Cli, contextPath string, opt buildOptions) (reference.Reference, error) {
func runBuild(dockerCli command.Cli, contextPath string, opt buildOptions) error {
err := checkMinimalEngineVersion(dockerCli)
if err != nil {
return nil, err
return err
}

if err = checkBuildArgsUniqueness(opt.args); err != nil {
return nil, err
if opt.imageIDFile != "" {
// Avoid leaving a stale file if we eventually fail
if err := os.Remove(opt.imageIDFile); err != nil && !os.IsNotExist(err) {
return err
}
}

var ref reference.Reference
ref, err = packager.GetNamedTagged(opt.tag)
if err != nil {
return nil, err
if err = checkBuildArgsUniqueness(opt.args); err != nil {
return err
}

application, err := getAppFolder(opt, contextPath)
if err != nil {
return nil, err
return err
}

app, err := packager.Extract(application)
if err != nil {
return nil, err
return err
}
defer app.Cleanup()

bundle, err := buildImageUsingBuildx(app, contextPath, opt, dockerCli)
if err != nil {
return err
}

var ref reference.Reference
ref, err = packager.GetNamedTagged(opt.tag)
if err != nil {
return err
}

id, err := packager.PersistInBundleStore(ref, bundle)
if err != nil {
return err
}

if opt.imageIDFile != "" {
if err = ioutil.WriteFile(opt.imageIDFile, []byte(id.String()), 0644); err != nil {
fmt.Fprintf(dockerCli.Err(), "Failed to write application image id in %s: %s", opt.imageIDFile, err)
}
}

fmt.Printf("Successfully built %s\n", id)
if ref != nil {
fmt.Printf("Successfully tagged %s\n", ref.String())
}
return err
}

func buildImageUsingBuildx(app *types.App, contextPath string, opt buildOptions, dockerCli command.Cli) (*bundle.Bundle, error) {
buildopts, err := parseCompose(app, contextPath, opt)
if err != nil {
return nil, err
}

buildopts["com.docker.app.invocation-image"], err = createInvocationImageBuildOptions(dockerCli, app)
if err != nil {
return nil, err
}

debugBuildOpts(buildopts)

ctx, cancel := context.WithCancel(appcontext.Context())
defer cancel()
const drivername = "buildx_buildkit_default"
Expand All @@ -119,9 +145,7 @@ func runBuild(dockerCli command.Cli, contextPath string, opt buildOptions) (refe
Driver: d,
},
}

pw := progress.NewPrinter(ctx, os.Stderr, opt.progress)

// We rely on buildx "docker" builder integrated in docker engine, so don't need a DockerAPI here
resp, err := build.Build(ctx, driverInfo, buildopts, nil, dockerCli.ConfigFile(), pw)
if err != nil {
Expand All @@ -137,8 +161,7 @@ func runBuild(dockerCli command.Cli, contextPath string, opt buildOptions) (refe
if err != nil {
return nil, err
}

return packager.PersistInBundleStore(ref, bundle)
return bundle, nil
}

func getAppFolder(opt buildOptions, contextPath string) (string, error) {
Expand Down
1 change: 1 addition & 0 deletions internal/packager/bundle.go
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ func MakeCNABImageName(appName, appVersion, suffix string) (string, error) {
return name, nil
}

// PersistInBundleStore do store a bundle with optional reference and return it's ID
func PersistInBundleStore(ref reference.Reference, bndle *bundle.Bundle) (reference.Reference, error) {
appstore, err := store.NewApplicationStore(config.Dir())
if err != nil {
Expand Down
21 changes: 12 additions & 9 deletions internal/store/bundle.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import (

//
type BundleStore interface {
// Store do store the bundle with optional reference, and return it's unique ID
Store(ref reference.Reference, bndle *bundle.Bundle) (reference.Reference, error)
Read(ref reference.Reference) (*bundle.Bundle, error)
List() ([]reference.Reference, error)
Expand Down Expand Up @@ -46,25 +47,27 @@ type bundleStore struct {
//

func (b *bundleStore) Store(ref reference.Reference, bndle *bundle.Bundle) (reference.Reference, error) {
digest, err := ComputeDigest(bndle)
if err != nil {
return nil, errors.Wrapf(err, "failed to store bundle %q", ref)
}
id := ID{digest.Encoded()}

if ref == nil {
digest, err := ComputeDigest(bndle)
if err != nil {
return nil, errors.Wrapf(err, "failed to store bundle %q", ref)
}
ref = ID{digest.Encoded()}
ref = id
}
dir, err := b.storePath(ref)
if err != nil {
return nil, errors.Wrapf(err, "failed to store bundle %q", ref)
return id, errors.Wrapf(err, "failed to store bundle %q", ref)
}
path := filepath.Join(dir, "bundle.json")
if err := os.MkdirAll(dir, 0755); err != nil {
return nil, errors.Wrapf(err, "failed to store bundle %q", ref)
return id, errors.Wrapf(err, "failed to store bundle %q", ref)
}
if err = bndle.WriteFile(path, 0644); err != nil {
return nil, errors.Wrapf(err, "failed to store bundle %q", ref)
return id, errors.Wrapf(err, "failed to store bundle %q", ref)
}
return ref, nil
return id, nil
}

func (b *bundleStore) Read(ref reference.Reference) (*bundle.Bundle, error) {
Expand Down
2 changes: 1 addition & 1 deletion internal/version.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import (

var (
// Version is the git tag that this was built from.
Version = "unknown"
Version = "v0.9.0-zeta1-20-g29f299f945"
// GitCommit is the commit that this was built from.
GitCommit = "unknown"
// BuildTime is the time at which the binary was built.
Expand Down