fn compute_and_store_initial_selection()

in focus/operations/src/clone.rs [620:672]


fn compute_and_store_initial_selection(
    repo: &Repo,
    projects_and_targets: Vec<String>,
    template: Option<ClonedRepoTemplate>,
) -> Result<TargetSet> {
    let mut selections = repo.selection_manager()?;
    let operations = projects_and_targets
        .iter()
        .map(|value| Operation::new(OperationAction::default_add(), value))
        .collect::<Vec<Operation>>();

    // FIXME: ideally, we would check to make sure there is no `focus`
    // directory, aand then create `focus/mandatory.projects.json` (and add it to
    // the gitignore), but we don't have any facilities for modifying the
    // mandatory projects programmatically.
    let operations = match template {
        None => operations,
        Some(template) => operations
            .into_iter()
            .chain(
                template
                    .entries()
                    .into_iter()
                    .map(|entry| Operation::new(OperationAction::default_add(), entry)),
            )
            .collect(),
    };

    let result = selections.process(&operations)?;
    if !result.is_success() {
        bail!("Selecting projects and targets failed");
    }
    selections.save()?;
    let selection = selections.computed_selection()?;

    let target_set = selections.compute_complete_target_set()?;
    debug!(target_set = ?target_set, project_and_targets = ?projects_and_targets, selection_projects = ?selection.projects, selection_targets = ?selection.targets, "computing the target set");

    // For open-source projects, it's likely that `.focus` will be created in
    // their working tree and not ignored by default, which means that the next
    // `focus add`/`focus sync` attempt will fail because the working tree is
    // not clean. Improve the experience by ignoring `.focus` by default.
    let info_dir = repo.git_dir().join("info");
    std::fs::create_dir_all(&info_dir).context("Creating .git/info")?;
    let exclude_path = info_dir.join("exclude");
    let mut exclude_file = OpenOptions::new()
        .append(true)
        .open(exclude_path)
        .context("Opening .git/info/exclude")?;
    writeln!(exclude_file, "/.focus/").context("Writing initial .git/info/exclude")?;

    Ok(target_set)
}