fn mutate()

in focus/operations/src/selection.rs [83:182]


fn mutate(
    sparse_repo: impl AsRef<Path>,
    sync_if_changed: bool,
    action: OperationAction,
    projects_and_targets: Vec<String>,
    app: Arc<focus_util::app::App>,
) -> Result<bool> {
    let mut synced = false;
    let repo = Repo::open(sparse_repo.as_ref(), app.clone())?;
    let mut selections = repo.selection_manager().context("Loading the selection")?;
    let backup = if sync_if_changed {
        Some(
            selections
                .create_backup()
                .context("Creating a backup of the current selection")?,
        )
    } else {
        None
    };

    let mut projects_and_targets = projects_and_targets;

    match action {
        OperationAction::Add(AddOptions { unroll: true }) => {
            let mut projects = vec![];
            let mut targets = vec![];
            for i in projects_and_targets.clone() {
                if Target::try_from(i.as_str()).is_ok() {
                    targets.push(i);
                } else {
                    projects.extend(
                        selections
                            .project_catalog()
                            .optional_projects
                            .underlying
                            .get(&i)
                            .with_context(|| {
                                format!("Couldn't find project definition for {}.", i)
                            })?
                            .projects
                            .clone(),
                    );
                    targets.extend(
                        selections
                            .project_catalog()
                            .optional_projects
                            .underlying
                            .get(&i)
                            .with_context(|| {
                                format!("Couldn't find project definition for {}.", i)
                            })?
                            .targets
                            .clone(),
                    );
                };
            }
            projects_and_targets = targets;
            projects_and_targets.extend(projects);
        }
        OperationAction::Remove(RemoveOptions { all: true }) => {
            let projects: Vec<String> = selections
                .selection()?
                .projects
                .into_iter()
                .map(|x| x.name)
                .collect();
            let targets = selections
                .selection()?
                .targets
                .into_iter()
                .map(|x| match x {
                    Target::Bazel(c) => format!("bazel:{}", c),
                    Target::Directory(c) => format!("bazel:{}", c),
                })
                .collect();
            projects_and_targets = targets;
            projects_and_targets.extend(projects);
        }
        _ => (),
    }
    if selections
        .mutate(action, &projects_and_targets)
        .context("Updating the selection")?
    {
        selections.save().context("Saving selection")?;
        if sync_if_changed {
            info!("Synchronizing after selection changed");
            // TODO: Use the correct sync mode here. Sync will override for SyncMode::Incremental, but that feels janky.
            let result = super::sync::run(
                &SyncRequest::new(sparse_repo.as_ref(), SyncMode::Incremental),
                app,
            )
            .context("Synchronizing changes")?;
            synced = result.status == super::sync::SyncStatus::Success;
            backup.unwrap().discard();
        }
    }

    Ok(synced)
}