зеркало из https://github.com/microsoft/docker.git
89 строки
1.8 KiB
Go
89 строки
1.8 KiB
Go
package docker
|
|
|
|
import (
|
|
"errors"
|
|
"io"
|
|
"io/ioutil"
|
|
"os/exec"
|
|
)
|
|
|
|
type Archive io.Reader
|
|
|
|
type Compression uint32
|
|
|
|
const (
|
|
Uncompressed Compression = iota
|
|
Bzip2
|
|
Gzip
|
|
Xz
|
|
)
|
|
|
|
func (compression *Compression) Flag() string {
|
|
switch *compression {
|
|
case Bzip2:
|
|
return "j"
|
|
case Gzip:
|
|
return "z"
|
|
case Xz:
|
|
return "J"
|
|
}
|
|
return ""
|
|
}
|
|
|
|
func Tar(path string, compression Compression) (io.Reader, error) {
|
|
cmd := exec.Command("bsdtar", "-f", "-", "-C", path, "-c"+compression.Flag(), ".")
|
|
return CmdStream(cmd)
|
|
}
|
|
|
|
func Untar(archive io.Reader, path string) error {
|
|
cmd := exec.Command("bsdtar", "-f", "-", "-C", path, "-x")
|
|
cmd.Stdin = archive
|
|
output, err := cmd.CombinedOutput()
|
|
if err != nil {
|
|
return errors.New(err.Error() + ": " + string(output))
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// 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.
|
|
func CmdStream(cmd *exec.Cmd) (io.Reader, error) {
|
|
stdout, err := cmd.StdoutPipe()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
stderr, err := cmd.StderrPipe()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
pipeR, pipeW := io.Pipe()
|
|
errChan := make(chan []byte)
|
|
// Collect stderr, we will use it in case of an error
|
|
go func() {
|
|
errText, e := ioutil.ReadAll(stderr)
|
|
if e != nil {
|
|
errText = []byte("(...couldn't fetch stderr: " + e.Error() + ")")
|
|
}
|
|
errChan <- errText
|
|
}()
|
|
// Copy stdout to the returned pipe
|
|
go func() {
|
|
_, err := io.Copy(pipeW, stdout)
|
|
if err != nil {
|
|
pipeW.CloseWithError(err)
|
|
}
|
|
errText := <-errChan
|
|
if err := cmd.Wait(); err != nil {
|
|
pipeW.CloseWithError(errors.New(err.Error() + ": " + string(errText)))
|
|
} else {
|
|
pipeW.Close()
|
|
}
|
|
}()
|
|
// Run the command and return the pipe
|
|
if err := cmd.Start(); err != nil {
|
|
return nil, err
|
|
}
|
|
return pipeR, nil
|
|
}
|