@@ -4,12 +4,12 @@ import (
44 "fmt"
55 "os"
66 "path/filepath"
7- "strings"
87 "sync"
98 "sync/atomic"
109 "time"
1110
12- "github.com/olekukonko/ts"
11+ "github.com/git-lfs/git-lfs/git/githistory/log"
12+ "github.com/git-lfs/git-lfs/tools/humanize"
1313)
1414
1515// ProgressMeter provides a progress bar type output for the TransferQueue. It
@@ -23,14 +23,13 @@ type ProgressMeter struct {
2323 estimatedBytes int64
2424 currentBytes int64
2525 skippedBytes int64
26- started int32
2726 estimatedFiles int32
28- startTime time.Time
29- finished chan interface {}
27+ paused uint32
3028 logger * progressLogger
3129 fileIndex map [string ]int64 // Maps a file name to its transfer number
3230 fileIndexMutex * sync.Mutex
3331 dryRun bool
32+ updates chan * log.Update
3433}
3534
3635type env interface {
@@ -91,10 +90,9 @@ func WithOSEnv(os env) meterOption {
9190func NewMeter (options ... meterOption ) * ProgressMeter {
9291 m := & ProgressMeter {
9392 logger : & progressLogger {},
94- startTime : time .Now (),
9593 fileIndex : make (map [string ]int64 ),
9694 fileIndexMutex : & sync.Mutex {},
97- finished : make (chan interface {} ),
95+ updates : make (chan * log. Update ),
9896 }
9997
10098 for _ , opt := range options {
@@ -106,29 +104,27 @@ func NewMeter(options ...meterOption) *ProgressMeter {
106104
107105// Start begins sending status updates to the optional log file, and stdout.
108106func (p * ProgressMeter ) Start () {
109- if atomic .CompareAndSwapInt32 (& p .started , 0 , 1 ) {
110- go p .writer ()
111- }
107+ atomic .StoreUint32 (& p .paused , 0 )
112108}
113109
114110// Pause stops sending status updates temporarily, until Start() is called again.
115111func (p * ProgressMeter ) Pause () {
116- if atomic .CompareAndSwapInt32 (& p .started , 1 , 0 ) {
117- p .finished <- true
118- }
112+ atomic .StoreUint32 (& p .paused , 1 )
119113}
120114
121115// Add tells the progress meter that a single file of the given size will
122116// possibly be transferred. If a file doesn't need to be transferred for some
123117// reason, be sure to call Skip(int64) with the same size.
124118func (p * ProgressMeter ) Add (size int64 ) {
119+ defer p .update ()
125120 atomic .AddInt32 (& p .estimatedFiles , 1 )
126121 atomic .AddInt64 (& p .estimatedBytes , size )
127122}
128123
129124// Skip tells the progress meter that a file of size `size` is being skipped
130125// because the transfer is unnecessary.
131126func (p * ProgressMeter ) Skip (size int64 ) {
127+ defer p .update ()
132128 atomic .AddInt64 (& p .skippedFiles , 1 )
133129 atomic .AddInt64 (& p .skippedBytes , size )
134130 // Reduce bytes and files so progress easier to parse
@@ -139,6 +135,7 @@ func (p *ProgressMeter) Skip(size int64) {
139135// StartTransfer tells the progress meter that a transferring file is being
140136// added to the TransferQueue.
141137func (p * ProgressMeter ) StartTransfer (name string ) {
138+ defer p .update ()
142139 idx := atomic .AddInt64 (& p .transferringFiles , 1 )
143140 p .fileIndexMutex .Lock ()
144141 p .fileIndex [name ] = idx
@@ -147,12 +144,14 @@ func (p *ProgressMeter) StartTransfer(name string) {
147144
148145// TransferBytes increments the number of bytes transferred
149146func (p * ProgressMeter ) TransferBytes (direction , name string , read , total int64 , current int ) {
147+ defer p .update ()
150148 atomic .AddInt64 (& p .currentBytes , int64 (current ))
151149 p .logBytes (direction , name , read , total )
152150}
153151
154152// FinishTransfer increments the finished transfer count
155153func (p * ProgressMeter ) FinishTransfer (name string ) {
154+ defer p .update ()
156155 atomic .AddInt64 (& p .finishedFiles , 1 )
157156 p .fileIndexMutex .Lock ()
158157 delete (p .fileIndex , name )
@@ -161,102 +160,62 @@ func (p *ProgressMeter) FinishTransfer(name string) {
161160
162161// Finish shuts down the ProgressMeter
163162func (p * ProgressMeter ) Finish () {
164- close (p .finished )
165163 p .update ()
166- p .logger .Close ()
167- if ! p .dryRun && p .estimatedBytes > 0 {
168- fmt .Fprintf (os .Stdout , "\n " )
169- }
164+ close (p .updates )
170165}
171166
172- func (p * ProgressMeter ) logBytes (direction , name string , read , total int64 ) {
173- p .fileIndexMutex .Lock ()
174- idx := p .fileIndex [name ]
175- p .fileIndexMutex .Unlock ()
176- line := fmt .Sprintf ("%s %d/%d %d/%d %s\n " , direction , idx , p .estimatedFiles , read , total , name )
177- if err := p .logger .Write ([]byte (line )); err != nil {
178- p .logger .Shutdown ()
179- }
167+ func (p * ProgressMeter ) Updates () <- chan * log.Update {
168+ return p .updates
180169}
181170
182- func (p * ProgressMeter ) writer () {
183- p .update ()
184- for {
185- select {
186- case <- p .finished :
187- return
188- case <- time .After (time .Millisecond * 200 ):
189- p .update ()
190- }
191- }
171+ func (p * ProgressMeter ) Throttled () bool {
172+ return true
192173}
193174
194175func (p * ProgressMeter ) update () {
195- if p .dryRun || ( p . estimatedFiles == 0 && p . skippedFiles == 0 ) {
176+ if p .skipUpdate ( ) {
196177 return
197178 }
198179
180+ p .updates <- & log.Update {
181+ S : p .str (),
182+ At : time .Now (),
183+ }
184+ }
185+
186+ func (p * ProgressMeter ) skipUpdate () bool {
187+ return p .dryRun ||
188+ (p .estimatedFiles == 0 && p .skippedFiles == 0 ) ||
189+ atomic .LoadUint32 (& p .paused ) == 1
190+ }
191+
192+ func (p * ProgressMeter ) str () string {
199193 // (%d of %d files, %d skipped) %f B / %f B, %f B skipped
200194 // skipped counts only show when > 0
201195
202- out := fmt .Sprintf ("\r Git LFS: (%d of %d files" , p .finishedFiles , p .estimatedFiles )
196+ out := fmt .Sprintf ("\r Git LFS: (%d of %d files" ,
197+ p .finishedFiles ,
198+ p .estimatedFiles )
203199 if p .skippedFiles > 0 {
204200 out += fmt .Sprintf (", %d skipped" , p .skippedFiles )
205201 }
206- out += fmt .Sprintf (") %s / %s" , formatBytes (p .currentBytes ), formatBytes (p .estimatedBytes ))
202+ out += fmt .Sprintf (") %s / %s" ,
203+ humanize .FormatBytes (uint64 (p .currentBytes )),
204+ humanize .FormatBytes (uint64 (p .estimatedBytes )))
207205 if p .skippedBytes > 0 {
208- out += fmt .Sprintf (", %s skipped" , formatBytes (p .skippedBytes ))
209- }
210-
211- fmt .Fprintf (os .Stdout , pad (out ))
212- }
213-
214- func formatBytes (i int64 ) string {
215- switch {
216- case i > 1099511627776 :
217- return fmt .Sprintf ("%#0.2f TB" , float64 (i )/ 1099511627776 )
218- case i > 1073741824 :
219- return fmt .Sprintf ("%#0.2f GB" , float64 (i )/ 1073741824 )
220- case i > 1048576 :
221- return fmt .Sprintf ("%#0.2f MB" , float64 (i )/ 1048576 )
222- case i > 1024 :
223- return fmt .Sprintf ("%#0.2f KB" , float64 (i )/ 1024 )
224- }
225-
226- return fmt .Sprintf ("%d B" , i )
227- }
228-
229- const defaultWidth = 80
230-
231- // pad pads the given message to occupy the entire maximum width of the terminal
232- // LFS is attached to. In doing so, this safeguards subsequent prints of shorter
233- // messages from leaving stray characters from the previous message on the
234- // screen by writing over them with whitespace padding.
235- func pad (msg string ) string {
236- width := defaultWidth
237- size , err := ts .GetSize ()
238- if err == nil {
239- // If `ts.GetSize()` was successful, set the width to the number
240- // of columns present in the terminal LFS is attached to.
241- // Otherwise, fall-back to `defaultWidth`.
242- width = size .Col ()
206+ out += fmt .Sprintf (", %s skipped" ,
207+ humanize .FormatBytes (uint64 (p .skippedBytes )))
243208 }
244209
245- // Pad the string with whitespace so that printing at the start of the
246- // line removes all traces from the last print.removes all traces from
247- // the last print.
248- padding := strings .Repeat (" " , maxInt (0 , width - len (msg )))
249-
250- return msg + padding
210+ return out
251211}
252212
253- // maxInt returns the greater of two `int`s, "a", or "b". This function
254- // originally comes from `github.com/git-lfs/git-lfs/tools#MaxInt`, but would
255- // introduce an import cycle if depended on directly.
256- func maxInt (a , b int ) int {
257- if a > b {
258- return a
213+ func (p * ProgressMeter ) logBytes (direction , name string , read , total int64 ) {
214+ p .fileIndexMutex .Lock ()
215+ idx := p .fileIndex [name ]
216+ p .fileIndexMutex .Unlock ()
217+ line := fmt .Sprintf ("%s %d/%d %d/%d %s\n " , direction , idx , p .estimatedFiles , read , total , name )
218+ if err := p .logger .Write ([]byte (line )); err != nil {
219+ p .logger .Shutdown ()
259220 }
260-
261- return b
262221}
0 commit comments