From 8d610ab8de7d3f62116632de6975f00c845dc842 Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Mon, 15 Apr 2024 07:27:26 +0200 Subject: [PATCH 1/5] doc: make clear that `Time::seconds` is UTC. --- gix-date/src/lib.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/gix-date/src/lib.rs b/gix-date/src/lib.rs index 42dda4a533c..34ab8a93c93 100644 --- a/gix-date/src/lib.rs +++ b/gix-date/src/lib.rs @@ -23,11 +23,11 @@ pub use parse::function::parse; #[derive(PartialEq, Eq, Debug, Hash, Ord, PartialOrd, Clone, Copy)] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct Time { - /// time in seconds since epoch. + /// The seconds that passed since UNIX epoch. This makes it UTC, or `+0000`. pub seconds: SecondsSinceUnixEpoch, - /// time offset in seconds, may be negative to match the `sign` field. + /// The time's offset in seconds, which may be negative to match the `sign` field. pub offset: OffsetInSeconds, - /// the sign of `offset`, used to encode `-0000` which would otherwise loose sign information. + /// the sign of `offset`, used to encode `-0000` which would otherwise lose sign information. pub sign: time::Sign, } From 5b47567bff0b46cb1b6e933bf7ebdb75909bb2ba Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Fri, 19 Apr 2024 18:41:43 +0200 Subject: [PATCH 2/5] fix: assure empty paths are always matching a `Search` This improvement was triggered by [this question](https://github.com/rust-lang/cargo/pull/13777#pullrequestreview-2011470503). --- gix-pathspec/src/search/matching.rs | 27 +++++++++++++++++---------- gix-pathspec/tests/search/mod.rs | 25 +++++++++++++++++++++++++ 2 files changed, 42 insertions(+), 10 deletions(-) diff --git a/gix-pathspec/src/search/matching.rs b/gix-pathspec/src/search/matching.rs index f0eba2a59c3..69f62a91c6c 100644 --- a/gix-pathspec/src/search/matching.rs +++ b/gix-pathspec/src/search/matching.rs @@ -31,6 +31,21 @@ impl Search { is_dir: Option, attributes: &mut dyn FnMut(&BStr, Case, bool, &mut gix_attributes::search::Outcome) -> bool, ) -> Option> { + static MATCH_ALL_STAND_IN: Pattern = Pattern { + path: BString::new(Vec::new()), + signature: MagicSignature::empty(), + search_mode: SearchMode::ShellGlob, + attributes: Vec::new(), + prefix_len: 0, + nil: true, + }; + if relative_path.is_empty() { + return Some(Match { + pattern: &MATCH_ALL_STAND_IN, + sequence_number: 0, + kind: Always, + }); + } let basename_not_important = None; if relative_path .get(..self.common_prefix_len) @@ -106,14 +121,6 @@ impl Search { }); if res.is_none() && self.all_patterns_are_excluded { - static MATCH_ALL_STAND_IN: Pattern = Pattern { - path: BString::new(Vec::new()), - signature: MagicSignature::empty(), - search_mode: SearchMode::ShellGlob, - attributes: Vec::new(), - prefix_len: 0, - nil: true, - }; Some(Match { pattern: &MATCH_ALL_STAND_IN, sequence_number: patterns_len, @@ -133,7 +140,7 @@ impl Search { /// is ignored. /// Returns `false` if this pathspec has no chance of ever matching `relative_path`. pub fn can_match_relative_path(&self, relative_path: &BStr, is_dir: Option) -> bool { - if self.patterns.is_empty() { + if self.patterns.is_empty() || relative_path.is_empty() { return true; } let common_prefix_len = self.common_prefix_len.min(relative_path.len()); @@ -194,7 +201,7 @@ impl Search { /// When `leading` is `true`, then `d` matches `d/d` as well. Thus, `relative_path` must may be /// partially included in `pathspec`, otherwise it has to be fully included. pub fn directory_matches_prefix(&self, relative_path: &BStr, leading: bool) -> bool { - if self.patterns.is_empty() { + if self.patterns.is_empty() || relative_path.is_empty() { return true; } let common_prefix_len = self.common_prefix_len.min(relative_path.len()); diff --git a/gix-pathspec/tests/search/mod.rs b/gix-pathspec/tests/search/mod.rs index 938786d07b1..07cd328e994 100644 --- a/gix-pathspec/tests/search/mod.rs +++ b/gix-pathspec/tests/search/mod.rs @@ -57,6 +57,31 @@ fn directory_matches_prefix_starting_wildcards_always_match() -> crate::Result { Ok(()) } +#[test] +fn empty_dir_always_matches() -> crate::Result { + for specs in [ + &["*ir"] as &[_], + &[], + &["included", ":!excluded"], + &[":!all", ":!excluded"], + ] { + let mut search = gix_pathspec::Search::from_specs(pathspecs(specs), None, Path::new(""))?; + assert_eq!( + search + .pattern_matching_relative_path("".into(), None, &mut no_attrs) + .map(|m| m.kind), + Some(Always), + "{specs:?}" + ); + assert!(search.directory_matches_prefix("".into(), false)); + assert!(search.directory_matches_prefix("".into(), false)); + for is_dir in [Some(true), Some(false), None] { + assert!(search.can_match_relative_path("".into(), is_dir)); + } + } + Ok(()) +} + #[test] fn directory_matches_prefix_leading() -> crate::Result { let search = gix_pathspec::Search::from_specs(pathspecs(&["d/d/generated/b"]), None, Path::new(""))?; From 44a2e005ea8241d026ae542dd4a71cfb6cfd8308 Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Fri, 19 Apr 2024 18:51:02 +0200 Subject: [PATCH 3/5] cleanup path classificaiton after fixes in `gix-pathspec` --- gix-dir/src/walk/classify.rs | 18 ++++-------------- gix-dir/tests/walk/mod.rs | 22 +++++++++++++--------- 2 files changed, 17 insertions(+), 23 deletions(-) diff --git a/gix-dir/src/walk/classify.rs b/gix-dir/src/walk/classify.rs index 4639f2fc19c..a57319535ba 100644 --- a/gix-dir/src/walk/classify.rs +++ b/gix-dir/src/walk/classify.rs @@ -21,13 +21,7 @@ pub fn root( let mut path_buf = worktree_root.to_owned(); // These initial values kick in if worktree_relative_root.is_empty(); let file_kind = path_buf.symlink_metadata().map(|m| m.file_type().into()).ok(); - let pathspec_orig = std::mem::replace( - ctx.pathspec, - gix_pathspec::Search::from_specs(None, None, "".as_ref()).expect("empty is valid"), - ); - let res = path(&mut path_buf, buf, 0, file_kind, || None, options, ctx); - *ctx.pathspec = pathspec_orig; - let mut out = res?; + let mut out = path(&mut path_buf, buf, 0, file_kind, || None, options, ctx)?; let worktree_root_is_repository = out .disk_kind .map_or(false, |kind| matches!(kind, entry::Kind::Repository)); @@ -59,9 +53,6 @@ pub fn root( } last_length = Some(buf.len()); } - if out.pathspec_match.is_none() { - out.pathspec_match = Some(PathspecMatch::Always); - } Ok((out, worktree_root_is_repository)) } /// The product of [`path()`] calls. @@ -181,10 +172,9 @@ pub fn path( out.property = entry::Property::DotGit.into(); return Ok(out); } - let pathspec_could_match = rela_path.is_empty() - || ctx - .pathspec - .can_match_relative_path(rela_path.as_bstr(), disk_kind.map(|ft| ft.is_dir())); + let pathspec_could_match = ctx + .pathspec + .can_match_relative_path(rela_path.as_bstr(), disk_kind.map(|ft| ft.is_dir())); if !pathspec_could_match { return Ok(out.with_status(entry::Status::Pruned)); } diff --git a/gix-dir/tests/walk/mod.rs b/gix-dir/tests/walk/mod.rs index df964377e64..dc880059856 100644 --- a/gix-dir/tests/walk/mod.rs +++ b/gix-dir/tests/walk/mod.rs @@ -2732,7 +2732,7 @@ fn worktree_root_can_be_symlink() -> crate::Result { #[test] fn root_may_not_go_through_dot_git() -> crate::Result { let root = fixture("with-nested-dot-git"); - for (dir, expected_pathspec) in [("", Verbatim), ("subdir", Always)] { + for (dir, expected_pathspec) in [("", Some(Verbatim)), ("subdir", None)] { let troot = root.join("dir").join(".git").join(dir); let ((out, _root), entries) = collect(&root, Some(&troot), |keep, ctx| { walk(&root, ctx, options_emit_all(), keep) @@ -2747,9 +2747,11 @@ fn root_may_not_go_through_dot_git() -> crate::Result { ); assert_eq!( entries, - [entry("dir/.git", Pruned, Directory) - .with_property(DotGit) - .with_match(expected_pathspec)], + [{ + let mut e = entry("dir/.git", Pruned, Directory).with_property(DotGit); + e.0.pathspec_match = expected_pathspec; + e + }], "{dir}: no traversal happened as root passes though .git" ); } @@ -3165,7 +3167,7 @@ fn root_can_be_pruned_early_with_pathspec() -> crate::Result { assert_eq!( entries, - [entry("dir", Pruned, Directory)], + [entry_nomatch("dir", Pruned, Directory)], "the pathspec didn't match the root, early abort" ); Ok(()) @@ -3927,7 +3929,7 @@ fn untracked_and_ignored_collapse_mix() { #[test] fn root_cannot_pass_through_case_altered_capital_dot_git_if_case_insensitive() -> crate::Result { let root = fixture("with-nested-capitalized-dot-git"); - for (dir, expected_pathspec) in [("", Verbatim), ("subdir", Always)] { + for (dir, expected_pathspec) in [("", Some(Verbatim)), ("subdir", None)] { let troot = root.join("dir").join(".GIT").join(dir); let ((out, _root), entries) = collect(&root, Some(&troot), |keep, ctx| { walk( @@ -3950,9 +3952,11 @@ fn root_cannot_pass_through_case_altered_capital_dot_git_if_case_insensitive() - ); assert_eq!( entries, - [entry("dir/.GIT", Pruned, Directory) - .with_property(DotGit) - .with_match(expected_pathspec)], + [{ + let mut e = entry("dir/.GIT", Pruned, Directory).with_property(DotGit); + e.0.pathspec_match = expected_pathspec; + e + }], "{dir}: no traversal happened as root passes though .git, it compares in a case-insensitive fashion" ); } From f2d8955eacc1a0ce8678f3e9026e696926bae654 Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Mon, 22 Apr 2024 08:48:20 +0200 Subject: [PATCH 4/5] feat: add `file::Store::force_refresh_packed_buffer()` to public API (#1348) That way it's possible to explicitly refresh if the caller knows that some other operation might have invalidated the in-memory cache. The `mtime` based approach doesn't work reliably on all filesystems due to coarse granularity of time. --- gix-ref/src/store/file/packed.rs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/gix-ref/src/store/file/packed.rs b/gix-ref/src/store/file/packed.rs index c5c42d5a357..8c6d8b7cf4d 100644 --- a/gix-ref/src/store/file/packed.rs +++ b/gix-ref/src/store/file/packed.rs @@ -84,7 +84,14 @@ pub(crate) mod modifiable { pub(crate) type MutableSharedBuffer = OwnShared>; impl file::Store { - pub(crate) fn force_refresh_packed_buffer(&self) -> Result<(), packed::buffer::open::Error> { + /// Forcefully reload the packed refs buffer. + /// + /// This method should be used if it's clear that the buffer on disk has changed, to + /// make the latest changes visible before other operations are done on this instance. + /// + /// As some filesystems don't have nanosecond granularity, changes are likely to be missed + /// if they happen within one second otherwise. + pub fn force_refresh_packed_buffer(&self) -> Result<(), packed::buffer::open::Error> { self.packed.force_refresh(|| { let modified = self.packed_refs_path().metadata()?.modified()?; self.open_packed_buffer().map(|packed| Some(modified).zip(packed)) From 28a7afc89228abb97207a5c52a0d1fb5966a573e Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Mon, 22 Apr 2024 08:56:00 +0200 Subject: [PATCH 5/5] Upgrade lock-file to latest version to avoid `cargo-deny` failure --- Cargo.lock | 24 ++++++++++++------------ deny.toml | 5 ++++- 2 files changed, 16 insertions(+), 13 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index acb053ba08d..93ee941713c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -802,24 +802,24 @@ dependencies = [ [[package]] name = "curl" -version = "0.4.44" +version = "0.4.46" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "509bd11746c7ac09ebd19f0b17782eae80aadee26237658a6b4808afb5c11a22" +checksum = "1e2161dd6eba090ff1594084e95fd67aeccf04382ffea77999ea94ed42ec67b6" dependencies = [ "curl-sys", "libc", "openssl-probe", "openssl-sys", "schannel", - "socket2 0.4.10", - "winapi", + "socket2 0.5.5", + "windows-sys 0.52.0", ] [[package]] name = "curl-sys" -version = "0.4.70+curl-8.5.0" +version = "0.4.72+curl-8.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c0333d8849afe78a4c8102a429a446bfdd055832af071945520e835ae2d841e" +checksum = "29cbdc8314c447d11e8fd156dcdd031d9e02a7a976163e396b548c03153bc9ea" dependencies = [ "cc", "libc", @@ -828,7 +828,7 @@ dependencies = [ "pkg-config", "rustls-ffi", "vcpkg", - "windows-sys 0.48.0", + "windows-sys 0.52.0", ] [[package]] @@ -3042,7 +3042,7 @@ dependencies = [ "http", "hyper", "hyper-util", - "rustls 0.22.2", + "rustls 0.22.4", "rustls-pki-types", "tokio", "tokio-rustls", @@ -3964,7 +3964,7 @@ dependencies = [ "once_cell", "percent-encoding", "pin-project-lite", - "rustls 0.22.2", + "rustls 0.22.4", "rustls-pemfile 1.0.4", "rustls-pki-types", "serde", @@ -4074,9 +4074,9 @@ dependencies = [ [[package]] name = "rustls" -version = "0.22.2" +version = "0.22.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e87c9956bd9807afa1f77e0f7594af32566e830e088a5576d27c5b6f30f49d41" +checksum = "bf4ef73721ac7bcd79b2b315da7779d8fc09718c6b3d2d1b2d94850eb8c18432" dependencies = [ "log", "ring 0.17.7", @@ -4674,7 +4674,7 @@ version = "0.25.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "775e0c0f0adb3a2f22a00c4745d728b479985fc15ee7ca6a2608388c5569860f" dependencies = [ - "rustls 0.22.2", + "rustls 0.22.4", "rustls-pki-types", "tokio", ] diff --git a/deny.toml b/deny.toml index ddddea8f5f6..1e8ed3f49e0 100644 --- a/deny.toml +++ b/deny.toml @@ -22,7 +22,10 @@ yanked = "warn" # 2019-12-17 there are no security notice advisories in # https://github.com/rustsec/advisory-db notice = "warn" -ignore = [] +ignore = [ + # this is `rustls@0.20.9` coming in with `curl`, which doesn't have an update yet. It's only active optionally, not by default. + "RUSTSEC-2024-0336", +]