Artifact 9ba3a9315ff5a20f9e186d732fd8dccf0a6b3aba78160d322aac0a1651ce6b24:
- File
internal/checkout/update_undo.go
— part of check-in
[858c20561f]
at
2026-10-19 22:58:21
on branch feat/submanifest-reader
— fix(undo): save and restore symlinks as fossil's undo does
Move checkout's link-aware diskView into vfile.Disk, so checkout, undo and stash share one RepoFILE view: Stat, Read, Write (which deletes a link before writing, makes a symlink when allow-symlinks is on, creates the directory and sets the executable bit as file_setexe does), SetExe, MTime and Remove. The allow-symlinks setting is read by vfile.OpenDisk.
undo.Save, Undo, Redo, Swap, ReadFile and RestoreFiles now take a Disk: a symlink is read as its target's name and recorded with isLink, and is deleted and made a symlink again on restore, as undo_save and undo_one do, so Undo of an Update no longer writes through a link. (user: [email protected], size: 1302) [annotate] [blame] [check-ins using] [more...]
//go:build !js package checkout import ( "database/sql" "github.com/danmestas/go-libfossil/internal/undo" "github.com/danmestas/go-libfossil/internal/vfile" ) // updateUndo is the undo state Update saves: the files its steps change, as // they were before, and how they were seen on disk. type updateUndo struct { disk vfile.Disk files []undo.File } // readUpdateUndo reads the file of every step that writes or removes one, // under its name in the checkout, as fossil's update calls undo_save. func (c *Checkout) readUpdateUndo(steps []updateStep) (updateUndo, error) { disk, err := c.newDiskView() if err != nil { return updateUndo{}, err } u := updateUndo{disk: disk} for _, s := range steps { switch s.action { case updateWrite, updateAddOver, updateMerge, updateRemove: default: continue } f, err := undo.ReadFile(u.disk, c.dir, s.name) if err != nil { return updateUndo{}, err } u.files = append(u.files, f) } return u, nil } // save records u as the undo state within tx, before vfile moves. func (u updateUndo) save(tx *sql.Tx) error { return undo.SaveTx(tx, u.files) } // rollBackUpdate puts u's files back after an update failed partway. func (c *Checkout) rollBackUpdate(u updateUndo) error { return undo.RestoreFiles(u.disk, c.dir, u.files) }