use std::path::{Path, PathBuf};
#[derive(Debug, Clone)]
#[non_exhaustive]
pub struct WorktreeHandle {
pub path: PathBuf,
pub branch: String,
pub base_commit: String,
pub state: WorktreeState,
pub created_at: String,
pub creator_pid: u32,
pub creator_name: String,
pub adapter: Option<String>,
pub setup_complete: bool,
pub port: Option<u16>,
pub session_uuid: String,
}
impl WorktreeHandle {
#[allow(clippy::too_many_arguments)]
pub fn new(
path: PathBuf,
branch: String,
base_commit: String,
state: WorktreeState,
created_at: String,
creator_pid: u32,
creator_name: String,
adapter: Option<String>,
setup_complete: bool,
port: Option<u16>,
session_uuid: String,
) -> Self {
Self {
path,
branch,
base_commit,
state,
created_at,
creator_pid,
creator_name,
adapter,
setup_complete,
port,
session_uuid,
}
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash, serde::Serialize)]
#[non_exhaustive]
pub enum WorktreeState {
Pending,
Creating,
Active,
Merging,
Deleting,
Deleted,
Orphaned,
Broken,
Locked,
}
impl<'de> serde::Deserialize<'de> for WorktreeState {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
let s = String::deserialize(deserializer)?;
Ok(match s.as_str() {
"Pending" => Self::Pending,
"Creating" => Self::Creating,
"Active" => Self::Active,
"Merging" => Self::Merging,
"Deleting" => Self::Deleting,
"Deleted" => Self::Deleted,
"Orphaned" => Self::Orphaned,
"Broken" => Self::Broken,
"Locked" => Self::Locked,
_ => Self::Broken,
})
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub enum ReflinkMode {
Required,
#[default]
Preferred,
Disabled,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum CopyOutcome {
Reflinked,
StandardCopy { bytes_written: u64 },
None,
}
#[derive(Debug, Clone)]
#[non_exhaustive]
pub struct Config {
pub max_worktrees: usize,
pub disk_threshold_percent: u8,
pub gc_max_age_days: u32,
pub port_range_start: u16,
pub port_range_end: u16,
pub min_free_disk_mb: u64,
pub home_override: Option<PathBuf>,
pub max_total_disk_bytes: Option<u64>,
pub circuit_breaker_threshold: u32,
pub stale_metadata_ttl_days: u32,
pub lock_timeout_ms: u64,
pub creator_name: String,
pub offline: bool,
}
impl Default for Config {
fn default() -> Self {
Self {
max_worktrees: 20,
disk_threshold_percent: 90,
gc_max_age_days: 7,
port_range_start: 3100,
port_range_end: 5100,
min_free_disk_mb: 500,
home_override: None,
max_total_disk_bytes: None,
circuit_breaker_threshold: 3,
stale_metadata_ttl_days: 30,
lock_timeout_ms: 30_000,
creator_name: "iso-code".to_string(),
offline: false,
}
}
}
#[derive(Debug, Clone, Default)]
#[non_exhaustive]
pub struct CreateOptions {
pub base: Option<String>,
pub setup: bool,
pub ignore_disk_limit: bool,
pub lock: bool,
pub lock_reason: Option<String>,
pub reflink_mode: ReflinkMode,
pub allocate_port: bool,
}
#[derive(Debug, Clone, Default)]
#[non_exhaustive]
pub struct AttachOptions {
pub setup: bool,
pub allocate_port: bool,
}
#[derive(Debug, Clone, Default)]
#[non_exhaustive]
pub struct DeleteOptions {
pub force: bool,
pub force_dirty: bool,
pub force_locked: bool,
}
#[derive(Debug, Clone)]
#[non_exhaustive]
pub struct GcOptions {
pub dry_run: bool,
pub max_age_days: Option<u32>,
pub force: bool,
}
impl Default for GcOptions {
fn default() -> Self {
Self {
dry_run: true,
max_age_days: None,
force: false,
}
}
}
#[derive(Debug, Clone)]
#[non_exhaustive]
pub struct GcReport {
pub orphans: Vec<PathBuf>,
pub removed: Vec<PathBuf>,
pub evicted: Vec<PathBuf>,
pub freed_bytes: u64,
pub dry_run: bool,
}
impl GcReport {
pub fn new(
orphans: Vec<PathBuf>,
removed: Vec<PathBuf>,
evicted: Vec<PathBuf>,
freed_bytes: u64,
dry_run: bool,
) -> Self {
Self { orphans, removed, evicted, freed_bytes, dry_run }
}
}
#[derive(Debug, Clone)]
#[non_exhaustive]
pub struct GitCapabilities {
pub version: GitVersion,
pub has_list_nul: bool,
pub has_repair: bool,
pub has_orphan: bool,
pub has_relative_paths: bool,
pub has_merge_tree_write: bool,
}
impl GitCapabilities {
pub fn new(
version: GitVersion,
has_list_nul: bool,
has_repair: bool,
has_orphan: bool,
has_relative_paths: bool,
has_merge_tree_write: bool,
) -> Self {
Self { version, has_list_nul, has_repair, has_orphan, has_relative_paths, has_merge_tree_write }
}
}
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
pub struct GitVersion {
pub major: u32,
pub minor: u32,
pub patch: u32,
}
impl GitVersion {
pub const MINIMUM: GitVersion = GitVersion { major: 2, minor: 20, patch: 0 };
pub const HAS_LIST_NUL: GitVersion = GitVersion { major: 2, minor: 36, patch: 0 };
pub const HAS_REPAIR: GitVersion = GitVersion { major: 2, minor: 30, patch: 0 };
pub const HAS_MERGE_TREE_WRITE: GitVersion = GitVersion { major: 2, minor: 38, patch: 0 };
}
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
pub struct PortLease {
pub port: u16,
pub branch: String,
pub session_uuid: String,
pub pid: u32,
pub created_at: chrono::DateTime<chrono::Utc>,
pub expires_at: chrono::DateTime<chrono::Utc>,
pub status: String,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum GitCryptStatus {
NotUsed,
LockedNoKey,
Locked,
Unlocked,
}
pub trait EcosystemAdapter: Send + Sync {
fn name(&self) -> &str;
fn detect(&self, worktree_path: &Path) -> bool;
fn setup(
&self,
worktree_path: &Path,
source_worktree: &Path,
) -> Result<(), crate::error::WorktreeError>;
fn teardown(&self, worktree_path: &Path) -> Result<(), crate::error::WorktreeError>;
fn branch_name(&self, input: &str) -> String {
input.to_string()
}
}