Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

build: fix localstate for remote context and stdin #2560

Merged
merged 2 commits into from
Jun 28, 2024
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.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 20 additions & 20 deletions build/localstate.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,29 +15,29 @@ func saveLocalState(so *client.SolveOpt, target string, opts Options, node build
}
lp := opts.Inputs.ContextPath
dp := opts.Inputs.DockerfilePath
if lp != "" || dp != "" {
if lp != "" {
lp, err = filepath.Abs(lp)
if err != nil {
return err
}
}
if dp != "" {
dp, err = filepath.Abs(dp)
if err != nil {
return err
}
if dp != "" && !IsRemoteURL(lp) && lp != "-" && dp != "-" {
dp, err = filepath.Abs(dp)
if err != nil {
return err
}
l, err := localstate.New(configDir)
}
if lp != "" && !IsRemoteURL(lp) && lp != "-" {
lp, err = filepath.Abs(lp)
if err != nil {
return err
}
return l.SaveRef(node.Builder, node.Name, so.Ref, localstate.State{
Target: target,
LocalPath: lp,
DockerfilePath: dp,
GroupRef: opts.GroupRef,
})
}
return nil
if lp == "" && dp == "" {
return nil
}
l, err := localstate.New(configDir)
if err != nil {
return err
}
return l.SaveRef(node.Builder, node.Name, so.Ref, localstate.State{
Target: target,
LocalPath: lp,
DockerfilePath: dp,
GroupRef: opts.GroupRef,
})
}
5 changes: 3 additions & 2 deletions localstate/localstate.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,10 @@ const (
type State struct {
// Target is the name of the invoked target (default if empty)
Target string
// LocalPath is the absolute path to the context
// LocalPath is the absolute path to the context or remote context
LocalPath string
// DockerfilePath is the absolute path to the Dockerfile
// DockerfilePath is the absolute path to the Dockerfile or relative if
// context is remote
DockerfilePath string
// GroupRef is the ref of the state group that this ref belongs to
GroupRef string `json:",omitempty"`
Expand Down
170 changes: 170 additions & 0 deletions tests/build.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ import (
"github.com/containerd/containerd/platforms"
"github.com/containerd/continuity/fs/fstest"
"github.com/creack/pty"
"github.com/docker/buildx/localstate"
"github.com/docker/buildx/util/gitutil"
"github.com/moby/buildkit/client"
"github.com/moby/buildkit/frontend/subrequests/lint"
"github.com/moby/buildkit/frontend/subrequests/outline"
Expand All @@ -42,6 +44,10 @@ func buildCmd(sb integration.Sandbox, opts ...cmdOpt) (string, error) {
var buildTests = []func(t *testing.T, sb integration.Sandbox){
testBuild,
testBuildStdin,
testBuildRemote,
testBuildLocalState,
testBuildLocalStateStdin,
testBuildLocalStateRemote,
testImageIDOutput,
testBuildLocalExport,
testBuildRegistryExport,
Expand Down Expand Up @@ -95,6 +101,170 @@ COPY --from=base /etc/bar /bar
require.NoError(t, err, string(out))
}

func testBuildRemote(t *testing.T, sb integration.Sandbox) {
dockerfile := []byte(`
FROM busybox:latest
COPY foo /foo
`)
dir := tmpdir(
t,
fstest.CreateFile("Dockerfile", dockerfile, 0600),
fstest.CreateFile("foo", []byte("foo"), 0600),
)
dirDest := t.TempDir()

git, err := gitutil.New(gitutil.WithWorkingDir(dir))
require.NoError(t, err)

gitutil.GitInit(git, t)
gitutil.GitAdd(git, t, "Dockerfile", "foo")
gitutil.GitCommit(git, t, "initial commit")
addr := gitutil.GitServeHTTP(git, t)

out, err := buildCmd(sb, withDir(dir), withArgs("--output=type=local,dest="+dirDest, addr))
require.NoError(t, err, out)
require.FileExists(t, filepath.Join(dirDest, "foo"))
}

func testBuildLocalState(t *testing.T, sb integration.Sandbox) {
dockerfile := []byte(`
FROM busybox:latest AS base
COPY foo /etc/foo
RUN cp /etc/foo /etc/bar

FROM scratch
COPY --from=base /etc/bar /bar
`)
dir := tmpdir(
t,
fstest.CreateFile("build.Dockerfile", dockerfile, 0600),
fstest.CreateFile("foo", []byte("foo"), 0600),
)

out, err := buildCmd(sb, withDir(dir), withArgs(
"-f", "build.Dockerfile",
"--metadata-file", filepath.Join(dir, "md.json"),
".",
))
require.NoError(t, err, out)

dt, err := os.ReadFile(filepath.Join(dir, "md.json"))
require.NoError(t, err)

type mdT struct {
BuildRef string `json:"buildx.build.ref"`
}
var md mdT
err = json.Unmarshal(dt, &md)
require.NoError(t, err)

ls, err := localstate.New(buildxConfig(sb))
require.NoError(t, err)

refParts := strings.Split(md.BuildRef, "/")
require.Len(t, refParts, 3)

ref, err := ls.ReadRef(refParts[0], refParts[1], refParts[2])
require.NoError(t, err)
require.NotNil(t, ref)
require.DirExists(t, ref.LocalPath)
require.FileExists(t, ref.DockerfilePath)
}

func testBuildLocalStateStdin(t *testing.T, sb integration.Sandbox) {
dockerfile := []byte(`
FROM busybox:latest AS base
COPY foo /etc/foo
RUN cp /etc/foo /etc/bar

FROM scratch
COPY --from=base /etc/bar /bar
`)
dir := tmpdir(
t,
fstest.CreateFile("foo", []byte("foo"), 0600),
)

cmd := buildxCmd(sb, withDir(dir), withArgs("build", "--progress=quiet", "--metadata-file", filepath.Join(dir, "md.json"), "-f-", dir))
cmd.Stdin = bytes.NewReader(dockerfile)
out, err := cmd.CombinedOutput()
require.NoError(t, err, string(out))

dt, err := os.ReadFile(filepath.Join(dir, "md.json"))
require.NoError(t, err)

type mdT struct {
BuildRef string `json:"buildx.build.ref"`
}
var md mdT
err = json.Unmarshal(dt, &md)
require.NoError(t, err)

ls, err := localstate.New(buildxConfig(sb))
require.NoError(t, err)

refParts := strings.Split(md.BuildRef, "/")
require.Len(t, refParts, 3)

ref, err := ls.ReadRef(refParts[0], refParts[1], refParts[2])
require.NoError(t, err)
require.NotNil(t, ref)
require.DirExists(t, ref.LocalPath)
require.Equal(t, "-", ref.DockerfilePath)
}

func testBuildLocalStateRemote(t *testing.T, sb integration.Sandbox) {
dockerfile := []byte(`
FROM busybox:latest
COPY foo /foo
`)
dir := tmpdir(
t,
fstest.CreateFile("build.Dockerfile", dockerfile, 0600),
fstest.CreateFile("foo", []byte("foo"), 0600),
)
dirDest := t.TempDir()

git, err := gitutil.New(gitutil.WithWorkingDir(dir))
require.NoError(t, err)

gitutil.GitInit(git, t)
gitutil.GitAdd(git, t, "build.Dockerfile", "foo")
gitutil.GitCommit(git, t, "initial commit")
addr := gitutil.GitServeHTTP(git, t)

out, err := buildCmd(sb, withDir(dir), withArgs(
"-f", "build.Dockerfile",
"--metadata-file", filepath.Join(dirDest, "md.json"),
"--output", "type=local,dest="+dirDest,
addr,
))
require.NoError(t, err, out)
require.FileExists(t, filepath.Join(dirDest, "foo"))

dt, err := os.ReadFile(filepath.Join(dirDest, "md.json"))
require.NoError(t, err)

type mdT struct {
BuildRef string `json:"buildx.build.ref"`
}
var md mdT
err = json.Unmarshal(dt, &md)
require.NoError(t, err)

ls, err := localstate.New(buildxConfig(sb))
require.NoError(t, err)

refParts := strings.Split(md.BuildRef, "/")
require.Len(t, refParts, 3)

ref, err := ls.ReadRef(refParts[0], refParts[1], refParts[2])
require.NoError(t, err)
require.NotNil(t, ref)
require.Equal(t, addr, ref.LocalPath)
require.Equal(t, "build.Dockerfile", ref.DockerfilePath)
}

func testBuildLocalExport(t *testing.T, sb integration.Sandbox) {
dir := createTestProject(t)
out, err := buildCmd(sb, withArgs(fmt.Sprintf("--output=type=local,dest=%s/result", dir), dir))
Expand Down
9 changes: 8 additions & 1 deletion tests/integration.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ func buildxCmd(sb integration.Sandbox, opts ...cmdOpt) *exec.Cmd {

if builder := sb.Address(); builder != "" {
cmd.Env = append(cmd.Env,
"BUILDX_CONFIG=/tmp/buildx-"+builder,
"BUILDX_CONFIG="+buildxConfig(sb),
"BUILDX_BUILDER="+builder,
)
}
Expand Down Expand Up @@ -86,6 +86,13 @@ func dockerCmd(sb integration.Sandbox, opts ...cmdOpt) *exec.Cmd {
return cmd
}

func buildxConfig(sb integration.Sandbox) string {
if builder := sb.Address(); builder != "" {
return "/tmp/buildx-" + builder
}
return ""
}

func isMobyWorker(sb integration.Sandbox) bool {
name, hasFeature := driverName(sb.Name())
return name == "docker" && !hasFeature
Expand Down