1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
//! Tools for editing the commit graph.

mod evolve;
mod execute;
mod plan;
pub mod rewrite_hooks;

use std::sync::Mutex;

pub use evolve::{find_abandoned_children, find_rewrite_target};
pub use execute::{
    execute_rebase_plan, move_branches, ExecuteRebasePlanOptions, ExecuteRebasePlanResult,
    FailedMergeInfo, MergeConflictRemediation,
};
pub use plan::{
    BuildRebasePlanError, BuildRebasePlanOptions, OidOrLabel, RebaseCommand, RebasePlan,
    RebasePlanBuilder, RebasePlanPermissions,
};
use tracing::instrument;

use crate::core::task::{Resource, ResourcePool};
use crate::git::Repo;

/// A thread-safe [`Repo`] resource pool.
#[derive(Debug)]
pub struct RepoResource {
    repo: Mutex<Repo>,
}

impl RepoResource {
    /// Make a copy of the provided [`Repo`] and use that to populate the
    /// [`ResourcePool`].
    #[instrument]
    pub fn new_pool(repo: &Repo) -> eyre::Result<ResourcePool<Self>> {
        let repo = Mutex::new(repo.try_clone()?);
        let resource = Self { repo };
        Ok(ResourcePool::new(resource))
    }
}

impl Resource for RepoResource {
    type Output = Repo;

    type Error = eyre::Error;

    fn try_create(&self) -> Result<Self::Output, Self::Error> {
        let repo = self
            .repo
            .lock()
            .map_err(|_| eyre::eyre!("Poisoned mutex for RepoResource"))?;
        let repo = repo.try_clone()?;
        Ok(repo)
    }
}

/// Type synonym for [`ResourcePool<RepoResource>`].
pub type RepoPool = ResourcePool<RepoResource>;

/// Testing helpers.
pub mod testing {
    use std::collections::HashSet;
    use std::path::PathBuf;

    use chashmap::CHashMap;

    use crate::core::dag::Dag;
    use crate::core::rewrite::{BuildRebasePlanOptions, RebasePlanPermissions};
    use crate::git::NonZeroOid;

    use super::RebasePlanBuilder;

    /// Create a `RebasePlanPermissions` that can rewrite any commit, for testing.
    pub fn omnipotent_rebase_plan_permissions(
        dag: &Dag,
        build_options: BuildRebasePlanOptions,
    ) -> eyre::Result<RebasePlanPermissions> {
        Ok(RebasePlanPermissions {
            build_options,
            allowed_commits: dag.query_all()?,
        })
    }

    /// Get the internal touched paths cache for a `RebasePlanBuilder`.
    pub fn get_builder_touched_paths_cache<'a>(
        builder: &'a RebasePlanBuilder,
    ) -> &'a CHashMap<NonZeroOid, HashSet<PathBuf>> {
        &builder.touched_paths_cache
    }
}