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
 | |
| }
 |