Refactoring: new packages console, http, Progress is interface.

This commit is contained in:
Andrey Smirnov
2014-02-19 13:08:55 +04:00
parent bd119dbfed
commit 2d589bd23d
18 changed files with 193 additions and 138 deletions

134
console/progress.go Normal file
View File

@@ -0,0 +1,134 @@
package console
import (
"fmt"
"github.com/cheggaaa/pb"
"github.com/smira/aptly/aptly"
)
const (
codePrint = iota
codeProgress
codeHideProgress
)
type printTask struct {
code int
message string
}
// Progress is a progress displaying subroutine, it allows to show download and other operations progress
// mixed with progress bar
type Progress struct {
stop chan bool
stopped chan bool
queue chan printTask
bar *pb.ProgressBar
barShown bool
}
// Check interface
var (
_ aptly.Progress = (*Progress)(nil)
)
// NewProgress creates new progress instance
func NewProgress() *Progress {
return &Progress{
stop: make(chan bool),
stopped: make(chan bool),
queue: make(chan printTask, 100),
}
}
// Start makes progress start its work
func (p *Progress) Start() {
go p.worker()
}
// Shutdown shuts down progress display
func (p *Progress) Shutdown() {
p.ShutdownBar()
p.stop <- true
<-p.stopped
}
// InitBar starts progressbar for count bytes or count items
func (p *Progress) InitBar(count int64, isBytes bool) {
if p.bar != nil {
panic("bar already initialized")
}
if RunningOnTerminal() {
p.bar = pb.New(0)
p.bar.Total = count
p.bar.NotPrint = true
p.bar.Callback = func(out string) {
p.queue <- printTask{code: codeProgress, message: out}
}
if isBytes {
p.bar.SetUnits(pb.U_BYTES)
p.bar.ShowSpeed = true
}
p.bar.Start()
}
}
// ShutdownBar stops progress bar and hides it
func (p *Progress) ShutdownBar() {
if p.bar == nil {
return
}
p.bar.Finish()
p.bar = nil
p.queue <- printTask{code: codeHideProgress}
}
// Write is implementation of io.Writer to support updating of progress bar
func (p *Progress) Write(s []byte) (int, error) {
if p.bar != nil {
p.bar.Add(len(s))
}
return len(s), nil
}
// AddBar increments progress for progress bar
func (p *Progress) AddBar(count int) {
if p.bar != nil {
p.bar.Add(count)
}
}
// Printf does printf but in safe manner: not overwriting progress bar
func (p *Progress) Printf(msg string, a ...interface{}) {
p.queue <- printTask{code: codePrint, message: fmt.Sprintf(msg, a...)}
}
func (p *Progress) worker() {
for {
select {
case task := <-p.queue:
switch task.code {
case codePrint:
if p.barShown {
fmt.Print("\r\033[2K")
p.barShown = false
}
fmt.Print(task.message)
case codeProgress:
if p.bar != nil {
fmt.Print("\r" + task.message)
p.barShown = true
}
case codeHideProgress:
if p.barShown {
fmt.Print("\r\033[2K")
p.barShown = false
}
}
case <-p.stop:
p.stopped <- true
return
}
}
}

13
console/terminal.go Normal file
View File

@@ -0,0 +1,13 @@
// +build !freebsd
package console
import (
"code.google.com/p/go.crypto/ssh/terminal"
"syscall"
)
// RunningOnTerminal checks whether stdout is terminal
func RunningOnTerminal() bool {
return terminal.IsTerminal(syscall.Stdout)
}

10
console/terminal_bsd.go Normal file
View File

@@ -0,0 +1,10 @@
// +build freebsd
package console
// RunningOnTerminal checks whether stdout is terminal
//
// Stub for FreeBSD, until in go1.3 terminal.IsTerminal would start working for FreeBSD
func RunningOnTerminal() bool {
return false
}