Skip to content

Commit dd366a5

Browse files
cruesslerByron
authored andcommitted
refactor: use revspecs for revision and path
1 parent dbb1532 commit dd366a5

File tree

3 files changed

+27
-145
lines changed

3 files changed

+27
-145
lines changed

Diff for: gitoxide-core/src/repository/diff.rs

+22-136
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
1-
use gix::bstr::{BStr, BString, ByteSlice};
1+
use anyhow::Context;
2+
use gix::bstr::{BString, ByteSlice};
23
use gix::diff::blob::intern::TokenSource;
34
use gix::diff::blob::UnifiedDiffBuilder;
45
use gix::objs::tree::EntryMode;
56
use gix::odb::store::RefreshMode;
67
use gix::prelude::ObjectIdExt;
7-
use gix::ObjectId;
88

99
pub fn tree(
1010
mut repo: gix::Repository,
@@ -118,156 +118,42 @@ fn typed_location(mut location: BString, mode: EntryMode) -> BString {
118118
pub fn file(
119119
mut repo: gix::Repository,
120120
out: &mut dyn std::io::Write,
121-
old_treeish: BString,
122-
new_treeish: BString,
123-
path: BString,
121+
old_revspec: BString,
122+
new_revspec: BString,
124123
) -> Result<(), anyhow::Error> {
125124
repo.object_cache_size_if_unset(repo.compute_object_cache_size_for_tree_diffs(&**repo.index_or_empty()?));
126125
repo.objects.refresh = RefreshMode::Never;
127126

128-
let old_tree_id = repo.rev_parse_single(old_treeish.as_bstr())?;
129-
let new_tree_id = repo.rev_parse_single(new_treeish.as_bstr())?;
130-
131-
let old_tree = old_tree_id.object()?.peel_to_tree()?;
132-
let new_tree = new_tree_id.object()?.peel_to_tree()?;
133-
134-
let mut old_tree_buf = Vec::new();
135-
let mut new_tree_buf = Vec::new();
136-
137-
use gix::diff::object::FindExt;
138-
139-
let old_tree_iter = repo.objects.find_tree_iter(&old_tree.id(), &mut old_tree_buf)?;
140-
let new_tree_iter = repo.objects.find_tree_iter(&new_tree.id(), &mut new_tree_buf)?;
141-
142-
use gix::diff::tree::{
143-
recorder::{self, Location},
144-
Recorder,
145-
};
146-
147-
struct FindChangeToPath {
148-
inner: Recorder,
149-
interesting_path: BString,
150-
change: Option<recorder::Change>,
151-
}
152-
153-
impl FindChangeToPath {
154-
fn new(interesting_path: &BStr) -> Self {
155-
let inner = Recorder::default().track_location(Some(Location::Path));
156-
157-
FindChangeToPath {
158-
inner,
159-
interesting_path: interesting_path.into(),
160-
change: None,
161-
}
162-
}
163-
}
164-
165-
use gix::diff::tree::{visit, Visit};
127+
let old_resolved_revspec = repo.rev_parse(old_revspec.as_bstr())?;
128+
let new_resolved_revspec = repo.rev_parse(new_revspec.as_bstr())?;
166129

167-
impl Visit for FindChangeToPath {
168-
fn pop_front_tracked_path_and_set_current(&mut self) {
169-
self.inner.pop_front_tracked_path_and_set_current();
170-
}
171-
172-
fn push_back_tracked_path_component(&mut self, component: &BStr) {
173-
self.inner.push_back_tracked_path_component(component);
174-
}
175-
176-
fn push_path_component(&mut self, component: &BStr) {
177-
self.inner.push_path_component(component);
178-
}
179-
180-
fn pop_path_component(&mut self) {
181-
self.inner.pop_path_component();
182-
}
183-
184-
fn visit(&mut self, change: visit::Change) -> visit::Action {
185-
if self.inner.path() == self.interesting_path {
186-
self.change = Some(match change {
187-
visit::Change::Deletion {
188-
entry_mode,
189-
oid,
190-
relation,
191-
} => recorder::Change::Deletion {
192-
entry_mode,
193-
oid,
194-
path: self.inner.path_clone(),
195-
relation,
196-
},
197-
visit::Change::Addition {
198-
entry_mode,
199-
oid,
200-
relation,
201-
} => recorder::Change::Addition {
202-
entry_mode,
203-
oid,
204-
path: self.inner.path_clone(),
205-
relation,
206-
},
207-
visit::Change::Modification {
208-
previous_entry_mode,
209-
previous_oid,
210-
entry_mode,
211-
oid,
212-
} => recorder::Change::Modification {
213-
previous_entry_mode,
214-
previous_oid,
215-
entry_mode,
216-
oid,
217-
path: self.inner.path_clone(),
218-
},
219-
});
220-
221-
visit::Action::Cancel
222-
} else {
223-
visit::Action::Continue
224-
}
225-
}
226-
}
227-
228-
let mut recorder = FindChangeToPath::new(path.as_ref());
229-
let state = gix::diff::tree::State::default();
230-
let result = gix::diff::tree(old_tree_iter, new_tree_iter, state, &repo.objects, &mut recorder);
231-
232-
let change = match result {
233-
Ok(_) | Err(gix::diff::tree::Error::Cancelled) => recorder.change,
234-
Err(error) => return Err(error.into()),
235-
};
130+
let old_blob_id = old_resolved_revspec
131+
.single()
132+
.context(format!("rev-spec '{old_revspec}' must resolve to a single object"))?;
133+
let new_blob_id = new_resolved_revspec
134+
.single()
135+
.context(format!("rev-spec '{new_revspec}' must resolve to a single object"))?;
236136

237-
let Some(change) = change else {
238-
anyhow::bail!(
239-
"There was no change to {} between {} and {}",
240-
&path,
241-
old_treeish,
242-
new_treeish
243-
)
244-
};
137+
let (old_path, _) = old_resolved_revspec
138+
.path_and_mode()
139+
.context(format!("rev-spec '{old_revspec}' must contain a path"))?;
140+
let (new_path, _) = new_resolved_revspec
141+
.path_and_mode()
142+
.context(format!("rev-spec '{new_revspec}' must contain a path"))?;
245143

246144
let mut resource_cache = repo.diff_resource_cache(gix::diff::blob::pipeline::Mode::ToGit, Default::default())?;
247145

248-
let (previous_oid, oid) = match change {
249-
recorder::Change::Addition { oid, .. } => {
250-
// Setting `previous_oid` to `ObjectId::empty_blob` makes `diff` see an addition.
251-
(ObjectId::empty_blob(gix::hash::Kind::Sha1), oid)
252-
}
253-
recorder::Change::Deletion { oid: previous_oid, .. } => {
254-
// Setting `oid` to `ObjectId::empty_blob` makes `diff` see a deletion.
255-
(previous_oid, ObjectId::empty_blob(gix::hash::Kind::Sha1))
256-
}
257-
recorder::Change::Modification { previous_oid, oid, .. } => (previous_oid, oid),
258-
};
259-
260146
resource_cache.set_resource(
261-
previous_oid,
147+
old_blob_id.into(),
262148
gix::object::tree::EntryKind::Blob,
263-
path.as_slice().into(),
149+
old_path,
264150
gix::diff::blob::ResourceKind::OldOrSource,
265151
&repo.objects,
266152
)?;
267153
resource_cache.set_resource(
268-
oid,
154+
new_blob_id.into(),
269155
gix::object::tree::EntryKind::Blob,
270-
path.as_slice().into(),
156+
new_path,
271157
gix::diff::blob::ResourceKind::NewOrDestination,
272158
&repo.objects,
273159
)?;

Diff for: src/plumbing/main.rs

+3-4
Original file line numberDiff line numberDiff line change
@@ -278,9 +278,8 @@ pub fn main() -> Result<()> {
278278
},
279279
),
280280
crate::plumbing::options::diff::SubCommands::File {
281-
old_treeish,
282-
new_treeish,
283-
path,
281+
old_revspec,
282+
new_revspec,
284283
} => prepare_and_run(
285284
"diff-file",
286285
trace,
@@ -289,7 +288,7 @@ pub fn main() -> Result<()> {
289288
progress_keep_open,
290289
None,
291290
move |_progress, out, _err| {
292-
core::repository::diff::file(repository(Mode::Lenient)?, out, old_treeish, new_treeish, path)
291+
core::repository::diff::file(repository(Mode::Lenient)?, out, old_revspec, new_revspec)
293292
},
294293
),
295294
},

Diff for: src/plumbing/options/mod.rs

+2-5
Original file line numberDiff line numberDiff line change
@@ -521,13 +521,10 @@ pub mod diff {
521521
File {
522522
/// A rev-spec representing the 'before' or old tree.
523523
#[clap(value_parser = crate::shared::AsBString)]
524-
old_treeish: BString,
524+
old_revspec: BString,
525525
/// A rev-spec representing the 'after' or new tree.
526526
#[clap(value_parser = crate::shared::AsBString)]
527-
new_treeish: BString,
528-
/// The path to the file to run diff for.
529-
#[clap(value_parser = crate::shared::AsBString)]
530-
path: BString,
527+
new_revspec: BString,
531528
},
532529
}
533530
}

0 commit comments

Comments
 (0)