github.com/akerouanton/docker@v1.11.0-rc3/pkg/progress/progressreader.go (about)

     1  package progress
     2  
     3  import (
     4  	"io"
     5  )
     6  
     7  // Reader is a Reader with progress bar.
     8  type Reader struct {
     9  	in         io.ReadCloser // Stream to read from
    10  	out        Output        // Where to send progress bar to
    11  	size       int64
    12  	current    int64
    13  	lastUpdate int64
    14  	id         string
    15  	action     string
    16  }
    17  
    18  // NewProgressReader creates a new ProgressReader.
    19  func NewProgressReader(in io.ReadCloser, out Output, size int64, id, action string) *Reader {
    20  	return &Reader{
    21  		in:     in,
    22  		out:    out,
    23  		size:   size,
    24  		id:     id,
    25  		action: action,
    26  	}
    27  }
    28  
    29  func (p *Reader) Read(buf []byte) (n int, err error) {
    30  	read, err := p.in.Read(buf)
    31  	p.current += int64(read)
    32  	updateEvery := int64(1024 * 512) //512kB
    33  	if p.size > 0 {
    34  		// Update progress for every 1% read if 1% < 512kB
    35  		if increment := int64(0.01 * float64(p.size)); increment < updateEvery {
    36  			updateEvery = increment
    37  		}
    38  	}
    39  	if p.current-p.lastUpdate > updateEvery || err != nil {
    40  		p.updateProgress(err != nil && read == 0)
    41  		p.lastUpdate = p.current
    42  	}
    43  
    44  	return read, err
    45  }
    46  
    47  // Close closes the progress reader and its underlying reader.
    48  func (p *Reader) Close() error {
    49  	if p.current < p.size {
    50  		// print a full progress bar when closing prematurely
    51  		p.current = p.size
    52  		p.updateProgress(false)
    53  	}
    54  	return p.in.Close()
    55  }
    56  
    57  func (p *Reader) updateProgress(last bool) {
    58  	p.out.WriteProgress(Progress{ID: p.id, Action: p.action, Current: p.current, Total: p.size, LastUpdate: last})
    59  }