summaryrefslogtreecommitdiffstats
path: root/vendor/gix/src/diff.rs
blob: af3c987048a3b046a4c2de8696e3907b74faa808 (plain)
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
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
pub use gix_diff::*;

///
pub mod rename {
    /// Determine how to do rename tracking.
    #[derive(Debug, Copy, Clone, Eq, PartialEq)]
    pub enum Tracking {
        /// Do not track renames at all, the fastest option.
        Disabled,
        /// Track renames.
        Renames,
        /// Track renames and copies.
        ///
        /// This is the most expensive option.
        RenamesAndCopies,
    }
}

///
#[cfg(feature = "blob-diff")]
mod utils {
    use gix_diff::{rewrites::Copies, Rewrites};

    use crate::{
        config::{cache::util::ApplyLeniency, tree::Diff},
        diff::rename::Tracking,
        Repository,
    };

    ///
    pub mod new_rewrites {
        /// The error returned by [`new_rewrites()`](super::new_rewrites()).
        #[derive(Debug, thiserror::Error)]
        #[allow(missing_docs)]
        pub enum Error {
            #[error(transparent)]
            ConfigDiffRenames(#[from] crate::config::key::GenericError),
            #[error(transparent)]
            ConfigDiffRenameLimit(#[from] crate::config::unsigned_integer::Error),
        }
    }

    ///
    pub mod resource_cache {
        /// The error returned by [`resource_cache()`](super::resource_cache()).
        #[derive(Debug, thiserror::Error)]
        #[allow(missing_docs)]
        pub enum Error {
            #[error(transparent)]
            DiffAlgorithm(#[from] crate::config::diff::algorithm::Error),
            #[error(transparent)]
            WorktreeFilterOptions(#[from] crate::filter::pipeline::options::Error),
            #[error(transparent)]
            DiffDrivers(#[from] crate::config::diff::drivers::Error),
            #[error(transparent)]
            DiffPipelineOptions(#[from] crate::config::diff::pipeline_options::Error),
            #[error(transparent)]
            CommandContext(#[from] crate::config::command_context::Error),
            #[error(transparent)]
            AttributeStack(#[from] crate::config::attribute_stack::Error),
        }
    }

    /// Create an instance by reading all relevant information from the `config`uration, while being `lenient` or not.
    /// Returns `Ok(None)` if nothing is configured.
    ///
    /// Note that missing values will be defaulted similar to what git does.
    #[allow(clippy::result_large_err)]
    pub fn new_rewrites(
        config: &gix_config::File<'static>,
        lenient: bool,
    ) -> Result<Option<Rewrites>, new_rewrites::Error> {
        let key = "diff.renames";
        let copies = match config
            .boolean_by_key(key)
            .map(|value| Diff::RENAMES.try_into_renames(value))
            .transpose()
            .with_leniency(lenient)?
        {
            Some(renames) => match renames {
                Tracking::Disabled => return Ok(None),
                Tracking::Renames => None,
                Tracking::RenamesAndCopies => Some(Copies::default()),
            },
            None => return Ok(None),
        };

        let default = Rewrites::default();
        Ok(Rewrites {
            copies,
            limit: config
                .integer_by_key("diff.renameLimit")
                .map(|value| Diff::RENAME_LIMIT.try_into_usize(value))
                .transpose()
                .with_leniency(lenient)?
                .unwrap_or(default.limit),
            ..default
        }
        .into())
    }

    /// Return a low-level utility to efficiently prepare a the blob-level diff operation between two resources,
    /// and cache these diffable versions so that matrix-like MxN diffs are efficient.
    ///
    /// `repo` is used to obtain the needed configuration values, and `index` is used to potentially read `.gitattributes`
    /// files from which may affect the diff operation.
    /// `mode` determines how the diffable files will look like, and also how fast, in average, these conversions are.
    /// `attribute_source` controls where `.gitattributes` will be read from, and it's typically adjusted based on the
    /// `roots` - if there are no worktree roots, `.gitattributes` are also not usually read from worktrees.
    /// `roots` provide information about where to get diffable data from, so source and destination can either be sourced from
    /// a worktree, or from the object database, or both.
    pub fn resource_cache(
        repo: &Repository,
        index: &gix_index::State,
        mode: gix_diff::blob::pipeline::Mode,
        attribute_source: gix_worktree::stack::state::attributes::Source,
        roots: gix_diff::blob::pipeline::WorktreeRoots,
    ) -> Result<gix_diff::blob::Platform, resource_cache::Error> {
        let diff_algo = repo.config.diff_algorithm()?;
        let diff_cache = gix_diff::blob::Platform::new(
            gix_diff::blob::platform::Options {
                algorithm: Some(diff_algo),
                skip_internal_diff_if_external_is_configured: false,
            },
            gix_diff::blob::Pipeline::new(
                roots,
                gix_filter::Pipeline::new(repo.command_context()?, crate::filter::Pipeline::options(repo)?),
                repo.config.diff_drivers()?,
                repo.config.diff_pipeline_options()?,
            ),
            mode,
            repo.attributes_only(
                // TODO(perf): this could benefit from not having to build an intermediate index,
                //             and traverse the a tree directly.
                index,
                attribute_source,
            )?
            .inner,
        );
        Ok(diff_cache)
    }
}
#[cfg(feature = "blob-diff")]
pub use utils::{new_rewrites, resource_cache};