Files
clr-installer/progress/progress.go
John Akre c7fae814b5 swupd: Concatenate printPrefix with description
Now printPrefix is concatenated into the progress bar description. The
printPrefix is only intended for the mass installer, so it is removed
from the gui/tui progress bar descriptions.

Signed-off-by: John Akre <john.w.akre@intel.com>
2019-10-16 09:15:21 -07:00

136 lines
3.3 KiB
Go

// Copyright © 2018 Intel Corporation
//
// SPDX-License-Identifier: GPL-3.0-only
package progress
import (
"fmt"
"time"
)
// Client is the interface a frontend must implement in order to be notified about
// the install progress
type Client interface {
// Desc is called when a new progress unit is started
Desc(desc string)
// Partial is called on behalf of a MultiStep progress task - it's called for each
// partial step completion
Partial(total int, step int)
// Step is called on behalf of a Loop progress task - it's called based on the
// time returned by LoopWaitDuration
Step()
// Success is called whenever a progress task is completed successfully
Success()
// Failure is called whenever a progress task is failed to be completed
Failure()
// LoopWaitDuration gives the implementation the opportunity configure the loop progress
// step period
LoopWaitDuration() time.Duration
}
// Progress is the internal interface for the progress subsystem, currently we have
// two different implementations a MultiStep and a Loop based one
type Progress interface {
Partial(step int)
Success()
Failure()
}
// BaseProgress is the common implementation between MultiStep and Loop progress
type BaseProgress struct {
total int
}
// Loop defines the specific data for Loop progress implementation
type Loop struct {
BaseProgress
done chan bool
}
var (
impl Client
)
// Set defines the default progress client implementation
func Set(pi Client) {
impl = pi
}
// MultiStep creates a new MultiStep implementation
func MultiStep(total int, format string, a ...interface{}) Progress {
if impl == nil {
panic("No progress implementation was configured. Use progress.Set() before using progress.")
}
desc := fmt.Sprintf(format, a...)
prg := &BaseProgress{total: total}
impl.Desc(desc)
return prg
}
func runStepLoop(prg *Loop, dur time.Duration) {
for {
select {
case <-prg.done:
return
default:
impl.Step()
time.Sleep(dur)
}
}
}
// NewLoop creates a new Loop based progress implementation
func NewLoop(format string, a ...interface{}) Progress {
if impl == nil {
panic("No progress implementation was configured. Use progress.Set() before using progress.")
}
desc := fmt.Sprintf(format, a...)
prg := &Loop{}
prg.done = make(chan bool)
impl.Desc(desc)
go runStepLoop(prg, impl.LoopWaitDuration())
return prg
}
// Success notifies the actual implementation we have finished a task
// successfully, this is the specific implementation for Loop based progress
func (prg *Loop) Success() {
prg.done <- true
impl.Success()
}
// Failure notifies the actual implementation we have finished a task
// unsuccessfully, this is the specific implementation for Loop based progress
func (prg *Loop) Failure() {
prg.done <- true
impl.Failure()
}
// Partial notifies the actual implementation we've moved one step on the
// set of steps for the MultiStep progress implementation
func (prg *BaseProgress) Partial(step int) {
impl.Partial(prg.total, step)
}
// Success is the common BaseProgress implementation and simply notify the actual
// implementation we've finished a task successfully
func (prg *BaseProgress) Success() {
impl.Success()
}
// Failure is the common BaseProgress implementation and simply notify the actual
// implementation we've finished a task unsuccessfully
func (prg *BaseProgress) Failure() {
impl.Failure()
}