Skip to content

Commit 55d71dc

Browse files
committed
first sketch of addition is working (#16)
1 parent cd86f5b commit 55d71dc

File tree

3 files changed

+128
-22
lines changed

3 files changed

+128
-22
lines changed

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ test = false
1717
[dependencies]
1818
# git-repository = "0.22.1"
1919
git-repository = { version = "0.22.1", git = "https://github.com/Byron/gitoxide", branch = "for-crates-index-diff" }
20+
similar = { version = "2.2.0", features = ["bytes"] }
2021
serde = { version = "1", features = ["std", "derive"] }
2122
serde_json = "1"
2223
thiserror = "1.0.32"

src/index/diff.rs

Lines changed: 84 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@ pub enum Error {
2424
PeelToTree(#[from] git::object::peel::to_kind::Error),
2525
#[error(transparent)]
2626
Diff(#[from] git::diff::tree::changes::Error),
27+
#[error(transparent)]
28+
VersionDecode(#[from] serde_json::Error),
2729
}
2830

2931
/// Find changes without modifying the underling repository
@@ -160,7 +162,6 @@ impl Index {
160162
from: impl Into<git::hash::ObjectId>,
161163
to: impl Into<git::hash::ObjectId>,
162164
) -> Result<Vec<Change>, Error> {
163-
let changes = Vec::new();
164165
self.repo.object_cache_size_if_unset(4 * 1024 * 1024);
165166
let into_tree = |id: git::hash::ObjectId| -> Result<git::Tree<'_>, Error> {
166167
Ok(id
@@ -171,36 +172,97 @@ impl Index {
171172
};
172173
let from = into_tree(from.into())?;
173174
let to = into_tree(to.into())?;
174-
struct Delegate;
175-
impl git::diff::tree::Visit for Delegate {
176-
fn pop_front_tracked_path_and_set_current(&mut self) {
177-
todo!()
178-
}
179-
180-
fn push_back_tracked_path_component(&mut self, _component: &BStr) {
181-
todo!()
175+
struct Delegate<'repo> {
176+
changes: Vec<Change>,
177+
err: Option<Error>,
178+
repo: &'repo git::Repository,
179+
}
180+
impl<'repo> Delegate<'repo> {
181+
fn from_repo(repo: &'repo git::Repository) -> Self {
182+
Delegate {
183+
changes: Vec::new(),
184+
err: None,
185+
repo,
186+
}
182187
}
183-
184-
fn push_path_component(&mut self, _component: &BStr) {
185-
todo!()
188+
fn handle(&mut self, change: git::diff::tree::visit::Change) -> Result<(), Error> {
189+
use git::diff::tree::visit::Change::*;
190+
use git::objs::tree::EntryMode::*;
191+
fn entry_data(
192+
repo: &git::Repository,
193+
entry: git::objs::tree::EntryMode,
194+
oid: git::hash::ObjectId,
195+
) -> Result<Option<git::Object<'_>>, Error> {
196+
matches!(entry, Blob | BlobExecutable)
197+
.then(|| repo.find_object(oid))
198+
.transpose()
199+
.map_err(Into::into)
200+
}
201+
use git::bstr::ByteSlice;
202+
match change {
203+
Addition { entry_mode, oid } => {
204+
if let Some(obj) = entry_data(self.repo, entry_mode, oid)? {
205+
for line in (&obj.data).lines() {
206+
self.changes.push(Change::Added(serde_json::from_slice::<
207+
CrateVersion,
208+
>(
209+
line
210+
)?));
211+
}
212+
}
213+
}
214+
Deletion { entry_mode, oid } => {
215+
if let Some(_obj) = entry_data(self.repo, entry_mode, oid)? {
216+
todo!("deletion")
217+
}
218+
}
219+
Modification {
220+
previous_entry_mode: _,
221+
previous_oid: _,
222+
entry_mode: _,
223+
oid: _,
224+
} => {
225+
todo!("modification")
226+
}
227+
}
228+
Ok(())
186229
}
187-
188-
fn pop_path_component(&mut self) {
189-
todo!()
230+
fn into_result(self) -> Result<Vec<Change>, Error> {
231+
match self.err {
232+
Some(err) => Err(err),
233+
None => Ok(self.changes),
234+
}
190235
}
236+
}
237+
impl git::diff::tree::Visit for Delegate<'_> {
238+
fn pop_front_tracked_path_and_set_current(&mut self) {}
239+
fn push_back_tracked_path_component(&mut self, _component: &BStr) {}
240+
fn push_path_component(&mut self, _component: &BStr) {}
241+
fn pop_path_component(&mut self) {}
191242

192-
fn visit(&mut self, _change: git::diff::tree::visit::Change) -> Action {
193-
todo!()
243+
fn visit(&mut self, change: git::diff::tree::visit::Change) -> Action {
244+
match self.handle(change) {
245+
Ok(()) => Action::Continue,
246+
Err(err) => {
247+
self.err = err.into();
248+
Action::Cancel
249+
}
250+
}
194251
}
195252
}
196-
git::objs::TreeRefIter::from_bytes(&from.data).changes_needed(
253+
254+
let mut delegate = Delegate::from_repo(&self.repo);
255+
let file_changes = git::objs::TreeRefIter::from_bytes(&from.data).changes_needed(
197256
git::objs::TreeRefIter::from_bytes(&to.data),
198257
git::diff::tree::State::default(),
199258
|id, buf| self.repo.objects.find_tree_iter(id, buf).ok(),
200-
&mut Delegate,
201-
)?;
202-
203-
Ok(changes)
259+
&mut delegate,
260+
);
261+
match file_changes.err() {
262+
None | Some(git::diff::tree::changes::Error::Cancelled) => { /*error in delegate*/ }
263+
Some(err) => return Err(err.into()),
264+
}
265+
delegate.into_result()
204266
}
205267
}
206268

tests/index/changes_between_commits.rs

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,23 @@ fn addition() -> crate::Result {
2020
Ok(())
2121
}
2222

23+
#[test]
24+
fn addition2() -> crate::Result {
25+
let changes = changes2(index_ro()?, ":/initial commit")?;
26+
assert_eq!(changes.len(), 3228);
27+
assert!(matches!(
28+
changes
29+
.first()
30+
.and_then(|c| c.added().map(|v| v.name.as_str())),
31+
Some("gi-get-artifact")
32+
));
33+
assert!(matches!(
34+
changes.last().expect("present"),
35+
Change::Added(CrateVersion {name, ..}) if name == "gizmo"
36+
));
37+
Ok(())
38+
}
39+
2340
#[test]
2441
fn deletion() -> crate::Result {
2542
let changes = changes(&index_ro()?, "@~326")?;
@@ -41,6 +58,20 @@ fn new_version() -> crate::Result {
4158
Ok(())
4259
}
4360

61+
#[test]
62+
#[ignore]
63+
fn new_version2() -> crate::Result {
64+
let changes = changes2(index_ro()?, ":/Updating crate `git-repository#0.22.1`")?;
65+
assert_eq!(changes.len(), 1);
66+
assert_eq!(
67+
changes
68+
.first()
69+
.and_then(|c| c.added().map(|v| v.name.as_str())),
70+
Some("git-repository")
71+
);
72+
Ok(())
73+
}
74+
4475
#[test]
4576
fn yanked() -> crate::Result {
4677
let changes = changes(&index_ro()?, ":/Yanking crate `github_release_rs#0.1.0`")?;
@@ -90,3 +121,15 @@ fn changes(index: &Index, revspec: &str) -> crate::Result<Vec<Change>> {
90121
.unwrap_or_else(|| git::hash::ObjectId::empty_tree(repo.object_hash()).attach(&repo));
91122
Ok(index.changes_between_commits(ancestor_tree, commit)?)
92123
}
124+
fn changes2(mut index: Index, revspec: &str) -> crate::Result<Vec<Change>> {
125+
let repo = git::open(index.repository().path())?;
126+
let commit = repo.rev_parse(revspec)?.single().unwrap();
127+
let ancestor_tree = commit
128+
.object()?
129+
.into_commit()
130+
.parent_ids()
131+
.next()
132+
.and_then(|parent| parent.object().ok()?.into_commit().tree_id().ok())
133+
.unwrap_or_else(|| git::hash::ObjectId::empty_tree(repo.object_hash()).attach(&repo));
134+
Ok(index.changes_between_commits2(ancestor_tree, commit)?)
135+
}

0 commit comments

Comments
 (0)