Skip to content

Commit 9d3c523

Browse files
csweichelaledbf
authored andcommitted
[docker] Pass dependency image names as build args
Do enable chaining Docker packages and re-using a prior build as base image.
1 parent 19bb625 commit 9d3c523

File tree

4 files changed

+185
-17
lines changed

4 files changed

+185
-17
lines changed

pkg/leeway/build.go

Lines changed: 72 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,14 @@ package leeway
22

33
import (
44
"archive/tar"
5+
"compress/gzip"
56
"context"
67
"crypto/rand"
78
"crypto/sha256"
89
"encoding/base64"
910
"encoding/hex"
1011
"encoding/json"
12+
"errors"
1113
"fmt"
1214
"io"
1315
"os"
@@ -1239,7 +1241,10 @@ func (p *Package) buildDocker(buildctx *buildContext, wd, result string) (res *p
12391241
return nil, err
12401242
}
12411243

1242-
var buildCommands [][]string
1244+
var (
1245+
buildCommands [][]string
1246+
imageDependencies = make(map[string]string)
1247+
)
12431248
buildCommands = append(buildCommands, []string{"cp", dockerfile, "Dockerfile"})
12441249
for _, dep := range p.GetDependencies() {
12451250
fn, exists := buildctx.LocalCache.Location(dep)
@@ -1252,6 +1257,15 @@ func (p *Package) buildDocker(buildctx *buildContext, wd, result string) (res *p
12521257
{"mkdir", tgt},
12531258
{"tar", "xfz", fn, "--no-same-owner", "-C", tgt},
12541259
}...)
1260+
1261+
if dep.Type != DockerPackage {
1262+
continue
1263+
}
1264+
depimg, err := extractImageNameFromCache(dep.Name, fn)
1265+
if err != nil {
1266+
return nil, err
1267+
}
1268+
imageDependencies[strings.ToUpper(strings.ReplaceAll(dep.FilesystemSafeName(), "-", "_"))] = depimg
12551269
}
12561270

12571271
buildCommands = append(buildCommands, p.PreparationCommands...)
@@ -1265,6 +1279,9 @@ func (p *Package) buildDocker(buildctx *buildContext, wd, result string) (res *p
12651279
for arg, val := range cfg.BuildArgs {
12661280
buildcmd = append(buildcmd, "--build-arg", fmt.Sprintf("%s=%s", arg, val))
12671281
}
1282+
for arg, val := range imageDependencies {
1283+
buildcmd = append(buildcmd, "--build-arg", fmt.Sprintf("DEP_%s=%s", arg, val))
1284+
}
12681285
buildcmd = append(buildcmd, "--build-arg", fmt.Sprintf("__GIT_COMMIT=%s", p.C.Git().Commit))
12691286
if cfg.Squash {
12701287
buildcmd = append(buildcmd, "--squash")
@@ -1415,6 +1432,60 @@ func dockerExportPostBuild(builddir, result string) func(sources fileset) (subj
14151432
}
14161433
}
14171434

1435+
// extractImageNameFromCache extracts the Docker image name of a previously built package
1436+
// from the cache tar.gz file of that package.
1437+
func extractImageNameFromCache(pkgName, cacheBundleFN string) (imgname string, err error) {
1438+
defer func() {
1439+
if err != nil {
1440+
err = fmt.Errorf("cannot extract image ref from cache for %s: %w", pkgName, err)
1441+
}
1442+
}()
1443+
1444+
f, err := os.Open(cacheBundleFN)
1445+
if err != nil {
1446+
return "", err
1447+
}
1448+
defer f.Close()
1449+
1450+
gzin, err := gzip.NewReader(f)
1451+
if err != nil {
1452+
return "", err
1453+
}
1454+
defer gzin.Close()
1455+
1456+
tarin := tar.NewReader(gzin)
1457+
for {
1458+
hdr, err := tarin.Next()
1459+
if errors.Is(err, io.EOF) {
1460+
break
1461+
}
1462+
if err != nil {
1463+
return "", err
1464+
}
1465+
1466+
if hdr.Typeflag != tar.TypeReg {
1467+
continue
1468+
}
1469+
if filepath.Base(hdr.Name) != dockerImageNamesFiles {
1470+
continue
1471+
}
1472+
1473+
imgnames := make([]byte, hdr.Size)
1474+
n, err := io.ReadFull(tarin, imgnames)
1475+
if err != nil {
1476+
return "", err
1477+
}
1478+
if int64(n) != hdr.Size {
1479+
return "", fmt.Errorf("cannot read %s from cache: %w", dockerImageNamesFiles, io.ErrShortBuffer)
1480+
}
1481+
1482+
lines := strings.Split(string(imgnames), "\n")
1483+
return lines[0], nil
1484+
}
1485+
1486+
return "", nil
1487+
}
1488+
14181489
// buildGeneric implements the build process for generic packages.
14191490
// If you change anything in this process that's not backwards compatible, make sure you increment BuildGenericProccessVersion.
14201491
func (p *Package) buildGeneric(buildctx *buildContext, wd, result string) (res *packageBuild, err error) {

pkg/leeway/build_test.go

Lines changed: 92 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,102 @@
1-
package leeway
1+
package leeway_test
22

33
import (
4+
"os"
5+
"path/filepath"
46
"testing"
7+
8+
"github.com/gitpod-io/leeway/pkg/leeway"
9+
"github.com/gitpod-io/leeway/pkg/testutil"
10+
log "github.com/sirupsen/logrus"
511
)
612

7-
func TestCodecovComponentName(t *testing.T) {
8-
tests := []struct {
9-
Test string
10-
Package string
11-
Expected string
12-
}{
13-
{"valid package format", "components/ee/ws-scheduler", "components-ee-ws-scheduler-coverage.out"},
14-
{"lower case", "COMPONENTS/gitpod-cli:app", "components-gitpod-cli-app-coverage.out"},
15-
{"special character", "components/~ü:app", "components-app-coverage.out"},
16-
{"with numbers", "components/1icens0r:app", "components-1icens0r-app-coverage.out"},
13+
const dummyDocker = `#!/bin/bash
14+
15+
POSITIONAL_ARGS=()
16+
17+
while [[ $# -gt 0 ]]; do
18+
case $1 in
19+
-o)
20+
OUTPUT="$2"
21+
shift # past argument
22+
shift # past value
23+
;;
24+
*)
25+
POSITIONAL_ARGS+=("$1") # save positional arg
26+
shift # past argument
27+
;;
28+
esac
29+
done
30+
31+
set -- "${POSITIONAL_ARGS[@]}" # restore positional parameters
32+
33+
if [ "${POSITIONAL_ARGS}" == "save" ]; then
34+
tar cvvfz "${OUTPUT}" -T /dev/null
35+
fi
36+
`
37+
38+
func TestBuildDockerDeps(t *testing.T) {
39+
if *dut {
40+
pth, err := os.MkdirTemp("", "")
41+
if err != nil {
42+
t.Fatal(err)
43+
}
44+
err = os.WriteFile(filepath.Join(pth, "docker"), []byte(dummyDocker), 0755)
45+
if err != nil {
46+
t.Fatal(err)
47+
}
48+
t.Cleanup(func() { os.RemoveAll(pth) })
49+
50+
os.Setenv("PATH", pth+":"+os.Getenv("PATH"))
51+
log.WithField("path", os.Getenv("PATH")).Debug("modified path to use dummy docker")
52+
}
53+
runDUT()
54+
55+
tests := []*CommandFixtureTest{
56+
{
57+
Name: "docker dependency",
58+
T: t,
59+
Args: []string{"build", "-v", "-c", "none", "comp:pkg1"},
60+
StderrSub: "DEP_COMP__PKG0=foobar:1234",
61+
NoStdoutSub: "already built",
62+
ExitCode: 0,
63+
Fixture: &testutil.Setup{
64+
Components: []testutil.Component{
65+
{
66+
Location: "comp",
67+
Files: map[string]string{
68+
"pkg0.Dockerfile": "FROM alpine:latest",
69+
"pkg1.Dockerfile": "FROM ${DEP_COMP__PKG0}",
70+
},
71+
Packages: []leeway.Package{
72+
{
73+
PackageInternal: leeway.PackageInternal{
74+
Name: "pkg0",
75+
Type: leeway.DockerPackage,
76+
},
77+
Config: leeway.DockerPkgConfig{
78+
Dockerfile: "pkg0.Dockerfile",
79+
Image: []string{"foobar:1234"},
80+
},
81+
},
82+
{
83+
PackageInternal: leeway.PackageInternal{
84+
Name: "pkg1",
85+
Type: leeway.DockerPackage,
86+
Dependencies: []string{":pkg0"},
87+
},
88+
Config: leeway.DockerPkgConfig{
89+
Dockerfile: "pkg1.Dockerfile",
90+
},
91+
},
92+
},
93+
},
94+
},
95+
},
96+
},
1797
}
1898

1999
for _, test := range tests {
20-
name := codecovComponentName(test.Package)
21-
if name != test.Expected {
22-
t.Errorf("%s: expected: %v, actual: %v", test.Test, test.Expected, name)
23-
}
100+
test.Run()
24101
}
25102
}

pkg/leeway/package_test.go

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -309,3 +309,23 @@ func NewTestPackage(name string) *Package {
309309
Config: GenericPkgConfig{},
310310
}
311311
}
312+
313+
func TestCodecovComponentName(t *testing.T) {
314+
tests := []struct {
315+
Test string
316+
Package string
317+
Expected string
318+
}{
319+
{"valid package format", "components/ee/ws-scheduler", "components-ee-ws-scheduler-coverage.out"},
320+
{"lower case", "COMPONENTS/gitpod-cli:app", "components-gitpod-cli-app-coverage.out"},
321+
{"special character", "components/~ü:app", "components-app-coverage.out"},
322+
{"with numbers", "components/1icens0r:app", "components-1icens0r-app-coverage.out"},
323+
}
324+
325+
for _, test := range tests {
326+
name := codecovComponentName(test.Package)
327+
if name != test.Expected {
328+
t.Errorf("%s: expected: %v, actual: %v", test.Test, test.Expected, name)
329+
}
330+
}
331+
}

pkg/leeway/scripts_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -141,7 +141,7 @@ func (ft *CommandFixtureTest) Run() {
141141
t.Fatalf("cannot materialize fixture: %v", err)
142142
}
143143
t.Logf("materialized fixture workspace: %s", loc)
144-
t.Cleanup(func() { os.RemoveAll(loc) })
144+
// t.Cleanup(func() { os.RemoveAll(loc) })
145145
}
146146

147147
env := os.Environ()

0 commit comments

Comments
 (0)