Skip to content

Commit cadd71c

Browse files
authored
Merge pull request #2515 from 89luca89/main
feat: add file upload progress
2 parents 9646cde + 182034d commit cadd71c

2 files changed

Lines changed: 79 additions & 0 deletions

File tree

pkg/devspace/build/builder/kaniko/kaniko.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import (
1111
"github.com/sirupsen/logrus"
1212

1313
"github.com/loft-sh/devspace/pkg/util/interrupt"
14+
"github.com/loft-sh/devspace/pkg/util/progressreader"
1415

1516
"github.com/docker/docker/pkg/archive"
1617
"github.com/docker/docker/pkg/idtools"
@@ -223,6 +224,9 @@ func (b *Builder) BuildImage(ctx devspacecontext.Context, contextPath, dockerfil
223224
return err
224225
}
225226

227+
// Wrap it with our custom io.ReadCloser in order to show progress.
228+
buildCtx = &progressreader.ProgressReader{ReadCloser: buildCtx, Ctx: ctx}
229+
226230
// Copy complete context
227231
_, stderr, err := ctx.KubeClient().ExecBuffered(ctx.Context(), buildPod, buildPod.Spec.InitContainers[0].Name, []string{"tar", "xp", "-C", kanikoContextPath + "/."}, buildCtx)
228232
if err != nil {
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
package progressreader
2+
3+
import (
4+
"fmt"
5+
devspacecontext "github.com/loft-sh/devspace/pkg/devspace/context"
6+
"io"
7+
"time"
8+
)
9+
10+
// ProgressReader wraps an existing io.ReadCloser.
11+
type ProgressReader struct {
12+
io.ReadCloser
13+
Ctx devspacecontext.Context
14+
total int64 // Total # of bytes transferred
15+
transferEnd time.Time
16+
transferStart time.Time
17+
transferStep time.Time
18+
}
19+
20+
// Override Read method in order to print some progress
21+
// during reading.
22+
func (r *ProgressReader) Read(p []byte) (int, error) {
23+
if r.transferStart.IsZero() {
24+
// initialize start timer
25+
r.transferStart = time.Now()
26+
}
27+
28+
curr, err := r.ReadCloser.Read(p)
29+
r.total += int64(curr)
30+
31+
if err == nil {
32+
// initialize the transfer current step, or check if at least 1s is passed
33+
// in order to not spam progress updates too much
34+
if r.transferStep.IsZero() || time.Now().Second() >= (r.transferStep.Second()+3) {
35+
r.transferStep = time.Now()
36+
37+
r.Ctx.Log().Info("Uploaded " + toHumanReadable(r.total) + " " + r.Rate()+ "\r")
38+
}
39+
}
40+
41+
if err == io.EOF {
42+
r.transferEnd = time.Now()
43+
}
44+
45+
return curr, err
46+
}
47+
48+
// Rate returns the rate of progress in b/s
49+
func (r *ProgressReader) Rate() string {
50+
end := r.transferEnd
51+
if end.IsZero() {
52+
end = time.Now()
53+
}
54+
return toHumanReadable(int64((float64(r.total)/(end.Sub(r.transferStart).Seconds())))) + "/s"
55+
}
56+
57+
// convert bytes input to a human readable format (Gb,Mb,Kb,b)
58+
func toHumanReadable(input int64) string {
59+
conversion := float64(input / 1024)
60+
61+
if conversion < 0 {
62+
return fmt.Sprintf("%d b", input)
63+
}
64+
65+
if conversion < 1000 {
66+
return fmt.Sprintf("%.2f Kb", conversion)
67+
}
68+
69+
conversion = conversion / 1024
70+
if conversion < 1000 {
71+
return fmt.Sprintf("%.2f Mb", conversion)
72+
}
73+
74+
return fmt.Sprintf("%.2f Gb", conversion/1024)
75+
}

0 commit comments

Comments
 (0)