From ce4e953b4e09728bd0972773a0d3de9cc8f18f0e Mon Sep 17 00:00:00 2001 From: UncleGedd <42304551+UncleGedd@users.noreply.github.com> Date: Wed, 8 Nov 2023 11:57:30 -0600 Subject: [PATCH] fix: adds error channel to RenderProgressBarForLocalDirWrite (#2117) ## Description Adds an error channel to `utils.RenderProgressBarForLocalDirWrite` to handle the case where an operation (e.g. `oras.Copy`) is not successful and we want to kill the goroutine without displaying a 'success' message Co-authored-by: Wayne Starr --- src/internal/packager/images/pull.go | 7 ++++--- src/pkg/oci/pull.go | 4 +++- src/pkg/utils/bytes.go | 9 +++++++-- 3 files changed, 14 insertions(+), 6 deletions(-) diff --git a/src/internal/packager/images/pull.go b/src/internal/packager/images/pull.go index ed0b70d478..131d1128ac 100644 --- a/src/internal/packager/images/pull.go +++ b/src/internal/packager/images/pull.go @@ -185,10 +185,11 @@ func (i *ImageConfig) PullAll() ([]ImgInfo, error) { // Create a thread to update a progress bar as we save the image files to disk doneSaving := make(chan int) + errorSaving := make(chan int) var progressBarWaitGroup sync.WaitGroup progressBarWaitGroup.Add(1) updateText := fmt.Sprintf("Pulling %d images", imageCount) - go utils.RenderProgressBarForLocalDirWrite(i.ImagesPath, totalBytes, &progressBarWaitGroup, doneSaving, updateText, updateText) + go utils.RenderProgressBarForLocalDirWrite(i.ImagesPath, totalBytes, &progressBarWaitGroup, doneSaving, errorSaving, updateText, updateText) // Spawn a goroutine for each layer to write it to disk using crane @@ -324,7 +325,7 @@ func (i *ImageConfig) PullAll() ([]ImgInfo, error) { onLayerWritingError := func(err error) error { // Send a signal to the progress bar that we're done and wait for the thread to finish - doneSaving <- 1 + errorSaving <- 1 progressBarWaitGroup.Wait() message.WarnErr(err, "Failed to write image layers, trying again up to 3 times...") if strings.HasPrefix(err.Error(), "expected blob size") { @@ -391,7 +392,7 @@ func (i *ImageConfig) PullAll() ([]ImgInfo, error) { onImageSavingError := func(err error) error { // Send a signal to the progress bar that we're done and wait for the thread to finish - doneSaving <- 1 + errorSaving <- 1 progressBarWaitGroup.Wait() message.WarnErr(err, "Failed to write image config or manifest, trying again up to 3 times...") return err diff --git a/src/pkg/oci/pull.go b/src/pkg/oci/pull.go index 6152d57dda..310778c78c 100644 --- a/src/pkg/oci/pull.go +++ b/src/pkg/oci/pull.go @@ -229,12 +229,14 @@ func (o *OrasRemote) CopyWithProgress(layers []ocispec.Descriptor, store oras.Ta // Create a thread to update a progress bar as we save the package to disk doneSaving := make(chan int) + encounteredErr := make(chan int) var wg sync.WaitGroup wg.Add(1) successText := fmt.Sprintf("Pulling %q", helpers.OCIURLPrefix+o.repo.Reference.String()) - go utils.RenderProgressBarForLocalDirWrite(destinationDir, estimatedBytes, &wg, doneSaving, "Pulling", successText) + go utils.RenderProgressBarForLocalDirWrite(destinationDir, estimatedBytes, &wg, doneSaving, encounteredErr, "Pulling", successText) _, err := oras.Copy(o.ctx, o.repo, o.repo.Reference.String(), store, o.repo.Reference.String(), copyOpts) if err != nil { + encounteredErr <- 1 return err } diff --git a/src/pkg/utils/bytes.go b/src/pkg/utils/bytes.go index 42e8be579b..464e11e061 100644 --- a/src/pkg/utils/bytes.go +++ b/src/pkg/utils/bytes.go @@ -57,8 +57,8 @@ func ByteFormat(inputNum float64, precision int) string { } // RenderProgressBarForLocalDirWrite creates a progress bar that continuously tracks the progress of writing files to a local directory and all of its subdirectories. -// NOTE: This function runs infinitely until the completeChan is triggered, this function should be run in a goroutine while a different thread/process is writing to the directory. -func RenderProgressBarForLocalDirWrite(filepath string, expectedTotal int64, wg *sync.WaitGroup, completeChan chan int, updateText string, successText string) { +// NOTE: This function runs infinitely until either completeChan or errChan is triggered, this function should be run in a goroutine while a different thread/process is writing to the directory. +func RenderProgressBarForLocalDirWrite(filepath string, expectedTotal int64, wg *sync.WaitGroup, completeChan chan int, errChan chan int, updateText string, successText string) { // Create a progress bar title := fmt.Sprintf("%s (%s of %s)", updateText, ByteFormat(float64(0), 2), ByteFormat(float64(expectedTotal), 2)) @@ -72,6 +72,11 @@ func RenderProgressBarForLocalDirWrite(filepath string, expectedTotal int64, wg wg.Done() return + case <-errChan: + progressBar.Stop() + wg.Done() + return + default: // Read the directory size currentBytes, dirErr := GetDirSize(filepath)