Skip to content

Commit

Permalink
Merge branch 'reset'
Browse files Browse the repository at this point in the history
  • Loading branch information
Byron committed Sep 23, 2023
2 parents b009db0 + f094f71 commit 54a8495
Show file tree
Hide file tree
Showing 28 changed files with 453 additions and 39 deletions.
4 changes: 4 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion gitoxide-core/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -44,10 +44,11 @@ serde = ["gix/serde", "dep:serde_json", "dep:serde", "bytesize/serde"]

[dependencies]
# deselect everything else (like "performance") as this should be controllable by the parent application.
gix = { version = "^0.53.1", path = "../gix", default-features = false, features = ["blob-diff", "revision", "mailmap", "excludes", "attributes", "worktree-mutation", "credentials", "interrupt"] }
gix = { version = "^0.53.1", path = "../gix", default-features = false, features = ["blob-diff", "revision", "mailmap", "excludes", "attributes", "worktree-mutation", "credentials", "interrupt", "status"] }
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"] }
gix-transport-configuration-only = { package = "gix-transport", version = "^0.36.0", path = "../gix-transport", default-features = false }
gix-archive-for-configuration-only = { package = "gix-archive", version = "^0.4.0", path = "../gix-archive", optional = true, features = ["tar", "tar_gz"] }
gix-status = { version = "0.1.0", path = "../gix-status" }
serde = { version = "1.0.114", optional = true, default-features = false, features = ["derive"] }
anyhow = "1.0.42"
thiserror = "1.0.34"
Expand Down
1 change: 1 addition & 0 deletions gitoxide-core/src/repository/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ pub mod mailmap;
pub mod odb;
pub mod remote;
pub mod revision;
pub mod status;
pub mod submodule;
pub mod tree;
pub mod verify;
120 changes: 120 additions & 0 deletions gitoxide-core/src/repository/status.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
use crate::OutputFormat;
use anyhow::{bail, Context};
use gix::bstr::{BStr, BString};
use gix::index::Entry;
use gix::prelude::FindExt;
use gix::Progress;
use gix_status::index_as_worktree::content::FastEq;
use gix_status::index_as_worktree::Change;

pub enum Submodules {
/// display all information about submodules, including ref changes, modifications and untracked files.
All,
/// Compare only the configuration of the superprojects commit with the actually checked out `HEAD` commit.
RefChange,
/// See if there are worktree modifications compared to the index, but do not check for untracked files.
Modifications,
}

pub struct Options {
pub format: OutputFormat,
pub submodules: Submodules,
pub thread_limit: Option<usize>,
}

pub fn show(
repo: gix::Repository,
pathspecs: Vec<BString>,
out: impl std::io::Write,
mut err: impl std::io::Write,
mut progress: impl gix::NestedProgress,
Options {
format,
// TODO: implement this
submodules: _,
thread_limit,
}: Options,
) -> anyhow::Result<()> {
if format != OutputFormat::Human {
bail!("Only human format is supported right now");
}
let mut index = repo.index()?;
let index = gix::threading::make_mut(&mut index);
let pathspec = repo.pathspec(
pathspecs,
true,
index,
gix::worktree::stack::state::attributes::Source::WorktreeThenIdMapping,
)?;
let mut progress = progress.add_child("traverse index");
let start = std::time::Instant::now();
gix_status::index_as_worktree(
index,
repo.work_dir()
.context("This operation cannot be run on a bare repository")?,
&mut Printer(out),
FastEq,
{
let odb = repo.objects.clone().into_arc()?;
move |id, buf| odb.find_blob(id, buf)
},
&mut progress,
pathspec.detach()?,
gix_status::index_as_worktree::Options {
fs: repo.filesystem_options()?,
thread_limit,
stat: repo.stat_options()?,
},
)?;

writeln!(err, "\nhead -> index and untracked files aren't implemented yet")?;
progress.show_throughput(start);
Ok(())
}

struct Printer<W>(W);

impl<'index, W> gix_status::index_as_worktree::VisitEntry<'index> for Printer<W>
where
W: std::io::Write,
{
type ContentChange = ();

fn visit_entry(
&mut self,
entry: &'index Entry,
rela_path: &'index BStr,
change: Option<Change<Self::ContentChange>>,
conflict: bool,
) {
self.visit_inner(entry, rela_path, change, conflict).ok();
}
}

impl<W: std::io::Write> Printer<W> {
fn visit_inner(
&mut self,
_entry: &Entry,
rela_path: &BStr,
change: Option<Change<()>>,
conflict: bool,
) -> anyhow::Result<()> {
if let Some(change) = conflict
.then_some('U')
.or_else(|| change.as_ref().and_then(change_to_char))
{
writeln!(&mut self.0, "{change} {rela_path}")?;
}
Ok(())
}
}

fn change_to_char(change: &Change<()>) -> Option<char> {
// Known status letters: https://github.com/git/git/blob/6807fcfedab84bc8cd0fbf721bc13c4e68cda9ae/diff.h#L613
Some(match change {
Change::Removed => 'D',
Change::Type => 'T',
Change::Modification { .. } => 'M',
Change::IntentToAdd => return None,
})
}
4 changes: 2 additions & 2 deletions gix-features/src/parallel/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,7 @@ pub fn in_parallel_if<I, S, O, R>(
condition: impl FnOnce() -> bool,
input: impl Iterator<Item = I> + Send,
thread_limit: Option<usize>,
new_thread_state: impl Fn(usize) -> S + Send + Clone,
new_thread_state: impl FnOnce(usize) -> S + Send + Clone,
consume: impl FnMut(I, &mut S) -> O + Send + Clone,
reducer: R,
) -> Result<<R as Reduce>::Output, <R as Reduce>::Error>
Expand All @@ -161,7 +161,7 @@ pub fn in_parallel_if<I, S, O, R>(
_condition: impl FnOnce() -> bool,
input: impl Iterator<Item = I>,
thread_limit: Option<usize>,
new_thread_state: impl Fn(usize) -> S,
new_thread_state: impl FnOnce(usize) -> S,
consume: impl FnMut(I, &mut S) -> O,
reducer: R,
) -> Result<<R as Reduce>::Output, <R as Reduce>::Error>
Expand Down
10 changes: 10 additions & 0 deletions gix-features/src/threading.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,11 @@ mod _impl {
v.write()
}

/// Get a mutable reference to the underlying data, with semantics similar to [Arc::make_mut()].
pub fn make_mut<T: Clone>(this: &mut OwnShared<T>) -> &mut T {
OwnShared::make_mut(this)
}

/// Get a mutable reference through a [`Mutable`] for read-write access.
pub fn lock<T>(v: &Mutable<T>) -> parking_lot::MutexGuard<'_, T> {
v.lock()
Expand Down Expand Up @@ -75,6 +80,11 @@ mod _impl {
v.borrow_mut()
}

/// Get a mutable reference to the underlying data, with semantics similar to [Rc::make_mut()].
pub fn make_mut<T: Clone>(this: &mut OwnShared<T>) -> &mut T {
OwnShared::make_mut(this)
}

/// Get a mutable reference through a [`Mutable`] for read-write access.
pub fn lock<T>(v: &Mutable<T>) -> RefMut<'_, T> {
v.borrow_mut()
Expand Down
6 changes: 6 additions & 0 deletions gix-fs/src/snapshot.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,12 @@ impl<T: std::fmt::Debug> Deref for FileSnapshot<T> {
}
}

impl<T: std::fmt::Debug> std::ops::DerefMut for FileSnapshot<T> {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.value
}
}

impl<T: std::fmt::Debug> Deref for SharedFileSnapshotMut<T> {
type Target = MutableOnDemand<Option<SharedFileSnapshot<T>>>;

Expand Down
4 changes: 2 additions & 2 deletions gix-index/src/entry/stat.rs
Original file line number Diff line number Diff line change
Expand Up @@ -95,8 +95,8 @@ impl Stat {
use std::os::unix::fs::MetadataExt;
#[cfg(unix)]
let res = Stat {
mtime: mtime.try_into()?,
ctime: ctime.try_into()?,
mtime: mtime.try_into().unwrap_or_default(),
ctime: ctime.try_into().unwrap_or_default(),
// truncating to 32 bits is fine here because
// that's what the linux syscalls returns
// just rust upcasts to 64 bits for some reason?
Expand Down
1 change: 1 addition & 0 deletions gix-index/src/init.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ mod from_tree {
where
Find: for<'a> FnMut(&gix_hash::oid, &'a mut Vec<u8>) -> Option<TreeRefIter<'a>>,
{
let _span = gix_features::trace::coarse!("gix_index::State::from_tree()");
let mut buf = Vec::new();
let root = find(tree, &mut buf).ok_or(breadthfirst::Error::NotFound { oid: tree.into() })?;

Expand Down
7 changes: 5 additions & 2 deletions gix-pathspec/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -93,9 +93,12 @@ pub struct Pattern {
pub attributes: Vec<gix_attributes::Assignment>,
/// If `true`, we are a special Nil pattern and always match.
nil: bool,
/// The length of bytes in `path` that belong to the prefix, which will always be matched case-insensitively.
/// The length of bytes in `path` that belong to the prefix, which will always be matched case-sensitively
/// on case-sensitive filesystems.
///
/// That way, even though pathspecs are applied from the top, we can emulate having changed directory into
/// a specific sub-directory in a case-sensitive file-system.
/// a specific sub-directory in a case-sensitive file-system, even if the rest of the pathspec can be set to
/// match case-insensitively.
/// Is set by [Pattern::normalize()].
prefix_len: usize,
}
Expand Down
2 changes: 1 addition & 1 deletion gix-pathspec/src/search/matching.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use crate::{

impl Search {
/// Return the first [`Match`] of `relative_path`, or `None`.
/// `is_dir` is true if `relative_path` is a directory.
/// `is_dir` is `true` if `relative_path` is a directory.
/// `attributes` is called as `attributes(relative_path, case, is_dir, outcome) -> has_match` to obtain for attributes for `relative_path`, if
/// the underlying pathspec defined an attribute filter, to be stored in `outcome`, returning true if there was a match.
/// All attributes of the pathspec have to be present in the defined value for the pathspec to match.
Expand Down
6 changes: 4 additions & 2 deletions gix-pathspec/src/search/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,10 @@ impl Search {
/// Return the portion of the prefix among all of the pathspecs involved in this search, or an empty string if
/// there is none. It doesn't have to end at a directory boundary though, nor does it denote a directory.
///
/// Note that the common_prefix can be matched case-insensitively, which makes it useful to skip large portions of input.
/// Further, excluded pathspecs don't participate which makes this common prefix inclusive.
/// Note that the common_prefix is always matched case-sensitively, and it is useful to skip large portions of input.
/// Further, excluded pathspecs don't participate which makes this common prefix inclusive. To work correclty though,
/// one will have to additionally match paths that have the common prefix with that pathspec itself to assure it is
/// not excluded.
pub fn common_prefix(&self) -> &BStr {
self.patterns
.iter()
Expand Down
1 change: 1 addition & 0 deletions gix-status/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ gix-hash = { version = "^0.13.0", path = "../gix-hash" }
gix-object = { version = "^0.36.0", path = "../gix-object" }
gix-path = { version = "^0.10.0", path = "../gix-path" }
gix-features = { version = "^0.34.0", path = "../gix-features" }
gix-pathspec = { version = "0.2.0", path = "../gix-pathspec" }

thiserror = "1.0.26"
filetime = "0.2.15"
Expand Down
Loading

0 comments on commit 54a8495

Please sign in to comment.