@SuppressWarnings("UseOfSystemOutOrSystemErr")
  private List<PatchAction> calculateActions(PatchSpec spec) throws IOException {
    LOG.info("Calculating difference...");
    System.out.println("Calculating difference...");

    File olderDir = new File(spec.getOldFolder());
    File newerDir = new File(spec.getNewFolder());

    Set<String> ignored = new HashSet<>(spec.getIgnoredFiles());
    Set<String> critical = new HashSet<>(spec.getCriticalFiles());
    Set<String> optional = new HashSet<>(spec.getOptionalFiles());
    Set<String> strict = new HashSet<>(spec.getStrictFiles());

    Map<String, Long> oldChecksums = digestFiles(olderDir, ignored);
    Map<String, Long> newChecksums = digestFiles(newerDir, ignored);
    DiffCalculator.Result diff = DiffCalculator.calculate(oldChecksums, newChecksums, critical, optional, true);

    LOG.info("Preparing actions...");
    System.out.println("Preparing actions...");

    List<PatchAction> actions = new ArrayList<>();

    // 'delete' actions before 'create' actions to prevent newly created files to be deleted if the names differ only in case.
    for (Map.Entry<String, Long> each : diff.filesToDelete.entrySet()) {
      // Add them in reverse order so directory structures start deleting the files before the directory itself.
      actions.add(0, new DeleteAction(this, each.getKey(), each.getValue()));
    }

    for (String each : diff.filesToCreate.keySet()) {
      actions.add(new CreateAction(this, each));
    }

    for (Map.Entry<String, DiffCalculator.Update> each : diff.filesToUpdate.entrySet()) {
      DiffCalculator.Update update = each.getValue();
      actions.add(new UpdateAction(this, each.getKey(), update.source, update.checksum, update.move));
    }

    if (spec.isStrict()) {
      for (Map.Entry<String, Long> each : diff.commonFiles.entrySet()) {
        actions.add(new ValidateAction(this, each.getKey(), each.getValue()));
      }
    }

    for (PatchAction action : actions) {
      LOG.info(action.getPath());
      action.setCritical(critical.contains(action.getPath()));
      action.setOptional(optional.contains(action.getPath()));
      action.setStrict(strict.contains(action.getPath()));
    }

    return actions;
  }
@SuppressWarnings("UseOfSystemOutOrSystemErr")
  private List<PatchAction> calculateActions(PatchSpec spec)