Skip to content

Commit 0bf1d5b

Browse files
authored
Merge pull request #1884 from GitoxideLabs/improvements
various improvements
2 parents 339bdf8 + 5054780 commit 0bf1d5b

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

54 files changed

+224
-101
lines changed

gitoxide-core/src/repository/archive.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ pub fn stream(
3030
let (mut stream, index) = repo.worktree_stream(tree)?;
3131
if !add_paths.is_empty() {
3232
let root = gix::path::realpath(
33-
repo.work_dir()
33+
repo.workdir()
3434
.ok_or_else(|| anyhow!("Adding files requires a worktree directory that contains them"))?,
3535
)?;
3636
for path in add_paths {

gitoxide-core/src/repository/attributes/query.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ pub(crate) mod function {
8383
gix::worktree::stack::state::attributes::Source::WorktreeThenIdMapping
8484
.adjust_for_bare(repo.is_bare()),
8585
)?;
86-
let workdir = repo.work_dir();
86+
let workdir = repo.workdir();
8787
for pattern in pathspec.search().patterns() {
8888
let path = pattern.path();
8989
let entry = cache.at_entry(

gitoxide-core/src/repository/attributes/validate_baseline.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,7 @@ pub(crate) mod function {
114114
};
115115
let work_dir = ignore
116116
.then(|| {
117-
repo.work_dir()
117+
repo.workdir()
118118
.map(ToOwned::to_owned)
119119
.ok_or_else(|| anyhow!("repository at {:?} must have a worktree checkout", repo.path()))
120120
})
@@ -249,7 +249,7 @@ pub(crate) mod function {
249249
}
250250
bail!(
251251
"{}: Validation failed with {} mismatches out of {}",
252-
gix::path::realpath(repo.work_dir().unwrap_or(repo.git_dir()))?.display(),
252+
gix::path::realpath(repo.workdir().unwrap_or(repo.git_dir()))?.display(),
253253
mismatches.len(),
254254
progress.counter().load(Ordering::Relaxed)
255255
);

gitoxide-core/src/repository/clean.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ pub(crate) mod function {
5353
if format != OutputFormat::Human {
5454
bail!("JSON output isn't implemented yet");
5555
}
56-
let Some(workdir) = repo.work_dir() else {
56+
let Some(workdir) = repo.workdir() else {
5757
bail!("Need a worktree to clean, this is a bare repository");
5858
};
5959

gitoxide-core/src/repository/exclude.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ pub fn query(
6060
let mut pathspec = repo.pathspec(
6161
true,
6262
patterns.iter(),
63-
repo.work_dir().is_some(),
63+
repo.workdir().is_some(),
6464
&index,
6565
gix::worktree::stack::state::attributes::Source::WorktreeThenIdMapping.adjust_for_bare(repo.is_bare()),
6666
)?;
@@ -82,12 +82,12 @@ pub fn query(
8282
let pathspec = repo.pathspec(
8383
true,
8484
patterns.iter(),
85-
repo.work_dir().is_some(),
85+
repo.workdir().is_some(),
8686
&index,
8787
gix::worktree::stack::state::attributes::Source::WorktreeThenIdMapping
8888
.adjust_for_bare(repo.is_bare()),
8989
)?;
90-
let workdir = repo.work_dir();
90+
let workdir = repo.workdir();
9191
for pattern in pathspec.search().patterns() {
9292
let path = pattern.path();
9393
let entry = cache.at_entry(

gitoxide-core/src/repository/merge/file.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ pub fn file(
4040
let base_id = repo.rev_parse_single(base.as_bstr()).ok();
4141
let ours_id = repo.rev_parse_single(ours.as_bstr()).ok();
4242
let theirs_id = repo.rev_parse_single(theirs.as_bstr()).ok();
43-
let roots = worktree_roots(base_id, ours_id, theirs_id, repo.work_dir())?;
43+
let roots = worktree_roots(base_id, ours_id, theirs_id, repo.workdir())?;
4444

4545
let mut cache = repo.merge_resource_cache(roots)?;
4646
let null = repo.object_hash().null();

gix-fs/src/snapshot.rs

+11-2
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
// TODO: tests
2-
use std::ops::Deref;
3-
42
use gix_features::threading::{get_mut, get_ref, MutableOnDemand, OwnShared};
3+
use std::ops::Deref;
54

65
/// A structure holding enough information to reload a value if its on-disk representation changes as determined by its modified time.
76
#[derive(Debug)]
@@ -39,6 +38,16 @@ impl<T: Clone + std::fmt::Debug> Clone for FileSnapshot<T> {
3938
}
4039
}
4140

41+
impl<T: Clone + std::fmt::Debug> FileSnapshot<T> {
42+
/// Return the contained instance if nobody else is holding it, or clone it otherwise.
43+
pub fn into_owned_or_cloned(self: OwnShared<Self>) -> T {
44+
match OwnShared::try_unwrap(self) {
45+
Ok(this) => this.value,
46+
Err(this) => this.value.clone(),
47+
}
48+
}
49+
}
50+
4251
/// A snapshot of a resource which is up-to-date in the moment it is retrieved.
4352
pub type SharedFileSnapshot<T> = OwnShared<FileSnapshot<T>>;
4453

File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.

gix-fs/tests/fs.rs renamed to gix-fs/tests/fs/main.rs

+1
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,5 @@ type Result<T = ()> = std::result::Result<T, Box<dyn std::error::Error + Send +
33
mod capabilities;
44
mod dir;
55
mod read_dir;
6+
mod snapshot;
67
mod stack;
File renamed without changes.

gix-fs/tests/fs/snapshot.rs

+54
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
use gix_fs::SharedFileSnapshotMut;
2+
use std::path::Path;
3+
4+
#[test]
5+
fn journey() -> Result<(), Box<dyn std::error::Error>> {
6+
let tmp = tempfile::tempdir().unwrap();
7+
if !has_nanosecond_times(tmp.path())? {
8+
return Ok(());
9+
}
10+
11+
let file_path = tmp.path().join("content");
12+
let smut = SharedFileSnapshotMut::<String>::new();
13+
14+
let check = || file_path.metadata().ok()?.modified().ok();
15+
let open = || {
16+
Ok(match std::fs::read_to_string(&file_path) {
17+
Ok(s) => Some(s),
18+
Err(err) if err.kind() == std::io::ErrorKind::NotFound => None,
19+
Err(err) => return Err(err),
20+
})
21+
};
22+
let snap = smut.recent_snapshot(check, open)?;
23+
assert!(snap.is_none());
24+
25+
std::fs::write(&file_path, "content")?;
26+
let snap = smut.recent_snapshot(check, open)?.expect("content read");
27+
assert_eq!(&**snap, "content", "it read the file for the first time");
28+
29+
std::fs::write(&file_path, "change")?;
30+
let snap = smut.recent_snapshot(check, open)?.expect("content read");
31+
assert_eq!(&**snap, "change", "it picks up the change");
32+
33+
std::fs::remove_file(&file_path)?;
34+
let snap = smut.recent_snapshot(check, open)?;
35+
assert!(snap.is_none(), "file deleted, nothing to see here");
36+
37+
std::fs::write(&file_path, "new")?;
38+
let snap = smut.recent_snapshot(check, open)?.expect("content read again");
39+
let owned: String = snap.into_owned_or_cloned();
40+
assert_eq!(owned, "new", "owned versions are possible easily and efficiently");
41+
Ok(())
42+
}
43+
44+
fn has_nanosecond_times(root: &Path) -> std::io::Result<bool> {
45+
let test_file = root.join("nanosecond-test");
46+
47+
std::fs::write(&test_file, "a")?;
48+
let first_time = test_file.metadata()?.modified()?;
49+
50+
std::fs::write(&test_file, "b")?;
51+
let second_time = test_file.metadata()?.modified()?;
52+
53+
Ok(first_time != second_time)
54+
}
File renamed without changes.

gix-status/src/lib.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,8 @@ pub use index_as_worktree_with_renames::function::index_as_worktree_with_renames
4747
/// It can efficiently validate paths when these are queried in sort-order, which leads to each component
4848
/// to only be checked once.
4949
pub struct SymlinkCheck {
50-
inner: gix_fs::Stack,
50+
/// Supports querying additional information, like the stack root.
51+
pub inner: gix_fs::Stack,
5152
}
5253

5354
mod stack;

gix/examples/clone.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -27,11 +27,11 @@ fn main() -> anyhow::Result<()> {
2727

2828
println!(
2929
"Checking out into {:?} ...",
30-
prepare_checkout.repo().work_dir().expect("should be there")
30+
prepare_checkout.repo().workdir().expect("should be there")
3131
);
3232

3333
let (repo, _) = prepare_checkout.main_worktree(gix::progress::Discard, &gix::interrupt::IS_INTERRUPTED)?;
34-
println!("Repo cloned into {:?}", repo.work_dir().expect("directory pre-created"));
34+
println!("Repo cloned into {:?}", repo.workdir().expect("directory pre-created"));
3535

3636
let remote = repo
3737
.find_default_remote(gix::remote::Direction::Fetch)

gix/examples/stats.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ use gix::{prelude::ObjectIdExt, Reference};
44

55
fn main() -> Result<(), Box<dyn std::error::Error>> {
66
let mut repo = gix::discover(".")?;
7-
println!("Repo: {}", repo.work_dir().unwrap_or_else(|| repo.git_dir()).display());
7+
println!("Repo: {}", repo.workdir().unwrap_or_else(|| repo.git_dir()).display());
88
let mut max_parents = 0;
99
let mut avg_parents = 0;
1010
repo.object_cache_size(32 * 1024);

gix/src/clone/access.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ impl PrepareFetch {
6868
impl Drop for PrepareFetch {
6969
fn drop(&mut self) {
7070
if let Some(repo) = self.repo.take() {
71-
std::fs::remove_dir_all(repo.work_dir().unwrap_or_else(|| repo.path())).ok();
71+
std::fs::remove_dir_all(repo.workdir().unwrap_or_else(|| repo.path())).ok();
7272
}
7373
}
7474
}

gix/src/clone/checkout.rs

+3-5
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@ pub mod main_worktree {
9292
.repo
9393
.as_ref()
9494
.expect("BUG: this method may only be called until it is successful");
95-
let workdir = repo.work_dir().ok_or_else(|| Error::BareRepository {
95+
let workdir = repo.workdir().ok_or_else(|| Error::BareRepository {
9696
git_dir: repo.git_dir().to_owned(),
9797
})?;
9898

@@ -118,9 +118,7 @@ pub mod main_worktree {
118118
})?;
119119
let mut index = gix_index::File::from_state(index, repo.index_path());
120120

121-
let mut opts = repo
122-
.config
123-
.checkout_options(repo, gix_worktree::stack::state::attributes::Source::IdMapping)?;
121+
let mut opts = repo.checkout_options(gix_worktree::stack::state::attributes::Source::IdMapping)?;
124122
opts.destination_is_initially_empty = true;
125123

126124
let mut files = progress.add_child_with_id("checkout".to_string(), ProgressId::CheckoutFiles.into());
@@ -173,7 +171,7 @@ impl PrepareCheckout {
173171
impl Drop for PrepareCheckout {
174172
fn drop(&mut self) {
175173
if let Some(repo) = self.repo.take() {
176-
std::fs::remove_dir_all(repo.work_dir().unwrap_or_else(|| repo.path())).ok();
174+
std::fs::remove_dir_all(repo.workdir().unwrap_or_else(|| repo.path())).ok();
177175
}
178176
}
179177
}

gix/src/config/cache/init.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -303,7 +303,7 @@ impl crate::Repository {
303303
}
304304

305305
fn apply_changed_values(&mut self) {
306-
self.refs.write_reflog = util::reflog_or_default(self.config.reflog, self.work_dir().is_some());
306+
self.refs.write_reflog = util::reflog_or_default(self.config.reflog, self.workdir().is_some());
307307
self.refs.namespace.clone_from(&self.config.refs_namespace);
308308
}
309309
}

gix/src/dirwalk/iter.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ pub struct Outcome {
3434
/// The pathspecs used to guide the operation,
3535
pub pathspec: PathspecDetached,
3636
/// The root actually being used for the traversal, and useful to transform the paths returned for the user.
37-
/// It's always within the [`work-dir`](Repository::work_dir).
37+
/// It's always within the [`work-dir`](Repository::workdir).
3838
pub traversal_root: PathBuf,
3939
/// The actual result of the dirwalk.
4040
pub dirwalk: gix_dir::walk::Outcome,

gix/src/dirwalk/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ pub struct Outcome<'repo> {
6464
/// The pathspecs used to guide the operation,
6565
pub pathspec: Pathspec<'repo>,
6666
/// The root actually being used for the traversal, and useful to transform the paths returned for the user.
67-
/// It's always within the [`work-dir`](crate::Repository::work_dir).
67+
/// It's always within the [`work-dir`](crate::Repository::workdir).
6868
pub traversal_root: PathBuf,
6969
/// The actual result of the dirwalk.
7070
pub dirwalk: gix_dir::walk::Outcome,

gix/src/filter.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -228,7 +228,7 @@ impl Pipeline<'_> {
228228

229229
let rela_path_as_path = gix_path::from_bstr(rela_path);
230230
let repo = self.repo;
231-
let worktree_dir = repo.work_dir().ok_or(Error::MissingWorktree)?;
231+
let worktree_dir = repo.workdir().ok_or(Error::MissingWorktree)?;
232232
let path = worktree_dir.join(&rela_path_as_path);
233233
let md = match std::fs::symlink_metadata(&path) {
234234
Ok(md) => md,

gix/src/pathspec.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ impl<'repo> Pathspec<'repo> {
6060
patterns,
6161
prefix,
6262
&gix_path::realpath_opts(
63-
repo.work_dir().unwrap_or_else(|| repo.git_dir()),
63+
repo.workdir().unwrap_or_else(|| repo.git_dir()),
6464
repo.options.current_dir_or_empty(),
6565
gix_path::realpath::MAX_SYMLINKS,
6666
)?,

gix/src/remote/connection/fetch/update_refs/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -444,7 +444,7 @@ fn insert_head(
444444
head: Option<crate::Head<'_>>,
445445
out: &mut BTreeMap<gix_ref::FullName, Vec<PathBuf>>,
446446
) -> Result<(), update::Error> {
447-
if let Some((head, wd)) = head.and_then(|head| head.repo.work_dir().map(|wd| (head, wd))) {
447+
if let Some((head, wd)) = head.and_then(|head| head.repo.workdir().map(|wd| (head, wd))) {
448448
out.entry("HEAD".try_into().expect("valid"))
449449
.or_default()
450450
.push(wd.to_owned());

gix/src/remote/connection/fetch/update_refs/tests.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,7 @@ mod update {
126126
(
127127
"+refs/remotes/origin/g:refs/heads/main",
128128
fetch::refs::update::Mode::RejectedCurrentlyCheckedOut {
129-
worktree_dirs: vec![repo.work_dir().expect("present").to_owned()],
129+
worktree_dirs: vec![repo.workdir().expect("present").to_owned()],
130130
},
131131
None,
132132
"checked out branches cannot be written, as it requires a merge of sorts which isn't done here",
@@ -498,7 +498,7 @@ mod update {
498498
"refs/heads/main",
499499
fetch::refs::Update {
500500
mode: fetch::refs::update::Mode::RejectedCurrentlyCheckedOut {
501-
worktree_dirs: vec![repo.work_dir().expect("present").to_owned()],
501+
worktree_dirs: vec![repo.workdir().expect("present").to_owned()],
502502
},
503503
type_change: None,
504504
edit_index: None,

gix/src/repository/attributes.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ impl Repository {
5050
Ok(AttributeStack::new(
5151
gix_worktree::Stack::new(
5252
// this is alright as we don't cause mutation of that directory, it's virtual.
53-
self.work_dir().unwrap_or(self.git_dir()),
53+
self.workdir().unwrap_or(self.git_dir()),
5454
state,
5555
case,
5656
buf,
@@ -82,7 +82,7 @@ impl Repository {
8282
Ok(AttributeStack::new(
8383
gix_worktree::Stack::new(
8484
// this is alright as we don't cause mutation of that directory, it's virtual.
85-
self.work_dir().unwrap_or(self.git_dir()),
85+
self.workdir().unwrap_or(self.git_dir()),
8686
state,
8787
case,
8888
buf,
@@ -127,7 +127,7 @@ impl Repository {
127127
Ok(AttributeStack::new(
128128
gix_worktree::Stack::new(
129129
// this is alright as we don't cause mutation of that directory, it's virtual.
130-
self.work_dir().unwrap_or(self.git_dir()),
130+
self.workdir().unwrap_or(self.git_dir()),
131131
state,
132132
case,
133133
buf,

gix/src/repository/checkout.rs

+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
use crate::{config, Repository};
2+
3+
impl Repository {
4+
/// Return options that can be used to drive a low-level checkout operation.
5+
/// Use `attributes_source` to determine where `.gitattributes` files should be read from, which depends on
6+
/// the presence of a worktree to begin with.
7+
/// Here, typically this value would be [`gix_worktree::stack::state::attributes::Source::IdMapping`]
8+
pub fn checkout_options(
9+
&self,
10+
attributes_source: gix_worktree::stack::state::attributes::Source,
11+
) -> Result<gix_worktree_state::checkout::Options, config::checkout_options::Error> {
12+
self.config.checkout_options(self, attributes_source)
13+
}
14+
}

gix/src/repository/config/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,7 @@ impl crate::Repository {
107107
.into()
108108
},
109109
git_dir: self.git_dir().to_owned().into(),
110-
worktree_dir: self.work_dir().map(ToOwned::to_owned),
110+
worktree_dir: self.workdir().map(ToOwned::to_owned),
111111
no_replace_objects: config::shared::is_replace_refs_enabled(
112112
&self.config.resolved,
113113
self.config.lenient_config,

gix/src/repository/dirwalk.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ impl Repository {
3636
delegate: &mut dyn gix_dir::walk::Delegate,
3737
) -> Result<dirwalk::Outcome<'_>, dirwalk::Error> {
3838
let _span = gix_trace::coarse!("gix::dirwalk");
39-
let workdir = self.work_dir().ok_or(dirwalk::Error::MissingWorkDir)?;
39+
let workdir = self.workdir().ok_or(dirwalk::Error::MissingWorkDir)?;
4040
let mut excludes = self.excludes(
4141
index,
4242
None,
@@ -56,7 +56,7 @@ impl Repository {
5656
let accelerate_lookup = fs_caps.ignore_case.then(|| index.prepare_icase_backing());
5757
let mut opts = gix_dir::walk::Options::from(options);
5858
let worktree_relative_worktree_dirs_storage;
59-
if let Some(workdir) = self.work_dir().filter(|_| opts.for_deletion.is_some()) {
59+
if let Some(workdir) = self.workdir().filter(|_| opts.for_deletion.is_some()) {
6060
let linked_worktrees = self.worktrees()?;
6161
if !linked_worktrees.is_empty() {
6262
let real_workdir = gix_path::realpath_opts(

gix/src/repository/impls.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ impl std::fmt::Debug for crate::Repository {
3131
f.debug_struct("Repository")
3232
.field("kind", &self.kind())
3333
.field("git_dir", &self.git_dir())
34-
.field("work_dir", &self.work_dir())
34+
.field("workdir", &self.workdir())
3535
.finish()
3636
}
3737
}

0 commit comments

Comments
 (0)