diff --git a/cmd/skopeo/copy.go b/cmd/skopeo/copy.go index d08790bc..1b8214ed 100644 --- a/cmd/skopeo/copy.go +++ b/cmd/skopeo/copy.go @@ -65,7 +65,8 @@ func copyHandler(context *cli.Context) { logrus.Fatalf("Error parsing manifest: %s", err.Error()) } for _, layer := range layers { - stream, err := src.GetBlob(layer) + // TODO(mitr): do not ignore the size param returned here + stream, _, err := src.GetBlob(layer) if err != nil { logrus.Fatalf("Error reading layer %s: %s", layer, err.Error()) } diff --git a/directory/directory.go b/directory/directory.go index 45e98859..cfe5d394 100644 --- a/directory/directory.go +++ b/directory/directory.go @@ -93,8 +93,16 @@ func (s *dirImageSource) GetManifest(_ []string) ([]byte, string, error) { return m, "", err } -func (s *dirImageSource) GetBlob(digest string) (io.ReadCloser, error) { - return os.Open(layerPath(s.dir, digest)) +func (s *dirImageSource) GetBlob(digest string) (io.ReadCloser, int64, error) { + r, err := os.Open(layerPath(s.dir, digest)) + if err != nil { + return nil, 0, nil + } + fi, err := os.Stat(layerPath(s.dir, digest)) + if err != nil { + return nil, 0, nil + } + return r, fi.Size(), nil } func (s *dirImageSource) GetSignatures() ([][]byte, error) { diff --git a/docker/docker_image_src.go b/docker/docker_image_src.go index 184ef990..1483ef7a 100644 --- a/docker/docker_image_src.go +++ b/docker/docker_image_src.go @@ -5,6 +5,7 @@ import ( "io" "io/ioutil" "net/http" + "strconv" "github.com/Sirupsen/logrus" "github.com/projectatomic/skopeo/docker/utils" @@ -78,18 +79,22 @@ func (s *dockerImageSource) GetManifest(mimetypes []string) ([]byte, string, err return manblob, res.Header.Get("Content-Type"), nil } -func (s *dockerImageSource) GetBlob(digest string) (io.ReadCloser, error) { +func (s *dockerImageSource) GetBlob(digest string) (io.ReadCloser, int64, error) { url := fmt.Sprintf(blobsURL, s.ref.RemoteName(), digest) logrus.Infof("Downloading %s", url) res, err := s.c.makeRequest("GET", url, nil, nil) if err != nil { - return nil, err + return nil, 0, err } if res.StatusCode != http.StatusOK { // print url also - return nil, fmt.Errorf("Invalid status code returned when fetching blob %d", res.StatusCode) + return nil, 0, fmt.Errorf("Invalid status code returned when fetching blob %d", res.StatusCode) } - return res.Body, nil + size, err := strconv.ParseInt(res.Header.Get("Content-Length"), 10, 64) + if err != nil { + size = 0 + } + return res.Body, size, nil } func (s *dockerImageSource) GetSignatures() ([][]byte, error) { diff --git a/image/image.go b/image/image.go index 77226be2..509c9b31 100644 --- a/image/image.go +++ b/image/image.go @@ -204,7 +204,7 @@ func (i *genericImage) Layers(layers ...string) error { } func (i *genericImage) getLayer(dest types.ImageDestination, digest string) error { - stream, err := i.src.GetBlob(digest) + stream, _, err := i.src.GetBlob(digest) if err != nil { return err } diff --git a/openshift/openshift.go b/openshift/openshift.go index d86e7d47..58491195 100644 --- a/openshift/openshift.go +++ b/openshift/openshift.go @@ -200,9 +200,9 @@ func (s *openshiftImageSource) GetManifest(mimetypes []string) ([]byte, string, return s.docker.GetManifest(mimetypes) } -func (s *openshiftImageSource) GetBlob(digest string) (io.ReadCloser, error) { +func (s *openshiftImageSource) GetBlob(digest string) (io.ReadCloser, int64, error) { if err := s.ensureImageIsResolved(); err != nil { - return nil, err + return nil, 0, err } return s.docker.GetBlob(digest) } diff --git a/types/types.go b/types/types.go index a82a2a1f..09640fad 100644 --- a/types/types.go +++ b/types/types.go @@ -30,7 +30,8 @@ type ImageSource interface { // It may use a remote (= slow) service. GetManifest([]string) ([]byte, string, error) // Note: Calling GetBlob() may have ordering dependencies WRT other methods of this type. FIXME: How does this work with (docker save) on stdin? - GetBlob(digest string) (io.ReadCloser, error) + // the second return value is the size of the blob. If not known 0 is returned + GetBlob(digest string) (io.ReadCloser, int64, error) // GetSignatures returns the image's signatures. It may use a remote (= slow) service. GetSignatures() ([][]byte, error) // Delete image from registry, if operation is supported