ProjectTransaction class final

One change to a project, journalled so it can be undone.

Every step is recorded before it is taken: the files backed up (and whether they existed), the folders moved aside, the folders moved in. A failure calls rollBack, which puts every file and folder back byte for byte; a crash leaves the journal behind, and recover rolls it back (or finishes a change that had committed) the next time a tool starts. Both can be cut short and run again: each step is only taken while it is still needed.

Take a ProjectLock first: two transactions at once would undo each other's work.

final lock = ProjectLock.acquire(project);
try {
  ProjectTransaction.recover(project);
  final txn = ProjectTransaction.begin(project, trash: 'my_tool');
  try {
    txn.write('config/settings.json', text);
    txn.commit();
  } catch (_) {
    txn.rollBack(); // nothing, once commit() got through
    rethrow;
  }
} finally {
  lock.release();
}

Properties

dir → Directory
Where the journal, backups and moved-aside folders are kept.
final
hashCode → int
The hash code for this object.
no setterinherited
project → JustProject
The project being changed.
final
runtimeType → Type
A representation of the runtime type of the object.
no setterinherited
stamp → String
The stamp this change files its trash under.
no setter
trash → String
The folder under trashRoot that replaced and removed folders go to when the change commits: restorable, by hand or by the tool that made the change.
final
trashRoot → String
The project folder that holds every tool's trash: defaultTrashRoot, unless the change's tool keeps its own (an app that restores from a folder of its own, say).
final

Methods

backUp(List<String> files) → void
Backs up files (paths in the project; missing ones are noted as missing, so a rollback deletes what the change created). A symbolic link is backed up as a link, and the file it leads to too — what a write through it changes. Throws a FileSystemException, backing up nothing more, for a path that leads outside the project.
commit() → void
Makes the change final: folders moved aside go to the trash, and the journal is removed.
delete(String rel) → void
Deletes the file rel, backing it up first. Nothing when it is already gone. A symbolic link is deleted itself, not what it leads to, and a rollback makes it again.
moveAside(String id, String path) → void
Moves the folder at path out of the way, keeping it as id until the change commits or rolls back. id is a plain folder name, as for stage, used once in a change.
moveIn(String id, String path) → void
Moves the folder staged as id to path, which must not exist.
noSuchMethod(Invocation invocation) → dynamic
Invoked when a nonexistent method or property is accessed.
inherited
rollBack() → void
Puts every file and folder back as it was, and removes the journal.
stage(String id, Map<String, Uint8List> files, {Set<String> executable = const {}}) → void
Writes files (relative path → bytes) into a staging folder id, beside the project, ready for moveIn. On macOS and Linux the paths in executable are made executable (chmod +x), as an archive's entries say (ZipEntry.isExecutable); Windows has no such bit.
toString() → String
A string representation of this object.
inherited
write(String rel, String text) → void
Writes text to rel, backing it up first.
writeBytes(String rel, List<int> bytes) → void
Writes bytes to rel, backing it up first.
writeIfChanged(String rel, String text) → void
write, unless rel already holds exactly text.

Operators

operator ==(Object other) → bool
The equality operator.
inherited

Static Methods

begin(JustProject project, {DateTime? now, required String trash, String trashRoot = defaultTrashRoot}) → ProjectTransaction
Starts a change to project, stamped now, whose replaced folders go to <trashRoot>/<trash>/<stamp>/ when it commits. Both are kept in the journal, so recover finishes a change the same way.
recover(JustProject project, {List<String> alsoIn = const [], String trash = 'just', String trashRoot = defaultTrashRoot}) → bool
Finishes or undoes every change a crash left in project: one that had committed is completed, any other is rolled back. Returns whether there was one. Hold the ProjectLock while calling it. It can be run any number of times, and after being cut short. A change already rolled back whose journal could not be removed then is only tidied away: undoing it again would undo what changed since.

Constants

defaultTrashRoot → const String
Where replaced and removed folders go unless a change says otherwise: .just_trash/<trash>/<stamp>/ in the project.
journals → const String
Where every journal lives in a project.
staging → const String
Where staged folders wait before moveIn.