add flag to retain all progress bars (#1582)
## Description Adds the --save-progress-bars flag, which prevents the observe package from removing completed progress bars. ## Type of change - [x] 🌻 Feature ## Issue(s) * #1581 ## Test Plan - [x] 💪 Manual
This commit is contained in:
parent
dea9d4d609
commit
162713dc54
@ -14,15 +14,16 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
noProgressBarsFN = "no-progress-bars"
|
hideProgressBarsFN = "hide-progress"
|
||||||
progressBarWidth = 32
|
retainProgressBarsFN = "retain-progress"
|
||||||
|
progressBarWidth = 32
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
wg sync.WaitGroup
|
wg sync.WaitGroup
|
||||||
// TODO: Revisit this being a global nd make it a parameter to the progress methods
|
// TODO: Revisit this being a global nd make it a parameter to the progress methods
|
||||||
// so that each bar can be initialized with different contexts if needed.
|
// so that each bar can be initialized with different contexts if needed.
|
||||||
con context.Context
|
contxt context.Context
|
||||||
writer io.Writer
|
writer io.Writer
|
||||||
progress *mpb.Progress
|
progress *mpb.Progress
|
||||||
cfg *config
|
cfg *config
|
||||||
@ -34,37 +35,49 @@ func init() {
|
|||||||
makeSpinFrames(progressBarWidth)
|
makeSpinFrames(progressBarWidth)
|
||||||
}
|
}
|
||||||
|
|
||||||
// adds the persistent boolean flag --no-progress-bars to the provided command.
|
// adds the persistent boolean flag --hide-progress to the provided command.
|
||||||
// This is a hack for help displays. Due to seeding the context, we also
|
// This is a hack for help displays. Due to seeding the context, we also
|
||||||
// need to parse the configuration before we execute the command.
|
// need to parse the configuration before we execute the command.
|
||||||
func AddProgressBarFlags(parent *cobra.Command) {
|
func AddProgressBarFlags(parent *cobra.Command) {
|
||||||
fs := parent.PersistentFlags()
|
fs := parent.PersistentFlags()
|
||||||
fs.Bool(noProgressBarsFN, false, "turn off the progress bar displays")
|
fs.Bool(hideProgressBarsFN, false, "turn off the progress bar displays")
|
||||||
|
fs.Bool(retainProgressBarsFN, false, "retain the progress bar displays after completion")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Due to races between the lazy evaluation of flags in cobra and the need to init observer
|
// Due to races between the lazy evaluation of flags in cobra and the need to init observer
|
||||||
// behavior in a ctx, these options get pre-processed manually here using pflags. The canonical
|
// behavior in a ctx, these options get pre-processed manually here using pflags. The canonical
|
||||||
// AddProgressBarFlag() ensures the flags are displayed as part of the help/usage output.
|
// AddProgressBarFlag() ensures the flags are displayed as part of the help/usage output.
|
||||||
func PreloadFlags() bool {
|
func PreloadFlags() *config {
|
||||||
fs := pflag.NewFlagSet("seed-observer", pflag.ContinueOnError)
|
fs := pflag.NewFlagSet("seed-observer", pflag.ContinueOnError)
|
||||||
fs.ParseErrorsWhitelist.UnknownFlags = true
|
fs.ParseErrorsWhitelist.UnknownFlags = true
|
||||||
fs.Bool(noProgressBarsFN, false, "turn off the progress bar displays")
|
fs.Bool(hideProgressBarsFN, false, "turn off the progress bar displays")
|
||||||
|
fs.Bool(retainProgressBarsFN, false, "retain the progress bar displays after completion")
|
||||||
// prevents overriding the corso/cobra help processor
|
// prevents overriding the corso/cobra help processor
|
||||||
fs.BoolP("help", "h", false, "")
|
fs.BoolP("help", "h", false, "")
|
||||||
|
|
||||||
// parse the os args list to find the log level flag
|
// parse the os args list to find the observer display flags
|
||||||
if err := fs.Parse(os.Args[1:]); err != nil {
|
if err := fs.Parse(os.Args[1:]); err != nil {
|
||||||
return false
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// retrieve the user's preferred display
|
// retrieve the user's preferred display
|
||||||
// automatically defaults to "info"
|
// automatically defaults to "info"
|
||||||
shouldHide, err := fs.GetBool(noProgressBarsFN)
|
shouldHide, err := fs.GetBool(hideProgressBarsFN)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
return shouldHide
|
// retrieve the user's preferred display
|
||||||
|
// automatically defaults to "info"
|
||||||
|
shouldAlwaysShow, err := fs.GetBool(retainProgressBarsFN)
|
||||||
|
if err != nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return &config{
|
||||||
|
doNotDisplay: shouldHide,
|
||||||
|
keepBarsAfterComplete: shouldAlwaysShow,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
@ -73,7 +86,8 @@ func PreloadFlags() bool {
|
|||||||
|
|
||||||
// config handles observer configuration
|
// config handles observer configuration
|
||||||
type config struct {
|
type config struct {
|
||||||
doNotDisplay bool
|
doNotDisplay bool
|
||||||
|
keepBarsAfterComplete bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c config) hidden() bool {
|
func (c config) hidden() bool {
|
||||||
@ -82,20 +96,20 @@ func (c config) hidden() bool {
|
|||||||
|
|
||||||
// SeedWriter adds default writer to the observe package.
|
// SeedWriter adds default writer to the observe package.
|
||||||
// Uses a noop writer until seeded.
|
// Uses a noop writer until seeded.
|
||||||
func SeedWriter(ctx context.Context, w io.Writer, hide bool) {
|
func SeedWriter(ctx context.Context, w io.Writer, c *config) {
|
||||||
writer = w
|
writer = w
|
||||||
con = ctx
|
contxt = ctx
|
||||||
|
|
||||||
if con == nil {
|
if contxt == nil {
|
||||||
con = context.Background()
|
contxt = context.Background()
|
||||||
}
|
}
|
||||||
|
|
||||||
cfg = &config{
|
if c != nil {
|
||||||
doNotDisplay: hide,
|
cfg = c
|
||||||
}
|
}
|
||||||
|
|
||||||
progress = mpb.NewWithContext(
|
progress = mpb.NewWithContext(
|
||||||
con,
|
contxt,
|
||||||
mpb.WithWidth(progressBarWidth),
|
mpb.WithWidth(progressBarWidth),
|
||||||
mpb.WithWaitGroup(&wg),
|
mpb.WithWaitGroup(&wg),
|
||||||
mpb.WithOutput(writer),
|
mpb.WithOutput(writer),
|
||||||
@ -109,7 +123,7 @@ func Complete() {
|
|||||||
progress.Wait()
|
progress.Wait()
|
||||||
}
|
}
|
||||||
|
|
||||||
SeedWriter(con, writer, cfg.doNotDisplay)
|
SeedWriter(contxt, writer, cfg)
|
||||||
}
|
}
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@ -168,7 +182,7 @@ func MessageWithCompletion(message string) (chan<- struct{}, func()) {
|
|||||||
go func(ci <-chan struct{}) {
|
go func(ci <-chan struct{}) {
|
||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
case <-con.Done():
|
case <-contxt.Done():
|
||||||
bar.SetTotal(-1, true)
|
bar.SetTotal(-1, true)
|
||||||
case <-ci:
|
case <-ci:
|
||||||
// We don't care whether the channel was signalled or closed
|
// We don't care whether the channel was signalled or closed
|
||||||
@ -195,17 +209,20 @@ func ItemProgress(rc io.ReadCloser, header, iname string, totalBytes int64) (io.
|
|||||||
|
|
||||||
wg.Add(1)
|
wg.Add(1)
|
||||||
|
|
||||||
bar := progress.New(
|
barOpts := []mpb.BarOption{
|
||||||
totalBytes,
|
|
||||||
mpb.NopStyle(),
|
|
||||||
mpb.BarRemoveOnComplete(),
|
|
||||||
mpb.PrependDecorators(
|
mpb.PrependDecorators(
|
||||||
decor.Name(header, decor.WCSyncSpaceR),
|
decor.Name(header, decor.WCSyncSpaceR),
|
||||||
decor.Name(iname, decor.WCSyncSpaceR),
|
decor.Name(iname, decor.WCSyncSpaceR),
|
||||||
decor.CountersKibiByte(" %.1f/%.1f ", decor.WC{W: 8}),
|
decor.CountersKibiByte(" %.1f/%.1f ", decor.WC{W: 8}),
|
||||||
decor.NewPercentage("%d ", decor.WC{W: 4}),
|
decor.NewPercentage("%d ", decor.WC{W: 4}),
|
||||||
),
|
),
|
||||||
)
|
}
|
||||||
|
|
||||||
|
if !cfg.keepBarsAfterComplete {
|
||||||
|
barOpts = append(barOpts, mpb.BarRemoveOnComplete())
|
||||||
|
}
|
||||||
|
|
||||||
|
bar := progress.New(totalBytes, mpb.NopStyle(), barOpts...)
|
||||||
|
|
||||||
return bar.ProxyReader(rc), waitAndCloseBar(bar)
|
return bar.ProxyReader(rc), waitAndCloseBar(bar)
|
||||||
}
|
}
|
||||||
@ -232,23 +249,25 @@ func ProgressWithCount(header, message string, count int64) (chan<- struct{}, fu
|
|||||||
|
|
||||||
wg.Add(1)
|
wg.Add(1)
|
||||||
|
|
||||||
bar := progress.New(
|
barOpts := []mpb.BarOption{
|
||||||
count,
|
|
||||||
mpb.NopStyle(),
|
|
||||||
mpb.BarRemoveOnComplete(),
|
|
||||||
mpb.PrependDecorators(
|
mpb.PrependDecorators(
|
||||||
decor.Name(header, decor.WCSyncSpaceR),
|
decor.Name(header, decor.WCSyncSpaceR),
|
||||||
decor.Counters(0, " %d/%d "),
|
decor.Counters(0, " %d/%d "),
|
||||||
decor.Name(message),
|
decor.Name(message),
|
||||||
),
|
),
|
||||||
)
|
}
|
||||||
|
|
||||||
|
if !cfg.keepBarsAfterComplete {
|
||||||
|
barOpts = append(barOpts, mpb.BarRemoveOnComplete())
|
||||||
|
}
|
||||||
|
|
||||||
|
bar := progress.New(count, mpb.NopStyle(), barOpts...)
|
||||||
|
|
||||||
ch := make(chan struct{})
|
ch := make(chan struct{})
|
||||||
|
|
||||||
go func(ci <-chan struct{}) {
|
go func(ci <-chan struct{}) {
|
||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
case <-con.Done():
|
case <-contxt.Done():
|
||||||
bar.Abort(true)
|
bar.Abort(true)
|
||||||
return
|
return
|
||||||
|
|
||||||
@ -319,25 +338,29 @@ func CollectionProgress(user, category, dirName string) (chan<- struct{}, func()
|
|||||||
|
|
||||||
wg.Add(1)
|
wg.Add(1)
|
||||||
|
|
||||||
bar := progress.New(
|
barOpts := []mpb.BarOption{
|
||||||
-1, // -1 to indicate an unbounded count
|
mpb.PrependDecorators(decor.Name(category)),
|
||||||
mpb.SpinnerStyle(spinFrames...),
|
|
||||||
mpb.BarRemoveOnComplete(),
|
|
||||||
mpb.PrependDecorators(
|
|
||||||
decor.Name(category),
|
|
||||||
),
|
|
||||||
mpb.AppendDecorators(
|
mpb.AppendDecorators(
|
||||||
decor.CurrentNoUnit("%d - ", decor.WCSyncSpace),
|
decor.CurrentNoUnit("%d - ", decor.WCSyncSpace),
|
||||||
decor.Name(fmt.Sprintf("%s - %s", user, dirName)),
|
decor.Name(fmt.Sprintf("%s - %s", user, dirName)),
|
||||||
),
|
),
|
||||||
|
}
|
||||||
|
|
||||||
|
if !cfg.keepBarsAfterComplete {
|
||||||
|
barOpts = append(barOpts, mpb.BarRemoveOnComplete())
|
||||||
|
}
|
||||||
|
|
||||||
|
bar := progress.New(
|
||||||
|
-1, // -1 to indicate an unbounded count
|
||||||
|
mpb.SpinnerStyle(spinFrames...),
|
||||||
|
barOpts...,
|
||||||
)
|
)
|
||||||
|
|
||||||
ch := make(chan struct{})
|
ch := make(chan struct{})
|
||||||
|
|
||||||
go func(ci <-chan struct{}) {
|
go func(ci <-chan struct{}) {
|
||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
case <-con.Done():
|
case <-contxt.Done():
|
||||||
bar.SetTotal(-1, true)
|
bar.SetTotal(-1, true)
|
||||||
return
|
return
|
||||||
|
|
||||||
|
|||||||
@ -33,13 +33,13 @@ func (suite *ObserveProgressUnitSuite) TestItemProgress() {
|
|||||||
t := suite.T()
|
t := suite.T()
|
||||||
|
|
||||||
recorder := strings.Builder{}
|
recorder := strings.Builder{}
|
||||||
observe.SeedWriter(ctx, &recorder, false)
|
observe.SeedWriter(ctx, &recorder, nil)
|
||||||
|
|
||||||
defer func() {
|
defer func() {
|
||||||
// don't cross-contaminate other tests.
|
// don't cross-contaminate other tests.
|
||||||
observe.Complete()
|
observe.Complete()
|
||||||
//nolint:forbidigo
|
//nolint:forbidigo
|
||||||
observe.SeedWriter(context.Background(), nil, false)
|
observe.SeedWriter(context.Background(), nil, nil)
|
||||||
}()
|
}()
|
||||||
|
|
||||||
from := make([]byte, 100)
|
from := make([]byte, 100)
|
||||||
@ -87,13 +87,13 @@ func (suite *ObserveProgressUnitSuite) TestCollectionProgress_unblockOnCtxCancel
|
|||||||
t := suite.T()
|
t := suite.T()
|
||||||
|
|
||||||
recorder := strings.Builder{}
|
recorder := strings.Builder{}
|
||||||
observe.SeedWriter(ctx, &recorder, false)
|
observe.SeedWriter(ctx, &recorder, nil)
|
||||||
|
|
||||||
defer func() {
|
defer func() {
|
||||||
// don't cross-contaminate other tests.
|
// don't cross-contaminate other tests.
|
||||||
observe.Complete()
|
observe.Complete()
|
||||||
//nolint:forbidigo
|
//nolint:forbidigo
|
||||||
observe.SeedWriter(context.Background(), nil, false)
|
observe.SeedWriter(context.Background(), nil, nil)
|
||||||
}()
|
}()
|
||||||
|
|
||||||
progCh, closer := observe.CollectionProgress("test", "testcat", "testertons")
|
progCh, closer := observe.CollectionProgress("test", "testcat", "testertons")
|
||||||
@ -122,13 +122,13 @@ func (suite *ObserveProgressUnitSuite) TestCollectionProgress_unblockOnChannelCl
|
|||||||
t := suite.T()
|
t := suite.T()
|
||||||
|
|
||||||
recorder := strings.Builder{}
|
recorder := strings.Builder{}
|
||||||
observe.SeedWriter(ctx, &recorder, false)
|
observe.SeedWriter(ctx, &recorder, nil)
|
||||||
|
|
||||||
defer func() {
|
defer func() {
|
||||||
// don't cross-contaminate other tests.
|
// don't cross-contaminate other tests.
|
||||||
observe.Complete()
|
observe.Complete()
|
||||||
//nolint:forbidigo
|
//nolint:forbidigo
|
||||||
observe.SeedWriter(context.Background(), nil, false)
|
observe.SeedWriter(context.Background(), nil, nil)
|
||||||
}()
|
}()
|
||||||
|
|
||||||
progCh, closer := observe.CollectionProgress("test", "testcat", "testertons")
|
progCh, closer := observe.CollectionProgress("test", "testcat", "testertons")
|
||||||
@ -153,12 +153,12 @@ func (suite *ObserveProgressUnitSuite) TestObserveProgress() {
|
|||||||
defer flush()
|
defer flush()
|
||||||
|
|
||||||
recorder := strings.Builder{}
|
recorder := strings.Builder{}
|
||||||
observe.SeedWriter(ctx, &recorder, false)
|
observe.SeedWriter(ctx, &recorder, nil)
|
||||||
|
|
||||||
defer func() {
|
defer func() {
|
||||||
// don't cross-contaminate other tests.
|
// don't cross-contaminate other tests.
|
||||||
//nolint:forbidigo
|
//nolint:forbidigo
|
||||||
observe.SeedWriter(context.Background(), nil, false)
|
observe.SeedWriter(context.Background(), nil, nil)
|
||||||
}()
|
}()
|
||||||
|
|
||||||
message := "Test Message"
|
message := "Test Message"
|
||||||
@ -174,12 +174,12 @@ func (suite *ObserveProgressUnitSuite) TestObserveProgressWithCompletion() {
|
|||||||
defer flush()
|
defer flush()
|
||||||
|
|
||||||
recorder := strings.Builder{}
|
recorder := strings.Builder{}
|
||||||
observe.SeedWriter(ctx, &recorder, false)
|
observe.SeedWriter(ctx, &recorder, nil)
|
||||||
|
|
||||||
defer func() {
|
defer func() {
|
||||||
// don't cross-contaminate other tests.
|
// don't cross-contaminate other tests.
|
||||||
//nolint:forbidigo
|
//nolint:forbidigo
|
||||||
observe.SeedWriter(context.Background(), nil, false)
|
observe.SeedWriter(context.Background(), nil, nil)
|
||||||
}()
|
}()
|
||||||
|
|
||||||
message := "Test Message"
|
message := "Test Message"
|
||||||
@ -204,12 +204,12 @@ func (suite *ObserveProgressUnitSuite) TestObserveProgressWithChannelClosed() {
|
|||||||
defer flush()
|
defer flush()
|
||||||
|
|
||||||
recorder := strings.Builder{}
|
recorder := strings.Builder{}
|
||||||
observe.SeedWriter(ctx, &recorder, false)
|
observe.SeedWriter(ctx, &recorder, nil)
|
||||||
|
|
||||||
defer func() {
|
defer func() {
|
||||||
// don't cross-contaminate other tests.
|
// don't cross-contaminate other tests.
|
||||||
//nolint:forbidigo
|
//nolint:forbidigo
|
||||||
observe.SeedWriter(context.Background(), nil, false)
|
observe.SeedWriter(context.Background(), nil, nil)
|
||||||
}()
|
}()
|
||||||
|
|
||||||
message := "Test Message"
|
message := "Test Message"
|
||||||
@ -236,12 +236,12 @@ func (suite *ObserveProgressUnitSuite) TestObserveProgressWithContextCancelled()
|
|||||||
ctx, cancel := context.WithCancel(ctx)
|
ctx, cancel := context.WithCancel(ctx)
|
||||||
|
|
||||||
recorder := strings.Builder{}
|
recorder := strings.Builder{}
|
||||||
observe.SeedWriter(ctx, &recorder, false)
|
observe.SeedWriter(ctx, &recorder, nil)
|
||||||
|
|
||||||
defer func() {
|
defer func() {
|
||||||
// don't cross-contaminate other tests.
|
// don't cross-contaminate other tests.
|
||||||
//nolint:forbidigo
|
//nolint:forbidigo
|
||||||
observe.SeedWriter(context.Background(), nil, false)
|
observe.SeedWriter(context.Background(), nil, nil)
|
||||||
}()
|
}()
|
||||||
|
|
||||||
message := "Test Message"
|
message := "Test Message"
|
||||||
@ -265,12 +265,12 @@ func (suite *ObserveProgressUnitSuite) TestObserveProgressWithCount() {
|
|||||||
defer flush()
|
defer flush()
|
||||||
|
|
||||||
recorder := strings.Builder{}
|
recorder := strings.Builder{}
|
||||||
observe.SeedWriter(ctx, &recorder, false)
|
observe.SeedWriter(ctx, &recorder, nil)
|
||||||
|
|
||||||
defer func() {
|
defer func() {
|
||||||
// don't cross-contaminate other tests.
|
// don't cross-contaminate other tests.
|
||||||
//nolint:forbidigo
|
//nolint:forbidigo
|
||||||
observe.SeedWriter(context.Background(), nil, false)
|
observe.SeedWriter(context.Background(), nil, nil)
|
||||||
}()
|
}()
|
||||||
|
|
||||||
header := "Header"
|
header := "Header"
|
||||||
@ -298,12 +298,12 @@ func (suite *ObserveProgressUnitSuite) TestObserveProgressWithCountChannelClosed
|
|||||||
defer flush()
|
defer flush()
|
||||||
|
|
||||||
recorder := strings.Builder{}
|
recorder := strings.Builder{}
|
||||||
observe.SeedWriter(ctx, &recorder, false)
|
observe.SeedWriter(ctx, &recorder, nil)
|
||||||
|
|
||||||
defer func() {
|
defer func() {
|
||||||
// don't cross-contaminate other tests.
|
// don't cross-contaminate other tests.
|
||||||
//nolint:forbidigo
|
//nolint:forbidigo
|
||||||
observe.SeedWriter(context.Background(), nil, false)
|
observe.SeedWriter(context.Background(), nil, nil)
|
||||||
}()
|
}()
|
||||||
|
|
||||||
header := "Header"
|
header := "Header"
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user