Skip to content

Commit d0c4563

Browse files
committed
Allow mutation of entries during iteration, while obtaining their path (#301)
1 parent 72af261 commit d0c4563

File tree

3 files changed

+32
-20
lines changed

3 files changed

+32
-20
lines changed

git-index/src/lib.rs

+9
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ pub mod entry;
1313

1414
mod access {
1515
use crate::{Entry, State, Version};
16+
use bstr::{BStr, ByteSlice};
1617

1718
impl State {
1819
pub fn version(&self) -> Version {
@@ -23,6 +24,14 @@ mod access {
2324
&self.entries
2425
}
2526

27+
pub fn entries_mut_with_paths(&mut self) -> impl Iterator<Item = (&mut Entry, &BStr)> {
28+
let paths = &self.path_backing;
29+
self.entries.iter_mut().map(move |e| {
30+
let path = (&paths[e.path.clone()]).as_bstr();
31+
(e, path)
32+
})
33+
}
34+
2635
pub fn entries_mut(&mut self) -> &mut [Entry] {
2736
&mut self.entries
2837
}

git-worktree/Cargo.toml

+2-1
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,11 @@ doctest = false
1414

1515
[dependencies]
1616
git-index = { version = "^0.1.0", path = "../git-index" }
17-
quick-error = "2.0.1"
1817
git-hash = { version = "^0.9.0", path = "../git-hash" }
1918
git-object = { version = "^0.17.0", path = "../git-object" }
2019

20+
quick-error = "2.0.1"
21+
2122
[dev-dependencies]
2223
git-odb = { path = "../git-odb" }
2324
walkdir = "2.3.2"

git-worktree/src/lib.rs

+21-19
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
#![forbid(unsafe_code, rust_2018_idioms)]
22

33
use git_hash::oid;
4+
use git_index::Entry;
45
use git_object::bstr::ByteSlice;
56
use quick_error::quick_error;
6-
use std::convert::TryFrom;
7+
use std::convert::TryInto;
78
use std::fs::{create_dir_all, OpenOptions};
89
use std::io::Write;
910
use std::path::{Path, PathBuf};
@@ -46,13 +47,12 @@ where
4647
{
4748
let path = path.as_ref();
4849
let mut buf = Vec::new();
49-
let mut entry_time = Vec::new(); // Entries whose timestamps have to be updated
50-
for (i, entry) in index.entries().iter().enumerate() {
50+
for (entry, entry_path) in index.entries_mut_with_paths() {
5151
if entry.flags.contains(git_index::entry::Flags::SKIP_WORKTREE) {
5252
continue;
5353
}
54-
let entry_path = entry.path(index).to_path()?;
55-
let dest = path.join(entry_path);
54+
55+
let dest = path.join(entry_path.to_path()?); // TODO: try to use os_str_bytes to avoid UTF8 conversion. Put that into git-ref too
5656
create_dir_all(dest.parent().expect("entry paths are never empty"))?;
5757

5858
match entry.mode {
@@ -70,11 +70,12 @@ where
7070
let met = file.metadata()?;
7171
let ctime = met
7272
.created()
73-
.map_or(Ok(Duration::default()), |x| x.duration_since(std::time::UNIX_EPOCH));
73+
.map_or(Ok(Duration::default()), |x| x.duration_since(std::time::UNIX_EPOCH))?;
7474
let mtime = met
7575
.modified()
76-
.map_or(Ok(Duration::default()), |x| x.duration_since(std::time::UNIX_EPOCH));
77-
entry_time.push((ctime?, mtime?, i));
76+
.map_or(Ok(Duration::default()), |x| x.duration_since(std::time::UNIX_EPOCH))?;
77+
78+
update_fstat(entry, ctime, mtime)?;
7879
}
7980
git_index::entry::Mode::SYMLINK => {
8081
let obj = find(&entry.id, &mut buf).ok_or_else(|| Error::NotFound(entry.id, path.to_path_buf()))?;
@@ -96,25 +97,26 @@ where
9697
let met = std::fs::symlink_metadata(&dest)?;
9798
let ctime = met
9899
.created()
99-
.map_or(Ok(Duration::default()), |x| x.duration_since(std::time::UNIX_EPOCH));
100+
.map_or(Ok(Duration::default()), |x| x.duration_since(std::time::UNIX_EPOCH))?;
100101
let mtime = met
101102
.modified()
102-
.map_or(Ok(Duration::default()), |x| x.duration_since(std::time::UNIX_EPOCH));
103-
entry_time.push((ctime?, mtime?, i));
103+
.map_or(Ok(Duration::default()), |x| x.duration_since(std::time::UNIX_EPOCH))?;
104+
update_fstat(entry, ctime, mtime)?;
104105
}
105106
git_index::entry::Mode::DIR => todo!(),
106107
git_index::entry::Mode::COMMIT => todo!(),
107108
_ => unreachable!(),
108109
}
109110
}
110-
let entries = index.entries_mut();
111-
for (ctime, mtime, i) in entry_time {
112-
let stat = &mut entries[i].stat;
113-
stat.mtime.secs = u32::try_from(mtime.as_secs())?;
114-
stat.mtime.nsecs = mtime.subsec_nanos();
115-
stat.ctime.secs = u32::try_from(ctime.as_secs())?;
116-
stat.ctime.nsecs = ctime.subsec_nanos();
117-
}
111+
Ok(())
112+
}
113+
114+
fn update_fstat(entry: &mut Entry, ctime: Duration, mtime: Duration) -> Result<(), Error> {
115+
let stat = &mut entry.stat;
116+
stat.mtime.secs = mtime.as_secs().try_into()?;
117+
stat.mtime.nsecs = mtime.subsec_nanos();
118+
stat.ctime.secs = ctime.as_secs().try_into()?;
119+
stat.ctime.nsecs = ctime.subsec_nanos();
118120
Ok(())
119121
}
120122

0 commit comments

Comments
 (0)