aboutsummaryrefslogtreecommitdiff
path: root/pkg/machine/pull.go
diff options
context:
space:
mode:
Diffstat (limited to 'pkg/machine/pull.go')
-rw-r--r--pkg/machine/pull.go96
1 files changed, 68 insertions, 28 deletions
diff --git a/pkg/machine/pull.go b/pkg/machine/pull.go
index 3c8422a30..280b47f96 100644
--- a/pkg/machine/pull.go
+++ b/pkg/machine/pull.go
@@ -1,8 +1,9 @@
-// +build amd64,!windows arm64,!windows
+// +build amd64 arm64
package machine
import (
+ "bufio"
"fmt"
"io"
"io/ioutil"
@@ -17,6 +18,7 @@ import (
"github.com/containers/image/v5/pkg/compression"
"github.com/containers/storage/pkg/archive"
"github.com/sirupsen/logrus"
+ "github.com/ulikunitz/xz"
"github.com/vbauerster/mpb/v6"
"github.com/vbauerster/mpb/v6/decor"
)
@@ -43,7 +45,7 @@ func NewGenericDownloader(vmType, vmName, pullPath string) (DistributionDownload
return nil, err
}
if len(getURL.Scheme) > 0 {
- urlSplit := strings.Split(pullPath, "/")
+ urlSplit := strings.Split(getURL.Path, "/")
imageName = urlSplit[len(urlSplit)-1]
dl.LocalUncompressedFile = filepath.Join(dataDir, imageName)
dl.URL = getURL
@@ -63,39 +65,48 @@ func NewGenericDownloader(vmType, vmName, pullPath string) (DistributionDownload
return gd, nil
}
-func (g GenericDownload) getLocalUncompressedName() string {
+func (d Download) getLocalUncompressedName() string {
var (
extension string
)
switch {
- case strings.HasSuffix(g.LocalPath, ".bz2"):
+ case strings.HasSuffix(d.LocalPath, ".bz2"):
extension = ".bz2"
- case strings.HasSuffix(g.LocalPath, ".gz"):
+ case strings.HasSuffix(d.LocalPath, ".gz"):
extension = ".gz"
- case strings.HasSuffix(g.LocalPath, ".xz"):
+ case strings.HasSuffix(d.LocalPath, ".xz"):
extension = ".xz"
}
- uncompressedFilename := filepath.Join(filepath.Dir(g.LocalUncompressedFile), g.VMName+"_"+g.ImageName)
+ uncompressedFilename := filepath.Join(filepath.Dir(d.LocalPath), d.VMName+"_"+d.ImageName)
return strings.TrimSuffix(uncompressedFilename, extension)
}
-func (g GenericDownload) DownloadImage() error {
+func (g GenericDownload) Get() *Download {
+ return &g.Download
+}
+
+func (g GenericDownload) HasUsableCache() (bool, error) {
// If we have a URL for this "downloader", we now pull it
- if g.URL != nil {
- if err := DownloadVMImage(g.URL, g.LocalPath); err != nil {
+ return g.URL == nil, nil
+}
+
+func DownloadImage(d DistributionDownload) error {
+ // check if the latest image is already present
+ ok, err := d.HasUsableCache()
+ if err != nil {
+ return err
+ }
+ if !ok {
+ if err := DownloadVMImage(d.Get().URL, d.Get().LocalPath); err != nil {
return err
}
}
- return Decompress(g.LocalPath, g.getLocalUncompressedName())
-}
-
-func (g GenericDownload) Get() *Download {
- return &g.Download
+ return Decompress(d.Get().LocalPath, d.Get().getLocalUncompressedName())
}
// DownloadVMImage downloads a VM image from url to given path
// with download status
-func DownloadVMImage(downloadURL fmt.Stringer, localImagePath string) error {
+func DownloadVMImage(downloadURL *url2.URL, localImagePath string) error {
out, err := os.Create(localImagePath)
if err != nil {
return err
@@ -120,7 +131,7 @@ func DownloadVMImage(downloadURL fmt.Stringer, localImagePath string) error {
return fmt.Errorf("error downloading VM image %s: %s", downloadURL, resp.Status)
}
size := resp.ContentLength
- urlSplit := strings.Split(downloadURL.String(), "/")
+ urlSplit := strings.Split(downloadURL.Path, "/")
prefix := "Downloading VM image: " + urlSplit[len(urlSplit)-1]
onComplete := prefix + ": done"
@@ -177,24 +188,50 @@ func Decompress(localPath, uncompressedPath string) error {
// Will error out if file without .xz already exists
// Maybe extracting then renameing is a good idea here..
// depends on xz: not pre-installed on mac, so it becomes a brew dependency
-func decompressXZ(src string, output io.Writer) error {
- cmd := exec.Command("xzcat", "-k", src)
- //cmd := exec.Command("xz", "-d", "-k", "-v", src)
- stdOut, err := cmd.StdoutPipe()
- if err != nil {
- return err
+func decompressXZ(src string, output io.WriteCloser) error {
+ var read io.Reader
+ var cmd *exec.Cmd
+ // Prefer xz utils for fastest performance, fallback to go xi2 impl
+ if _, err := exec.LookPath("xzcat"); err == nil {
+ cmd = exec.Command("xzcat", "-k", src)
+ read, err = cmd.StdoutPipe()
+ if err != nil {
+ return err
+ }
+ cmd.Stderr = os.Stderr
+ } else {
+ file, err := os.Open(src)
+ if err != nil {
+ return err
+ }
+ defer file.Close()
+ // 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(file)
+ read, err = xz.NewReader(buf)
+ if err != nil {
+ return err
+ }
}
- //cmd.Stdout = os.Stdout
- cmd.Stderr = os.Stderr
+
+ done := make(chan bool)
go func() {
- if _, err := io.Copy(output, stdOut); err != nil {
+ if _, err := io.Copy(output, read); err != nil {
logrus.Error(err)
}
+ output.Close()
+ done <- true
}()
- return cmd.Run()
+
+ if cmd != nil {
+ return cmd.Run()
+ }
+ <-done
+ return nil
}
-func decompressEverythingElse(src string, output io.Writer) error {
+func decompressEverythingElse(src string, output io.WriteCloser) error {
f, err := os.Open(src)
if err != nil {
return err
@@ -207,6 +244,9 @@ func decompressEverythingElse(src string, output io.Writer) error {
if err := uncompressStream.Close(); err != nil {
logrus.Error(err)
}
+ if err := output.Close(); err != nil {
+ logrus.Error(err)
+ }
}()
_, err = io.Copy(output, uncompressStream)