use crate::{ObjectId, TreeChange, TreeCompareLimits, TreeValue, index};
#[derive(Clone, Copy, Debug)]
pub enum Baseline {
Head,
Tree(Option<ObjectId>),
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum Untracked {
Omit,
RawFilesWithoutIgnores,
}
#[derive(Clone, Copy, Debug)]
pub struct Limits {
pub index: index::Limits,
pub trees: TreeCompareLimits,
pub packs: crate::PackLimits,
pub read: crate::ReadLimits,
pub max_object_bytes: usize,
pub max_file_bytes: usize,
pub max_worktree_bytes: usize,
pub max_directory_entries: usize,
pub max_path_bytes: usize,
pub max_depth: usize,
}
impl Default for Limits {
fn default() -> Self {
Self {
index: index::Limits::default(),
trees: TreeCompareLimits::default(),
packs: crate::PackLimits::default(),
read: crate::ReadLimits::default(),
max_object_bytes: 256 * 1024 * 1024,
max_file_bytes: 16 * 1024 * 1024,
max_worktree_bytes: 256 * 1024 * 1024,
max_directory_entries: 1_000_000,
max_path_bytes: 64 * 1024 * 1024,
max_depth: 64,
}
}
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum Comparison {
RawBytesAndPosixModes,
}
#[derive(Debug)]
pub struct Report {
pub comparison: Comparison,
pub baseline_tree: Option<ObjectId>,
pub index_missing: bool,
pub staged: Vec<TreeChange>,
pub unstaged: Vec<WorktreeChange>,
pub unmerged: Vec<index::Entry>,
pub unchecked_gitlinks: Vec<index::Entry>,
pub untracked_policy: Untracked,
pub raw_untracked: Vec<Vec<u8>>,
pub boundaries: Vec<Vec<u8>>,
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct WorktreeChange {
pub path: Vec<u8>,
pub index: TreeValue,
pub change: Change,
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub enum Change {
Deleted,
Modified(TreeValue),
Obstructed {
path: Vec<u8>,
},
}
#[derive(Debug, thiserror::Error)]
pub enum Error {
#[error("unsupported status observation at {path:?}: {reason}")]
Unsupported {
path: Vec<u8>,
reason: &'static str,
},
#[error("status limit exceeded: {0}")]
Limit(&'static str),
#[error("status cancelled")]
Cancelled,
#[error("concurrent status change at {0:?}")]
Changed(Vec<u8>),
#[error("status I/O at {path:?}")]
Io {
path: Vec<u8>,
#[source]
source: std::io::Error,
},
#[error(transparent)]
Index(#[from] index::StorageError),
#[error(transparent)]
Reference(#[from] crate::refs::ReferenceError),
#[error(transparent)]
Tree(#[from] crate::TreeCompareError),
#[error("cannot open status object reader")]
Objects(#[source] crate::ObjectReadError),
#[error("reading status object {id} at {path:?}")]
Object {
id: ObjectId,
path: Vec<u8>,
#[source]
source: Box<crate::ObjectReadError>,
},
#[error("invalid status object {id} at {path:?}: {reason}")]
InvalidObject {
id: ObjectId,
path: Vec<u8>,
reason: &'static str,
},
#[error("invalid HEAD commit")]
Commit(#[from] crate::CommitError),
}
pub(super) fn check(cancel: &std::sync::atomic::AtomicBool) -> Result<(), Error> {
if cancel.load(std::sync::atomic::Ordering::Relaxed) {
Err(Error::Cancelled)
} else {
Ok(())
}
}
#[cfg(any(target_os = "linux", target_os = "macos"))]
pub(super) fn charge(
remaining: &mut usize,
count: usize,
label: &'static str,
) -> Result<(), Error> {
*remaining = remaining.checked_sub(count).ok_or(Error::Limit(label))?;
Ok(())
}
#[cfg(any(target_os = "linux", target_os = "macos"))]
pub(super) fn value(entry: &index::Entry) -> TreeValue {
TreeValue {
id: entry.id,
mode: match entry.mode {
index::Mode::Regular => crate::EntryMode::Blob,
index::Mode::Executable => crate::EntryMode::Executable,
index::Mode::Symlink => crate::EntryMode::Symlink,
index::Mode::SparseDirectory => crate::EntryMode::Tree,
index::Mode::Gitlink => crate::EntryMode::Gitlink,
},
}
}