prepare static method

Future<RefSource> prepare({
  1. required String projectDir,
  2. required String ref,
  3. required Directory stagingRoot,
  4. bool fetch = true,
})

Resolves ref in projectDir's repository and stages its files under stagingRoot. Fetches first (unless fetch is false), so a branch is built as it is on the remote.

Implementation

static Future<RefSource> prepare({
  required String projectDir,
  required String ref,
  required Directory stagingRoot,
  bool fetch = true,
}) async {
  final git = _Git(projectDir);
  final top = await git.output(['rev-parse', '--show-toplevel']);
  if (top == null) {
    throw BuildException(
      '--ref needs the project to be in a git repository.',
      fix: 'Run the build without --ref, or from the repository.',
    );
  }

  if (fetch) {
    final fetched = await git
        .run(['fetch', '--quiet'], timeout: const Duration(seconds: 90));
    if (!fetched) {
      Logger.warning('Could not fetch from the remote (offline?): building '
          '"$ref" as this computer last saw it.');
    }
  }

  final notes = <String>[];
  final resolved = await _resolve(git, ref, notes);
  final commit = await git
      .output(['rev-parse', '--verify', '--quiet', '$resolved^{commit}']);
  if (commit == null) {
    throw BuildException(
      '"$ref" is not a branch, tag or commit in this repository.',
      fix: 'Check the name with "git branch -a" or "git tag".',
    );
  }

  final tree = Directory(p.join(stagingRoot.path, poolName(ref), 'source'));
  if (tree.existsSync()) tree.deleteSync(recursive: true);
  tree.createSync(recursive: true);

  // The project may be a folder inside the repository ("apps/bank/").
  final prefix = await git.output(['rev-parse', '--show-prefix']) ?? '';
  final treeish = prefix.isEmpty
      ? commit
      : '$commit:${prefix.substring(0, prefix.length - 1)}';
  // From the top: run in a subfolder, git archive only exports that
  // subfolder of the tree it is given.
  await _extract(top, treeish, tree);

  if (File(p.join(tree.path, '.gitmodules')).existsSync()) {
    notes.add('This repository has git submodules, which --ref builds '
        "don't include. Build without --ref if the app needs them.");
  }

  final copied = await _addLocalFiles(git, projectDir, tree);
  if (copied > 0) {
    notes.add('Added $copied local-only file(s) from the working copy '
        '(client .env/.secrets, keystores and other git-ignored files).');
  }

  return RefSource._(
    ref: ref,
    resolvedRef: resolved,
    commit: commit,
    tree: tree,
    notes: notes,
  );
}