Compare commits
1
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7d8ef03247 |
+23
-26
@@ -225,16 +225,20 @@ var errInterrupted = errors.New("interrupted before the command finished")
|
||||
// op's cleanup (removing decrypted scratch files) runs before the
|
||||
// process exits; the wait is bounded by shutdownTimeout. report is
|
||||
// called with a failure so the caller can show it to the user before
|
||||
// it becomes errReported. An interrupted op is not reported, whatever
|
||||
// it returned; RunOperation returns errInterrupted instead.
|
||||
// it becomes errReported.
|
||||
//
|
||||
// The run counts as interrupted unless op returned, without an
|
||||
// interrupt having cancelled it, before RunWithApp returned. An
|
||||
// interrupted op is not reported, whatever it returned; RunOperation
|
||||
// returns errInterrupted instead.
|
||||
func RunOperation(
|
||||
ctx context.Context, opts AppOptions,
|
||||
op func(v *vaultik.Vaultik) error, report func(err error),
|
||||
) error {
|
||||
var (
|
||||
mu sync.Mutex
|
||||
failed bool
|
||||
interrupted bool
|
||||
finished bool // op returned before any interrupt cancelled it
|
||||
failed bool // op finished with an error
|
||||
)
|
||||
|
||||
opts.Invokes = append(opts.Invokes,
|
||||
@@ -247,21 +251,19 @@ func RunOperation(
|
||||
err := op(v)
|
||||
|
||||
// Only stop, called from OnStop below, cancels the
|
||||
// Vaultik context; before op has returned, that
|
||||
// happens only on an interrupt. Check the context,
|
||||
// not err: an interrupted op need not return
|
||||
// Vaultik context, so a live context means no
|
||||
// interrupt cancelled op. Check the context, not
|
||||
// err: an interrupted op need not return
|
||||
// context.Canceled (`snapshot verify --json`
|
||||
// returns a verification failure).
|
||||
switch {
|
||||
case v.Context().Err() != nil:
|
||||
mu.Lock()
|
||||
interrupted = true
|
||||
mu.Unlock()
|
||||
case err != nil:
|
||||
if v.Context().Err() == nil {
|
||||
if err != nil {
|
||||
report(err)
|
||||
}
|
||||
|
||||
mu.Lock()
|
||||
failed = true
|
||||
finished = true
|
||||
failed = err != nil
|
||||
mu.Unlock()
|
||||
}
|
||||
|
||||
@@ -282,12 +284,6 @@ func RunOperation(
|
||||
if !stop(ctx) {
|
||||
log.Warn("Shutdown timed out before the operation " +
|
||||
"finished; decrypted temporary files may remain")
|
||||
|
||||
// op has not returned, so the app is stopping on
|
||||
// an interrupt.
|
||||
mu.Lock()
|
||||
interrupted = true
|
||||
mu.Unlock()
|
||||
}
|
||||
|
||||
return nil
|
||||
@@ -300,16 +296,17 @@ func RunOperation(
|
||||
return err
|
||||
}
|
||||
|
||||
// RunWithApp returns only after OnStop has waited for the goroutine
|
||||
// to return, whether the shutdown came from op finishing or from an
|
||||
// interrupt, so the goroutine's write to failed or interrupted is in
|
||||
// place by the time we read it. If OnStop timed out, the goroutine
|
||||
// may still be running, and OnStop has set interrupted itself.
|
||||
// RunWithApp returns only after the app was asked to stop, either by
|
||||
// an interrupt or by the goroutine's Shutdown call. When op finished
|
||||
// without being cancelled, the goroutine set finished before that
|
||||
// call. So if finished is unset here, an interrupt stopped the app,
|
||||
// and op either returned after it was cancelled or is still running
|
||||
// because the shutdown timed out.
|
||||
mu.Lock()
|
||||
defer mu.Unlock()
|
||||
|
||||
switch {
|
||||
case interrupted:
|
||||
case !finished:
|
||||
return errInterrupted
|
||||
case failed:
|
||||
return errReported
|
||||
|
||||
Reference in New Issue
Block a user