Skip to content

Commit

Permalink
add status.showUntrackedFiles to config-tree and use it in status()
Browse files Browse the repository at this point in the history
  • Loading branch information
Byron committed Mar 11, 2024
1 parent f8ce3d0 commit 22abf60
Show file tree
Hide file tree
Showing 13 changed files with 274 additions and 17 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

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

1 change: 1 addition & 0 deletions gix/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -323,6 +323,7 @@ parking_lot = "0.12.1"
document-features = { version = "0.2.0", optional = true }

[dev-dependencies]
pretty_assertions = "1.4.0"
gix-testtools = { path = "../tests/tools" }
is_ci = "1.1.1"
anyhow = "1"
Expand Down
7 changes: 7 additions & 0 deletions gix/src/config/tree/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,9 @@ pub(crate) mod root {
pub const SAFE: sections::Safe = sections::Safe;
/// The `ssh` section.
pub const SSH: sections::Ssh = sections::Ssh;
/// The `status` section.
#[cfg(feature = "status")]
pub const STATUS: sections::Status = sections::Status;
/// The `user` section.
pub const USER: sections::User = sections::User;
/// The `url` section.
Expand Down Expand Up @@ -89,6 +92,8 @@ pub(crate) mod root {
&Self::REMOTE,
&Self::SAFE,
&Self::SSH,
#[cfg(feature = "status")]
&Self::STATUS,
&Self::USER,
&Self::URL,
]
Expand All @@ -104,6 +109,8 @@ pub use sections::{
};
#[cfg(feature = "blob-diff")]
pub use sections::{diff, Diff};
#[cfg(feature = "status")]
pub use sections::{status, Status};

/// Generic value implementations for static instantiation.
pub mod keys;
Expand Down
7 changes: 7 additions & 0 deletions gix/src/config/tree/sections/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,13 @@ mod safe;
pub struct Ssh;
pub mod ssh;

/// The `status` top-level section.
#[derive(Copy, Clone, Default)]
#[cfg(feature = "status")]
pub struct Status;
#[cfg(feature = "status")]
pub mod status;

/// The `user` top-level section.
#[derive(Copy, Clone, Default)]
pub struct User;
Expand Down
58 changes: 58 additions & 0 deletions gix/src/config/tree/sections/status.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
use crate::config;
use crate::config::tree::sections::Status;
use crate::config::tree::{keys, Key, Section};

impl Status {
/// The `status.showUntrackedFiles` key
pub const SHOW_UNTRACKED_FILES: ShowUntrackedFiles = ShowUntrackedFiles::new_with_validate(
"showUntrackedFiles",
&config::Tree::STATUS,
validate::ShowUntrackedFiles,
);
}

/// The `status.showUntrackedFiles` key.
pub type ShowUntrackedFiles = keys::Any<validate::ShowUntrackedFiles>;

mod show_untracked_files {
use std::borrow::Cow;

use crate::{bstr::BStr, config, config::tree::status::ShowUntrackedFiles, status};

impl ShowUntrackedFiles {
pub fn try_into_show_untracked_files(
&'static self,
value: Cow<'_, BStr>,
) -> Result<status::UntrackedFiles, config::key::GenericErrorWithValue> {
use crate::bstr::ByteSlice;
Ok(match value.as_ref().as_bytes() {
b"no" => status::UntrackedFiles::None,
b"normal" => status::UntrackedFiles::Collapsed,
b"all" => status::UntrackedFiles::Files,
_ => return Err(config::key::GenericErrorWithValue::from_value(self, value.into_owned())),
})
}
}
}

impl Section for Status {
fn name(&self) -> &str {
"status"
}

fn keys(&self) -> &[&dyn Key] {
&[&Self::SHOW_UNTRACKED_FILES]
}
}

mod validate {
use crate::{bstr::BStr, config::tree::keys};

pub struct ShowUntrackedFiles;
impl keys::Validate for ShowUntrackedFiles {
fn validate(&self, value: &BStr) -> Result<(), Box<dyn std::error::Error + Send + Sync + 'static>> {
super::Status::SHOW_UNTRACKED_FILES.try_into_show_untracked_files(value.into())?;
Ok(())
}
}
}
53 changes: 48 additions & 5 deletions gix/src/status/mod.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use crate::config::cache::util::ApplyLeniencyDefault;
use crate::{config, Repository};
pub use gix_status as plumbing;
use std::ops::Deref;
Expand Down Expand Up @@ -71,23 +72,52 @@ pub enum Submodule {
},
}

/// How untracked files should be handled.
#[derive(Default, Copy, Clone, Debug, Ord, PartialOrd, Eq, PartialEq, Hash)]
pub enum UntrackedFiles {
/// Do not show any untracked files.
///
/// This can mean no directory walk is performed.
None,
/// If possible, collapse files into their parent folders to reduce the amount of
/// emitted untracked files.
#[default]
Collapsed,
/// Show each individual untracked file or directory (if empty directories are emitted) that the dirwalk encountered .
Files,
}

impl Default for Submodule {
fn default() -> Self {
Submodule::AsConfigured { check_dirty: false }
}
}

/// The error returned by [status()](Repository::status).
#[derive(Debug, thiserror::Error)]
#[allow(missing_docs)]
pub enum Error {
#[error(transparent)]
DirwalkOptions(#[from] config::boolean::Error),
#[error(transparent)]
ConfigureUntrackedFiles(#[from] config::key::GenericErrorWithValue),
}

/// Status
impl Repository {
/// Obtain a platform for configuring iterators for traversing git repository status information.
///
/// By default, this is set to the fastest and most immediate way of obtaining a status,
/// which is most similar to
///
/// `git status --untracked=all --ignored=no --no-renames`
/// `git status --ignored=no`
///
/// which implies that submodule information is provided by default.
///
/// Note that `status.showUntrackedFiles` is respected, which leads to untracked files being
/// collapsed by default. If that needs to be controlled,
/// [configure the directory walk explicitly](Platform::dirwalk_options) or more [implicitly](Platform::untracked_files).
///
/// Pass `progress` to receive progress information on file modifications on this repository.
/// Use [`progress::Discard`](crate::progress::Discard) to discard all progress information.
///
Expand All @@ -96,11 +126,11 @@ impl Repository {
/// Whereas Git runs the index-modified check before the directory walk to set entries
/// as up-to-date to (potentially) safe some disk-access, we run both in parallel which
/// ultimately is much faster.
pub fn status<P>(&self, progress: P) -> Result<Platform<'_, P>, config::boolean::Error>
pub fn status<P>(&self, progress: P) -> Result<Platform<'_, P>, Error>
where
P: gix_features::progress::Progress + 'static,
{
Ok(Platform {
let platform = Platform {
repo: self,
progress,
index: None,
Expand All @@ -112,7 +142,20 @@ impl Repository {
rewrites: None,
thread_limit: None,
},
})
};

let untracked = self
.config
.resolved
.string("status", None, "showUntrackedFiles")
.map(|value| {
config::tree::Status::SHOW_UNTRACKED_FILES
.try_into_show_untracked_files(value)
.with_lenient_default(self.config.lenient_config)
})
.transpose()?
.unwrap_or_default();
Ok(platform.untracked_files(untracked))
}
}

Expand All @@ -126,7 +169,7 @@ pub mod is_dirty {
#[allow(missing_docs)]
pub enum Error {
#[error(transparent)]
StatusPlatform(#[from] crate::config::boolean::Error),
StatusPlatform(#[from] crate::status::Error),
#[error(transparent)]
CreateStatusIterator(#[from] crate::status::index_worktree::iter::Error),
}
Expand Down
19 changes: 18 additions & 1 deletion gix/src/status/platform.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use crate::status::{index_worktree, OwnedOrStaticAtomic, Platform, Submodule};
use crate::status::{index_worktree, OwnedOrStaticAtomic, Platform, Submodule, UntrackedFiles};
use std::sync::atomic::AtomicBool;

/// Builder
Expand All @@ -17,6 +17,23 @@ where
self
}

/// A simple way to explicitly set the desired way of listing `untracked_files`, overriding any value
/// set by the git configuration.
///
/// Note that if [`None`](UntrackedFiles::None) is used, the directory walk will be disabled entirely
/// after this call. Further, if no dirwalk options are present anymore, this call has no effect.
pub fn untracked_files(mut self, untracked_files: UntrackedFiles) -> Self {
let mode = match untracked_files {
UntrackedFiles::None => {
self.index_worktree_options.dirwalk_options.take();
return self;
}
UntrackedFiles::Collapsed => gix_dir::walk::EmissionMode::CollapseDirectory,
UntrackedFiles::Files => gix_dir::walk::EmissionMode::Matching,
};
self.dirwalk_options(|cb| cb.emit_untracked(mode))
}

/// Set the interrupt flag to `should_interrupt`, which typically is an application-wide flag
/// that is ultimately controlled by user interrupts.
///
Expand Down
3 changes: 1 addition & 2 deletions gix/src/submodule/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -298,7 +298,7 @@ pub mod status {
#[error(transparent)]
IgnoreConfiguration(#[from] config::Error),
#[error(transparent)]
StatusPlatform(#[from] crate::config::boolean::Error),
StatusPlatform(#[from] crate::status::Error),
#[error(transparent)]
Status(#[from] crate::status::index_worktree::iter::Error),
#[error(transparent)]
Expand Down Expand Up @@ -384,7 +384,6 @@ pub mod status {

let statusses = adjust_options(sm_repo.status(gix_features::progress::Discard)?)
.index_worktree_options_mut(|opts| {
assert!(opts.dirwalk_options.is_some(), "BUG: it's supposed to be the default");
if ignore == config::Ignore::Untracked {
opts.dirwalk_options = None;
}
Expand Down
31 changes: 31 additions & 0 deletions gix/tests/config/tree.rs
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,37 @@ mod ssh {
}
}

#[cfg(feature = "status")]
mod status {
use crate::config::tree::bcow;
use gix::config::tree::Status;
use gix::status::UntrackedFiles;

#[test]
fn default() -> crate::Result {
for (actual, expected) in [
("no", UntrackedFiles::None),
("normal", UntrackedFiles::Collapsed),
("all", UntrackedFiles::Files),
] {
assert_eq!(
Status::SHOW_UNTRACKED_FILES.try_into_show_untracked_files(bcow(actual))?,
expected
);
}

assert_eq!(
Status::SHOW_UNTRACKED_FILES
.try_into_show_untracked_files(bcow("NO"))
.unwrap_err()
.to_string(),
"The key \"status.showUntrackedFiles=NO\" was invalid",
"case-sensitive comparisons"
);
Ok(())
}
}

mod push {
use crate::config::tree::bcow;
use gix::config::tree::Push;
Expand Down
Binary file not shown.
Binary file modified gix/tests/fixtures/generated-archives/make_submodules.tar.xz
Binary file not shown.
16 changes: 16 additions & 0 deletions gix/tests/fixtures/make_status_repos.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
#!/bin/bash
set -eu -o pipefail

git init -q untracked-only
(cd untracked-only
touch this
mkdir subdir
>subdir/that

git add .
git commit -q -m init

mkdir new
touch new/untracked subdir/untracked
)

Loading

0 comments on commit 22abf60

Please sign in to comment.