Skip to content

Commit

Permalink
initial support for obtaining the diff.algorithm lazily (#450)
Browse files Browse the repository at this point in the history
  • Loading branch information
Byron committed Oct 28, 2022
1 parent b39ca20 commit f362ab2
Show file tree
Hide file tree
Showing 5 changed files with 88 additions and 5 deletions.
35 changes: 35 additions & 0 deletions git-repository/src/config/cache/access.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,46 @@ use std::{convert::TryInto, path::PathBuf, time::Duration};

use git_lock::acquire::Fail;

use crate::config::cache::util::check_lenient_default;
use crate::config::checkout_options;
use crate::{config::Cache, remote, repository::identity};

/// Access
impl Cache {
pub(crate) fn diff_algorithm(&self) -> Result<git_diff::text::Algorithm, crate::config::diff::algorithm::Error> {
use crate::config::diff::algorithm::Error;
self.diff_algorithm
.get_or_try_init(|| {
let res = (|| {
let name = self
.resolved
.string("diff", None, "algorithm")
.unwrap_or(Cow::Borrowed("myers".into()));
if name.eq_ignore_ascii_case(b"myers") || name.eq_ignore_ascii_case(b"default") {
Ok(git_diff::text::Algorithm::Myers)
} else if name.eq_ignore_ascii_case(b"minimal") {
Ok(git_diff::text::Algorithm::MyersMinimal)
} else if name.eq_ignore_ascii_case(b"histogram") {
Ok(git_diff::text::Algorithm::Histogram)
} else if name.eq_ignore_ascii_case(b"patience") {
if self.lenient_config {
Ok(git_diff::text::Algorithm::Histogram)
} else {
Err(Error::Unimplemented {
name: name.into_owned(),
})
}
} else {
Err(Error::Unknown {
name: name.into_owned(),
})
}
})();
check_lenient_default(res, self.lenient_config, || git_diff::text::Algorithm::Myers)
})
.copied()
}

pub(crate) fn personas(&self) -> &identity::Personas {
self.personas
.get_or_init(|| identity::Personas::from_config_and_env(&self.resolved, self.git_prefix))
Expand Down
2 changes: 2 additions & 0 deletions git-repository/src/config/cache/init.rs
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,7 @@ impl Cache {
url_rewrite: Default::default(),
#[cfg(any(feature = "blocking-network-client", feature = "async-network-client"))]
url_scheme: Default::default(),
diff_algorithm: Default::default(),
git_prefix,
})
}
Expand Down Expand Up @@ -179,6 +180,7 @@ impl Cache {

self.personas = Default::default();
self.url_rewrite = Default::default();
self.diff_algorithm = Default::default();
#[cfg(any(feature = "blocking-network-client", feature = "async-network-client"))]
{
self.url_scheme = Default::default();
Expand Down
8 changes: 8 additions & 0 deletions git-repository/src/config/cache/util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,14 @@ pub(crate) fn check_lenient<T, E>(v: Result<Option<T>, E>, lenient: bool) -> Res
}
}

pub(crate) fn check_lenient_default<T, E>(v: Result<T, E>, lenient: bool, default: impl FnOnce() -> T) -> Result<T, E> {
match v {
Ok(v) => Ok(v),
Err(_) if lenient => Ok(default()),
Err(err) => Err(err),
}
}

pub(crate) fn parse_core_abbrev(
config: &git_config::File<'static>,
object_hash: git_hash::Kind,
Expand Down
28 changes: 25 additions & 3 deletions git-repository/src/config/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@ pub(crate) mod section {
}

/// The error returned when failing to initialize the repository configuration.
///
/// This configuration is on the critical path when opening a repository.
#[derive(Debug, thiserror::Error)]
#[allow(missing_docs)]
pub enum Error {
Expand Down Expand Up @@ -71,6 +73,24 @@ pub enum Error {
LogAllRefUpdates { value: BString },
}

///
pub mod diff {
///
pub mod algorithm {
use crate::bstr::BString;

/// The error produced when obtaining `diff.algorithm`.
#[derive(Debug, thiserror::Error)]
#[allow(missing_docs)]
pub enum Error {
#[error("Unknown diff algorithm named '{name}'")]
Unknown { name: BString },
#[error("The '{name}' algorithm is not yet implemented")]
Unimplemented { name: BString },
}
}
}

///
pub mod checkout_options {
/// The error produced when collecting all information needed for checking out files into a worktree.
Expand Down Expand Up @@ -105,12 +125,14 @@ pub(crate) struct Cache {
/// The representation of `core.logallrefupdates`, or `None` if the variable wasn't set.
pub reflog: Option<git_ref::store::WriteReflog>,
/// identities for later use, lazy initialization.
pub personas: OnceCell<identity::Personas>,
pub(crate) personas: OnceCell<identity::Personas>,
/// A lazily loaded rewrite list for remote urls
pub url_rewrite: OnceCell<remote::url::Rewrite>,
pub(crate) url_rewrite: OnceCell<remote::url::Rewrite>,
/// A lazily loaded mapping to know which url schemes to allow
#[cfg(any(feature = "blocking-network-client", feature = "async-network-client"))]
pub url_scheme: OnceCell<remote::url::SchemePermission>,
pub(crate) url_scheme: OnceCell<remote::url::SchemePermission>,
/// The algorithm to use when diffing blobs
pub(crate) diff_algorithm: OnceCell<git_diff::text::Algorithm>,
/// The config section filter from the options used to initialize this instance. Keep these in sync!
filter_config_section: fn(&git_config::file::Metadata) -> bool,
/// The object kind to pick if a prefix is ambiguous.
Expand Down
20 changes: 18 additions & 2 deletions git-repository/src/object/tree/diff.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ pub struct Change<'a, 'old, 'new> {
pub mod change {
use git_object::tree::EntryMode;

use crate::{bstr::ByteSlice, Id};
use crate::{bstr::ByteSlice, Id, Repository};

/// An event emitted when finding differences between two trees.
#[derive(Debug, Clone, Copy)]
Expand Down Expand Up @@ -87,20 +87,36 @@ pub mod change {
pub struct DiffPlatform<'old, 'new> {
old: crate::Object<'old>,
new: crate::Object<'new>,
algo: git_diff::text::Algorithm,
}

impl<'old, 'new> Event<'old, 'new> {
fn repo(&self) -> &Repository {
match self {
Event::Addition { id, .. } => id.repo,
Event::Deletion { id, .. } => id.repo,
Event::Modification { id, .. } => id.repo,
}
}
}

impl<'old, 'new> Event<'old, 'new> {
/// Produce a platform for performing a line-diff, or `None` if this is not a [`Modification`][Event::Modification]
/// or one of the entries to compare is not a blob.
pub fn diff(&self) -> Option<Result<DiffPlatform<'old, 'new>, crate::object::find::existing::Error>> {
// let algo = self.repo().config.diff_algorithm()?;
match self {
Event::Modification {
previous_entry_mode: EntryMode::BlobExecutable | EntryMode::Blob,
previous_id,
entry_mode: EntryMode::BlobExecutable | EntryMode::Blob,
id,
} => match previous_id.object().and_then(|old| id.object().map(|new| (old, new))) {
Ok((old, new)) => Some(Ok(DiffPlatform { old, new })),
Ok((old, new)) => Some(Ok(DiffPlatform {
old,
new,
algo: git_diff::text::Algorithm::Myers,
})),
Err(err) => Some(Err(err)),
},
_ => None,
Expand Down

0 comments on commit f362ab2

Please sign in to comment.