diff --git a/go.mod b/go.mod index f5e26f9935..41545c1e62 100644 --- a/go.mod +++ b/go.mod @@ -41,7 +41,6 @@ require ( github.com/hashicorp/go-multierror v1.1.1 github.com/hugelgupf/p9 v0.3.1-0.20230822151754-54f5c5530921 github.com/json-iterator/go v1.1.12 - github.com/klauspost/compress v1.17.7 github.com/linuxkit/virtsock v0.0.0-20220523201153-1a23e78aa7a2 github.com/mattn/go-shellwords v1.0.12 github.com/mattn/go-sqlite3 v1.14.22 @@ -65,7 +64,6 @@ require ( github.com/spf13/pflag v1.0.5 github.com/stretchr/testify v1.9.0 github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635 - github.com/ulikunitz/xz v0.5.11 github.com/vbauerster/mpb/v8 v8.7.2 github.com/vishvananda/netlink v1.2.1-beta.2 go.etcd.io/bbolt v1.3.9 @@ -149,6 +147,7 @@ require ( github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/jinzhu/copier v0.4.0 // indirect github.com/josharian/intern v1.0.0 // indirect + github.com/klauspost/compress v1.17.7 // indirect github.com/klauspost/cpuid/v2 v2.2.6 // indirect github.com/klauspost/pgzip v1.2.6 // indirect github.com/kr/fs v0.1.0 // indirect @@ -198,6 +197,7 @@ require ( github.com/twitchyliquid64/golang-asm v0.15.1 // indirect github.com/u-root/uio v0.0.0-20230305220412-3e8cd9d6bf63 // indirect github.com/ugorji/go/codec v1.2.12 // indirect + github.com/ulikunitz/xz v0.5.11 // indirect github.com/vbatts/tar-split v0.11.5 // indirect github.com/vishvananda/netns v0.0.4 // indirect github.com/yusufpapurcu/wmi v1.2.4 // indirect diff --git a/pkg/machine/compression/compression_test.go b/pkg/machine/compression/compression_test.go index 8230746972..9c51cd8bca 100644 --- a/pkg/machine/compression/compression_test.go +++ b/pkg/machine/compression/compression_test.go @@ -112,6 +112,8 @@ func Test_Decompress(t *testing.T) { }{ {name: "zip", args: args{src: "./testdata/sample.zip", dst: "./testdata/hellozip"}, want: "zip\n"}, {name: "zip with trailing zeros", args: args{src: "./testdata/sample-withzeros.zip", dst: "./testdata/hellozip-withzeros"}, want: "zip\n\x00\x00\x00\x00\x00\x00"}, + {name: "xz", args: args{src: "./testdata/sample.xz", dst: "./testdata/helloxz"}, want: "xz\n"}, + {name: "xz with trailing zeros", args: args{src: "./testdata/sample-withzeros.xz", dst: "./testdata/helloxz-withzeros"}, want: "xz\n\x00\x00\x00\x00\x00\x00\x00"}, {name: "gzip", args: args{src: "./testdata/sample.gz", dst: "./testdata/hellogz"}, want: "gzip\n"}, {name: "gzip with trailing zeros", args: args{src: "./testdata/sample-withzeros.gz", dst: "./testdata/hellogzip-withzeros"}, want: "gzip\n\x00\x00\x00\x00\x00"}, {name: "bzip2", args: args{src: "./testdata/sample.bz2", dst: "./testdata/hellobz2"}, want: "bzip2\n"}, diff --git a/pkg/machine/compression/decompress.go b/pkg/machine/compression/decompress.go index 56816d5b95..c13335307b 100644 --- a/pkg/machine/compression/decompress.go +++ b/pkg/machine/compression/decompress.go @@ -4,7 +4,6 @@ import ( "io" "os" "path/filepath" - "runtime" "strings" "github.com/containers/podman/v5/pkg/machine/define" @@ -46,24 +45,15 @@ func Decompress(compressedVMFile *define.VMFile, decompressedFilePath string) er func newDecompressor(compressedFilePath string, compressedFileMagicNum []byte) (decompressor, error) { compressionType := archive.DetectCompression(compressedFileMagicNum) - os := runtime.GOOS hasZipSuffix := strings.HasSuffix(compressedFilePath, zipExt) switch { - case compressionType == archive.Xz: - return newXzDecompressor(compressedFilePath) // Zip files are not guaranteed to have a magic number at the beginning // of the file, so we need to use the file name to detect them. case compressionType == archive.Uncompressed && hasZipSuffix: return newZipDecompressor(compressedFilePath) case compressionType == archive.Uncompressed: return newUncompressedDecompressor(compressedFilePath) - // Using special compressors on MacOS because default ones - // in c/image/pkg/compression are slow with sparse files. - case compressionType == archive.Gzip && os == macOs: - return newGzipDecompressor(compressedFilePath) - case compressionType == archive.Zstd && os == macOs: - return newZstdDecompressor(compressedFilePath) default: return newGenericDecompressor(compressedFilePath) } diff --git a/pkg/machine/compression/generic.go b/pkg/machine/compression/generic.go index f3995bd92b..0b70ff92e9 100644 --- a/pkg/machine/compression/generic.go +++ b/pkg/machine/compression/generic.go @@ -4,6 +4,7 @@ import ( "io" "io/fs" "os" + "runtime" "github.com/containers/image/v5/pkg/compression" "github.com/sirupsen/logrus" @@ -54,7 +55,15 @@ func (d *genericDecompressor) decompress(w io.WriteSeeker, r io.Reader) error { } }() - _, err = io.Copy(w, decompressedFileReader) + // Use sparse-optimized copy for macOS as applehv, + // macOS native hypervisor, uses large raw VM disk + // files mostly empty (~2GB of content ~8GB empty). + if runtime.GOOS == macOs { + err = d.sparseOptimizedCopy(w, decompressedFileReader) + } else { + _, err = io.Copy(w, decompressedFileReader) + } + return err } diff --git a/pkg/machine/compression/gzip.go b/pkg/machine/compression/gzip.go deleted file mode 100644 index 7bbe164d0c..0000000000 --- a/pkg/machine/compression/gzip.go +++ /dev/null @@ -1,31 +0,0 @@ -package compression - -import ( - "io" - - image "github.com/containers/image/v5/pkg/compression" - "github.com/sirupsen/logrus" -) - -type gzipDecompressor struct { - genericDecompressor -} - -func newGzipDecompressor(compressedFilePath string) (*gzipDecompressor, error) { - d, err := newGenericDecompressor(compressedFilePath) - return &gzipDecompressor{*d}, err -} - -func (d *gzipDecompressor) decompress(w io.WriteSeeker, r io.Reader) error { - gzReader, err := image.GzipDecompressor(r) - if err != nil { - return err - } - defer func() { - if err := gzReader.Close(); err != nil { - logrus.Errorf("Unable to close gz file: %q", err) - } - }() - - return d.sparseOptimizedCopy(w, gzReader) -} diff --git a/pkg/machine/compression/xz.go b/pkg/machine/compression/xz.go deleted file mode 100644 index d4f492d88e..0000000000 --- a/pkg/machine/compression/xz.go +++ /dev/null @@ -1,66 +0,0 @@ -package compression - -import ( - "bufio" - "io" - "os" - "os/exec" - - "github.com/sirupsen/logrus" - "github.com/ulikunitz/xz" -) - -type xzDecompressor struct { - genericDecompressor -} - -func newXzDecompressor(compressedFilePath string) (*xzDecompressor, error) { - d, err := newGenericDecompressor(compressedFilePath) - return &xzDecompressor{*d}, err -} - -// Will error out if file without .Xz already exists -// Maybe extracting then renaming is a good idea here.. -// depends on Xz: not pre-installed on mac, so it becomes a brew dependency -func (*xzDecompressor) decompress(w io.WriteSeeker, r io.Reader) error { - var cmd *exec.Cmd - var read io.Reader - - // Prefer Xz utils for fastest performance, fallback to go xi2 impl - if _, err := exec.LookPath("xz"); err == nil { - cmd = exec.Command("xz", "-d", "-c") - cmd.Stdin = r - read, err = cmd.StdoutPipe() - if err != nil { - return err - } - cmd.Stderr = os.Stderr - } else { - // This XZ implementation is reliant on buffering. It is also 3x+ slower than XZ utils. - // Consider replacing with a faster implementation (e.g. xi2) if podman machine is - // updated with a larger image for the distribution base. - buf := bufio.NewReader(r) - read, err = xz.NewReader(buf) - if err != nil { - return err - } - } - - done := make(chan bool) - go func() { - if _, err := io.Copy(w, read); err != nil { - logrus.Error(err) - } - done <- true - }() - - if cmd != nil { - err := cmd.Start() - if err != nil { - return err - } - return cmd.Wait() - } - <-done - return nil -} diff --git a/pkg/machine/compression/zstd.go b/pkg/machine/compression/zstd.go deleted file mode 100644 index 7b78ab3cc1..0000000000 --- a/pkg/machine/compression/zstd.go +++ /dev/null @@ -1,26 +0,0 @@ -package compression - -import ( - "io" - - "github.com/klauspost/compress/zstd" -) - -type zstdDecompressor struct { - genericDecompressor -} - -func newZstdDecompressor(compressedFilePath string) (*zstdDecompressor, error) { - d, err := newGenericDecompressor(compressedFilePath) - return &zstdDecompressor{*d}, err -} - -func (d *zstdDecompressor) decompress(w io.WriteSeeker, r io.Reader) error { - zstdReader, err := zstd.NewReader(r) - if err != nil { - return err - } - defer zstdReader.Close() - - return d.sparseOptimizedCopy(w, zstdReader) -}