Skip to content

Commit 8a6fa4c

Browse files
authored
Add multi progress bar to uploads (#2134)
* Add multi progress bar to uploads * Shows the progress of each upload as a distinct item. * Update fast_push.go Signed-off-by: Will Sackfield <[email protected]> * Update fast_push.go Signed-off-by: Will Sackfield <[email protected]> --------- Signed-off-by: Will Sackfield <[email protected]>
1 parent 0e36b61 commit 8a6fa4c

File tree

3 files changed

+61
-16
lines changed

3 files changed

+61
-16
lines changed

go.mod

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,12 +23,13 @@ require (
2323
github.com/spf13/cobra v1.8.1
2424
github.com/spf13/pflag v1.0.5
2525
github.com/stretchr/testify v1.10.0
26+
github.com/vbauerster/mpb/v8 v8.9.1
2627
github.com/vincent-petithory/dataurl v1.0.0
2728
github.com/xeipuuv/gojsonschema v1.2.0
2829
github.com/xeonx/timeago v1.0.0-rc5
2930
golang.org/x/exp v0.0.0-20240909161429-701f63a606c0
3031
golang.org/x/sync v0.10.0
31-
golang.org/x/sys v0.28.0
32+
golang.org/x/sys v0.29.0
3233
golang.org/x/term v0.27.0
3334
golang.org/x/tools v0.28.0
3435
gopkg.in/yaml.v2 v2.4.0
@@ -51,6 +52,8 @@ require (
5152
github.com/GaijinEntertainment/go-exhaustruct/v3 v3.3.0 // indirect
5253
github.com/Masterminds/semver/v3 v3.3.0 // indirect
5354
github.com/OpenPeeDeeP/depguard/v2 v2.2.0 // indirect
55+
github.com/VividCortex/ewma v1.2.0 // indirect
56+
github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d // indirect
5457
github.com/alecthomas/go-check-sumtype v0.2.0 // indirect
5558
github.com/alexkohler/nakedret/v2 v2.0.5 // indirect
5659
github.com/alexkohler/prealloc v1.0.0 // indirect

go.sum

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,10 @@ github.com/Masterminds/semver/v3 v3.3.0 h1:B8LGeaivUe71a5qox1ICM/JLl0NqZSW5CHyL+
6262
github.com/Masterminds/semver/v3 v3.3.0/go.mod h1:4V+yj/TJE1HU9XfppCwVMZq3I84lprf4nC11bSS5beM=
6363
github.com/OpenPeeDeeP/depguard/v2 v2.2.0 h1:vDfG60vDtIuf0MEOhmLlLLSzqaRM8EMcgJPdp74zmpA=
6464
github.com/OpenPeeDeeP/depguard/v2 v2.2.0/go.mod h1:CIzddKRvLBC4Au5aYP/i3nyaWQ+ClszLIuVocRiCYFQ=
65+
github.com/VividCortex/ewma v1.2.0 h1:f58SaIzcDXrSy3kWaHNvuJgJ3Nmz59Zji6XoJR/q1ow=
66+
github.com/VividCortex/ewma v1.2.0/go.mod h1:nz4BbCtbLyFDeC9SUHbtcT5644juEuWfUAUnGx7j5l4=
67+
github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d h1:licZJFw2RwpHMqeKTCYkitsPqHNxTmd4SNR5r94FGM8=
68+
github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d/go.mod h1:asat636LX7Bqt5lYEZ27JNDcqxfjdBQuJ/MM4CN/Lzo=
6569
github.com/alecthomas/assert/v2 v2.2.2 h1:Z/iVC0xZfWTaFNE6bA3z07T86hd45Xe2eLt6WVy2bbk=
6670
github.com/alecthomas/assert/v2 v2.2.2/go.mod h1:pXcQ2Asjp247dahGEmsZ6ru0UVwnkhktn7S0bBDLxvQ=
6771
github.com/alecthomas/go-check-sumtype v0.2.0 h1:Bo+e4DFf3rs7ME9w/0SU/g6nmzJaphduP8Cjiz0gbwY=
@@ -664,6 +668,8 @@ github.com/uudashr/iface v1.2.1 h1:vHHyzAUmWZ64Olq6NZT3vg/z1Ws56kyPdBOd5kTXDF8=
664668
github.com/uudashr/iface v1.2.1/go.mod h1:4QvspiRd3JLPAEXBQ9AiZpLbJlrWWgRChOKDJEuQTdg=
665669
github.com/vbatts/tar-split v0.11.3 h1:hLFqsOLQ1SsppQNTMpkpPXClLDfC2A3Zgy9OUU+RVck=
666670
github.com/vbatts/tar-split v0.11.3/go.mod h1:9QlHN18E+fEH7RdG+QAJJcuya3rqT7eXSTY7wGrAokY=
671+
github.com/vbauerster/mpb/v8 v8.9.1 h1:LH5R3lXPfE2e3lIGxN7WNWv3Hl5nWO6LRi2B0L0ERHw=
672+
github.com/vbauerster/mpb/v8 v8.9.1/go.mod h1:4XMvznPh8nfe2NpnDo1QTPvW9MVkUhbG90mPWvmOzcQ=
667673
github.com/vincent-petithory/dataurl v1.0.0 h1:cXw+kPto8NLuJtlMsI152irrVw9fRDX8AbShPRpg2CI=
668674
github.com/vincent-petithory/dataurl v1.0.0/go.mod h1:FHafX5vmDzyP+1CQATJn7WFKc9CvnvxyvZy6I1MrG/U=
669675
github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f h1:J9EGpcZtP0E/raorCMxlFGSTBrsSlaDGf3jU/qvAE2c=
@@ -902,8 +908,8 @@ golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
902908
golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
903909
golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
904910
golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
905-
golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA=
906-
golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
911+
golang.org/x/sys v0.29.0 h1:TPYlXGxvx1MGTn2GiZDhnjPA9wZzZeGKHHmKhHYvgaU=
912+
golang.org/x/sys v0.29.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
907913
golang.org/x/telemetry v0.0.0-20240228155512-f48c80bd79b2/go.mod h1:TeRTkGYfJXctD9OcfyVLyj2J3IxLnKwHJR8f4D8a3YE=
908914
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
909915
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=

pkg/docker/fast_push.go

Lines changed: 49 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ import (
1919
"github.com/aws/aws-sdk-go-v2/credentials"
2020
"github.com/aws/aws-sdk-go-v2/feature/s3/manager"
2121
"github.com/aws/aws-sdk-go-v2/service/s3"
22+
"github.com/vbauerster/mpb/v8"
23+
"github.com/vbauerster/mpb/v8/decor"
2224

2325
"github.com/replicate/cog/pkg/global"
2426
"github.com/replicate/cog/pkg/requirements"
@@ -55,6 +57,9 @@ func userAgent() string {
5557

5658
func FastPush(ctx context.Context, image string, projectDir string, command Command) error {
5759
g, _ := errgroup.WithContext(ctx)
60+
p := mpb.New(
61+
mpb.WithRefreshRate(180 * time.Millisecond),
62+
)
5863

5964
token, err := command.LoadLoginToken(global.ReplicateRegistryHost)
6065
if err != nil {
@@ -69,7 +74,7 @@ func FastPush(ctx context.Context, image string, projectDir string, command Comm
6974
// Upload weights
7075
for _, weight := range weights {
7176
g.Go(func() error {
72-
return uploadFile(ctx, weightsObjectType, weight.Digest, weight.Path, token)
77+
return uploadFile(ctx, weightsObjectType, weight.Digest, weight.Path, token, p, "weights - "+filepath.Base(weight.Path))
7378
})
7479
}
7580

@@ -84,7 +89,7 @@ func FastPush(ctx context.Context, image string, projectDir string, command Comm
8489
return err
8590
}
8691
g.Go(func() error {
87-
return uploadFile(ctx, filesObjectType, hash, aptTarFile, token)
92+
return uploadFile(ctx, filesObjectType, hash, aptTarFile, token, p, "apt")
8893
})
8994
}
9095

@@ -104,7 +109,7 @@ func FastPush(ctx context.Context, image string, projectDir string, command Comm
104109
return err
105110
}
106111
g.Go(func() error {
107-
return uploadFile(ctx, filesObjectType, hash, pythonTar, token)
112+
return uploadFile(ctx, filesObjectType, hash, pythonTar, token, p, "python-packages")
108113
})
109114
} else {
110115
requirementsTarFile := filepath.Join(tmpDir, requirementsTarFile)
@@ -127,7 +132,7 @@ func FastPush(ctx context.Context, image string, projectDir string, command Comm
127132
return err
128133
}
129134
g.Go(func() error {
130-
return uploadFile(ctx, filesObjectType, hash, srcTar, token)
135+
return uploadFile(ctx, filesObjectType, hash, srcTar, token, p, "src")
131136
})
132137

133138
// Wait for uploads
@@ -187,9 +192,45 @@ func checkVerificationStatus(req *http.Request, client *http.Client) (bool, erro
187192
return false, nil
188193
}
189194

190-
func uploadFile(ctx context.Context, objectType string, digest string, path string, token string) error {
195+
func uploadFile(ctx context.Context, objectType string, digest string, path string, token string, p *mpb.Progress, desc string) error {
191196
console.Debug("uploading file: " + path)
192197

198+
// Open the file for uploading
199+
file, err := os.Open(path)
200+
if err != nil {
201+
return err
202+
}
203+
defer file.Close()
204+
205+
// Find the file size
206+
fileInfo, err := file.Stat()
207+
if err != nil {
208+
return err
209+
}
210+
211+
// Start the progress bar
212+
trimDesc := desc
213+
if len(trimDesc) > 20 {
214+
trimDesc = trimDesc[:20]
215+
}
216+
if len(trimDesc) < 20 {
217+
trimDesc += strings.Repeat(" ", 20-len(trimDesc))
218+
}
219+
bar := p.New(fileInfo.Size(),
220+
mpb.BarStyle().Rbound("|"),
221+
mpb.PrependDecorators(
222+
decor.Name(trimDesc+" "),
223+
decor.Counters(decor.SizeB1024(0), "% .2f / % .2f"),
224+
),
225+
mpb.AppendDecorators(
226+
decor.EwmaETA(decor.ET_STYLE_GO, 30),
227+
decor.Name(" ] "),
228+
decor.EwmaSpeed(decor.SizeB1024(0), "% .2f", 30),
229+
),
230+
)
231+
defer bar.Abort(false)
232+
233+
// Declare that we want to upload a file.
193234
uploadUrl := startUploadURL(objectType, digest)
194235
client := &http.Client{}
195236
req, err := http.NewRequestWithContext(ctx, http.MethodPost, uploadUrl.String(), nil)
@@ -219,13 +260,6 @@ func uploadFile(ctx context.Context, objectType string, digest string, path stri
219260
return err
220261
}
221262

222-
// Open the file for uploading
223-
file, err := os.Open(path)
224-
if err != nil {
225-
return err
226-
}
227-
defer file.Close()
228-
229263
// Upload the file using an S3 client
230264
console.Debug("multi-part uploading file: " + path)
231265
cfg := aws.NewConfig()
@@ -244,10 +278,12 @@ func uploadFile(ctx context.Context, objectType string, digest string, path stri
244278
u.PartSize = 64 * 1024 * 1024 // 64MB per part
245279
})
246280

281+
proxyReader := bar.ProxyReader(file)
282+
defer proxyReader.Close()
247283
uploadParams := &s3.PutObjectInput{
248284
Bucket: aws.String(data.Bucket),
249285
Key: aws.String(data.Key),
250-
Body: file,
286+
Body: proxyReader,
251287
}
252288
_, err = uploader.Upload(ctx, uploadParams)
253289
if err != nil {

0 commit comments

Comments
 (0)