Skip to content

Commit 54a8495

Browse files
committed
Merge branch 'reset'
2 parents b009db0 + f094f71 commit 54a8495

File tree

28 files changed

+453
-39
lines changed

28 files changed

+453
-39
lines changed

Diff for: Cargo.lock

+4
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Diff for: gitoxide-core/Cargo.toml

+2-1
Original file line numberDiff line numberDiff line change
@@ -44,10 +44,11 @@ serde = ["gix/serde", "dep:serde_json", "dep:serde", "bytesize/serde"]
4444

4545
[dependencies]
4646
# deselect everything else (like "performance") as this should be controllable by the parent application.
47-
gix = { version = "^0.53.1", path = "../gix", default-features = false, features = ["blob-diff", "revision", "mailmap", "excludes", "attributes", "worktree-mutation", "credentials", "interrupt"] }
47+
gix = { version = "^0.53.1", path = "../gix", default-features = false, features = ["blob-diff", "revision", "mailmap", "excludes", "attributes", "worktree-mutation", "credentials", "interrupt", "status"] }
4848
gix-pack-for-configuration-only = { package = "gix-pack", version = "^0.42.0", path = "../gix-pack", default-features = false, features = ["pack-cache-lru-dynamic", "pack-cache-lru-static", "generate", "streaming-input"] }
4949
gix-transport-configuration-only = { package = "gix-transport", version = "^0.36.0", path = "../gix-transport", default-features = false }
5050
gix-archive-for-configuration-only = { package = "gix-archive", version = "^0.4.0", path = "../gix-archive", optional = true, features = ["tar", "tar_gz"] }
51+
gix-status = { version = "0.1.0", path = "../gix-status" }
5152
serde = { version = "1.0.114", optional = true, default-features = false, features = ["derive"] }
5253
anyhow = "1.0.42"
5354
thiserror = "1.0.34"

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

+1
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ pub mod mailmap;
4040
pub mod odb;
4141
pub mod remote;
4242
pub mod revision;
43+
pub mod status;
4344
pub mod submodule;
4445
pub mod tree;
4546
pub mod verify;

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

+120
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
use crate::OutputFormat;
2+
use anyhow::{bail, Context};
3+
use gix::bstr::{BStr, BString};
4+
use gix::index::Entry;
5+
use gix::prelude::FindExt;
6+
use gix::Progress;
7+
use gix_status::index_as_worktree::content::FastEq;
8+
use gix_status::index_as_worktree::Change;
9+
10+
pub enum Submodules {
11+
/// display all information about submodules, including ref changes, modifications and untracked files.
12+
All,
13+
/// Compare only the configuration of the superprojects commit with the actually checked out `HEAD` commit.
14+
RefChange,
15+
/// See if there are worktree modifications compared to the index, but do not check for untracked files.
16+
Modifications,
17+
}
18+
19+
pub struct Options {
20+
pub format: OutputFormat,
21+
pub submodules: Submodules,
22+
pub thread_limit: Option<usize>,
23+
}
24+
25+
pub fn show(
26+
repo: gix::Repository,
27+
pathspecs: Vec<BString>,
28+
out: impl std::io::Write,
29+
mut err: impl std::io::Write,
30+
mut progress: impl gix::NestedProgress,
31+
Options {
32+
format,
33+
// TODO: implement this
34+
submodules: _,
35+
thread_limit,
36+
}: Options,
37+
) -> anyhow::Result<()> {
38+
if format != OutputFormat::Human {
39+
bail!("Only human format is supported right now");
40+
}
41+
let mut index = repo.index()?;
42+
let index = gix::threading::make_mut(&mut index);
43+
let pathspec = repo.pathspec(
44+
pathspecs,
45+
true,
46+
index,
47+
gix::worktree::stack::state::attributes::Source::WorktreeThenIdMapping,
48+
)?;
49+
let mut progress = progress.add_child("traverse index");
50+
let start = std::time::Instant::now();
51+
gix_status::index_as_worktree(
52+
index,
53+
repo.work_dir()
54+
.context("This operation cannot be run on a bare repository")?,
55+
&mut Printer(out),
56+
FastEq,
57+
{
58+
let odb = repo.objects.clone().into_arc()?;
59+
move |id, buf| odb.find_blob(id, buf)
60+
},
61+
&mut progress,
62+
pathspec.detach()?,
63+
gix_status::index_as_worktree::Options {
64+
fs: repo.filesystem_options()?,
65+
thread_limit,
66+
stat: repo.stat_options()?,
67+
},
68+
)?;
69+
70+
writeln!(err, "\nhead -> index and untracked files aren't implemented yet")?;
71+
progress.show_throughput(start);
72+
Ok(())
73+
}
74+
75+
struct Printer<W>(W);
76+
77+
impl<'index, W> gix_status::index_as_worktree::VisitEntry<'index> for Printer<W>
78+
where
79+
W: std::io::Write,
80+
{
81+
type ContentChange = ();
82+
83+
fn visit_entry(
84+
&mut self,
85+
entry: &'index Entry,
86+
rela_path: &'index BStr,
87+
change: Option<Change<Self::ContentChange>>,
88+
conflict: bool,
89+
) {
90+
self.visit_inner(entry, rela_path, change, conflict).ok();
91+
}
92+
}
93+
94+
impl<W: std::io::Write> Printer<W> {
95+
fn visit_inner(
96+
&mut self,
97+
_entry: &Entry,
98+
rela_path: &BStr,
99+
change: Option<Change<()>>,
100+
conflict: bool,
101+
) -> anyhow::Result<()> {
102+
if let Some(change) = conflict
103+
.then_some('U')
104+
.or_else(|| change.as_ref().and_then(change_to_char))
105+
{
106+
writeln!(&mut self.0, "{change} {rela_path}")?;
107+
}
108+
Ok(())
109+
}
110+
}
111+
112+
fn change_to_char(change: &Change<()>) -> Option<char> {
113+
// Known status letters: https://github.com/git/git/blob/6807fcfedab84bc8cd0fbf721bc13c4e68cda9ae/diff.h#L613
114+
Some(match change {
115+
Change::Removed => 'D',
116+
Change::Type => 'T',
117+
Change::Modification { .. } => 'M',
118+
Change::IntentToAdd => return None,
119+
})
120+
}

Diff for: gix-features/src/parallel/mod.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -135,7 +135,7 @@ pub fn in_parallel_if<I, S, O, R>(
135135
condition: impl FnOnce() -> bool,
136136
input: impl Iterator<Item = I> + Send,
137137
thread_limit: Option<usize>,
138-
new_thread_state: impl Fn(usize) -> S + Send + Clone,
138+
new_thread_state: impl FnOnce(usize) -> S + Send + Clone,
139139
consume: impl FnMut(I, &mut S) -> O + Send + Clone,
140140
reducer: R,
141141
) -> Result<<R as Reduce>::Output, <R as Reduce>::Error>
@@ -161,7 +161,7 @@ pub fn in_parallel_if<I, S, O, R>(
161161
_condition: impl FnOnce() -> bool,
162162
input: impl Iterator<Item = I>,
163163
thread_limit: Option<usize>,
164-
new_thread_state: impl Fn(usize) -> S,
164+
new_thread_state: impl FnOnce(usize) -> S,
165165
consume: impl FnMut(I, &mut S) -> O,
166166
reducer: R,
167167
) -> Result<<R as Reduce>::Output, <R as Reduce>::Error>

Diff for: gix-features/src/threading.rs

+10
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,11 @@ mod _impl {
3030
v.write()
3131
}
3232

33+
/// Get a mutable reference to the underlying data, with semantics similar to [Arc::make_mut()].
34+
pub fn make_mut<T: Clone>(this: &mut OwnShared<T>) -> &mut T {
35+
OwnShared::make_mut(this)
36+
}
37+
3338
/// Get a mutable reference through a [`Mutable`] for read-write access.
3439
pub fn lock<T>(v: &Mutable<T>) -> parking_lot::MutexGuard<'_, T> {
3540
v.lock()
@@ -75,6 +80,11 @@ mod _impl {
7580
v.borrow_mut()
7681
}
7782

83+
/// Get a mutable reference to the underlying data, with semantics similar to [Rc::make_mut()].
84+
pub fn make_mut<T: Clone>(this: &mut OwnShared<T>) -> &mut T {
85+
OwnShared::make_mut(this)
86+
}
87+
7888
/// Get a mutable reference through a [`Mutable`] for read-write access.
7989
pub fn lock<T>(v: &Mutable<T>) -> RefMut<'_, T> {
8090
v.borrow_mut()

Diff for: gix-fs/src/snapshot.rs

+6
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,12 @@ impl<T: std::fmt::Debug> Deref for FileSnapshot<T> {
5757
}
5858
}
5959

60+
impl<T: std::fmt::Debug> std::ops::DerefMut for FileSnapshot<T> {
61+
fn deref_mut(&mut self) -> &mut Self::Target {
62+
&mut self.value
63+
}
64+
}
65+
6066
impl<T: std::fmt::Debug> Deref for SharedFileSnapshotMut<T> {
6167
type Target = MutableOnDemand<Option<SharedFileSnapshot<T>>>;
6268

Diff for: gix-index/src/entry/stat.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -95,8 +95,8 @@ impl Stat {
9595
use std::os::unix::fs::MetadataExt;
9696
#[cfg(unix)]
9797
let res = Stat {
98-
mtime: mtime.try_into()?,
99-
ctime: ctime.try_into()?,
98+
mtime: mtime.try_into().unwrap_or_default(),
99+
ctime: ctime.try_into().unwrap_or_default(),
100100
// truncating to 32 bits is fine here because
101101
// that's what the linux syscalls returns
102102
// just rust upcasts to 64 bits for some reason?

Diff for: gix-index/src/init.rs

+1
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ mod from_tree {
3939
where
4040
Find: for<'a> FnMut(&gix_hash::oid, &'a mut Vec<u8>) -> Option<TreeRefIter<'a>>,
4141
{
42+
let _span = gix_features::trace::coarse!("gix_index::State::from_tree()");
4243
let mut buf = Vec::new();
4344
let root = find(tree, &mut buf).ok_or(breadthfirst::Error::NotFound { oid: tree.into() })?;
4445

Diff for: gix-pathspec/src/lib.rs

+5-2
Original file line numberDiff line numberDiff line change
@@ -93,9 +93,12 @@ pub struct Pattern {
9393
pub attributes: Vec<gix_attributes::Assignment>,
9494
/// If `true`, we are a special Nil pattern and always match.
9595
nil: bool,
96-
/// The length of bytes in `path` that belong to the prefix, which will always be matched case-insensitively.
96+
/// The length of bytes in `path` that belong to the prefix, which will always be matched case-sensitively
97+
/// on case-sensitive filesystems.
98+
///
9799
/// That way, even though pathspecs are applied from the top, we can emulate having changed directory into
98-
/// a specific sub-directory in a case-sensitive file-system.
100+
/// a specific sub-directory in a case-sensitive file-system, even if the rest of the pathspec can be set to
101+
/// match case-insensitively.
99102
/// Is set by [Pattern::normalize()].
100103
prefix_len: usize,
101104
}

Diff for: gix-pathspec/src/search/matching.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ use crate::{
88

99
impl Search {
1010
/// Return the first [`Match`] of `relative_path`, or `None`.
11-
/// `is_dir` is true if `relative_path` is a directory.
11+
/// `is_dir` is `true` if `relative_path` is a directory.
1212
/// `attributes` is called as `attributes(relative_path, case, is_dir, outcome) -> has_match` to obtain for attributes for `relative_path`, if
1313
/// the underlying pathspec defined an attribute filter, to be stored in `outcome`, returning true if there was a match.
1414
/// All attributes of the pathspec have to be present in the defined value for the pathspec to match.

Diff for: gix-pathspec/src/search/mod.rs

+4-2
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,10 @@ impl Search {
3030
/// Return the portion of the prefix among all of the pathspecs involved in this search, or an empty string if
3131
/// there is none. It doesn't have to end at a directory boundary though, nor does it denote a directory.
3232
///
33-
/// Note that the common_prefix can be matched case-insensitively, which makes it useful to skip large portions of input.
34-
/// Further, excluded pathspecs don't participate which makes this common prefix inclusive.
33+
/// Note that the common_prefix is always matched case-sensitively, and it is useful to skip large portions of input.
34+
/// Further, excluded pathspecs don't participate which makes this common prefix inclusive. To work correclty though,
35+
/// one will have to additionally match paths that have the common prefix with that pathspec itself to assure it is
36+
/// not excluded.
3537
pub fn common_prefix(&self) -> &BStr {
3638
self.patterns
3739
.iter()

Diff for: gix-status/Cargo.toml

+1
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ gix-hash = { version = "^0.13.0", path = "../gix-hash" }
2020
gix-object = { version = "^0.36.0", path = "../gix-object" }
2121
gix-path = { version = "^0.10.0", path = "../gix-path" }
2222
gix-features = { version = "^0.34.0", path = "../gix-features" }
23+
gix-pathspec = { version = "0.2.0", path = "../gix-pathspec" }
2324

2425
thiserror = "1.0.26"
2526
filetime = "0.2.15"

0 commit comments

Comments
 (0)