// actionRunner handles running an action which may take a while to complete // providing progress bars and signal handling. func actionRunner(cmd *cli.Cmd, action action) func() { cmd.Spec = "[--silent] [--no-progress] " + cmd.Spec silent := cmd.BoolOpt("silent", false, "Set to true to disable all non-error output") noProgress := cmd.BoolOpt("no-progress", false, "Set to true to disable the progress bar") return func() { var infoWriter io.Writer = os.Stderr var ticker <-chan time.Time if err := action.init(); err != nil { fail("Initialization failed: %v", err) } done, err := action.start(infoWriter) if err != nil { fail("Startup failed: %v", err) } var bar *pb.ProgressBar if !*silent && !*noProgress { ticker = time.Tick(statsFrequency) bar = action.newProgressBar() if bar != nil { bar.Output = os.Stderr bar.ShowSpeed = true bar.ManualUpdate = true bar.SetMaxWidth(78) bar.Start() bar.Update() } } if *silent { infoWriter = ioutil.Discard } sigchan := make(chan os.Signal, 1) signal.Notify(sigchan, syscall.SIGTERM, syscall.SIGKILL, syscall.SIGINT) LOOP: for { select { case <-ticker: action.updateProgress(bar) bar.Update() case <-sigchan: bar.Finish() fmt.Fprintf(os.Stderr, "\nAborting..") action.abort() <-done fmt.Fprintf(os.Stderr, "Aborted.\n") break LOOP case err := <-done: if err != nil { fail("Processing failed: %v", err) } break LOOP } } if bar != nil { bar.Finish() } if !*silent { action.printFinalStats(infoWriter) } } }