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

* Builder: ADD improvements: use tar for copy + automatically unpack local archives
This commit is contained in:
Solomon Hykes 2013-06-17 13:32:34 -07:00
Родитель 389db5f598 5b8287617d
Коммит 22b0a38df5
4 изменённых файлов: 38 добавлений и 10 удалений

Просмотреть файл

@ -51,6 +51,7 @@ func Tar(path string, compression Compression) (io.Reader, error) {
return CmdStream(cmd) return CmdStream(cmd)
} }
// FIXME: specify behavior when target path exists vs. doesn't exist.
func Untar(archive io.Reader, path string) error { func Untar(archive io.Reader, path string) error {
cmd := exec.Command("bsdtar", "-f", "-", "-C", path, "-x") cmd := exec.Command("bsdtar", "-f", "-", "-C", path, "-x")
cmd.Stdin = archive cmd.Stdin = archive
@ -64,6 +65,30 @@ func Untar(archive io.Reader, path string) error {
return nil 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. // CmdStream executes a command, and returns its stdout as a stream.
// If the command fails to run or doesn't complete successfully, an error // If the command fails to run or doesn't complete successfully, an error
// will be returned, including anything written on stderr. // will be returned, including anything written on stderr.

Просмотреть файл

@ -202,21 +202,17 @@ func (b *buildFile) CmdAdd(args string) error {
if err := os.MkdirAll(destPath, 0700); err != nil { if err := os.MkdirAll(destPath, 0700); err != nil {
return err return err
} }
if err := CopyWithTar(origPath, destPath); err != nil {
files, err := ioutil.ReadDir(path.Join(b.context, orig))
if err != nil {
return err return err
} }
for _, fi := range files { // First try to unpack the source as an archive
if err := utils.CopyDirectory(path.Join(origPath, fi.Name()), path.Join(destPath, fi.Name())); err != nil { } else if err := UntarPath(origPath, destPath); err != nil {
return err utils.Debugf("Couldn't untar %s to %s: %s", origPath, destPath, err)
} // If that fails, just copy it as a regular file
}
} else {
if err := os.MkdirAll(path.Dir(destPath), 0700); err != nil { if err := os.MkdirAll(path.Dir(destPath), 0700); err != nil {
return err return err
} }
if err := utils.CopyDirectory(origPath, destPath); err != nil { if err := CopyWithTar(origPath, destPath); err != nil {
return err return err
} }
} }

Просмотреть файл

@ -23,6 +23,12 @@ from ` + unitTestImageName + `
run sh -c 'echo root:testpass > /tmp/passwd' run sh -c 'echo root:testpass > /tmp/passwd'
run mkdir -p /var/run/sshd` 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) { func TestBuild(t *testing.T) {
dockerfiles := []string{Dockerfile, DockerfileNoNewLine} dockerfiles := []string{Dockerfile, DockerfileNoNewLine}
for _, Dockerfile := range dockerfiles { for _, Dockerfile := range dockerfiles {

Просмотреть файл

@ -548,6 +548,7 @@ func GetKernelVersion() (*KernelVersionInfo, error) {
}, nil }, nil
} }
// FIXME: this is deprecated by CopyWithTar in archive.go
func CopyDirectory(source, dest string) error { func CopyDirectory(source, dest string) error {
if output, err := exec.Command("cp", "-ra", source, dest).CombinedOutput(); err != nil { if output, err := exec.Command("cp", "-ra", source, dest).CombinedOutput(); err != nil {
return fmt.Errorf("Error copy: %s (%s)", err, output) return fmt.Errorf("Error copy: %s (%s)", err, output)