recover static method

bool recover(
  1. JustProject project, {
  2. List<String> alsoIn = const [],
  3. String trash = 'just',
  4. String trashRoot = defaultTrashRoot,
})

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.

alsoIn names older journal folders to look in too, relative to the project (a tool that kept its own journals before it built on this one). A journal that doesn't name its trash — an older one — files its folders under trashRoot/trash.

Throws a FormatException when a journal can't be read, naming its folder: its backups are there to put back by hand.

Implementation

static bool recover(
  JustProject project, {
  List<String> alsoIn = const [],
  String trash = 'just',
  String trashRoot = defaultTrashRoot,
}) {
  var found = false;
  for (final rel in [journals, ...alsoIn]) {
    final root = project.dir(rel);
    if (!root.existsSync()) continue;
    // Newest first, so changes are undone in the reverse of their order.
    final dirs = root.listSync().whereType<Directory>().toList()
      ..sort((a, b) => _stampOrder(b.path, a.path));
    for (final d in dirs) {
      final journal = File('${d.path}/journal.json');
      if (!journal.existsSync()) {
        // A cleanup cut short, or a change that never got going.
        _deleteQuietly(d);
        continue;
      }
      if (File('${d.path}/$_rolledBackMarker').existsSync()) {
        ProjectTransaction._(project, d, 'just')._cleanUp();
        continue;
      }
      found = true;
      final t = _read(project, d, journal, trash, trashRoot);
      switch (t._state) {
        case _committed:
          t._finish();
        case _rolledBack:
          t._cleanUp();
        default:
          t.rollBack();
      }
    }
    try {
      if (root.existsSync() && root.listSync().isEmpty) root.deleteSync();
    } on FileSystemException {
      // Busy: harmless, cleared next time.
    }
  }
  return found;
}