pkg/archive: add interface for Untar

Docker-DCO-1.1-Signed-off-by: Cristian Staretu <cristian.staretu@gmail.com> (github: unclejack)
This commit is contained in:
unclejack 2014-11-06 20:01:37 +02:00
parent b87098729a
commit 513934f6b1

View file

@ -36,10 +36,17 @@ type (
NoLchown bool NoLchown bool
Name string Name string
} }
// Archiver allows the reuse of most utility functions of this package
// with a pluggable Untar function.
Archiver struct {
Untar func(io.Reader, string, *TarOptions) error
}
) )
var ( var (
ErrNotImplemented = errors.New("Function not implemented") ErrNotImplemented = errors.New("Function not implemented")
defaultArchiver = &Archiver{Untar}
) )
const ( const (
@ -549,45 +556,47 @@ loop:
return nil return nil
} }
// TarUntar is a convenience function which calls Tar and Untar, with func (archiver *Archiver) TarUntar(src, dst string) error {
// the output of one piped into the other. If either Tar or Untar fails,
// TarUntar aborts and returns the error.
func TarUntar(src string, dst string) error {
log.Debugf("TarUntar(%s %s)", src, dst) log.Debugf("TarUntar(%s %s)", src, dst)
archive, err := TarWithOptions(src, &TarOptions{Compression: Uncompressed}) archive, err := TarWithOptions(src, &TarOptions{Compression: Uncompressed})
if err != nil { if err != nil {
return err return err
} }
defer archive.Close() defer archive.Close()
return Untar(archive, dst, nil) return archiver.Untar(archive, dst, nil)
} }
// UntarPath is a convenience function which looks for an archive // TarUntar is a convenience function which calls Tar and Untar, with the output of one piped into the other.
// at filesystem path `src`, and unpacks it at `dst`. // If either Tar or Untar fails, TarUntar aborts and returns the error.
func UntarPath(src, dst string) error { func TarUntar(src, dst string) error {
return defaultArchiver.TarUntar(src, dst)
}
func (archiver *Archiver) UntarPath(src, dst string) error {
archive, err := os.Open(src) archive, err := os.Open(src)
if err != nil { if err != nil {
return err return err
} }
defer archive.Close() defer archive.Close()
if err := Untar(archive, dst, nil); err != nil { if err := archiver.Untar(archive, dst, nil); err != nil {
return err return err
} }
return nil return nil
} }
// CopyWithTar creates a tar archive of filesystem path `src`, and // UntarPath is a convenience function which looks for an archive
// unpacks it at filesystem path `dst`. // at filesystem path `src`, and unpacks it at `dst`.
// The archive is streamed directly with fixed buffering and no func UntarPath(src, dst string) error {
// intermediary disk IO. return defaultArchiver.UntarPath(src, dst)
// }
func CopyWithTar(src, dst string) error {
func (archiver *Archiver) CopyWithTar(src, dst string) error {
srcSt, err := os.Stat(src) srcSt, err := os.Stat(src)
if err != nil { if err != nil {
return err return err
} }
if !srcSt.IsDir() { if !srcSt.IsDir() {
return CopyFileWithTar(src, dst) return archiver.CopyFileWithTar(src, dst)
} }
// Create dst, copy src's content into it // Create dst, copy src's content into it
log.Debugf("Creating dest directory: %s", dst) log.Debugf("Creating dest directory: %s", dst)
@ -595,16 +604,18 @@ func CopyWithTar(src, dst string) error {
return err return err
} }
log.Debugf("Calling TarUntar(%s, %s)", src, dst) log.Debugf("Calling TarUntar(%s, %s)", src, dst)
return TarUntar(src, dst) return archiver.TarUntar(src, dst)
} }
// CopyFileWithTar emulates the behavior of the 'cp' command-line // CopyWithTar creates a tar archive of filesystem path `src`, and
// for a single file. It copies a regular file from path `src` to // unpacks it at filesystem path `dst`.
// path `dst`, and preserves all its metadata. // The archive is streamed directly with fixed buffering and no
// // intermediary disk IO.
// If `dst` ends with a trailing slash '/', the final destination path func CopyWithTar(src, dst string) error {
// will be `dst/base(src)`. return defaultArchiver.CopyWithTar(src, dst)
func CopyFileWithTar(src, dst string) (err error) { }
func (archiver *Archiver) CopyFileWithTar(src, dst string) (err error) {
log.Debugf("CopyFileWithTar(%s, %s)", src, dst) log.Debugf("CopyFileWithTar(%s, %s)", src, dst)
srcSt, err := os.Stat(src) srcSt, err := os.Stat(src)
if err != nil { if err != nil {
@ -652,7 +663,17 @@ func CopyFileWithTar(src, dst string) (err error) {
err = er err = er
} }
}() }()
return Untar(r, filepath.Dir(dst), nil) return archiver.Untar(r, filepath.Dir(dst), nil)
}
// CopyFileWithTar emulates the behavior of the 'cp' command-line
// for a single file. It copies a regular file from path `src` to
// path `dst`, and preserves all its metadata.
//
// If `dst` ends with a trailing slash '/', the final destination path
// will be `dst/base(src)`.
func CopyFileWithTar(src, dst string) (err error) {
return defaultArchiver.CopyFileWithTar(src, dst)
} }
// CmdStream executes a command, and returns its stdout as a stream. // CmdStream executes a command, and returns its stdout as a stream.