From 5b8287617de65d4e14ed6affb0eb46867e9ee617 Mon Sep 17 00:00:00 2001 From: Solomon Hykes Date: Fri, 14 Jun 2013 16:43:39 -0700 Subject: [PATCH] + Builder: ADD of a local file will detect tar archives and unpack them into the container instead of copying them as a regular file. * Builder: ADD uses tar/untar for copies instead of calling 'cp -ar'. This is more consistent, reduces the number of dependencies, and fixe #896. --- archive.go | 25 +++++++++++++++++++++++++ buildfile.go | 16 ++++++---------- buildfile_test.go | 6 ++++++ utils/utils.go | 1 + 4 files changed, 38 insertions(+), 10 deletions(-) diff --git a/archive.go b/archive.go index 06466627a1..44fdd56be3 100644 --- a/archive.go +++ b/archive.go @@ -51,6 +51,7 @@ func Tar(path string, compression Compression) (io.Reader, error) { return CmdStream(cmd) } +// FIXME: specify behavior when target path exists vs. doesn't exist. func Untar(archive io.Reader, path string) error { cmd := exec.Command("bsdtar", "-f", "-", "-C", path, "-x") cmd.Stdin = archive @@ -64,6 +65,30 @@ func Untar(archive io.Reader, path string) error { return nil } +// UntarPath is a convenience function which looks for an archive +// at filesystem path `src`, and unpacks it at `dst`. +func UntarPath(src, dst string) error { + if archive, err := os.Open(src); err != nil { + return err + } else if err := Untar(archive, dst); err != nil { + return err + } + return nil +} + +// CopyWithTar creates a tar archive of filesystem path `src`, and +// unpacks it at filesystem path `dst`. +// The archive is streamed directly with fixed buffering and no +// intermediary disk IO. +// +func CopyWithTar(src, dst string) error { + archive, err := Tar(src, Uncompressed) + if err != nil { + return err + } + return Untar(archive, dst) +} + // CmdStream executes a command, and returns its stdout as a stream. // If the command fails to run or doesn't complete successfully, an error // will be returned, including anything written on stderr. diff --git a/buildfile.go b/buildfile.go index 3c706b04ba..bb4ae721a9 100644 --- a/buildfile.go +++ b/buildfile.go @@ -200,21 +200,17 @@ func (b *buildFile) CmdAdd(args string) error { if err := os.MkdirAll(destPath, 0700); err != nil { return err } - - files, err := ioutil.ReadDir(path.Join(b.context, orig)) - if err != nil { + if err := CopyWithTar(origPath, destPath); err != nil { return err } - for _, fi := range files { - if err := utils.CopyDirectory(path.Join(origPath, fi.Name()), path.Join(destPath, fi.Name())); err != nil { - return err - } - } - } else { + // First try to unpack the source as an archive + } else if err := UntarPath(origPath, destPath); err != nil { + utils.Debugf("Couldn't untar %s to %s: %s", origPath, destPath, err) + // If that fails, just copy it as a regular file if err := os.MkdirAll(path.Dir(destPath), 0700); err != nil { return err } - if err := utils.CopyDirectory(origPath, destPath); err != nil { + if err := CopyWithTar(origPath, destPath); err != nil { return err } } diff --git a/buildfile_test.go b/buildfile_test.go index d9c60a70d5..33e6a3146b 100644 --- a/buildfile_test.go +++ b/buildfile_test.go @@ -23,6 +23,12 @@ from ` + unitTestImageName + ` run sh -c 'echo root:testpass > /tmp/passwd' run mkdir -p /var/run/sshd` +// FIXME: test building with a context + +// FIXME: test building with a local ADD as first command + +// FIXME: test building with 2 successive overlapping ADD commands + func TestBuild(t *testing.T) { dockerfiles := []string{Dockerfile, DockerfileNoNewLine} for _, Dockerfile := range dockerfiles { diff --git a/utils/utils.go b/utils/utils.go index 708c8bb19d..b77c1ea053 100644 --- a/utils/utils.go +++ b/utils/utils.go @@ -548,6 +548,7 @@ func GetKernelVersion() (*KernelVersionInfo, error) { }, nil } +// FIXME: this is deprecated by CopyWithTar in archive.go func CopyDirectory(source, dest string) error { if output, err := exec.Command("cp", "-ra", source, dest).CombinedOutput(); err != nil { return fmt.Errorf("Error copy: %s (%s)", err, output)