Skip to content
This repository was archived by the owner on Jul 18, 2025. It is now read-only.

Commit d8ad541

Browse files
committed
Introduce --iidfile option
Signed-off-by: Nicolas De Loof <[email protected]>
1 parent 277a41d commit d8ad541

File tree

5 files changed

+82
-39
lines changed

5 files changed

+82
-39
lines changed

e2e/build_test.go

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,15 @@ package e2e
33
import (
44
"encoding/json"
55
"io/ioutil"
6+
"os"
67
"path"
78
"strings"
89
"testing"
910

11+
"gotest.tools/fs"
12+
13+
"github.com/docker/app/internal/store"
14+
1015
"github.com/deislabs/cnab-go/bundle"
1116
"gotest.tools/assert"
1217
"gotest.tools/icmd"
@@ -15,9 +20,11 @@ import (
1520
func TestBuild(t *testing.T) {
1621
runWithDindSwarmAndRegistry(t, func(info dindSwarmAndRegistryInfo) {
1722
cmd := info.configuredCmd
23+
tmp := fs.NewDir(t, "TestBuild")
1824

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

2330
cfg := getDockerConfigDir(t, cmd)
@@ -34,6 +41,15 @@ func TestBuild(t *testing.T) {
3441
cmd.Command = dockerCli.Command("inspect", ref)
3542
icmd.RunCmd(cmd).Assert(t, icmd.Success)
3643
}
44+
45+
_, err = os.Stat(iidfile)
46+
assert.NilError(t, err)
47+
bytes, err := ioutil.ReadFile(iidfile)
48+
assert.NilError(t, err)
49+
iid := string(bytes)
50+
actualID, err := store.FromBundle(&bndl)
51+
assert.NilError(t, err)
52+
assert.Equal(t, iid, actualID.String())
3753
})
3854
}
3955

internal/commands/build/build.go

Lines changed: 51 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -32,12 +32,13 @@ import (
3232
)
3333

3434
type buildOptions struct {
35-
noCache bool
36-
progress string
37-
pull bool
38-
tag string
39-
folder string
40-
args []string
35+
noCache bool
36+
progress string
37+
pull bool
38+
tag string
39+
folder string
40+
imageIDFile string
41+
args []string
4142
}
4243

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

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

6765
return cmd
6866
}
6967

70-
func runBuild(dockerCli command.Cli, contextPath string, opt buildOptions) (reference.Reference, error) {
68+
func runBuild(dockerCli command.Cli, contextPath string, opt buildOptions) error {
7169
err := checkMinimalEngineVersion(dockerCli)
7270
if err != nil {
73-
return nil, err
71+
return err
7472
}
7573

76-
if err = checkBuildArgsUniqueness(opt.args); err != nil {
77-
return nil, err
74+
if opt.imageIDFile != "" {
75+
// Avoid leaving a stale file if we eventually fail
76+
if err := os.Remove(opt.imageIDFile); err != nil && !os.IsNotExist(err) {
77+
return err
78+
}
7879
}
7980

80-
var ref reference.Reference
81-
ref, err = packager.GetNamedTagged(opt.tag)
82-
if err != nil {
83-
return nil, err
81+
if err = checkBuildArgsUniqueness(opt.args); err != nil {
82+
return err
8483
}
8584

8685
application, err := getAppFolder(opt, contextPath)
8786
if err != nil {
88-
return nil, err
87+
return err
8988
}
9089

9190
app, err := packager.Extract(application)
9291
if err != nil {
93-
return nil, err
92+
return err
9493
}
9594
defer app.Cleanup()
9695

96+
bundle, err := buildImageUsingBuildx(app, contextPath, opt, dockerCli)
97+
if err != nil {
98+
return err
99+
}
100+
101+
var ref reference.Reference
102+
ref, err = packager.GetNamedTagged(opt.tag)
103+
if err != nil {
104+
return err
105+
}
106+
107+
id, err := packager.PersistInBundleStore(ref, bundle)
108+
if err != nil {
109+
return err
110+
}
111+
112+
if opt.imageIDFile != "" {
113+
if err = ioutil.WriteFile(opt.imageIDFile, []byte(id.String()), 0644); err != nil {
114+
fmt.Fprintf(dockerCli.Err(), "Failed to write application image id in %s: %s", opt.imageIDFile, err)
115+
}
116+
}
117+
118+
fmt.Printf("Successfully built %s\n", id)
119+
if ref != nil {
120+
fmt.Printf("Successfully tagged %s\n", ref.String())
121+
}
122+
return err
123+
}
124+
125+
func buildImageUsingBuildx(app *types.App, contextPath string, opt buildOptions, dockerCli command.Cli) (*bundle.Bundle, error) {
97126
buildopts, err := parseCompose(app, contextPath, opt)
98127
if err != nil {
99128
return nil, err
100129
}
101-
102130
buildopts["com.docker.app.invocation-image"], err = createInvocationImageBuildOptions(dockerCli, app)
103131
if err != nil {
104132
return nil, err
105133
}
106-
107134
debugBuildOpts(buildopts)
108-
109135
ctx, cancel := context.WithCancel(appcontext.Context())
110136
defer cancel()
111137
const drivername = "buildx_buildkit_default"
@@ -119,9 +145,7 @@ func runBuild(dockerCli command.Cli, contextPath string, opt buildOptions) (refe
119145
Driver: d,
120146
},
121147
}
122-
123148
pw := progress.NewPrinter(ctx, os.Stderr, opt.progress)
124-
125149
// We rely on buildx "docker" builder integrated in docker engine, so don't need a DockerAPI here
126150
resp, err := build.Build(ctx, driverInfo, buildopts, nil, dockerCli.ConfigFile(), pw)
127151
if err != nil {
@@ -137,8 +161,7 @@ func runBuild(dockerCli command.Cli, contextPath string, opt buildOptions) (refe
137161
if err != nil {
138162
return nil, err
139163
}
140-
141-
return packager.PersistInBundleStore(ref, bundle)
164+
return bundle, nil
142165
}
143166

144167
func getAppFolder(opt buildOptions, contextPath string) (string, error) {

internal/packager/bundle.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@ func MakeCNABImageName(appName, appVersion, suffix string) (string, error) {
7070
return name, nil
7171
}
7272

73+
// PersistInBundleStore do store a bundle with optional reference and return it's ID
7374
func PersistInBundleStore(ref reference.Reference, bndle *bundle.Bundle) (reference.Reference, error) {
7475
appstore, err := store.NewApplicationStore(config.Dir())
7576
if err != nil {

internal/store/bundle.go

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import (
1616

1717
//
1818
type BundleStore interface {
19+
// Store do store the bundle with optional reference, and return it's unique ID
1920
Store(ref reference.Reference, bndle *bundle.Bundle) (reference.Reference, error)
2021
Read(ref reference.Reference) (*bundle.Bundle, error)
2122
List() ([]reference.Reference, error)
@@ -46,25 +47,27 @@ type bundleStore struct {
4647
//
4748

4849
func (b *bundleStore) Store(ref reference.Reference, bndle *bundle.Bundle) (reference.Reference, error) {
50+
digest, err := ComputeDigest(bndle)
51+
if err != nil {
52+
return nil, errors.Wrapf(err, "failed to store bundle %q", ref)
53+
}
54+
id := ID{digest.Encoded()}
55+
4956
if ref == nil {
50-
digest, err := ComputeDigest(bndle)
51-
if err != nil {
52-
return nil, errors.Wrapf(err, "failed to store bundle %q", ref)
53-
}
54-
ref = ID{digest.Encoded()}
57+
ref = id
5558
}
5659
dir, err := b.storePath(ref)
5760
if err != nil {
58-
return nil, errors.Wrapf(err, "failed to store bundle %q", ref)
61+
return id, errors.Wrapf(err, "failed to store bundle %q", ref)
5962
}
6063
path := filepath.Join(dir, "bundle.json")
6164
if err := os.MkdirAll(dir, 0755); err != nil {
62-
return nil, errors.Wrapf(err, "failed to store bundle %q", ref)
65+
return id, errors.Wrapf(err, "failed to store bundle %q", ref)
6366
}
6467
if err = bndle.WriteFile(path, 0644); err != nil {
65-
return nil, errors.Wrapf(err, "failed to store bundle %q", ref)
68+
return id, errors.Wrapf(err, "failed to store bundle %q", ref)
6669
}
67-
return ref, nil
70+
return id, nil
6871
}
6972

7073
func (b *bundleStore) Read(ref reference.Reference) (*bundle.Bundle, error) {

internal/version.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import (
99

1010
var (
1111
// Version is the git tag that this was built from.
12-
Version = "unknown"
12+
Version = "v0.9.0-zeta1-20-g29f299f945"
1313
// GitCommit is the commit that this was built from.
1414
GitCommit = "unknown"
1515
// BuildTime is the time at which the binary was built.

0 commit comments

Comments
 (0)