Skip to content

Commit 3060d31

Browse files
committed
WIP: allow individual manifests to opt-in to buildx
Signed-off-by: Justin Chadwell <[email protected]>
1 parent 0dbb69e commit 3060d31

File tree

4 files changed

+85
-15
lines changed

4 files changed

+85
-15
lines changed

cmd/bashbrew/cmd-build.go

Lines changed: 29 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package main
22

33
import (
44
"fmt"
5+
"strings"
56

67
"github.com/urfave/cli"
78
)
@@ -77,6 +78,18 @@ func cmdBuild(c *cli.Context) error {
7778
return cli.NewMultiError(fmt.Errorf(`failed calculating "cache hash" for %q (tags %q)`, r.RepoName, entry.TagsString()), err)
7879
}
7980

81+
var buildkit bool
82+
switch strings.ToLower(entry.Buildkit) {
83+
case "false":
84+
buildkit = false
85+
case "true":
86+
buildkit = true
87+
case "":
88+
buildkit = false
89+
default:
90+
return cli.NewMultiError(fmt.Errorf(`invalid value for buildkit %s, expected "true" or "false"`, entry.Buildkit))
91+
}
92+
8093
// check whether we've already built this artifact
8194
_, err = dockerInspect("{{.Id}}", cacheTag)
8295
if err != nil {
@@ -95,16 +108,22 @@ func cmdBuild(c *cli.Context) error {
95108

96109
// TODO use "meta.StageNames" to do "docker build --target" so we can tag intermediate stages too for cache (streaming "git archive" directly to "docker build" makes that a little hard to accomplish without re-streaming)
97110

98-
var extraEnv []string = nil
99-
if fromScratch {
100-
// https://github.com/docker/cli/blob/v20.10.7/cli/command/image/build.go#L163
101-
extraEnv = []string{"DOCKER_DEFAULT_PLATFORM=" + ociArch.String()}
102-
// ideally, we would set this via an explicit "--platform" flag on "docker build", but it's not supported without buildkit until 20.10+ and this is a trivial way to get Docker to do the right thing in both cases without explicitly trying to detect whether we're on 20.10+
103-
}
104-
105-
err = dockerBuild(cacheTag, entry.ArchFile(arch), archive, extraEnv)
106-
if err != nil {
107-
return cli.NewMultiError(fmt.Errorf(`failed building %q (tags %q)`, r.RepoName, entry.TagsString()), err)
111+
if buildkit {
112+
// buildkit registry cache pulls from tagged images
113+
caches := r.Tags(namespace, uniq, entry)
114+
err = dockerBuildx(cacheTag, entry.ArchFile(arch), archive, ociArch.String(), caches)
115+
if err != nil {
116+
return cli.NewMultiError(fmt.Errorf(`failed building %q (tags %q)`, r.RepoName, entry.TagsString()), err)
117+
}
118+
} else {
119+
var platform string
120+
if fromScratch {
121+
platform = ociArch.String()
122+
}
123+
err = dockerBuild(cacheTag, entry.ArchFile(arch), archive, platform)
124+
if err != nil {
125+
return cli.NewMultiError(fmt.Errorf(`failed building %q (tags %q)`, r.RepoName, entry.TagsString()), err)
126+
}
108127
}
109128
archive.Close() // be sure this happens sooner rather than later (defer might take a while, and we want to reap zombies more aggressively)
110129
}

cmd/bashbrew/docker.go

Lines changed: 44 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,8 @@ import (
1313
"strconv"
1414
"strings"
1515

16-
"github.com/urfave/cli"
1716
"github.com/docker-library/bashbrew/manifest"
17+
"github.com/urfave/cli"
1818
)
1919

2020
type dockerfileMetadata struct {
@@ -237,16 +237,55 @@ func (r Repo) dockerBuildUniqueBits(entry *manifest.Manifest2822Entry) ([]string
237237
return uniqueBits, nil
238238
}
239239

240-
func dockerBuild(tag string, file string, context io.Reader, extraEnv []string) error {
240+
func dockerBuild(tag string, file string, context io.Reader, platform string) error {
241241
args := []string{"build", "--tag", tag, "--file", file, "--rm", "--force-rm"}
242242
args = append(args, "-")
243243
cmd := exec.Command("docker", args...)
244-
if extraEnv != nil {
245-
cmd.Env = append(os.Environ(), extraEnv...)
244+
if platform != "" {
245+
// https://github.com/docker/cli/blob/v20.10.7/cli/command/image/build.go#L163
246+
cmd.Env = append(os.Environ(), "DOCKER_DEFAULT_PLATFORM="+platform)
247+
// ideally, we would set this via an explicit "--platform" flag on "docker build", but it's not supported without buildkit until 20.10+ and this is a trivial way to get Docker to do the right thing in both cases without explicitly trying to detect whether we're on 20.10+
248+
246249
if debugFlag {
247-
fmt.Printf("$ export %q\n", extraEnv)
250+
fmt.Printf("$ export DOCKER_DEFAULT_PLATFORM=%q\n", platform)
251+
}
252+
}
253+
cmd.Stdin = context
254+
if debugFlag {
255+
cmd.Stdout = os.Stdout
256+
cmd.Stderr = os.Stderr
257+
fmt.Printf("$ docker %q\n", args)
258+
return cmd.Run()
259+
} else {
260+
buf := &bytes.Buffer{}
261+
cmd.Stdout = buf
262+
cmd.Stderr = buf
263+
err := cmd.Run()
264+
if err != nil {
265+
err = cli.NewMultiError(err, fmt.Errorf(`docker %q output:%s`, args, "\n"+buf.String()))
248266
}
267+
return err
249268
}
269+
}
270+
271+
func dockerBuildx(tag string, file string, context io.Reader, platform string, caches []string) error {
272+
// TODO: use makeGitContext when docker builder supports subdirectories
273+
args := []string{
274+
"buildx",
275+
"build",
276+
"--progress", "plain",
277+
"--tag", tag,
278+
"--file", file,
279+
"--cache-to", "type=inline",
280+
}
281+
for _, cache := range caches {
282+
args = append(args, "--cache-from", "type=registry,ref="+cache)
283+
}
284+
if platform != "" {
285+
args = append(args, "--platform", platform)
286+
}
287+
args = append(args, "-")
288+
cmd := exec.Command("docker", args...)
250289
cmd.Stdin = context
251290
if debugFlag {
252291
cmd.Stdout = os.Stdout

cmd/bashbrew/git.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,16 @@ func gitNormalizeForTagUsage(text string) string {
155155

156156
var gitRepoCache = map[string]string{}
157157

158+
func (r Repo) makeGitContext(arch string, entry *manifest.Manifest2822Entry) string {
159+
context := fmt.Sprintf(
160+
"%s#%s:%s",
161+
entry.ArchGitRepo(arch),
162+
entry.ArchGitCommit(arch),
163+
entry.ArchDirectory(arch),
164+
)
165+
return context
166+
}
167+
158168
func (r Repo) fetchGitRepo(arch string, entry *manifest.Manifest2822Entry) (string, error) {
159169
cacheKey := strings.Join([]string{
160170
entry.ArchGitRepo(arch),

manifest/rfc2822.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,8 @@ type Manifest2822Entry struct {
4444
Directory string
4545
File string
4646

47+
Buildkit string
48+
4749
// architecture-specific versions of the above fields
4850
ArchValues map[string]string
4951
// "ARCH-FIELD: VALUE"

0 commit comments

Comments
 (0)