mirror of
https://github.com/containers/podman.git
synced 2025-05-21 00:56:36 +08:00

The define package under Libpod is intended to be an extremely minimal package, including constants and very little else. However, as a result of some legacy code, it was dragging in all of libpod/image (and, less significantly, the util package). Fortunately, this was just to ensure that error constants were not duplicating, and there's nothing preventing us from importing in the other direction and keeping libpod/define free of dependencies. Signed-off-by: Matthew Heon <matthew.heon@pm.me>
148 lines
3.7 KiB
Go
148 lines
3.7 KiB
Go
package utils
|
|
|
|
import (
|
|
"bytes"
|
|
"fmt"
|
|
"io"
|
|
"os"
|
|
"os/exec"
|
|
"strconv"
|
|
"strings"
|
|
|
|
"github.com/containers/podman/v2/libpod/define"
|
|
"github.com/containers/storage/pkg/archive"
|
|
"github.com/pkg/errors"
|
|
"github.com/sirupsen/logrus"
|
|
)
|
|
|
|
// ExecCmd executes a command with args and returns its output as a string along
|
|
// with an error, if any
|
|
func ExecCmd(name string, args ...string) (string, error) {
|
|
cmd := exec.Command(name, args...)
|
|
var stdout bytes.Buffer
|
|
var stderr bytes.Buffer
|
|
cmd.Stdout = &stdout
|
|
cmd.Stderr = &stderr
|
|
|
|
err := cmd.Run()
|
|
if err != nil {
|
|
return "", fmt.Errorf("`%v %v` failed: %v %v (%v)", name, strings.Join(args, " "), stderr.String(), stdout.String(), err)
|
|
}
|
|
|
|
return stdout.String(), nil
|
|
}
|
|
|
|
// ExecCmdWithStdStreams execute a command with the specified standard streams.
|
|
func ExecCmdWithStdStreams(stdin io.Reader, stdout, stderr io.Writer, env []string, name string, args ...string) error {
|
|
cmd := exec.Command(name, args...)
|
|
cmd.Stdin = stdin
|
|
cmd.Stdout = stdout
|
|
cmd.Stderr = stderr
|
|
if env != nil {
|
|
cmd.Env = env
|
|
}
|
|
|
|
err := cmd.Run()
|
|
if err != nil {
|
|
return fmt.Errorf("`%v %v` failed: %v", name, strings.Join(args, " "), err)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// ErrDetach is an error indicating that the user manually detached from the
|
|
// container.
|
|
var ErrDetach = define.ErrDetach
|
|
|
|
// CopyDetachable is similar to io.Copy but support a detach key sequence to break out.
|
|
func CopyDetachable(dst io.Writer, src io.Reader, keys []byte) (written int64, err error) {
|
|
buf := make([]byte, 32*1024)
|
|
for {
|
|
nr, er := src.Read(buf)
|
|
if nr > 0 {
|
|
preservBuf := []byte{}
|
|
for i, key := range keys {
|
|
preservBuf = append(preservBuf, buf[0:nr]...)
|
|
if nr != 1 || buf[0] != key {
|
|
break
|
|
}
|
|
if i == len(keys)-1 {
|
|
return 0, ErrDetach
|
|
}
|
|
nr, er = src.Read(buf)
|
|
}
|
|
var nw int
|
|
var ew error
|
|
if len(preservBuf) > 0 {
|
|
nw, ew = dst.Write(preservBuf)
|
|
nr = len(preservBuf)
|
|
} else {
|
|
nw, ew = dst.Write(buf[0:nr])
|
|
}
|
|
if nw > 0 {
|
|
written += int64(nw)
|
|
}
|
|
if ew != nil {
|
|
err = ew
|
|
break
|
|
}
|
|
if nr != nw {
|
|
err = io.ErrShortWrite
|
|
break
|
|
}
|
|
}
|
|
if er != nil {
|
|
if er != io.EOF {
|
|
err = er
|
|
}
|
|
break
|
|
}
|
|
}
|
|
return written, err
|
|
}
|
|
|
|
// UntarToFileSystem untars an os.file of a tarball to a destination in the filesystem
|
|
func UntarToFileSystem(dest string, tarball *os.File, options *archive.TarOptions) error {
|
|
logrus.Debugf("untarring %s", tarball.Name())
|
|
return archive.Untar(tarball, dest, options)
|
|
}
|
|
|
|
// TarToFilesystem creates a tarball from source and writes to an os.file
|
|
// provided
|
|
func TarToFilesystem(source string, tarball *os.File) error {
|
|
tb, err := Tar(source)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
_, err = io.Copy(tarball, tb)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
logrus.Debugf("wrote tarball file %s", tarball.Name())
|
|
return nil
|
|
}
|
|
|
|
// Tar creates a tarball from source and returns a readcloser of it
|
|
func Tar(source string) (io.ReadCloser, error) {
|
|
logrus.Debugf("creating tarball of %s", source)
|
|
return archive.Tar(source, archive.Uncompressed)
|
|
}
|
|
|
|
// RemoveScientificNotationFromFloat returns a float without any
|
|
// scientific notation if the number has any.
|
|
// golang does not handle conversion of float64s that have scientific
|
|
// notation in them and otherwise stinks. please replace this if you have
|
|
// a better implementation.
|
|
func RemoveScientificNotationFromFloat(x float64) (float64, error) {
|
|
bigNum := strconv.FormatFloat(x, 'g', -1, 64)
|
|
breakPoint := strings.IndexAny(bigNum, "Ee")
|
|
if breakPoint > 0 {
|
|
bigNum = bigNum[:breakPoint]
|
|
}
|
|
result, err := strconv.ParseFloat(bigNum, 64)
|
|
if err != nil {
|
|
return x, errors.Wrapf(err, "unable to remove scientific number from calculations")
|
|
}
|
|
return result, nil
|
|
}
|