diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index afc1cea684a..ae35ff33c71 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -318,7 +318,7 @@ jobs: strategy: matrix: - target: [ wasm32-unknown-unknown, wasm32-wasi ] + target: [ wasm32-unknown-unknown, wasm32-wasip1 ] env: TARGET: ${{ matrix.target }} diff --git a/Cargo.toml b/Cargo.toml index b1b353eb1fb..cb92685da1d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -394,3 +394,4 @@ stable_sort_primitive = "allow" # x1 no_effect_underscore_binding = "allow" # x1 empty_docs = "allow" too_long_first_doc_paragraph = "allow" +large_stack_arrays = "allow" diff --git a/gitoxide-core/src/repository/attributes/query.rs b/gitoxide-core/src/repository/attributes/query.rs index 9081eb9ed78..72fac97ac2c 100644 --- a/gitoxide-core/src/repository/attributes/query.rs +++ b/gitoxide-core/src/repository/attributes/query.rs @@ -89,7 +89,7 @@ pub(crate) mod function { let entry = cache.at_entry( path, Some(is_dir_to_mode( - workdir.map_or(false, |wd| wd.join(gix::path::from_bstr(path)).is_dir()) + workdir.is_some_and(|wd| wd.join(gix::path::from_bstr(path)).is_dir()) || pattern.signature.contains(gix::pathspec::MagicSignature::MUST_BE_DIR), )), )?; diff --git a/gitoxide-core/src/repository/clean.rs b/gitoxide-core/src/repository/clean.rs index 8ccc8a90dfb..6d858182e72 100644 --- a/gitoxide-core/src/repository/clean.rs +++ b/gitoxide-core/src/repository/clean.rs @@ -128,10 +128,10 @@ pub(crate) mod function { let pathspec_includes_entry = match pathspec.as_mut() { None => entry .pathspec_match - .map_or(false, |m| m != gix::dir::entry::PathspecMatch::Excluded), + .is_some_and(|m| m != gix::dir::entry::PathspecMatch::Excluded), Some(pathspec) => pathspec .pattern_matching_relative_path(entry.rela_path.as_bstr(), entry.disk_kind.map(|k| k.is_dir())) - .map_or(false, |m| !m.is_excluded()), + .is_some_and(|m| !m.is_excluded()), }; pruned_entries += usize::from(!pathspec_includes_entry); if !pathspec_includes_entry && debug { diff --git a/gitoxide-core/src/repository/config.rs b/gitoxide-core/src/repository/config.rs index 48640688c05..c39272a2ebe 100644 --- a/gitoxide-core/src/repository/config.rs +++ b/gitoxide-core/src/repository/config.rs @@ -32,7 +32,7 @@ pub fn list( } let meta = section.meta(); - if last_meta.map_or(true, |last| last != meta) { + if last_meta != Some(meta) { write_meta(meta, &mut out)?; } last_meta = Some(meta); @@ -41,9 +41,10 @@ pub fn list( for event in matter { event.write_to(&mut out)?; } - if it.peek().map_or(false, |(next_section, _)| { - next_section.header().name() != section.header().name() - }) { + if it + .peek() + .is_some_and(|(next_section, _)| next_section.header().name() != section.header().name()) + { writeln!(&mut out)?; } } diff --git a/gitoxide-core/src/repository/exclude.rs b/gitoxide-core/src/repository/exclude.rs index a0cd212d08e..197e6d5d3b7 100644 --- a/gitoxide-core/src/repository/exclude.rs +++ b/gitoxide-core/src/repository/exclude.rs @@ -93,7 +93,7 @@ pub fn query( let entry = cache.at_entry( path, Some(is_dir_to_mode( - workdir.map_or(false, |wd| wd.join(gix::path::from_bstr(path)).is_dir()) + workdir.is_some_and(|wd| wd.join(gix::path::from_bstr(path)).is_dir()) || pattern.signature.contains(gix::pathspec::MagicSignature::MUST_BE_DIR), )), )?; diff --git a/gitoxide-core/src/repository/fetch.rs b/gitoxide-core/src/repository/fetch.rs index bf1cbcce21d..e8d229765bc 100644 --- a/gitoxide-core/src/repository/fetch.rs +++ b/gitoxide-core/src/repository/fetch.rs @@ -305,7 +305,7 @@ pub(crate) mod function { for fix in &map.fixes { match fix { Fix::MappingWithPartialDestinationRemoved { name, spec } => { - if prev_spec.map_or(true, |prev_spec| prev_spec != spec) { + if prev_spec.is_some_and(|prev_spec| prev_spec != spec) { prev_spec = spec.into(); spec.to_ref().write_to(&mut err)?; writeln!(err)?; diff --git a/gitoxide-core/src/repository/index/entries.rs b/gitoxide-core/src/repository/index/entries.rs index 5eaad0a1e56..74057464cf6 100644 --- a/gitoxide-core/src/repository/index/entries.rs +++ b/gitoxide-core/src/repository/index/entries.rs @@ -198,7 +198,7 @@ pub(crate) mod function { sms_by_path .iter() .find_map(|(path, sm)| (path == entry_path).then_some(sm)) - .filter(|sm| sm.git_dir_try_old_form().map_or(false, |dot_git| dot_git.exists())) + .filter(|sm| sm.git_dir_try_old_form().is_ok_and(|dot_git| dot_git.exists())) }) { let sm_path = gix::path::to_unix_separators_on_windows(sm.path()?); diff --git a/gitoxide-core/src/repository/remote.rs b/gitoxide-core/src/repository/remote.rs index 5a1cb061a34..eeb634566c2 100644 --- a/gitoxide-core/src/repository/remote.rs +++ b/gitoxide-core/src/repository/remote.rs @@ -190,7 +190,7 @@ mod refs_impl { for fix in &map.fixes { match fix { Fix::MappingWithPartialDestinationRemoved { name, spec } => { - if prev_spec.map_or(true, |prev_spec| prev_spec != spec) { + if prev_spec.is_some_and(|prev_spec| prev_spec != spec) { prev_spec = spec.into(); spec.to_ref().write_to(&mut err)?; writeln!(err)?; diff --git a/gitoxide-core/src/repository/revision/list.rs b/gitoxide-core/src/repository/revision/list.rs index 3ad5e7a9574..1698a29d494 100644 --- a/gitoxide-core/src/repository/revision/list.rs +++ b/gitoxide-core/src/repository/revision/list.rs @@ -108,7 +108,7 @@ pub(crate) mod function { } } progress.inc(); - if limit.map_or(false, |limit| limit == progress.step()) { + if limit.is_some_and(|limit| limit == progress.step()) { break; } } diff --git a/gix-dir/src/walk/classify.rs b/gix-dir/src/walk/classify.rs index 2fbae8753aa..d5fcbcafcd4 100644 --- a/gix-dir/src/walk/classify.rs +++ b/gix-dir/src/walk/classify.rs @@ -215,7 +215,7 @@ pub fn path( let is_dir = if symlinks_to_directories_are_ignored_like_directories && ctx.excludes.is_some() - && kind.map_or(false, |ft| ft == entry::Kind::Symlink) + && kind == Some(entry::Kind::Symlink) { path.metadata().ok().map(|md| is_dir_to_mode(md.is_dir())) } else { diff --git a/gix-filter/examples/arrow.rs b/gix-filter/examples/arrow.rs index 6f6d5a1c074..616084deb09 100644 --- a/gix-filter/examples/arrow.rs +++ b/gix-filter/examples/arrow.rs @@ -19,7 +19,7 @@ fn main() -> Result<(), Box> { match sub_command.as_str() { "process" => { - let disallow_delay = next_arg.as_deref().map_or(false, |arg| arg == "disallow-delay"); + let disallow_delay = next_arg.as_deref() == Some("disallow-delay"); let mut srv = gix_filter::driver::process::Server::handshake( stdin(), stdout(), diff --git a/gix-filter/src/driver/process/mod.rs b/gix-filter/src/driver/process/mod.rs index c2f62ddd260..b4e19c47a83 100644 --- a/gix-filter/src/driver/process/mod.rs +++ b/gix-filter/src/driver/process/mod.rs @@ -83,7 +83,7 @@ impl Status { /// Returns true if this is an `abort` status. pub fn is_abort(&self) -> bool { - self.message().map_or(false, |m| m == "abort") + self.message() == Some("abort") } /// Return true if the status is explicitly set to indicated delayed output processing diff --git a/gix-pack/src/multi_index/chunk.rs b/gix-pack/src/multi_index/chunk.rs index 95d3f21f97e..b0a1bddba78 100644 --- a/gix-pack/src/multi_index/chunk.rs +++ b/gix-pack/src/multi_index/chunk.rs @@ -69,7 +69,7 @@ pub mod index_names { ascii_path.is_ascii(), "must use ascii bytes for correct size computation" ); - count += (ascii_path.as_bytes().len() + 1/* null byte */) as u64; + count += (ascii_path.len() + 1/* null byte */) as u64; } let needed_alignment = CHUNK_ALIGNMENT - (count % CHUNK_ALIGNMENT); @@ -89,7 +89,7 @@ pub mod index_names { let path = path.as_ref().to_str().expect("UTF-8 path"); out.write_all(path.as_bytes())?; out.write_all(&[0])?; - written_bytes += path.as_bytes().len() as u64 + 1; + written_bytes += path.len() as u64 + 1; } let needed_alignment = CHUNK_ALIGNMENT - (written_bytes % CHUNK_ALIGNMENT); diff --git a/gix-packetline-blocking/src/line/async_io.rs b/gix-packetline-blocking/src/line/async_io.rs index 3a631c44c9a..83cf072023f 100644 --- a/gix-packetline-blocking/src/line/async_io.rs +++ b/gix-packetline-blocking/src/line/async_io.rs @@ -6,7 +6,7 @@ use futures_io::AsyncWrite; use crate::{encode, BandRef, Channel, ErrorRef, PacketLineRef, TextRef}; -impl<'a> BandRef<'a> { +impl BandRef<'_> { /// Serialize this instance to `out`, returning the amount of bytes written. /// /// The data written to `out` can be decoded with [`Borrowed::decode_band()]`. @@ -20,14 +20,14 @@ impl<'a> BandRef<'a> { } } -impl<'a> TextRef<'a> { +impl TextRef<'_> { /// Serialize this instance to `out`, appending a newline if there is none, returning the amount of bytes written. pub async fn write_to(&self, out: impl AsyncWrite + Unpin) -> io::Result { encode::text_to_write(self.0, out).await } } -impl<'a> ErrorRef<'a> { +impl ErrorRef<'_> { /// Serialize this line as error to `out`. /// /// This includes a marker to allow decoding it outside of a side-band channel, returning the amount of bytes written. @@ -36,7 +36,7 @@ impl<'a> ErrorRef<'a> { } } -impl<'a> PacketLineRef<'a> { +impl PacketLineRef<'_> { /// Serialize this instance to `out` in git `packetline` format, returning the amount of bytes written to `out`. pub async fn write_to(&self, out: impl AsyncWrite + Unpin) -> io::Result { match self { diff --git a/gix-packetline/src/line/async_io.rs b/gix-packetline/src/line/async_io.rs index 7f20aa030b7..c2526326bd5 100644 --- a/gix-packetline/src/line/async_io.rs +++ b/gix-packetline/src/line/async_io.rs @@ -4,7 +4,7 @@ use futures_io::AsyncWrite; use crate::{encode, BandRef, Channel, ErrorRef, PacketLineRef, TextRef}; -impl<'a> BandRef<'a> { +impl BandRef<'_> { /// Serialize this instance to `out`, returning the amount of bytes written. /// /// The data written to `out` can be decoded with [`Borrowed::decode_band()]`. @@ -18,14 +18,14 @@ impl<'a> BandRef<'a> { } } -impl<'a> TextRef<'a> { +impl TextRef<'_> { /// Serialize this instance to `out`, appending a newline if there is none, returning the amount of bytes written. pub async fn write_to(&self, out: impl AsyncWrite + Unpin) -> io::Result { encode::text_to_write(self.0, out).await } } -impl<'a> ErrorRef<'a> { +impl ErrorRef<'_> { /// Serialize this line as error to `out`. /// /// This includes a marker to allow decoding it outside of a side-band channel, returning the amount of bytes written. @@ -34,7 +34,7 @@ impl<'a> ErrorRef<'a> { } } -impl<'a> PacketLineRef<'a> { +impl PacketLineRef<'_> { /// Serialize this instance to `out` in git `packetline` format, returning the amount of bytes written to `out`. pub async fn write_to(&self, out: impl AsyncWrite + Unpin) -> io::Result { match self { diff --git a/gix-path/src/env/mod.rs b/gix-path/src/env/mod.rs index 154a0d1ddfa..cdc092dcb25 100644 --- a/gix-path/src/env/mod.rs +++ b/gix-path/src/env/mod.rs @@ -28,6 +28,23 @@ pub fn installation_config_prefix() -> Option<&'static Path> { installation_config().map(git::config_to_base_path) } +/// Return the shell that Git would prefer as login shell, the shell to execute Git commands from. +/// +/// On Windows, this is the `bash.exe` bundled with it, and on Unix it's the shell specified by `SHELL`, +/// or `None` if it is truly unspecified. +pub fn login_shell() -> Option<&'static Path> { + static PATH: Lazy> = Lazy::new(|| { + if cfg!(windows) { + installation_config_prefix() + .and_then(|p| p.parent()) + .map(|p| p.join("usr").join("bin").join("bash.exe")) + } else { + std::env::var_os("SHELL").map(PathBuf::from) + } + }); + PATH.as_deref() +} + /// Return the name of the Git executable to invoke it. /// If it's in the `PATH`, it will always be a short name. /// diff --git a/gix-path/tests/path.rs b/gix-path/tests/path.rs deleted file mode 100644 index 72cf2547b89..00000000000 --- a/gix-path/tests/path.rs +++ /dev/null @@ -1,80 +0,0 @@ -pub type Result = std::result::Result>; - -mod convert; -mod realpath; -mod home_dir { - #[test] - fn returns_existing_directory() { - if let Some(home) = gix_path::env::home_dir() { - assert!( - home.is_dir(), - "the home directory would typically exist, even though on unix we don't test for that." - ); - } - } -} - -mod env { - #[test] - fn exe_invocation() { - let actual = gix_path::env::exe_invocation(); - assert!( - !actual.as_os_str().is_empty(), - "it finds something as long as git is installed somewhere on the system (or a default location)" - ); - } - - #[test] - fn installation_config() { - assert_ne!( - gix_path::env::installation_config().map(|p| p.components().count()), - gix_path::env::installation_config_prefix().map(|p| p.components().count()), - "the prefix is a bit shorter than the installation config path itself" - ); - } - - #[test] - fn system_prefix() { - assert_ne!( - gix_path::env::system_prefix(), - None, - "git should be present when running tests" - ); - } - - #[test] - fn home_dir() { - assert_ne!( - gix_path::env::home_dir(), - None, - "we find a home on every system these tests execute" - ); - } - - mod xdg_config { - use std::ffi::OsStr; - - #[test] - fn prefers_xdg_config_bases() { - let actual = gix_path::env::xdg_config("test", &mut |n| { - (n == OsStr::new("XDG_CONFIG_HOME")).then(|| "marker".into()) - }) - .expect("set"); - #[cfg(unix)] - assert_eq!(actual.to_str(), Some("marker/git/test")); - #[cfg(windows)] - assert_eq!(actual.to_str(), Some("marker\\git\\test")); - } - - #[test] - fn falls_back_to_home() { - let actual = gix_path::env::xdg_config("test", &mut |n| (n == OsStr::new("HOME")).then(|| "marker".into())) - .expect("set"); - #[cfg(unix)] - assert_eq!(actual.to_str(), Some("marker/.config/git/test")); - #[cfg(windows)] - assert_eq!(actual.to_str(), Some("marker\\.config\\git\\test")); - } - } -} -mod util; diff --git a/gix-path/tests/convert/mod.rs b/gix-path/tests/path/convert/mod.rs similarity index 100% rename from gix-path/tests/convert/mod.rs rename to gix-path/tests/path/convert/mod.rs diff --git a/gix-path/tests/convert/normalize.rs b/gix-path/tests/path/convert/normalize.rs similarity index 100% rename from gix-path/tests/convert/normalize.rs rename to gix-path/tests/path/convert/normalize.rs diff --git a/gix-path/tests/path/env.rs b/gix-path/tests/path/env.rs new file mode 100644 index 00000000000..d2c4f9fd265 --- /dev/null +++ b/gix-path/tests/path/env.rs @@ -0,0 +1,71 @@ +#[test] +fn exe_invocation() { + let actual = gix_path::env::exe_invocation(); + assert!( + !actual.as_os_str().is_empty(), + "it finds something as long as git is installed somewhere on the system (or a default location)" + ); +} + +#[test] +fn login_shell() { + // On CI, the $SHELL variable isn't necessarily set. Maybe other ways to get the login shell should be used then. + if !gix_testtools::is_ci::cached() { + assert!(gix_path::env::login_shell() + .expect("There should always be the notion of a shell used by git") + .exists()); + } +} + +#[test] +fn installation_config() { + assert_ne!( + gix_path::env::installation_config().map(|p| p.components().count()), + gix_path::env::installation_config_prefix().map(|p| p.components().count()), + "the prefix is a bit shorter than the installation config path itself" + ); +} + +#[test] +fn system_prefix() { + assert_ne!( + gix_path::env::system_prefix(), + None, + "git should be present when running tests" + ); +} + +#[test] +fn home_dir() { + assert_ne!( + gix_path::env::home_dir(), + None, + "we find a home on every system these tests execute" + ); +} + +mod xdg_config { + use std::ffi::OsStr; + + #[test] + fn prefers_xdg_config_bases() { + let actual = gix_path::env::xdg_config("test", &mut |n| { + (n == OsStr::new("XDG_CONFIG_HOME")).then(|| "marker".into()) + }) + .expect("set"); + #[cfg(unix)] + assert_eq!(actual.to_str(), Some("marker/git/test")); + #[cfg(windows)] + assert_eq!(actual.to_str(), Some("marker\\git\\test")); + } + + #[test] + fn falls_back_to_home() { + let actual = gix_path::env::xdg_config("test", &mut |n| (n == OsStr::new("HOME")).then(|| "marker".into())) + .expect("set"); + #[cfg(unix)] + assert_eq!(actual.to_str(), Some("marker/.config/git/test")); + #[cfg(windows)] + assert_eq!(actual.to_str(), Some("marker\\.config\\git\\test")); + } +} diff --git a/gix-path/tests/path/main.rs b/gix-path/tests/path/main.rs new file mode 100644 index 00000000000..dae33bb7746 --- /dev/null +++ b/gix-path/tests/path/main.rs @@ -0,0 +1,18 @@ +pub type Result = std::result::Result>; + +mod convert; +mod realpath; +mod home_dir { + #[test] + fn returns_existing_directory() { + if let Some(home) = gix_path::env::home_dir() { + assert!( + home.is_dir(), + "the home directory would typically exist, even though on unix we don't test for that." + ); + } + } +} + +mod env; +mod util; diff --git a/gix-path/tests/realpath/mod.rs b/gix-path/tests/path/realpath.rs similarity index 100% rename from gix-path/tests/realpath/mod.rs rename to gix-path/tests/path/realpath.rs diff --git a/gix-path/tests/util/mod.rs b/gix-path/tests/path/util.rs similarity index 100% rename from gix-path/tests/util/mod.rs rename to gix-path/tests/path/util.rs diff --git a/gix-ref/src/store/file/transaction/commit.rs b/gix-ref/src/store/file/transaction/commit.rs index 89894f475bf..c9247dc4bcc 100644 --- a/gix-ref/src/store/file/transaction/commit.rs +++ b/gix-ref/src/store/file/transaction/commit.rs @@ -72,7 +72,7 @@ impl Transaction<'_, '_> { } }; if let Some((previous, new_oid)) = log_update { - let do_update = previous.as_ref().map_or(true, |previous| previous != new_oid); + let do_update = previous.as_ref() != Some(new_oid); if do_update { self.store.reflog_create_or_append( change.update.name.as_ref(), diff --git a/gix-submodule/src/lib.rs b/gix-submodule/src/lib.rs index 639af30fae3..72d4482d419 100644 --- a/gix-submodule/src/lib.rs +++ b/gix-submodule/src/lib.rs @@ -4,8 +4,6 @@ use std::{borrow::Cow, collections::BTreeMap}; -use bstr::BStr; - /// All relevant information about a git module, typically from `.gitmodules` files. /// /// Note that overrides from other configuration might be relevant, which is why this type @@ -64,7 +62,7 @@ impl File { let mut config_to_append = gix_config::File::new(config.meta_owned()); let mut prev_name = None; for ((module_name, field), values) in values { - if prev_name.map_or(true, |pn: &BStr| pn != module_name) { + if prev_name != Some(module_name) { config_to_append .new_section("submodule", Some(Cow::Owned(module_name.to_owned()))) .expect("all names come from valid configuration, so remain valid"); diff --git a/gix-validate/src/path.rs b/gix-validate/src/path.rs index 060f094d906..6cf4bb615c8 100644 --- a/gix-validate/src/path.rs +++ b/gix-validate/src/path.rs @@ -185,7 +185,7 @@ fn check_win_devices_and_illegal_characters(input: &BStr) -> Option) -> bool { - mode.map_or(false, |m| m == component::Mode::Symlink) + mode == Some(component::Mode::Symlink) } fn is_dot_hfs(input: &BStr, search_case_insensitive: &str) -> bool { diff --git a/gix/src/config/tree/sections/mod.rs b/gix/src/config/tree/sections/mod.rs index e4e8db0773f..85958d431ad 100644 --- a/gix/src/config/tree/sections/mod.rs +++ b/gix/src/config/tree/sections/mod.rs @@ -1,3 +1,4 @@ +#![allow(clippy::unnecessary_literal_bound)] #![allow(missing_docs)] /// The `author` top-level section. diff --git a/gix/src/remote/url/scheme_permission.rs b/gix/src/remote/url/scheme_permission.rs index 47fbd351b8a..936c2ddd0a7 100644 --- a/gix/src/remote/url/scheme_permission.rs +++ b/gix/src/remote/url/scheme_permission.rs @@ -63,7 +63,7 @@ impl SchemePermission { .map(|value| Protocol::ALLOW.try_into_allow(value, None)) .transpose()?; - let mut saw_user = allow.map_or(false, |allow| allow == Allow::User); + let mut saw_user = allow == Some(Allow::User); let allow_per_scheme = match config.sections_by_name_and_filter("protocol", &mut filter) { Some(it) => { let mut map = BTreeMap::default(); diff --git a/tests/tools/src/lib.rs b/tests/tools/src/lib.rs index a03ed9c5c91..e3ce748cc5c 100644 --- a/tests/tools/src/lib.rs +++ b/tests/tools/src/lib.rs @@ -652,6 +652,7 @@ fn configure_command<'a, I: IntoIterator, S: AsRef>( } fn bash_program() -> &'static Path { + // TODO: use `gix_path::env::login_shell()` when available. if cfg!(windows) { static GIT_BASH: Lazy> = Lazy::new(|| { GIT_CORE_DIR @@ -685,8 +686,7 @@ fn is_lfs_pointer_file(path: &Path) -> bool { std::fs::OpenOptions::new() .read(true) .open(path) - .and_then(|mut f| f.read_exact(&mut buf)) - .map_or(false, |_| buf.starts_with(PREFIX)) + .is_ok_and(|mut f| f.read_exact(&mut buf).is_ok_and(|_| buf.starts_with(PREFIX))) } /// The `script_identity` will be baked into the soon to be created `archive` as it identifies the script