pub mod git;
pub mod jj;
pub(crate) mod shared;
pub mod types;
pub use types::{ComparisonContext, DiffBase, RefreshResult, StackPosition, UpstreamDivergence, VcsBackend, VcsEventType, VcsWatchPaths};
use std::collections::HashSet;
use std::path::Path;
use std::sync::atomic::AtomicBool;
use std::sync::{Arc, OnceLock};
use anyhow::Result;
use rayon::ThreadPoolBuilder;
use crate::diff::FileDiff;
pub(crate) const PARALLEL_THRESHOLD: usize = 4;
const MAX_VCS_THREADS: usize = 16;
static VCS_POOL: OnceLock<rayon::ThreadPool> = OnceLock::new();
pub(crate) fn vcs_thread_pool() -> &'static rayon::ThreadPool {
VCS_POOL.get_or_init(|| {
let num_threads = std::thread::available_parallelism()
.map(|n| n.get().min(MAX_VCS_THREADS))
.unwrap_or(4);
ThreadPoolBuilder::new()
.num_threads(num_threads)
.build()
.expect("failed to build VCS thread pool")
})
}
pub fn detect(path: &Path) -> Result<Box<dyn Vcs>> {
if path.join(".jj").is_dir()
&& let Ok(root) = jj::get_repo_root(path)
{
return Ok(Box::new(jj::JjVcs::new(root)?));
}
if let Some(ancestor) = path.ancestors().find(|p| p.join(".jj").is_dir())
&& let Ok(root) = jj::get_repo_root(ancestor)
{
return Ok(Box::new(jj::JjVcs::new(root)?));
}
if let Ok(root) = git::get_repo_root(path) {
return Ok(Box::new(git::GitVcs::new(root)?));
}
anyhow::bail!("Not a git or jj repository")
}
pub trait Vcs: Send + Sync {
fn repo_path(&self) -> &Path;
fn comparison_context(&self) -> Result<ComparisonContext>;
fn refresh(&self, cancel_flag: &Arc<AtomicBool>) -> Result<RefreshResult>;
fn single_file_diff(&self, file_path: &str) -> Option<FileDiff>;
fn base_identifier(&self) -> Result<String>;
fn base_file_bytes(&self, file_path: &str) -> Result<Option<Vec<u8>>>;
fn working_file_bytes(&self, file_path: &str) -> Result<Option<Vec<u8>>>;
fn binary_files(&self) -> HashSet<String>;
fn fetch(&self) -> Result<()>;
fn has_conflicts(&self) -> Result<bool>;
fn is_locked(&self) -> bool;
fn watch_paths(&self) -> VcsWatchPaths;
fn classify_event(&self, path: &Path) -> VcsEventType;
fn backend(&self) -> VcsBackend;
fn current_revision_id(&self) -> Result<String>;
fn set_diff_base(&self, _base: DiffBase) {}
}