瀏覽代碼

Merge pull request #897 from dotcloud/fix-overlapping-add

* Builder: ADD improvements: use tar for copy + automatically unpack local archives
Solomon Hykes 12 年之前
父節點
當前提交
22b0a38df5
共有 4 個文件被更改,包括 38 次插入10 次删除
  1. 25 0
      archive.go
  2. 6 10
      buildfile.go
  3. 6 0
      buildfile_test.go
  4. 1 0
      utils/utils.go

+ 25 - 0
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.

+ 6 - 10
buildfile.go

@@ -202,21 +202,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
 		}
 	}

+ 6 - 0
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 {

+ 1 - 0
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)