aboutsummaryrefslogtreecommitdiff
path: root/cmd/krino/undo.go
diff options
context:
space:
mode:
Diffstat (limited to 'cmd/krino/undo.go')
-rw-r--r--cmd/krino/undo.go59
1 files changed, 18 insertions, 41 deletions
diff --git a/cmd/krino/undo.go b/cmd/krino/undo.go
index ecab2f3..5a7db4b 100644
--- a/cmd/krino/undo.go
+++ b/cmd/krino/undo.go
@@ -15,9 +15,7 @@ import (
"golang.org/x/term"
- "krino/internal/config"
"krino/internal/engine"
- "krino/internal/journal"
"krino/internal/lock"
"krino/internal/xdg"
)
@@ -113,7 +111,18 @@ func cmdUndo(g *globals, args []string, stdout, stderr io.Writer) int {
// PlanUndo only reads the log; nothing is touched yet (spec ยง10), which
// is what makes it safe to call before any lock is taken.
- up, err := e.PlanUndo(runID)
+ sess, err := e.NewSession(g.dry)
+ if err != nil {
+ fmt.Fprintf(stderr, "krino: %v\n", err)
+ return 1
+ }
+ defer func() {
+ if cerr := sess.Close(); cerr != nil {
+ fmt.Fprintf(stderr, "krino: %v\n", cerr)
+ }
+ }()
+
+ up, err := sess.PlanUndo(runID)
if err != nil {
fmt.Fprintf(stderr, "krino: %v\n", err)
return 1
@@ -137,7 +146,7 @@ func cmdUndo(g *globals, args []string, stdout, stderr io.Writer) int {
// right after acquisition.
var locks []*lock.Lock
if !g.dry {
- locks, err = acquireUndoLocks(ctx, e.Config, undoDirNames(up.Files), !g.yes)
+ locks, err = sess.LockDirs(ctx, undoDirNames(up.Files), !g.yes)
if err != nil {
if errors.Is(err, context.Canceled) || errors.Is(err, context.DeadlineExceeded) {
return 130
@@ -197,26 +206,12 @@ func cmdUndo(g *globals, args []string, stdout, stderr io.Writer) int {
// Ruling 2 (Task 7), carried over: journal.Open creates the state
// directory and the log file as a side effect of merely being called,
- // so it is opened only once we know something will actually be
+ // so the session opens it only now, when something will actually be
// applied - never for -n (returned above), and not merely because -y
- // or a review session ran, unlike cmdSort's own eager-open (which opens
- // before it knows whether anything is actionable, a difference forced
- // by cmdSort not yet having a plan to inspect at that point in its
- // flow; undo already does, so it opens later, and never opens if
- // undoActionableCount was 0 or the user chose [s]/[q] above).
- j, err := journal.Open(e.Config.LogFile())
- if err != nil {
- fmt.Fprintf(stderr, "krino: %v\n", err)
- return 1
- }
- defer func() {
- if cerr := j.Close(); cerr != nil {
- fmt.Fprintf(stderr, "krino: %v\n", cerr)
- }
- }()
- run := journal.NewRunID(e.Now())
-
- res, aerr := e.ApplyUndo(ctx, toApply, j, run)
+ // or a review session ran, unlike cmdSort, which opens before it knows
+ // whether anything is actionable (a difference forced by cmdSort not
+ // yet having a plan to inspect at that point in its flow).
+ res, aerr := sess.ApplyUndo(ctx, toApply)
if aerr != nil {
if errors.Is(aerr, context.Canceled) || errors.Is(aerr, context.DeadlineExceeded) {
// Interrupted mid-apply: the ctx.Err() check below turns this
@@ -269,24 +264,6 @@ func undoDirNames(files []engine.UndoFile) []string {
return out
}
-// acquireUndoLocks takes the lock for every name in dirs, in order,
-// mirroring cmdSort's per-directory lock.Acquire call. If any acquisition
-// fails - held with wait false, or ctx cancelled while waiting - every lock
-// already taken is released before returning, so a partial lock set is
-// never left held while the caller reports the error and stops.
-func acquireUndoLocks(ctx context.Context, cfg *config.Config, dirs []string, wait bool) ([]*lock.Lock, error) {
- locks := make([]*lock.Lock, 0, len(dirs))
- for _, name := range dirs {
- l, err := lock.Acquire(ctx, cfg.LockFile(name), wait)
- if err != nil {
- releaseUndoLocks(locks)
- return nil, fmt.Errorf("%s: %w", name, err)
- }
- locks = append(locks, l)
- }
- return locks, nil
-}
-
// releaseUndoLocks releases every lock in locks and returns any release
// errors, one lock's failure never stopping the rest from being released -
// the same "release on every path" guarantee cmdSort gives its own single