Add CLI progress bars to the packer tool
Since packing can be quite slow, it is nice to display progress to the caller. We use the excellent github.com/vbauerster/mpb library to do so, and add a bit of colour with github.com/logrusru/aurora. Finally, augment the inspector and packer with a summary printer that displays the overall file size/count, and compression ratio for each compression type.
This commit is contained in:
parent
984639d475
commit
6f532296ef
6 changed files with 273 additions and 12 deletions
|
|
@ -45,6 +45,24 @@ type FileToPack struct {
|
|||
DisableBrotli bool `yaml:"disable_brotli"`
|
||||
}
|
||||
|
||||
// Progress is a callback object which reports packing progress.
|
||||
type Progress interface {
|
||||
// Count reports the number of items that have begun processing.
|
||||
Count(n int)
|
||||
|
||||
// Begin denotes the processing of an input file.
|
||||
Begin(filename, compression string)
|
||||
|
||||
// End denotes the completion of input file processing.
|
||||
End(filename, compression string)
|
||||
}
|
||||
|
||||
type ignoreProgress int
|
||||
|
||||
func (ignoreProgress) Count(_ int) {}
|
||||
func (ignoreProgress) Begin(_, _ string) {}
|
||||
func (ignoreProgress) End(_, _ string) {}
|
||||
|
||||
const (
|
||||
// minCompressionSaving means we'll only use the compressed version of
|
||||
// the file if it's at least this many bytes smaller than the original.
|
||||
|
|
@ -68,8 +86,18 @@ const (
|
|||
sendfileLimit = 0x7FFFF000
|
||||
)
|
||||
|
||||
// Pack a file.
|
||||
// Pack a file. Use Pack2 for progress reporting.
|
||||
func Pack(filesToPack FilesToPack, outputFilename string) error {
|
||||
return Pack2(filesToPack, outputFilename, nil)
|
||||
}
|
||||
|
||||
// Pack2 will pack a file, with progress reporting. The progress interface may
|
||||
// be nil.
|
||||
func Pack2(filesToPack FilesToPack, outputFilename string, progress Progress) error {
|
||||
if progress == nil {
|
||||
progress = ignoreProgress(0)
|
||||
}
|
||||
|
||||
finalFname, w, err := writefile.New(outputFilename)
|
||||
if err != nil {
|
||||
return err
|
||||
|
|
@ -79,7 +107,8 @@ func Pack(filesToPack FilesToPack, outputFilename string) error {
|
|||
// we use this little structure to serialise file writes below, and
|
||||
// it has a couple of convenience methods for common operations
|
||||
packer := packer{
|
||||
w: w,
|
||||
w: w,
|
||||
progress: progress,
|
||||
}
|
||||
|
||||
// write initial header (will rewrite offset/length when known)
|
||||
|
|
@ -124,6 +153,7 @@ func Pack(filesToPack FilesToPack, outputFilename string) error {
|
|||
Files: make(map[string]*packed.File),
|
||||
}
|
||||
|
||||
var count int
|
||||
PackingLoop:
|
||||
for path, fileToPack := range filesToPack {
|
||||
select {
|
||||
|
|
@ -132,6 +162,8 @@ PackingLoop:
|
|||
break PackingLoop
|
||||
default:
|
||||
packer.packFile(path, fileToPack)
|
||||
count++
|
||||
progress.Count(count)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -199,12 +231,13 @@ func compressionWorthwhile(data []byte, compressed os.FileInfo) bool {
|
|||
// of compression. Unexported methods assume they are called in a context where
|
||||
// the lock is not needed or already taken; exported methods take the lock.
|
||||
type packer struct {
|
||||
w *os.File
|
||||
lock sync.Mutex
|
||||
cpus chan struct{}
|
||||
errors chan error
|
||||
aborted chan struct{}
|
||||
dir *packed.Directory
|
||||
w *os.File
|
||||
lock sync.Mutex
|
||||
cpus chan struct{}
|
||||
errors chan error
|
||||
aborted chan struct{}
|
||||
dir *packed.Directory
|
||||
progress Progress
|
||||
}
|
||||
|
||||
// pad will move the file write pointer to the next padding boundary. It is not
|
||||
|
|
@ -312,11 +345,15 @@ func (p *packer) packFile(path string, fileToPack FileToPack) {
|
|||
// list of operations on this input file that we'll carry out asynchronously
|
||||
ops := []func() error{
|
||||
func() error {
|
||||
p.progress.Begin(fileToPack.Filename, "uncompressed")
|
||||
defer p.progress.End(fileToPack.Filename, "uncompressed")
|
||||
return p.Uncompressed(fileToPack.Filename, info)
|
||||
},
|
||||
}
|
||||
if !fileToPack.DisableCompression && !fileToPack.DisableGzip {
|
||||
ops = append(ops, func() error {
|
||||
p.progress.Begin(fileToPack.Filename, "gzip")
|
||||
defer p.progress.End(fileToPack.Filename, "gzip")
|
||||
if err := p.Gzip(data, info); err != nil {
|
||||
return fmt.Errorf("gzip compression of %s "+
|
||||
"failed: %v", fileToPack.Filename, err)
|
||||
|
|
@ -326,6 +363,8 @@ func (p *packer) packFile(path string, fileToPack FileToPack) {
|
|||
}
|
||||
if !fileToPack.DisableCompression && !fileToPack.DisableBrotli {
|
||||
ops = append(ops, func() error {
|
||||
p.progress.Begin(fileToPack.Filename, "brotli")
|
||||
defer p.progress.End(fileToPack.Filename, "brotli")
|
||||
if err := p.Brotli(data, info); err != nil {
|
||||
return fmt.Errorf("brotli compression of %s "+
|
||||
"failed: %v", fileToPack.Filename, err)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue