From 7d7d1bac4737accd546b926c36113fd2e148872f Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Fri, 4 Jul 2025 05:58:59 +0200 Subject: [PATCH 1/3] doc: Improve and correct `normalize()` documentation (#2074) --- gix-path/Cargo.toml | 2 +- gix-path/src/convert.rs | 28 +++++++++++++++++++++++----- 2 files changed, 24 insertions(+), 6 deletions(-) diff --git a/gix-path/Cargo.toml b/gix-path/Cargo.toml index 5502116cfdb..e5644dbb062 100644 --- a/gix-path/Cargo.toml +++ b/gix-path/Cargo.toml @@ -12,7 +12,7 @@ include = ["src/**/*", "LICENSE-*"] rust-version = "1.70" [lib] -doctest = false +doctest = true [dependencies] gix-trace = { version = "^0.1.12", path = "../gix-trace" } diff --git a/gix-path/src/convert.rs b/gix-path/src/convert.rs index 000deb3798b..6391a4c2e8c 100644 --- a/gix-path/src/convert.rs +++ b/gix-path/src/convert.rs @@ -247,16 +247,34 @@ pub fn to_windows_separators<'a>(path: impl Into>) -> Cow<'a, BStr /// /// For example, this turns `a/./b/c/.././..` into `a`, and turns `/a/../b/..` into `/`. /// -/// If the input path was relative and ends up being the `current_dir`, `.` is returned instead of -/// the full path to `current_dir`. +/// ``` +/// # fn main() { +/// # use std::path::Path; +/// # use gix_path::normalize; +/// for (input, expected) in [ +/// ("a/./b/c/.././..", "a"), +/// ("/a/../b/..", "/"), +/// ("/base/a/..", "/base"), +/// ("./a/..", "."), +/// ("./a/../..", "/"), +/// (".///", ".///"), +/// ("a//b", "a//b"), +/// ("/base/../base", "/base"), +/// ] { +/// let input = Path::new(input); +/// let expected = Path::new(expected); +/// assert_eq!(normalize(input.into(), Path::new("/cwd")), Some(expected.into())); +/// } +/// # } +/// ``` /// -/// Single `.` components as well as duplicate separators are left untouched. +/// Leading `.` components as well as duplicate separators are left untouched. /// /// This is particularly useful when manipulating paths that are based on user input, and not /// resolving intermediate symlinks keeps the path similar to what the user provided. If that's not -/// desirable, use `[realpath()][crate::realpath()` instead. +/// desirable, use [`realpath()`](crate::realpath()) instead. /// -/// Note that we might access the `current_dir` if we run out of path components to pop off, which +/// Note that we will use the `current_dir` if we run out of path components to pop off, which /// is expected to be absolute as typical return value of `std::env::current_dir()` or /// `gix_fs::current_dir(…)` when `core.precomposeUnicode` is known. As a `current_dir` like `/c` /// can be exhausted by paths like `../../r`, `None` will be returned to indicate the inability to From 6f5c1859eab8f090824a08e14304d334e5a4943d Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Sun, 6 Jul 2025 15:28:04 +0200 Subject: [PATCH 2/3] fix: improve error message for when there is too many packs. Affects https://github.com/jj-vcs/jj/issues/6906 --- gix-odb/src/store_impls/dynamic/init.rs | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/gix-odb/src/store_impls/dynamic/init.rs b/gix-odb/src/store_impls/dynamic/init.rs index be6a1ea9475..8f62ca34e58 100644 --- a/gix-odb/src/store_impls/dynamic/init.rs +++ b/gix-odb/src/store_impls/dynamic/init.rs @@ -99,17 +99,24 @@ impl Store { let mut db_paths = crate::alternate::resolve(objects_dir.clone(), ¤t_dir) .map_err(|err| std::io::Error::new(std::io::ErrorKind::Other, err))?; db_paths.insert(0, objects_dir.clone()); - let num_slots = super::Store::collect_indices_and_mtime_sorted_by_size(db_paths, None, None) + let num_slots = Store::collect_indices_and_mtime_sorted_by_size(db_paths, None, None) .map_err(|err| std::io::Error::new(std::io::ErrorKind::Other, err))? .len(); - ((num_slots as f32 * multiplier) as usize).max(minimum) + let candidate = ((num_slots as f32 * multiplier) as usize).max(minimum); + if candidate > crate::store::types::PackId::max_indices() { + // A chance for this to work without 10% extra allocation - this already + // is an insane amount of packs. + num_slots + } else { + candidate + } } }; if slot_count > crate::store::types::PackId::max_indices() { return Err(std::io::Error::new( std::io::ErrorKind::Other, - "Cannot use more than 1^15 slots", + format!("Cannot use more than 2^15-1 slots, got {slot_count}"), )); } let mut replacements: Vec<_> = replacements.collect(); From cfa2159da997da47c73a0cafee945ad22c38a510 Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Wed, 9 Jul 2025 08:02:27 +0200 Subject: [PATCH 3/3] fix: `gix submodule list` now prints the submodule path in debug mode That way, special characters won't affect the terminal. --- gitoxide-core/src/repository/submodule.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/gitoxide-core/src/repository/submodule.rs b/gitoxide-core/src/repository/submodule.rs index 9938eb71a8e..0da81100eb4 100644 --- a/gitoxide-core/src/repository/submodule.rs +++ b/gitoxide-core/src/repository/submodule.rs @@ -31,7 +31,7 @@ fn print_sm(sm: Submodule<'_>, dirty_suffix: Option<&str>, out: &mut impl std::i } writeln!( out, - " {is_active} {path} {config} head:{head_id} index:{index_id} ({worktree}) [{url}]", + " {is_active} {path:?} {config} head:{head_id} index:{index_id} ({worktree}) [{url}]", is_active = if !sm.is_active()? || !state.repository_exists { "ⅹ" } else { @@ -48,8 +48,8 @@ fn print_sm(sm: Submodule<'_>, dirty_suffix: Option<&str>, out: &mut impl std::i worktree = match sm_repo { Some(repo) => { // TODO(name-revision): this is the simple version, `git` gives it - // multiple tries https://github.com/git/git/blob/fac96dfbb1c24369ba7d37a5affd8adfe6c650fd/builtin/submodule--helper.c#L161 - // and even uses `git name-rev`/`git describe --contains` which we can't do yet. + // multiple tries https://github.com/git/git/blob/fac96dfbb1c24369ba7d37a5affd8adfe6c650fd/builtin/submodule--helper.c#L161 + // and even uses `git name-rev`/`git describe --contains` which we can't do yet. repo.head_commit()? .describe() .names(SelectRef::AllRefs) @@ -60,7 +60,7 @@ fn print_sm(sm: Submodule<'_>, dirty_suffix: Option<&str>, out: &mut impl std::i .to_string() } None => { - "no worktree".to_string() + "no worktree".into() } }, url = sm.url()?.to_bstring()