1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132
|
package utils
import (
"bytes"
"fmt"
"io"
"os"
"os/exec"
"path/filepath"
"strings"
"time"
"github.com/sirupsen/logrus"
"github.com/vbauerster/mpb/v8"
"github.com/vbauerster/mpb/v8/decor"
"go.podman.io/storage/pkg/archive"
"go.podman.io/storage/pkg/chrootarchive"
)
// 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
cmd.Env = env
err := cmd.Run()
if err != nil {
return fmt.Errorf("`%v %v` failed: %v", name, strings.Join(args, " "), err)
}
return nil
}
// 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
}
defer tb.Close()
_, 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)
}
// TarWithChroot creates a tarball from source and returns a readcloser of it
// while chrooted to the source.
func TarWithChroot(source string) (io.ReadCloser, error) {
logrus.Debugf("creating tarball of %s", source)
return chrootarchive.Tar(source, nil, source)
}
// GuardedRemoveAll functions much like os.RemoveAll but
// will not delete certain catastrophic paths.
func GuardedRemoveAll(path string) error {
if path == "" || path == "/" {
return fmt.Errorf("refusing to recursively delete `%s`", path)
}
return os.RemoveAll(path)
}
// RemoveFilesExcept removes all files in a directory except for the one specified
// by excludeFile and will not delete certain catastrophic paths.
func RemoveFilesExcept(path string, excludeFile string) error {
if path == "" || path == "/" {
return fmt.Errorf("refusing to recursively delete `%s`", path)
}
files, err := os.ReadDir(path)
if err != nil {
return err
}
for _, file := range files {
if file.Name() != excludeFile {
if err := os.RemoveAll(filepath.Join(path, file.Name())); err != nil {
return err
}
}
}
return nil
}
func ProgressBar(prefix string, size int64, onComplete string) (*mpb.Progress, *mpb.Bar) {
p := mpb.New(
mpb.WithWidth(80), // Do not go below 80, see bug #17718
mpb.WithRefreshRate(180*time.Millisecond),
)
bar := p.AddBar(size,
mpb.BarFillerClearOnComplete(),
mpb.PrependDecorators(
decor.OnComplete(decor.Name(prefix), onComplete),
),
mpb.AppendDecorators(
decor.OnComplete(decor.CountersKibiByte("%.1f / %.1f"), ""),
),
)
if size == 0 {
bar.SetTotal(0, true)
}
return p, bar
}
|