Merge pull request #189 from tonistiigi/extraction

dockerfile: Add ADD from archive support
docker-18.09
Akihiro Suda 2017-12-05 16:09:28 +09:00 committed by GitHub
commit 9397eb2373
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 150 additions and 2 deletions

View File

@ -332,14 +332,17 @@ func dispatchWorkdir(d *dispatchState, c *instructions.WorkdirCommand) error {
}
func dispatchCopy(d *dispatchState, c instructions.SourcesAndDest, sourceState llb.State, isAddCommand bool) error {
// TODO: this should use CopyOp instead. Current implementation is inefficient and doesn't match Dockerfile path suffixes rules
img := llb.Image("tonistiigi/copy@sha256:260a4355be76e0609518ebd7c0e026831c80b8908d4afd3f8e8c942645b1e5cf")
// TODO: this should use CopyOp instead. Current implementation is inefficient
img := llb.Image("tonistiigi/copy@sha256:ca6620946b2db7ad92f80cc5834f5d0724e6ede1f00004c965f6ded61592553a")
dest := path.Join("/dest", pathRelativeToWorkingDir(d.state, c.Dest()))
if c.Dest() == "." || c.Dest()[len(c.Dest())-1] == filepath.Separator {
dest += string(filepath.Separator)
}
args := []string{"copy"}
if isAddCommand {
args = append(args, "--unpack")
}
mounts := make([]llb.RunOption, 0, len(c.Sources()))
for i, src := range c.Sources() {
if isAddCommand && urlutil.IsURL(src) {

View File

@ -1,7 +1,9 @@
package dockerfile
import (
"archive/tar"
"bytes"
"compress/gzip"
"fmt"
"io/ioutil"
"net/http"
@ -22,6 +24,7 @@ func TestIntegration(t *testing.T) {
testDockerfileDirs,
testDockerfileInvalidCommand,
testDockerfileADDFromURL,
testDockerfileAddArchive,
})
}
@ -197,6 +200,148 @@ ADD %s /dest/
require.Equal(t, fi.ModTime().Format(http.TimeFormat), modTime.Format(http.TimeFormat))
}
func testDockerfileAddArchive(t *testing.T, sb integration.Sandbox) {
t.Parallel()
buf := bytes.NewBuffer(nil)
tw := tar.NewWriter(buf)
expectedContent := []byte("content0")
err := tw.WriteHeader(&tar.Header{
Name: "foo",
Typeflag: tar.TypeReg,
Size: int64(len(expectedContent)),
Mode: 0644,
})
require.NoError(t, err)
_, err = tw.Write(expectedContent)
require.NoError(t, err)
err = tw.Close()
require.NoError(t, err)
dockerfile := []byte(`
FROM scratch
ADD t.tar /
`)
dir, err := tmpdir(
fstest.CreateFile("Dockerfile", dockerfile, 0600),
fstest.CreateFile("t.tar", buf.Bytes(), 0600),
)
require.NoError(t, err)
defer os.RemoveAll(dir)
args, trace := dfCmdArgs(dir, dir)
defer os.RemoveAll(trace)
destDir, err := tmpdir()
require.NoError(t, err)
defer os.RemoveAll(destDir)
cmd := sb.Cmd(args + fmt.Sprintf(" --exporter=local --exporter-opt output=%s", destDir))
require.NoError(t, cmd.Run())
dt, err := ioutil.ReadFile(filepath.Join(destDir, "foo"))
require.NoError(t, err)
require.Equal(t, expectedContent, dt)
// add gzip tar
buf2 := bytes.NewBuffer(nil)
gz := gzip.NewWriter(buf2)
_, err = gz.Write(buf.Bytes())
require.NoError(t, err)
err = gz.Close()
require.NoError(t, err)
dockerfile = []byte(`
FROM scratch
ADD t.tar.gz /
`)
dir, err = tmpdir(
fstest.CreateFile("Dockerfile", dockerfile, 0600),
fstest.CreateFile("t.tar.gz", buf2.Bytes(), 0600),
)
require.NoError(t, err)
defer os.RemoveAll(dir)
args, trace = dfCmdArgs(dir, dir)
defer os.RemoveAll(trace)
destDir, err = tmpdir()
require.NoError(t, err)
defer os.RemoveAll(destDir)
cmd = sb.Cmd(args + fmt.Sprintf(" --exporter=local --exporter-opt output=%s", destDir))
require.NoError(t, cmd.Run())
dt, err = ioutil.ReadFile(filepath.Join(destDir, "foo"))
require.NoError(t, err)
require.Equal(t, expectedContent, dt)
// COPY doesn't extract
dockerfile = []byte(`
FROM scratch
COPY t.tar.gz /
`)
dir, err = tmpdir(
fstest.CreateFile("Dockerfile", dockerfile, 0600),
fstest.CreateFile("t.tar.gz", buf2.Bytes(), 0600),
)
require.NoError(t, err)
defer os.RemoveAll(dir)
args, trace = dfCmdArgs(dir, dir)
defer os.RemoveAll(trace)
destDir, err = tmpdir()
require.NoError(t, err)
defer os.RemoveAll(destDir)
cmd = sb.Cmd(args + fmt.Sprintf(" --exporter=local --exporter-opt output=%s", destDir))
require.NoError(t, cmd.Run())
dt, err = ioutil.ReadFile(filepath.Join(destDir, "t.tar.gz"))
require.NoError(t, err)
require.Equal(t, buf2.Bytes(), dt)
// ADD from URL doesn't extract
resp := httpserver.Response{
Etag: identity.NewID(),
Content: buf2.Bytes(),
}
server := httpserver.NewTestServer(map[string]httpserver.Response{
"/t.tar.gz": resp,
})
defer server.Close()
dockerfile = []byte(fmt.Sprintf(`
FROM scratch
ADD %s /
`, server.URL+"/t.tar.gz"))
dir, err = tmpdir(
fstest.CreateFile("Dockerfile", dockerfile, 0600),
)
require.NoError(t, err)
defer os.RemoveAll(dir)
args, trace = dfCmdArgs(dir, dir)
defer os.RemoveAll(trace)
destDir, err = tmpdir()
require.NoError(t, err)
defer os.RemoveAll(destDir)
cmd = sb.Cmd(args + fmt.Sprintf(" --exporter=local --exporter-opt output=%s", destDir))
require.NoError(t, cmd.Run())
dt, err = ioutil.ReadFile(filepath.Join(destDir, "t.tar.gz"))
require.NoError(t, err)
require.Equal(t, buf2.Bytes(), dt)
}
func tmpdir(appliers ...fstest.Applier) (string, error) {
tmpdir, err := ioutil.TempDir("", "buildkit-dockerfile")
if err != nil {