func ProgressBarReader(r io.Reader, size int64) io.Reader { if size > 0 && size < 5120 { // TODO: isatty // Don't bother with progress bar below 50k return r } bar := ioprogress.DrawTextFormatBar(int64(56)) fmtfunc := func(progress, total int64) string { // Content-Length is set to -1 when unknown. if total == -1 { return fmt.Sprintf( "Progress: %v/?", ioprogress.ByteUnitStr(progress), ) } return fmt.Sprintf( "Progress: %s %s", bar(progress, total), ioprogress.DrawTextFormatBytes(progress, total), ) } return &ioprogress.Reader{ Reader: r, Size: size, DrawFunc: ioprogress.DrawTerminalf(os.Stderr, fmtfunc), DrawInterval: time.Second, } }
func getLayer(imgID, registry string, repoData *RepoData, imgSize int64, tmpDir string) (*os.File, error) { client := &http.Client{} req, err := http.NewRequest("GET", "https://"+path.Join(registry, "images", imgID, "layer"), nil) if err != nil { return nil, err } setAuthToken(req, repoData.Tokens) setCookie(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, fmt.Errorf("HTTP code: %d. URL: %s", 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.DrawTextFormatBar(barSize) 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 }