// getIoProgressReader returns a reader that wraps the HTTP response // body, so it prints a pretty progress bar when reading data from it. func getIoProgressReader(label string, res *http.Response) io.Reader { prefix := "Downloading " + label fmtBytesSize := 18 barSize := int64(80 - len(prefix) - fmtBytesSize) bar := ioprogress.DrawTextFormatBarForW(barSize, os.Stderr) fmtfunc := func(progress, total int64) string { // Content-Length is set to -1 when unknown. if total == -1 { return fmt.Sprintf( "%s: %v of an unknown total size", prefix, ioprogress.ByteUnitStr(progress), ) } return fmt.Sprintf( "%s: %s %s", prefix, bar(progress, total), ioprogress.DrawTextFormatBytes(progress, total), ) } return &ioprogress.Reader{ Reader: res.Body, Size: res.ContentLength, DrawFunc: ioprogress.DrawTerminalf(os.Stderr, fmtfunc), DrawInterval: time.Second, } }
func genProgressBar(file *os.File, label string) (io.Reader, error) { finfo, err := file.Stat() if err != nil { return nil, err } var prefix string if label != "" { prefix = "Uploading " + label } else { prefix = "Uploading" } fmtBytesSize := 18 barSize := int64(80 - len(prefix) - fmtBytesSize) bar := ioprogress.DrawTextFormatBarForW(barSize, os.Stderr) fmtfunc := func(progress, total int64) string { // Content-Length is set to -1 when unknown. if total == -1 { return fmt.Sprintf( "%s: %v of an unknown total size", prefix, ioprogress.ByteUnitStr(progress), ) } return fmt.Sprintf( "%s: %s %s", prefix, bar(progress, total), ioprogress.DrawTextFormatBytes(progress, total), ) } return &ioprogress.Reader{ Reader: file, Size: finfo.Size(), DrawFunc: ioprogress.DrawTerminalf(os.Stderr, fmtfunc), DrawInterval: time.Second, }, nil }
func newIoprogress(label string, size int64, rdr io.Reader) io.Reader { prefix := "Downloading " + label fmtBytesSize := 18 // if barSize < 2, drawing the bar will panic; 3 will at least give a spinny // thing. barSize := int64(80 - len(prefix) - fmtBytesSize) if barSize < 2 { barSize = 2 } bar := ioprogress.DrawTextFormatBarForW(barSize, os.Stderr) fmtfunc := func(progress, total int64) string { // Content-Length is set to -1 when unknown. if total == -1 { return fmt.Sprintf( "%s: %v of an unknown total size", prefix, ioprogress.ByteUnitStr(progress), ) } return fmt.Sprintf( "%s: %s %s", prefix, bar(progress, total), ioprogress.DrawTextFormatBytes(progress, total), ) } return &ioprogress.Reader{ Reader: rdr, Size: size, DrawFunc: ioprogress.DrawTerminalf(os.Stderr, fmtfunc), DrawInterval: time.Second, } }
func (rb *RepositoryBackend) getLayerV1(imgID, registry string, repoData *RepoData, imgSize int64, tmpDir string) (*os.File, error) { client := util.GetTLSClient(rb.insecure.SkipVerify) req, err := http.NewRequest("GET", rb.schema+path.Join(registry, "images", imgID, "layer"), nil) if err != nil { return nil, err } setAuthTokenV1(req, repoData.Tokens) setCookieV1(req, repoData.Cookie) res, err := client.Do(req) if err != nil { return nil, err } defer res.Body.Close() if res.StatusCode != 200 { res.Body.Close() return nil, &httpStatusErr{res.StatusCode, req.URL} } // if we didn't receive the size via X-Docker-Size when we retrieved the // layer's json, try Content-Length if imgSize == -1 { if hdr := res.Header.Get("Content-Length"); hdr != "" { imgSize, err = strconv.ParseInt(hdr, 10, 64) if err != nil { return nil, err } } } prefix := "Downloading " + imgID[:12] fmtBytesSize := 18 barSize := int64(80 - len(prefix) - fmtBytesSize) bar := ioprogress.DrawTextFormatBarForW(barSize, os.Stderr) fmtfunc := func(progress, total int64) string { return fmt.Sprintf( "%s: %s %s", prefix, bar(progress, total), ioprogress.DrawTextFormatBytes(progress, total), ) } progressReader := &ioprogress.Reader{ Reader: res.Body, Size: imgSize, DrawFunc: ioprogress.DrawTerminalf(os.Stderr, fmtfunc), DrawInterval: 500 * time.Millisecond, } layerFile, err := ioutil.TempFile(tmpDir, "dockerlayer-") if err != nil { return nil, err } _, err = io.Copy(layerFile, progressReader) if err != nil { return nil, err } if err := layerFile.Sync(); err != nil { return nil, err } return layerFile, nil }
func (rb *RepositoryBackend) getLayerV2(layerID string, dockerURL *types.ParsedDockerURL, tmpDir string) (*os.File, error) { url := rb.schema + path.Join(dockerURL.IndexURL, "v2", dockerURL.ImageName, "blobs", layerID) req, err := http.NewRequest("GET", url, nil) if err != nil { return nil, err } rb.setBasicAuth(req) res, err := rb.makeRequest(req, dockerURL.ImageName) if err != nil { return nil, err } defer res.Body.Close() if res.StatusCode == http.StatusTemporaryRedirect || res.StatusCode == http.StatusFound { location := res.Header.Get("Location") if location != "" { req, err = http.NewRequest("GET", location, nil) if err != nil { return nil, err } res, err = rb.makeRequest(req, dockerURL.ImageName) if err != nil { return nil, err } defer res.Body.Close() } } if res.StatusCode != http.StatusOK { return nil, fmt.Errorf("HTTP code: %d. URL: %s", res.StatusCode, req.URL) } var in io.Reader in = res.Body if hdr := res.Header.Get("Content-Length"); hdr != "" { imgSize, err := strconv.ParseInt(hdr, 10, 64) if err != nil { return nil, err } prefix := "Downloading " + layerID[:18] fmtBytesSize := 18 barSize := int64(80 - len(prefix) - fmtBytesSize) bar := ioprogress.DrawTextFormatBarForW(barSize, os.Stderr) fmtfunc := func(progress, total int64) string { return fmt.Sprintf( "%s: %s %s", prefix, bar(progress, total), ioprogress.DrawTextFormatBytes(progress, total), ) } in = &ioprogress.Reader{ Reader: res.Body, Size: imgSize, DrawFunc: ioprogress.DrawTerminalf(os.Stderr, fmtfunc), DrawInterval: 500 * time.Millisecond, } } layerFile, err := ioutil.TempFile(tmpDir, "dockerlayer-") if err != nil { return nil, err } _, err = io.Copy(layerFile, in) if err != nil { return nil, err } if err := layerFile.Sync(); err != nil { return nil, err } return layerFile, nil }