From d57dbeda4129258d8dd5288a444f17b077d43aef Mon Sep 17 00:00:00 2001 From: Steve Streeting Date: Fri, 11 Sep 2015 17:35:55 +0100 Subject: [PATCH] Add error collection goroutine so we can abort on fatal errors --- commands/command_prune.go | 48 +++++++++++++++++++++++++++++++-------- 1 file changed, 38 insertions(+), 10 deletions(-) diff --git a/commands/command_prune.go b/commands/command_prune.go index 92a48c2a..22bb3250 100644 --- a/commands/command_prune.go +++ b/commands/command_prune.go @@ -67,19 +67,26 @@ func prune(verifyRemote, dryRun, verbose bool) { progressChan := make(PruneProgressChan, 100) + // Collect errors + errorChan := make(chan error, 10) + var errorwait sync.WaitGroup + errorwait.Add(1) + var taskErrors []error + go pruneTaskCollectErrors(&taskErrors, errorChan, &errorwait) + // Populate the single list of local objects go pruneTaskGetLocalObjects(&localObjects, progressChan, &taskwait) // Now find files to be retained from many sources retainChan := make(chan string, 100) - go pruneTaskGetRetainedCurrentCheckout(retainChan, &taskwait) - go pruneTaskGetRetainedRecentRefs(retainChan, &taskwait) - go pruneTaskGetRetainedUnpushed(retainChan, &taskwait) - go pruneTaskGetRetainedWorktree(retainChan, &taskwait) + go pruneTaskGetRetainedCurrentCheckout(retainChan, errorChan, &taskwait) + go pruneTaskGetRetainedRecentRefs(retainChan, errorChan, &taskwait) + go pruneTaskGetRetainedUnpushed(retainChan, errorChan, &taskwait) + go pruneTaskGetRetainedWorktree(retainChan, errorChan, &taskwait) if verifyRemote { reachableObjects = lfs.NewStringSetWithCapacity(100) - go pruneTaskGetReachableObjects(&reachableObjects, &taskwait) + go pruneTaskGetReachableObjects(&reachableObjects, errorChan, &taskwait) } // Now collect all the retained objects, on separate wait @@ -96,6 +103,10 @@ func prune(verifyRemote, dryRun, verbose bool) { close(retainChan) // triggers retain collector to end now all tasks have retainwait.Wait() // make sure all retained objects added + close(errorChan) // triggers error collector to end now all tasks have + errorwait.Wait() // make sure all errors have been processed + pruneCheckErrors(taskErrors) + prunableObjects := make([]string, 0, len(localObjects)/2) // Build list of prunables (also queue for verify at same time if applicable) @@ -173,6 +184,15 @@ func pruneCheckVerified(prunableObjects []string, reachableObjects, verifiedObje } } +func pruneCheckErrors(taskErrors []error) { + if len(taskErrors) > 0 { + for _, err := range taskErrors { + LoggedError(err, "Prune error: %v", err) + } + Exit("Prune sub-tasks failed, cannot continue") + } +} + func pruneTaskDisplayProgress(progressChan PruneProgressChan, waitg *sync.WaitGroup) { defer waitg.Done() @@ -211,6 +231,14 @@ func pruneTaskCollectRetained(outRetainedObjects *lfs.StringSet, retainChan chan } +func pruneTaskCollectErrors(outtaskErrors *[]error, errorChan chan error, errorwait *sync.WaitGroup) { + defer errorwait.Done() + + for err := range errorChan { + *outtaskErrors = append(*outtaskErrors, err) + } +} + func pruneDeleteFiles(prunableObjects []string) { spinner := lfs.NewSpinner() var problems bytes.Buffer @@ -249,35 +277,35 @@ func pruneTaskGetLocalObjects(outLocalObjects *[]*lfs.Pointer, progChan PrunePro } // Background task, must call waitg.Done() once at end -func pruneTaskGetRetainedCurrentCheckout(retainChan chan string, waitg *sync.WaitGroup) { +func pruneTaskGetRetainedCurrentCheckout(retainChan chan string, errorChan chan error, waitg *sync.WaitGroup) { defer waitg.Done() // TODO } // Background task, must call waitg.Done() once at end -func pruneTaskGetRetainedRecentRefs(retainChan chan string, waitg *sync.WaitGroup) { +func pruneTaskGetRetainedRecentRefs(retainChan chan string, errorChan chan error, waitg *sync.WaitGroup) { defer waitg.Done() // TODO } // Background task, must call waitg.Done() once at end -func pruneTaskGetRetainedUnpushed(retainChan chan string, waitg *sync.WaitGroup) { +func pruneTaskGetRetainedUnpushed(retainChan chan string, errorChan chan error, waitg *sync.WaitGroup) { defer waitg.Done() // TODO } // Background task, must call waitg.Done() once at end -func pruneTaskGetRetainedWorktree(retainChan chan string, waitg *sync.WaitGroup) { +func pruneTaskGetRetainedWorktree(retainChan chan string, errorChan chan error, waitg *sync.WaitGroup) { defer waitg.Done() // TODO } // Background task, must call waitg.Done() once at end -func pruneTaskGetReachableObjects(outObjectSet *lfs.StringSet, waitg *sync.WaitGroup) { +func pruneTaskGetReachableObjects(outObjectSet *lfs.StringSet, errorChan chan error, waitg *sync.WaitGroup) { defer waitg.Done() // TODO