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 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115
use crate::{bstr::BStr, Tree};
/// Returned by the `for_each` function to control flow.
#[derive(Clone, Copy, PartialOrd, PartialEq, Ord, Eq, Hash)]
pub enum Action {
/// Continue the traversal of changes.
Continue,
/// Stop the traversal of changes and stop calling this function.
Cancel,
}
impl Default for Action {
fn default() -> Self {
Action::Continue
}
}
/// Represents any possible change in order to turn one tree into another.
#[derive(Debug, Clone, Copy)]
pub struct Change<'a, 'old, 'new> {
/// The location of the file or directory described by `event`, if tracking was enabled.
///
/// Otherwise this value is always an empty path.
pub location: &'a BStr,
/// The diff event itself to provide information about what would need to change.
pub event: change::Event<'a, 'old, 'new>,
}
///
pub mod change;
/// Diffing
impl<'repo> Tree<'repo> {
/// Return a platform to see the changes needed to create other trees, for instance.
///
/// # Performance
///
/// It's highly recommended to set an object cache to avoid extracting the same object multiple times.
/// By default, similar to `git diff`, rename tracking will be enabled if it is not configured.
#[allow(clippy::result_large_err)]
pub fn changes<'a>(&'a self) -> Result<Platform<'a, 'repo>, renames::Error> {
Ok(Platform {
state: Default::default(),
lhs: self,
tracking: None,
renames: self.repo.config.diff_renames()?.unwrap_or_default().into(),
})
}
}
/// The diffing platform returned by [`Tree::changes()`].
#[derive(Clone)]
pub struct Platform<'a, 'repo> {
state: git_diff::tree::State,
lhs: &'a Tree<'repo>,
tracking: Option<Tracking>,
renames: Option<Renames>,
}
#[derive(Clone, Copy)]
enum Tracking {
FileName,
Path,
}
/// A structure to capture how to perform rename tracking
#[derive(Debug, Copy, Clone, PartialEq)]
pub struct Renames {
/// If `Some(…)`, do also find copies. `None` is the default which does not try to detect copies at all.
///
/// Note that this is an even more expensive operation than detecting renames as files.
pub copies: Option<renames::Copies>,
/// The percentage of similarity needed for files to be considered renamed or copied, defaulting to `Some(0.5)`.
/// This field is similar to `git diff -M50%`.
///
/// If `None`, files are only considered equal if their content matches 100%.
/// Note that values greater than 1.0 have no different effect than 1.0.
pub percentage: Option<f32>,
/// The amount of files to consider for rename or copy tracking. Defaults to 1000.
/// If 0, there is no limit.
pub limit: usize,
}
///
pub mod renames;
/// Configuration
impl<'a, 'repo> Platform<'a, 'repo> {
/// Keep track of file-names, which makes the [`location`][Change::location] field usable with the filename of the changed item.
pub fn track_filename(&mut self) -> &mut Self {
self.tracking = Some(Tracking::FileName);
self
}
/// Keep track of the entire path of a change, relative to the repository.
///
/// This makes the [`location`][Change::location] field usable.
pub fn track_path(&mut self) -> &mut Self {
self.tracking = Some(Tracking::Path);
self
}
/// Provide `None` to disable rename tracking entirely, or pass `Some(<configuration>)` to control to
/// what extend rename tracking is performed.
///
/// Note that by default, the configuration determines rename tracking and standard git defaults are used
/// if nothing is configured, which turns on rename tracking with `-M50%`.
pub fn track_renames(&mut self, renames: Option<Renames>) -> &mut Self {
self.renames = renames;
self
}
}
///
pub mod for_each;