static int main_interleave_commits()

in src/split2mono.cpp [403:560]


static int main_interleave_commits(const char *cmd, int argc,
                                   const char *argv[]) {
  if (argc < 1)
    return usage("interleave-commits: missing <dbdir>", cmd);
  split2monodb db;
  if (db.opendb(argv[0]))
    return usage("could not open <dbdir>", cmd);
  --argc, ++argv;

  // Copied from svn2git.cpp.
  if (argc < 1)
    return usage("interleave-commits: missing <svn2git-db>", cmd);
  mmapped_file svn2git;
  unsigned char svn2git_magic[] = {'s', 2, 'g', 0xd, 0xb, 'm', 0xa, 'p'};
  if (svn2git.init(argv[0]) ||
      svn2git.num_bytes < (long)sizeof(svn2git_magic) ||
      memcmp(svn2git_magic, svn2git.bytes, sizeof(svn2git_magic)))
    return usage("invalid <svn2git-db>", cmd);
  --argc, ++argv;

  commit_interleaver interleaver(db, svn2git);

  if (argc < 1)
    return usage("interleave-commits: missing <head>", cmd);
  textual_sha1 head;
  if (head.from_input(*argv))
    return usage("invalid sha1 for <head>", cmd);
  interleaver.set_initial_head(head);
  --argc, ++argv;

  if (argc < 1)
    return usage("interleave-commits: missing (<ref>:<dir>)+", cmd);
  if (argc > dir_mask::max_size)
    return usage("interleave-commits: too many dirs (max: " +
                     std::to_string(dir_mask::max_size) + ")",
                 cmd);

  // Parse refs and directories.
  auto parse_sha1 = [&interleaver](const char *&current, sha1_ref &sha1) {
    // TODO: add a testcase where sha1 is non-zero.
    textual_sha1 text;
    if (text.from_input(current, &current))
      return 1;
    sha1 = interleaver.sha1s.lookup(text);
    return 0;
  };
  auto try_parse_ch = [](const char *&current, int ch) {
    if (*current != ch)
      return 1;
    ++current;
    return 0;
  };
  bool was_repeated_head_specified = false;
  for (; argc; ++argv, --argc) {
    const char *arg = *argv;
    sha1_ref head;
    bool is_tracked = false;
    bool is_repeat = false;

    // Skip over "--" and break out to continue to goals.
    if (!strcmp(arg, "--")) {
      ++argv, --argc;
      break;
    }

    if (try_parse_ch(arg, '-')) {
      is_tracked = true;
      if (!try_parse_ch(arg, '%'))
        is_repeat = true;
    }
    if ((is_tracked && !is_repeat && parse_sha1(arg, head)) ||
        try_parse_ch(arg, ':'))
      return error("invalid <sha1>:... in '" + std::string(*argv) + "'");

    if (!try_parse_ch(arg, '%')) {
      if (*arg)
        return error("invalid junk after '%' in '" + std::string(*argv) +
                     "'");

      // This is the head for all of the repeated dirs.
      if (was_repeated_head_specified)
        return error("repeated head already specified");
      was_repeated_head_specified = true;
      interleaver.repeated_head = head;
      continue;
    }

    int d = -1;
    bool is_new = false;
    if (interleaver.dirs.add_dir(arg, is_new, d))
      return error("invalid ...:<dir> in '" + std::string(*argv) + "'");
    if (!is_new)
      return usage("duplicate <dir> '" + std::string(arg) + "'", cmd);
    if (!is_tracked)
      continue;
    interleaver.dirs.tracked_dirs.set(d);
    interleaver.dirs.set_head(d, head);
    if (is_repeat) {
      interleaver.dirs.repeated_dirs.set(d);
      interleaver.dirs.list[d].is_repeated = true;
    }
  }

  if (was_repeated_head_specified && !interleaver.dirs.repeated_dirs.bits.any())
    return usage("head specified for repeated dirs, but no dirs", cmd);
  if (!was_repeated_head_specified && interleaver.dirs.repeated_dirs.bits.any())
    return usage("repeated dirs specified, but missing head", cmd);
  if (interleaver.repeated_head)
    interleaver.dirs.active_dirs.bits |= interleaver.dirs.repeated_dirs.bits;

  // Create sources now that dirs are stable.
  interleaver.initialize_sources();

  // Parse goals.
  for (; argc; ++argv, --argc) {
    const char *arg = *argv;
    sha1_ref goal;
    if (parse_sha1(arg, goal) || try_parse_ch(arg, ':'))
      return usage("invalid <sha1>:... in '" + std::string(*argv) + "'", cmd);
    if (!goal)
      return usage("invalid null goal in '" + std::string(*argv) + "'", cmd);

    if (arg[0] == '%' && !arg[1]) {
      if (!interleaver.repeat)
        return usage("goal set for undeclared repeat '%'", cmd);
      if (interleaver.repeat->goal &&
          interleaver.repeat->goal != interleaver.repeat->head)
        return usage("two goals for repeat '%'", cmd);
      interleaver.repeat->goal = goal;
      continue;
    }

    bool found = false;
    int d = interleaver.dirs.lookup_dir(arg, found);
    if (!found)
      return usage("unknown <dir> '" + std::string(arg) + "'", cmd);
    if (!interleaver.dirs.tracked_dirs.test(d))
      return usage("untracked <dir> '" + std::string(arg) + "'", cmd);
    if (interleaver.dirs.repeated_dirs.test(d))
      return usage("cannot have goal for repeat <dir> '" + std::string(arg)
                       + "'",
                   cmd);
    auto &source = interleaver.q.sources[interleaver.dirs.list[d].source_index];
    if (source.goal && source.goal != source.head)
      return usage("two goals for <dir> '" + std::string(arg) + "'", cmd);
    source.goal = goal;
  }

  for (auto &source : interleaver.q.sources)
    if (!source.goal)
      return usage(std::string("missing goal for <dir> '") +
                   (source.is_repeat
                        ? "-"
                        : interleaver.dirs.list[source.dir_index].name) +
                   "'", cmd);

  return interleaver.run();
}