diff options
Diffstat (limited to 'internal/engine')
| -rw-r--r-- | internal/engine/apply.go | 40 |
1 files changed, 23 insertions, 17 deletions
diff --git a/internal/engine/apply.go b/internal/engine/apply.go index 1e59aa1..e2d4db8 100644 --- a/internal/engine/apply.go +++ b/internal/engine/apply.go @@ -118,6 +118,11 @@ func (e *Engine) applyFile(ctx context.Context, dirName string, c plan.Chain, ap return unloggedStep(rel, c.Steps[i], sr, err) } return nil + }, func(i int, step plan.Step, entry string) error { + // The displaced file is in the Trash from this moment, whatever + // becomes of the step that needed its name, so its line is written + // here rather than with the rest of the step. + return e.logDisplace(j, run, dirName, rel, i+1, step, entry) }) if err != nil { return FileResult{}, err @@ -125,6 +130,24 @@ func (e *Engine) applyFile(ctx context.Context, dirName string, c plan.Chain, ap return FileResult{File: c.File, Steps: results}, nil } +// logDisplace writes the line for a file trashed to make room, as soon as +// it has reached the Trash. It is its own action with its own line (spec +// §9), independent of whether the step that needed the name then succeeds. +func (e *Engine) logDisplace(j *journal.Writer, run, dirName, rel string, stepNum int, step plan.Step, entry string) error { + dst := filepath.Join(trash.Dir(), "files", entry) + size, mtime := statSizeModTime(dst) + return j.Append(journal.Entry{ + Time: e.Now(), Run: run, Dir: dirName, File: rel, Step: stepNum, + Action: "displace", Status: "ok", Rule: step.Rule, + // Detail carries the trash entry name explicitly: Dst's shape + // (trash.Dir()/files/<entry>) is internal/apply's and this file's + // own convention, not a contract undo may quietly depend on. + // PlanUndo/ApplyUndo read the name from here, never by taking + // Dst's basename. + Src: step.Displaces, Dst: dst, Size: size, ModTime: mtime, Detail: entry, + }) +} + // unloggedStep is the error for a step whose log entry could not be // written. A step that ran is named with where its file is now: undo // cannot see it, so the user must be told where to look. @@ -233,23 +256,6 @@ func actionName(k plan.Kind) string { // step's planned destination (informational only — PlanUndo never reverses // a non-"ok" entry) and Size/ModTime stay zero. func (e *Engine) logStep(j *journal.Writer, run, dirName, rel string, stepNum int, step plan.Step, sr apply.StepResult) error { - if sr.DisplacedEntry != "" { - dst := filepath.Join(trash.Dir(), "files", sr.DisplacedEntry) - size, mtime := statSizeModTime(dst) - if err := j.Append(journal.Entry{ - Time: e.Now(), Run: run, Dir: dirName, File: rel, Step: stepNum, - Action: "displace", Status: "ok", Rule: step.Rule, - // Detail carries the trash entry name explicitly: Dst's shape - // (trash.Dir()/files/<entry>) is internal/apply's and this - // file's own convention, not a contract undo may quietly - // depend on. PlanUndo/ApplyUndo read the name from here, - // never by taking Dst's basename. - Src: step.Displaces, Dst: dst, Size: size, ModTime: mtime, Detail: sr.DisplacedEntry, - }); err != nil { - return err - } - } - for _, dir := range sr.Made { size, mtime := statSizeModTime(dir) if err := j.Append(journal.Entry{ |
