diff --git a/Cargo.lock b/Cargo.lock index 97facfe1d36..ad717b5216f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2873,11 +2873,11 @@ dependencies = [ [[package]] name = "hashlink" -version = "0.12.0" +version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a5081f264ed7adee96ea4b4778b6bb9da0a7228b084587aa3bd3ff05da7c5a3b" +checksum = "824e001ac4f3012dd16a264bec811403a67ca9deb6c102fc5049b32c4574b35f" dependencies = [ - "hashbrown 0.17.1", + "hashbrown 0.16.1", ] [[package]] @@ -3605,9 +3605,9 @@ dependencies = [ [[package]] name = "libsqlite3-sys" -version = "0.38.1" +version = "0.37.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6c19a05435c21ac299d71b6a9c13db3e3f47c520517d58990a462a1397a61db" +checksum = "b1f111c8c41e7c61a49cd34e44c7619462967221a6443b0ec299e0ac30cfb9b1" dependencies = [ "cc", "pkg-config", @@ -4665,9 +4665,9 @@ dependencies = [ [[package]] name = "rusqlite" -version = "0.40.1" +version = "0.39.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11438310b19e3109b6446c33d1ed5e889428cf2e278407bc7896bc4aaea43323" +checksum = "a0d2b0146dd9661bf67bb107c0bb2a55064d556eeb3fc314151b957f313bcd4e" dependencies = [ "bitflags 2.13.0", "fallible-iterator", @@ -5214,9 +5214,9 @@ dependencies = [ [[package]] name = "sysinfo" -version = "0.39.5" +version = "0.38.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c8bd2130a9b60bee2581bf82cfe89ee836424d1f37dcfa4ce21509611684673" +checksum = "92ab6a2f8bfe508deb3c6406578252e491d299cbbf3bc0529ecc3313aee4a52f" dependencies = [ "libc", "memchr", diff --git a/Cargo.toml b/Cargo.toml index 5a0733d3da0..27a5a76cde2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,9 +8,8 @@ authors = ["Sebastian Thiel "] edition = "2024" license = "MIT OR Apache-2.0" version = "0.58.0" -# Rust 1.85 is required so hash-related dependencies can use Rust 2024 crates, -# notably `sha2` 0.11 and `hashbrown` 0.17. -rust-version = "1.85" +# Rust 1.88 is required by `dua-core` 3.3, used for worktree removal. +rust-version = "1.88" default-run = "gix" include = ["/src/**/*", "/build.rs", "/LICENSE-*", "/README.md"] resolver = "2" diff --git a/etc/msrv-badge.svg b/etc/msrv-badge.svg index 92cae0b9f99..1ed987e7ea5 100644 --- a/etc/msrv-badge.svg +++ b/etc/msrv-badge.svg @@ -1,5 +1,5 @@ - - rustc: 1.85.0+ + + rustc: 1.88.0+ @@ -15,7 +15,7 @@ rustc - - 1.85.0+ + + 1.88.0+ diff --git a/gitoxide-core/Cargo.toml b/gitoxide-core/Cargo.toml index f7b06fad6d0..e4329b29ff2 100644 --- a/gitoxide-core/Cargo.toml +++ b/gitoxide-core/Cargo.toml @@ -81,11 +81,13 @@ crossbeam-channel = { version = "0.5.15", optional = true } smallvec = { version = "1.15.1", optional = true } # for 'query' and 'corpus' -rusqlite = { version = "0.40.1", optional = true, features = ["bundled", "fallible_uint"] } +# Specific version needed for MSRV 1.88 +rusqlite = { version = "0.39.0", optional = true, features = ["bundled", "fallible_uint"] } # for 'corpus' parking_lot = { version = "0.12.4", optional = true } -sysinfo = { version = "0.39.2", optional = true, default-features = false, features = ["system"] } +# Specific version needed for MSRV 1.88 +sysinfo = { version = "0.38.3", optional = true, default-features = false, features = ["system"] } serde_json = { version = "1.0.150", optional = true } tracing-forest = { version = "0.2.0", features = ["serde"], optional = true } tracing-subscriber = { version = "0.3.22", optional = true } diff --git a/gitoxide-core/src/remote.rs b/gitoxide-core/src/remote.rs index 4fc9acee667..9871bc4f416 100644 --- a/gitoxide-core/src/remote.rs +++ b/gitoxide-core/src/remote.rs @@ -14,7 +14,7 @@ use gix::{ protocol::{self, handshake::Ref, transport}, refs::{ Target, - transaction::{Change, LogChange, PreviousValue, RefEdit, RefLog}, + transaction::{PreviousValue, RefEdit}, }, }; @@ -167,17 +167,10 @@ fn ref_to_edit(ref_: &Ref) -> Result { Ref::Peeled { full_ref_name, tag, .. } => (full_ref_name, Target::Object(*tag)), Ref::Direct { full_ref_name, object } => (full_ref_name, Target::Object(*object)), }; - Ok(RefEdit { - change: Change::Update { - log: LogChange { - mode: RefLog::AndReference, - force_create_reflog: false, - message: "remote refs".into(), - }, - expected: PreviousValue::Any, - new: target, - }, - name: name.as_bstr().try_into()?, - deref: false, - }) + Ok(RefEdit::update( + name.as_bstr().try_into()?, + target, + PreviousValue::Any, + "remote refs", + )) } diff --git a/gix-actor/Cargo.toml b/gix-actor/Cargo.toml index 6fa60583b16..53ed2a4b336 100644 --- a/gix-actor/Cargo.toml +++ b/gix-actor/Cargo.toml @@ -9,7 +9,7 @@ repository = "https://github.com/GitoxideLabs/gitoxide" license = "MIT OR Apache-2.0" edition = "2024" include = ["/src/**/*", "/LICENSE-*"] -rust-version = "1.85" +rust-version = "1.88" [lib] doctest = true diff --git a/gix-archive/Cargo.toml b/gix-archive/Cargo.toml index f8884271d43..e207fb50512 100644 --- a/gix-archive/Cargo.toml +++ b/gix-archive/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0" description = "archive generation from of a worktree stream" authors = ["Sebastian Thiel "] edition = "2024" -rust-version = "1.85" +rust-version = "1.88" include = ["/src/**/*", "/LICENSE-*"] [lib] diff --git a/gix-attributes/Cargo.toml b/gix-attributes/Cargo.toml index 80d97432f77..6daa20e4b0f 100644 --- a/gix-attributes/Cargo.toml +++ b/gix-attributes/Cargo.toml @@ -9,7 +9,7 @@ description = "A crate of the gitoxide project dealing .gitattributes files" authors = ["Sebastian Thiel "] edition = "2024" include = ["/src/**/*", "/LICENSE-*"] -rust-version = "1.85" +rust-version = "1.88" [lib] doctest = true diff --git a/gix-bitmap/Cargo.toml b/gix-bitmap/Cargo.toml index 7a4cfa6b753..f7029db4b67 100644 --- a/gix-bitmap/Cargo.toml +++ b/gix-bitmap/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0" description = "A crate of the gitoxide project dedicated implementing the standard git bitmap format" authors = ["Sebastian Thiel "] edition = "2024" -rust-version = "1.85" +rust-version = "1.88" include = ["/src/**/*", "/LICENSE-*"] [lib] diff --git a/gix-blame/Cargo.toml b/gix-blame/Cargo.toml index e37f4152e82..82deb566de5 100644 --- a/gix-blame/Cargo.toml +++ b/gix-blame/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0" description = "A crate of the gitoxide project dedicated to implementing a 'blame' algorithm" authors = ["Christoph Rüßler ", "Sebastian Thiel "] edition = "2024" -rust-version = "1.85" +rust-version = "1.88" include = ["/src/**/*", "/LICENSE-*"] [features] diff --git a/gix-blame/src/file/function.rs b/gix-blame/src/file/function.rs index ef6acb4c6a1..047ed5a3384 100644 --- a/gix-blame/src/file/function.rs +++ b/gix-blame/src/file/function.rs @@ -140,14 +140,14 @@ pub fn file( let commit = find_commit(cache.as_ref(), &odb, &suspect, &mut buf)?; let commit_time = commit.commit_time()?; - if let Some(since) = options.since { - if commit_time < since.seconds { - if unblamed_to_out_is_done(&mut hunks_to_blame, &mut out, suspect) { - break 'outer; - } - - continue; + if let Some(since) = options.since + && commit_time < since.seconds + { + if unblamed_to_out_is_done(&mut hunks_to_blame, &mut out, suspect) { + break 'outer; } + + continue; } let parent_ids: ParentIds = collect_parents(commit, &odb, cache.as_ref(), &mut buf2)?; @@ -371,33 +371,31 @@ pub fn file( } } - if has_blame_been_passed { - if let Some(ref mut blame_path) = blame_path { - let blame_path_entry = BlamePathEntry { - source_file_path: current_file_path.clone(), - previous_source_file_path: Some(source_location.clone()), - commit_id: suspect, - blob_id: id, - previous_blob_id: source_id, - parent_index: index, - }; - blame_path.push(blame_path_entry); - } + if has_blame_been_passed && let Some(ref mut blame_path) = blame_path { + let blame_path_entry = BlamePathEntry { + source_file_path: current_file_path.clone(), + previous_source_file_path: Some(source_location.clone()), + commit_id: suspect, + blob_id: id, + previous_blob_id: source_id, + parent_index: index, + }; + blame_path.push(blame_path_entry); } } } } hunks_to_blame.retain_mut(|unblamed_hunk| { - if unblamed_hunk.suspects.len() == 1 { - if let Some(entry) = BlameEntry::from_unblamed_hunk(unblamed_hunk, suspect) { - // At this point, we have copied blame for every hunk to a parent. Hunks - // that have only `suspect` left in `suspects` have not passed blame to any - // parent, and so they can be converted to a `BlameEntry` and moved to - // `out`. - out.push(entry); - return false; - } + if unblamed_hunk.suspects.len() == 1 + && let Some(entry) = BlameEntry::from_unblamed_hunk(unblamed_hunk, suspect) + { + // At this point, we have copied blame for every hunk to a parent. Hunks + // that have only `suspect` left in `suspects` have not passed blame to any + // parent, and so they can be converted to a `BlameEntry` and moved to + // `out`. + out.push(entry); + return false; } unblamed_hunk.remove_blame(suspect); true diff --git a/gix-chunk/Cargo.toml b/gix-chunk/Cargo.toml index 90ee05771fd..2d9e82c7e2f 100644 --- a/gix-chunk/Cargo.toml +++ b/gix-chunk/Cargo.toml @@ -10,7 +10,7 @@ documentation = "https://github.com/git/git/blob/seen/Documentation/technical/ch license = "MIT OR Apache-2.0" edition = "2024" include = ["/src/**/*", "/LICENSE-*"] -rust-version = "1.85" +rust-version = "1.88" [lib] doctest = true diff --git a/gix-command/Cargo.toml b/gix-command/Cargo.toml index e17cee77d21..a7511fb29fe 100644 --- a/gix-command/Cargo.toml +++ b/gix-command/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0" description = "A crate of the gitoxide project handling internal git command execution" authors = ["Sebastian Thiel "] edition = "2024" -rust-version = "1.85" +rust-version = "1.88" include = ["/src/*.rs", "/LICENSE-*"] [lib] diff --git a/gix-command/src/prepare.rs b/gix-command/src/prepare.rs index 4a1c38070cf..a15089d6a5e 100644 --- a/gix-command/src/prepare.rs +++ b/gix-command/src/prepare.rs @@ -219,10 +219,10 @@ impl From for Command { cmd.arg("-c"); if !prep.args.is_empty() { if !gix_path::os_str_into_bstr(&prep.command).is_ok_and(|cmd| cmd.contains_str("$@")) { - if prep.quote_command { - if let Ok(command) = gix_path::os_str_into_bstr(&prep.command) { - prep.command = gix_path::from_bstring(gix_quote::single(command)).into(); - } + if prep.quote_command + && let Ok(command) = gix_path::os_str_into_bstr(&prep.command) + { + prep.command = gix_path::from_bstring(gix_quote::single(command)).into(); } prep.command.push(r#" "$@""#); } else { diff --git a/gix-commitgraph/Cargo.toml b/gix-commitgraph/Cargo.toml index d0823017713..164f4b11eeb 100644 --- a/gix-commitgraph/Cargo.toml +++ b/gix-commitgraph/Cargo.toml @@ -10,7 +10,7 @@ description = "Read-only access to the git commitgraph file format" authors = ["Conor Davis ", "Sebastian Thiel "] edition = "2024" include = ["/src/**/*", "/LICENSE-*"] -rust-version = "1.85" +rust-version = "1.88" [lib] doctest = false diff --git a/gix-commitgraph/src/file/init.rs b/gix-commitgraph/src/file/init.rs index a2864a6d4d7..ee98d0b7ad6 100644 --- a/gix-commitgraph/src/file/init.rs +++ b/gix-commitgraph/src/file/init.rs @@ -196,8 +196,8 @@ fn read_fan(d: &[u8]) -> ([u32; FAN_LEN], usize) { assert!(d.len() >= FAN_LEN * 4); let mut fan = [0; FAN_LEN]; - for (c, f) in d.chunks_exact(4).zip(fan.iter_mut()) { - *f = u32::from_be_bytes(c.try_into().unwrap()); + for (c, f) in d.as_chunks::<4>().0.iter().zip(fan.iter_mut()) { + *f = u32::from_be_bytes(*c); } (fan, FAN_LEN * 4) } diff --git a/gix-config-value/Cargo.toml b/gix-config-value/Cargo.toml index 2a1cebbcb9f..730bc421b2e 100644 --- a/gix-config-value/Cargo.toml +++ b/gix-config-value/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0" description = "A crate of the gitoxide project providing git-config value parsing" authors = ["Sebastian Thiel "] edition = "2024" -rust-version = "1.85" +rust-version = "1.88" include = ["/src/**/*", "/LICENSE-*"] [lib] diff --git a/gix-config-value/src/color.rs b/gix-config-value/src/color.rs index e85e084e0fd..46b5b10431f 100644 --- a/gix-config-value/src/color.rs +++ b/gix-config-value/src/color.rs @@ -255,17 +255,20 @@ impl FromStr for Name { return Ok(Self::Ansi(v)); } - if let Some(s) = s.strip_prefix('#') { - if s.len() == 6 && s.is_char_boundary(2) && s.is_char_boundary(4) && s.is_char_boundary(6) { - let rgb = ( - u8::from_str_radix(&s[..2], 16), - u8::from_str_radix(&s[2..4], 16), - u8::from_str_radix(&s[4..], 16), - ); - - if let (Ok(r), Ok(g), Ok(b)) = rgb { - return Ok(Self::Rgb(r, g, b)); - } + if let Some(s) = s.strip_prefix('#') + && s.len() == 6 + && s.is_char_boundary(2) + && s.is_char_boundary(4) + && s.is_char_boundary(6) + { + let rgb = ( + u8::from_str_radix(&s[..2], 16), + u8::from_str_radix(&s[2..4], 16), + u8::from_str_radix(&s[4..], 16), + ); + + if let (Ok(r), Ok(g), Ok(b)) = rgb { + return Ok(Self::Rgb(r, g, b)); } } diff --git a/gix-config/Cargo.toml b/gix-config/Cargo.toml index 62492578f77..3a99d2aba68 100644 --- a/gix-config/Cargo.toml +++ b/gix-config/Cargo.toml @@ -11,7 +11,7 @@ edition = "2024" keywords = ["git-config", "git", "config", "gitoxide"] categories = ["config", "parser-implementations"] include = ["/src/**/*", "/LICENSE-*", "/README.md"] -rust-version = "1.85" +rust-version = "1.88" [features] ## Enable support for the SHA-1 hash by forwarding the feature to dependencies. diff --git a/gix-config/src/file/includes/mod.rs b/gix-config/src/file/includes/mod.rs index d3018939de3..88782c9e0ff 100644 --- a/gix-config/src/file/includes/mod.rs +++ b/gix-config/src/file/includes/mod.rs @@ -68,17 +68,17 @@ fn resolve_includes_recursive( let mut paths = None; if header_name == "include" && header.subsection_name.is_none() { paths = Some(gather_paths(section, id, backing)); - } else if header_name == "includeIf" { - if let Some(condition) = &header.subsection_name { - let target_config_path = section.meta.path.as_deref(); - if include_condition_match( - condition.value_in(backing), - target_config_path, - search_config.unwrap_or(target_config), - options.includes, - )? { - paths = Some(gather_paths(section, id, backing)); - } + } else if header_name == "includeIf" + && let Some(condition) = &header.subsection_name + { + let target_config_path = section.meta.path.as_deref(); + if include_condition_match( + condition.value_in(backing), + target_config_path, + search_config.unwrap_or(target_config), + options.includes, + )? { + paths = Some(gather_paths(section, id, backing)); } } if let Some(paths) = paths { diff --git a/gix-config/src/file/section/mod.rs b/gix-config/src/file/section/mod.rs index 2376ec39042..a7770c8a3d7 100644 --- a/gix-config/src/file/section/mod.rs +++ b/gix-config/src/file/section/mod.rs @@ -256,16 +256,15 @@ impl<'file> SectionRef<'file> { _ => {} } event.write_to_in(self.backing, &mut out)?; - if let Event::ValueNotDone(_) = event { - if self + if let Event::ValueNotDone(_) = event + && self .body_data() .0 .get(idx + 1) .filter(|e| matches!(e, Event::Newline(_))) .is_none() - { - out.write_all(nl)?; - } + { + out.write_all(nl)?; } } Ok(()) diff --git a/gix-config/src/parse/from_bytes/mod.rs b/gix-config/src/parse/from_bytes/mod.rs index 27eba63472e..74a1eaad3ce 100644 --- a/gix-config/src/parse/from_bytes/mod.rs +++ b/gix-config/src/parse/from_bytes/mod.rs @@ -327,12 +327,14 @@ fn value(backing: &[u8], i: &mut &[u8], dispatch: &mut dyn FnMut(Event)) -> Pars let mut value_is_empty_so_far = true; loop { - if value_is_empty_so_far && !is_in_quotes && remaining.len() == value_start.len() { - if let Ok(whitespace) = take_git_whitespace1(&mut remaining) { - dispatch(Event::Whitespace(Span::new(backing, whitespace))); - value_start = remaining; - continue; - } + if value_is_empty_so_far + && !is_in_quotes + && remaining.len() == value_start.len() + && let Ok(whitespace) = take_git_whitespace1(&mut remaining) + { + dispatch(Event::Whitespace(Span::new(backing, whitespace))); + value_start = remaining; + continue; } let Some((&byte, rest)) = remaining.split_first() else { diff --git a/gix-credentials/Cargo.toml b/gix-credentials/Cargo.toml index fab0dc8142c..b55cd79182c 100644 --- a/gix-credentials/Cargo.toml +++ b/gix-credentials/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0" description = "A crate of the gitoxide project to interact with git credentials helpers" authors = ["Sebastian Thiel "] edition = "2024" -rust-version = "1.85" +rust-version = "1.88" include = ["/src/**/*", "/LICENSE-*"] [lib] diff --git a/gix-credentials/src/helper/cascade.rs b/gix-credentials/src/helper/cascade.rs index 1157d77a248..d1f2b7bd025 100644 --- a/gix-credentials/src/helper/cascade.rs +++ b/gix-credentials/src/helper/cascade.rs @@ -160,29 +160,29 @@ impl Cascade { } } - if prompt.mode != gix_prompt::Mode::Disable { - if let Some(ctx) = action.context_mut() { - ctx.url = url; - if ctx.username.is_none() { - let message = ctx.to_prompt("Username"); - prompt.mode = gix_prompt::Mode::Visible; - ctx.username = gix_prompt::ask(&message, &prompt) - .map_err(|err| protocol::Error::Prompt { - prompt: message, - source: err, - })? - .into(); - } - if ctx.password.is_none() { - let message = ctx.to_prompt("Password"); - prompt.mode = gix_prompt::Mode::Hidden; - ctx.password = gix_prompt::ask(&message, &prompt) - .map_err(|err| protocol::Error::Prompt { - prompt: message, - source: err, - })? - .into(); - } + if prompt.mode != gix_prompt::Mode::Disable + && let Some(ctx) = action.context_mut() + { + ctx.url = url; + if ctx.username.is_none() { + let message = ctx.to_prompt("Username"); + prompt.mode = gix_prompt::Mode::Visible; + ctx.username = gix_prompt::ask(&message, &prompt) + .map_err(|err| protocol::Error::Prompt { + prompt: message, + source: err, + })? + .into(); + } + if ctx.password.is_none() { + let message = ctx.to_prompt("Password"); + prompt.mode = gix_prompt::Mode::Hidden; + ctx.password = gix_prompt::ask(&message, &prompt) + .map_err(|err| protocol::Error::Prompt { + prompt: message, + source: err, + })? + .into(); } } diff --git a/gix-date/Cargo.toml b/gix-date/Cargo.toml index 09992209de0..dd2d8e10e07 100644 --- a/gix-date/Cargo.toml +++ b/gix-date/Cargo.toml @@ -9,7 +9,7 @@ description = "A crate of the gitoxide project parsing dates the way git does" authors = ["Sebastian Thiel "] edition = "2024" include = ["/src/**/*", "/LICENSE-*"] -rust-version = "1.85" +rust-version = "1.88" [lib] doctest = true diff --git a/gix-date/src/parse/git.rs b/gix-date/src/parse/git.rs index a691b3d59c7..68d7fd58ec2 100644 --- a/gix-date/src/parse/git.rs +++ b/gix-date/src/parse/git.rs @@ -178,12 +178,12 @@ fn split_time_and_offset(input: &str) -> (&str, &str) { } // Also handle space-separated offset - if let Some(space_pos) = input.rfind(' ') { - if space_pos > 5 { - let potential_offset = input[space_pos + 1..].trim(); - if potential_offset.starts_with('+') || potential_offset.starts_with('-') || potential_offset == "Z" { - return (&input[..space_pos], potential_offset); - } + if let Some(space_pos) = input.rfind(' ') + && space_pos > 5 + { + let potential_offset = input[space_pos + 1..].trim(); + if potential_offset.starts_with('+') || potential_offset.starts_with('-') || potential_offset == "Z" { + return (&input[..space_pos], potential_offset); } } diff --git a/gix-diff/Cargo.toml b/gix-diff/Cargo.toml index 0e154093f3a..8084d285656 100644 --- a/gix-diff/Cargo.toml +++ b/gix-diff/Cargo.toml @@ -9,7 +9,7 @@ description = "Calculate differences between various git objects" authors = ["Sebastian Thiel "] edition = "2024" include = ["/src/**/*", "/LICENSE-*"] -rust-version = "1.85" +rust-version = "1.88" [features] default = ["blob", "index"] diff --git a/gix-diff/benches/line_count.rs b/gix-diff/benches/line_count.rs index efdb888c40a..837902a05fd 100644 --- a/gix-diff/benches/line_count.rs +++ b/gix-diff/benches/line_count.rs @@ -41,7 +41,7 @@ impl Iterator for BenchmarkTokenizer { self.current += 1; - if self.current % self.skip_every == 0 { + if self.current.is_multiple_of(self.skip_every) { self.current += 1; } @@ -146,12 +146,12 @@ fn push_function(buf: &mut String, idx: usize, with_extra_logging: bool) { writeln!(buf, " let mut value = {idx};").unwrap(); buf.push_str(" if value % 3 == 0 {\n"); buf.push_str(" println!(\"triple: {}\", value);\n"); - if with_extra_logging && idx % 3 == 0 { + if with_extra_logging && idx.is_multiple_of(3) { buf.push_str(" println!(\"slider: {}\", value + 1);\n"); } buf.push_str(" } else {\n"); buf.push_str(" println!(\"plain: {}\", value);\n"); - if with_extra_logging && idx % 5 == 0 { + if with_extra_logging && idx.is_multiple_of(5) { buf.push_str(" println!(\"trace: {}\", value.saturating_sub(1));\n"); } buf.push_str(" }\n"); diff --git a/gix-dir/Cargo.toml b/gix-dir/Cargo.toml index d3d324caaad..5d75af230c9 100644 --- a/gix-dir/Cargo.toml +++ b/gix-dir/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0" description = "A crate of the gitoxide project dealing with directory walks" authors = ["Sebastian Thiel "] edition = "2024" -rust-version = "1.85" +rust-version = "1.88" include = ["/src/**/*", "/LICENSE-*"] [lib] diff --git a/gix-dir/src/walk/classify.rs b/gix-dir/src/walk/classify.rs index 51c477d8d20..6bf9d0b6961 100644 --- a/gix-dir/src/walk/classify.rs +++ b/gix-dir/src/walk/classify.rs @@ -163,8 +163,8 @@ pub fn path( ctx.pathspec_attributes, ) .map(Into::into); - if for_deletion.is_some() { - if let Some(excluded) = ctx + if for_deletion.is_some() + && let Some(excluded) = ctx .excludes .as_mut() .map_or(Ok(None), |stack| { @@ -178,9 +178,8 @@ pub fn path( }) .map_err(Error::ExcludesAccess)? .filter(|_| filename_start_idx > 0) - { - out.status = entry::Status::Ignored(excluded); - } + { + out.status = entry::Status::Ignored(excluded); } out.property = entry::Property::DotGit.into(); return Ok(out); diff --git a/gix-discover/Cargo.toml b/gix-discover/Cargo.toml index 9852c2f0cfa..77ea827d23d 100644 --- a/gix-discover/Cargo.toml +++ b/gix-discover/Cargo.toml @@ -9,7 +9,7 @@ description = "Discover git repositories and check if a directory is a git repos authors = ["Sebastian Thiel "] edition = "2024" include = ["/src/**/*", "/LICENSE-*"] -rust-version = "1.85" +rust-version = "1.88" [lib] doctest = true diff --git a/gix-discover/src/upwards/types.rs b/gix-discover/src/upwards/types.rs index e5e8de8ddf4..d4754292aad 100644 --- a/gix-discover/src/upwards/types.rs +++ b/gix-discover/src/upwards/types.rs @@ -139,10 +139,8 @@ pub(crate) fn parse_ceiling_dirs(ceiling_dirs: &OsStr) -> Vec { } let mut dir = ceiling_dir; - if should_normalize { - if let Ok(normalized) = gix_path::realpath(&dir) { - dir = normalized; - } + if should_normalize && let Ok(normalized) = gix_path::realpath(&dir) { + dir = normalized; } out.push(dir); } diff --git a/gix-error/Cargo.toml b/gix-error/Cargo.toml index 028eec1f68a..a2e103157e2 100644 --- a/gix-error/Cargo.toml +++ b/gix-error/Cargo.toml @@ -9,7 +9,7 @@ description = "A crate of the gitoxide project to provide common errors and erro authors = ["Sebastian Thiel "] edition = "2024" include = ["/src/**/*", "/LICENSE-*"] -rust-version = "1.85" +rust-version = "1.88" [features] ## The [`Exn`](crate::Exn) type converts to [`anyhow::Error`] natively so `?` can be used directly. diff --git a/gix-error/src/concrete/classify.rs b/gix-error/src/concrete/classify.rs index 63aaf6d1847..688410a7309 100644 --- a/gix-error/src/concrete/classify.rs +++ b/gix-error/src/concrete/classify.rs @@ -3,6 +3,48 @@ use std::fmt::{Display, Formatter}; use crate::Message; +/// The kind of resource exhaustion which prevented an operation from completing. +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +#[non_exhaustive] +pub enum ResourceExhaustionKind { + /// An application-configured allocation limit was exceeded. + AllocationLimit, + /// An allocation size could not be represented or memory could not be reserved. + AllocationFailure, +} + +/// An error caused by exhausting a finite resource. +#[derive(Debug)] +pub struct ResourceExhaustionError { + /// The kind of resource exhaustion. + pub kind: ResourceExhaustionKind, + /// The error message. + pub message: Cow<'static, str>, +} + +impl ResourceExhaustionError { + /// Create a new instance with `kind` that displays the given `message`. + pub fn new(kind: ResourceExhaustionKind, message: impl Into>) -> Self { + ResourceExhaustionError { + kind, + message: message.into(), + } + } + + /// Return the kind of resource exhaustion. + pub fn kind(&self) -> ResourceExhaustionKind { + self.kind + } +} + +impl Display for ResourceExhaustionError { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + f.write_str(self.message.as_ref()) + } +} + +impl std::error::Error for ResourceExhaustionError {} + /// An error caused by malformed or internally inconsistent data. #[derive(Debug)] pub struct CorruptionError { diff --git a/gix-error/src/error.rs b/gix-error/src/error.rs index d666077136c..01200d194cf 100644 --- a/gix-error/src/error.rs +++ b/gix-error/src/error.rs @@ -30,10 +30,10 @@ impl<'a> DisplaySource<'a> { impl std::fmt::Display for DisplaySource<'_> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { std::fmt::Display::fmt(self.error, f)?; - if !f.alternate() { - if let Some(location) = self.location { - crate::write_location(f, location)?; - } + if !f.alternate() + && let Some(location) = self.location + { + crate::write_location(f, location)?; } Ok(()) } @@ -44,6 +44,106 @@ impl crate::Error { pub fn downcast_any_ref(&self) -> Option<&T> { self.iter_errors().find_map(|error| error.downcast_ref()) } + + /// Return all known classifications in the same logical breadth-first order as [`Self::iter_errors()`]. + /// + /// Unknown errors are omitted. Classifications aren't deduplicated because distinct errors may independently have + /// the same meaning. Each item retains the classified error for downcasting and origin inspection. + pub fn classify(&self) -> impl Iterator> + '_ { + self.iter_errors().filter_map(classify_one) + } +} + +/// The semantic class of an error. +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +#[non_exhaustive] +pub enum Class { + /// Function or method input was invalid. + Validation, + /// Stored or streamed data was malformed or internally inconsistent. + Corruption, + /// A requested resource does not exist. + NotFound, + /// Retrying the operation may succeed. + Retryable, + /// A finite resource was exhausted. + ResourceExhaustion(crate::ResourceExhaustionKind), + /// An I/O failure not normalized to another semantic class. + Io(std::io::ErrorKind), +} + +/// A semantic class together with the concrete error which established it. +#[derive(Clone, Copy, Debug)] +pub struct Classification<'a> { + class: Class, + error: &'a (dyn std::error::Error + 'static), +} + +impl<'a> Classification<'a> { + /// Return the semantic class. + pub fn class(&self) -> Class { + self.class + } + + /// Return the concrete error which established the classification. + pub fn error(&self) -> &'a (dyn std::error::Error + 'static) { + self.error + } + + /// Return the original I/O error kind, if the underlying error is an [`std::io::Error`]. + pub fn io_kind(&self) -> Option { + self.error.downcast_ref::().map(std::io::Error::kind) + } +} + +fn classify_one<'a>(error: &'a (dyn std::error::Error + 'static)) -> Option> { + let class = if error.is::() { + Class::Validation + } else if error.is::() { + Class::Corruption + } else if error.is::() { + Class::NotFound + } else if error.is::() { + Class::Retryable + } else if let Some(error) = error.downcast_ref::() { + Class::ResourceExhaustion(error.kind()) + } else if error.is::() { + Class::ResourceExhaustion(crate::ResourceExhaustionKind::AllocationFailure) + } else { + let error = error.downcast_ref::()?; + match error.kind() { + std::io::ErrorKind::NotFound => Class::NotFound, + std::io::ErrorKind::OutOfMemory => { + Class::ResourceExhaustion(crate::ResourceExhaustionKind::AllocationFailure) + } + kind => Class::Io(kind), + } + }; + Some(Classification { class, error }) +} + +fn class_can_retry(class: Class) -> bool { + matches!( + class, + Class::Retryable | Class::Io(std::io::ErrorKind::Interrupted | std::io::ErrorKind::TimedOut) + ) +} + +fn classification_can_retry_lenient(classification: Classification<'_>) -> bool { + class_can_retry(classification.class()) + || classification.io_kind().is_some_and(|kind| { + use std::io::ErrorKind::*; + matches!( + kind, + UnexpectedEof + | OutOfMemory + | BrokenPipe + | AddrInUse + | ConnectionAborted + | ConnectionReset + | ConnectionRefused + ) + }) } #[cfg(any(feature = "tree-error", not(feature = "auto-chain-error")))] @@ -109,28 +209,43 @@ mod _impl { /// Return `true` if any stored error, or an error in its [`source()`](std::error::Error::source) chain, is: /// /// * explicitly marked with [`RetryableError`](crate::RetryableError), or - /// * an [`std::io::Error`] with kind `Interrupted`, `UnexpectedEof`, `OutOfMemory`, `TimedOut`, `BrokenPipe`, - /// `AddrInUse`, `ConnectionAborted`, `ConnectionReset`, or `ConnectionRefused`. + /// * an [`std::io::Error`] with kind `Interrupted` or `TimedOut`. /// /// Nested [`Error`] values are inspected recursively. `false` only means that no known retryable error was /// found; it does not guarantee that retrying cannot succeed. pub fn can_retry(&self) -> bool { - self.iter_errors().any(super::is_retryable) + self.classify() + .any(|classification| super::class_can_retry(classification.class())) + } + + /// Return `true` if any stored error, or an error in its [`source()`](std::error::Error::source) chain, is: + /// + /// * explicitly marked with [`RetryableError`](crate::RetryableError), or + /// * an [`std::io::Error`] with kind `Interrupted`, `UnexpectedEof`, `OutOfMemory`, `TimedOut`, `BrokenPipe`, + /// `AddrInUse`, `ConnectionAborted`, `ConnectionReset`, or `ConnectionRefused`. + /// + /// This applies a more lenient policy than [`Self::can_retry`]. Nested [`Error`] values are inspected recursively. + /// `false` only means that no known retryable error was found; it does not guarantee that retrying cannot succeed. + pub fn can_retry_lenient(&self) -> bool { + self.classify().any(super::classification_can_retry_lenient) } /// Return `true` if malformed or internally inconsistent data caused the failure. pub fn is_corrupted(&self) -> bool { - self.iter_errors().any(super::is_corrupted) + self.classify() + .any(|classification| classification.class() == crate::Class::Corruption) } /// Return `true` if a requested resource was not found. pub fn is_not_found(&self) -> bool { - self.iter_errors().any(super::is_not_found) + self.classify() + .any(|classification| classification.class() == crate::Class::NotFound) } /// Return `true` if invalid input caused the failure. pub fn is_validation(&self) -> bool { - self.iter_errors().any(super::is_validation) + self.classify() + .any(|classification| classification.class() == crate::Class::Validation) } } @@ -332,28 +447,43 @@ mod _impl { /// Return `true` if any stored error, or an error in its [`source()`](std::error::Error::source) chain, is: /// /// * explicitly marked with [`RetryableError`](crate::RetryableError), or - /// * an [`std::io::Error`] with kind `Interrupted`, `UnexpectedEof`, `OutOfMemory`, `TimedOut`, `BrokenPipe`, - /// `AddrInUse`, `ConnectionAborted`, `ConnectionReset`, or `ConnectionRefused`. + /// * an [`std::io::Error`] with kind `Interrupted` or `TimedOut`. /// /// Nested [`Error`] values are inspected recursively. `false` only means that no known retryable error was /// found; it does not guarantee that retrying cannot succeed. pub fn can_retry(&self) -> bool { - self.iter_errors().any(super::is_retryable) + self.classify() + .any(|classification| super::class_can_retry(classification.class())) + } + + /// Return `true` if any stored error, or an error in its [`source()`](std::error::Error::source) chain, is: + /// + /// * explicitly marked with [`RetryableError`](crate::RetryableError), or + /// * an [`std::io::Error`] with kind `Interrupted`, `UnexpectedEof`, `OutOfMemory`, `TimedOut`, `BrokenPipe`, + /// `AddrInUse`, `ConnectionAborted`, `ConnectionReset`, or `ConnectionRefused`. + /// + /// This applies a more lenient policy than [`Self::can_retry`]. Nested [`Error`] values are inspected recursively. + /// `false` only means that no known retryable error was found; it does not guarantee that retrying cannot succeed. + pub fn can_retry_lenient(&self) -> bool { + self.classify().any(super::classification_can_retry_lenient) } /// Return `true` if malformed or internally inconsistent data caused the failure. pub fn is_corrupted(&self) -> bool { - self.iter_errors().any(super::is_corrupted) + self.classify() + .any(|classification| classification.class() == crate::Class::Corruption) } /// Return `true` if a requested resource was not found. pub fn is_not_found(&self) -> bool { - self.iter_errors().any(super::is_not_found) + self.classify() + .any(|classification| classification.class() == crate::Class::NotFound) } /// Return `true` if invalid input caused the failure. pub fn is_validation(&self) -> bool { - self.iter_errors().any(super::is_validation) + self.classify() + .any(|classification| classification.class() == crate::Class::Validation) } } @@ -405,66 +535,31 @@ mod _impl { } /// Return `true` if `err` or any error in its [`source()`](std::error::Error::source) chain is explicitly marked with -/// [`RetryableError`](crate::RetryableError), or is an [`std::io::Error`] whose kind is `Interrupted`, `UnexpectedEof`, -/// `OutOfMemory`, `TimedOut`, `BrokenPipe`, `AddrInUse`, `ConnectionAborted`, `ConnectionReset`, or `ConnectionRefused`. +/// [`RetryableError`](crate::RetryableError), or is an [`std::io::Error`] whose kind is `Interrupted` or `TimedOut`. /// /// Nested [`crate::Error`] values are inspected recursively. `false` only means that no known retryable error was found; it /// does not guarantee that retrying cannot succeed. pub fn can_retry(err: &(dyn std::error::Error + 'static)) -> bool { - is_retryable(err) -} - -fn is_retryable(err: &(dyn std::error::Error + 'static)) -> bool { error_chain(err).any(|err| { if let Some(err) = err.downcast_ref::() { return err.can_retry(); } - if err.is::() { - return true; - } - let Some(err) = err.downcast_ref::() else { - return false; - }; - use std::io::ErrorKind::*; - matches!( - err.kind(), - Interrupted - | UnexpectedEof - | OutOfMemory - | TimedOut - | BrokenPipe - | AddrInUse - | ConnectionAborted - | ConnectionReset - | ConnectionRefused - ) - }) -} - -fn is_corrupted(err: &(dyn std::error::Error + 'static)) -> bool { - error_chain(err).any(|err| { - err.downcast_ref::() - .is_some_and(crate::Error::is_corrupted) - || err.is::() - }) -} - -fn is_not_found(err: &(dyn std::error::Error + 'static)) -> bool { - error_chain(err).any(|err| { - err.downcast_ref::() - .is_some_and(crate::Error::is_not_found) - || err.is::() - || err - .downcast_ref::() - .is_some_and(|err| err.kind() == std::io::ErrorKind::NotFound) + classify_one(err).is_some_and(|classification| class_can_retry(classification.class())) }) } -fn is_validation(err: &(dyn std::error::Error + 'static)) -> bool { +/// Return `true` if `err` or any error in its [`source()`](std::error::Error::source) chain is explicitly marked with +/// [`RetryableError`](crate::RetryableError), or is an [`std::io::Error`] whose kind is `Interrupted`, `UnexpectedEof`, +/// `OutOfMemory`, `TimedOut`, `BrokenPipe`, `AddrInUse`, `ConnectionAborted`, `ConnectionReset`, or `ConnectionRefused`. +/// +/// This applies a more lenient policy than [`can_retry`]. Nested [`crate::Error`] values are inspected recursively. +/// `false` only means that no known retryable error was found; it does not guarantee that retrying cannot succeed. +pub fn can_retry_lenient(err: &(dyn std::error::Error + 'static)) -> bool { error_chain(err).any(|err| { - err.downcast_ref::() - .is_some_and(crate::Error::is_validation) - || err.is::() + if let Some(err) = err.downcast_ref::() { + return err.can_retry_lenient(); + } + classify_one(err).is_some_and(classification_can_retry_lenient) }) } diff --git a/gix-error/src/exn/impls.rs b/gix-error/src/exn/impls.rs index c0b66ff06a1..d7e0dcd2c49 100644 --- a/gix-error/src/exn/impls.rs +++ b/gix-error/src/exn/impls.rs @@ -417,10 +417,10 @@ impl<'a> ErrorNode<'a> { let error = self.error(); let location = self.location(); let mut children = Vec::new(); - if !error.is::() { - if let Some(error) = error.source() { - children.push(ErrorNode::Source { error, location }); - } + if !error.is::() + && let Some(error) = error.source() + { + children.push(ErrorNode::Source { error, location }); } if let ErrorNode::Frame(frame) = self { children.extend(frame.children.iter().map(ErrorNode::Frame)); @@ -490,10 +490,10 @@ impl Frame { let root = ErrorNode::Frame(self); let children = root.children(); - if children.iter().all(|child| child.children().is_empty()) { - if let Some(last) = children.last() { - return Some(*last); - } + if children.iter().all(|child| child.children().is_empty()) + && let Some(last) = children.last() + { + return Some(*last); } let cause = walk(root, 0).2; @@ -709,14 +709,14 @@ fn flatten_error_nodes(root: Frame) -> Vec { logical_parent, } => { let error = ErrorHandle::new(unerase(error)); - if !error.error().is::() { - if let Some(source) = error.source() { - queue.push_back(Pending::Source { - error: source, - location, - logical_parent: node_index, - }); - } + if !error.error().is::() + && let Some(source) = error.source() + { + queue.push_back(Pending::Source { + error: source, + location, + logical_parent: node_index, + }); } queue.extend(children.into_iter().map(|frame| Pending::Frame { frame, @@ -733,14 +733,14 @@ fn flatten_error_nodes(root: Frame) -> Vec { location, logical_parent, } => { - if !error.error().is::() { - if let Some(source) = error.source() { - queue.push_back(Pending::Source { - error: source, - location, - logical_parent: node_index, - }); - } + if !error.error().is::() + && let Some(source) = error.source() + { + queue.push_back(Pending::Source { + error: source, + location, + logical_parent: node_index, + }); } out.push(OwnedErrorNode { error, diff --git a/gix-error/src/lib.rs b/gix-error/src/lib.rs index c99248635b1..9d86d6515df 100644 --- a/gix-error/src/lib.rs +++ b/gix-error/src/lib.rs @@ -372,12 +372,14 @@ mod test; pub use test::{TestError, TestResult}; mod error; -pub use error::{DisplaySource, can_retry}; +pub use error::{Class, Classification, DisplaySource, can_retry, can_retry_lenient}; /// Various kinds of concrete errors that implement [`std::error::Error`]. mod concrete; pub use concrete::chain::ChainedError; -pub use concrete::classify::{CorruptionError, NotFoundError, RetryableError}; +pub use concrete::classify::{ + CorruptionError, NotFoundError, ResourceExhaustionError, ResourceExhaustionKind, RetryableError, +}; pub use concrete::message::{Message, message}; pub use concrete::validate::ValidationError; diff --git a/gix-error/tests/error/classification.rs b/gix-error/tests/error/classification.rs new file mode 100644 index 00000000000..7bd619f0e42 --- /dev/null +++ b/gix-error/tests/error/classification.rs @@ -0,0 +1,144 @@ +use gix_error::{ + Class, CorruptionError, Error, ErrorExt, ResourceExhaustionError, ResourceExhaustionKind, RetryableError, + ValidationError, can_retry, can_retry_lenient, message, +}; + +#[test] +fn classifications_preserve_order_duplicates_and_sources() { + fn allocation_failure() -> std::collections::TryReserveError { + Vec::::new() + .try_reserve(usize::MAX) + .expect_err("the maximum capacity cannot be reserved") + } + let err = Error::from( + RetryableError::new(allocation_failure()).and_raise(CorruptionError::new("corrupt input caused allocation")), + ); + let classifications = err.classify().collect::>(); + + assert_eq!( + classifications + .iter() + .map(gix_error::Classification::class) + .collect::>(), + [ + Class::Corruption, + Class::Retryable, + Class::ResourceExhaustion(ResourceExhaustionKind::AllocationFailure), + ], + "classification follows the error graph without merging independent meanings" + ); + assert!(classifications[0].error().is::()); + assert!(classifications[1].error().is::()); + assert!(classifications[2].error().is::()); + + let duplicate = Error::from( + ValidationError::new("first") + .raise() + .chain(ValidationError::new("second")), + ); + assert_eq!( + duplicate.classify().map(|item| item.class()).collect::>(), + [Class::Validation, Class::Validation], + "a classification is emitted for each matching error node" + ); +} + +#[test] +fn io_errors_are_normalized_without_losing_their_origin() { + let cases = [ + (std::io::ErrorKind::NotFound, Class::NotFound), + ( + std::io::ErrorKind::OutOfMemory, + Class::ResourceExhaustion(ResourceExhaustionKind::AllocationFailure), + ), + ( + std::io::ErrorKind::PermissionDenied, + Class::Io(std::io::ErrorKind::PermissionDenied), + ), + ]; + + for (io_kind, expected_class) in cases { + let err = Error::from_error(std::io::Error::from(io_kind)); + let classification = err.classify().next().expect("all I/O errors are classified"); + assert_eq!(classification.class(), expected_class); + assert_eq!(classification.io_kind(), Some(io_kind)); + assert!(classification.error().is::()); + } +} + +#[test] +fn allocation_limits_are_resources_only() { + let err = Error::from_error(ResourceExhaustionError::new( + ResourceExhaustionKind::AllocationLimit, + "configured allocation limit exceeded", + )); + + assert_eq!( + err.classify().map(|item| item.class()).collect::>(), + [Class::ResourceExhaustion(ResourceExhaustionKind::AllocationLimit)] + ); + assert!(!err.is_corrupted()); + assert!(!err.can_retry()); +} + +#[test] +fn global_retry_policy_is_conservative() { + for kind in [std::io::ErrorKind::Interrupted, std::io::ErrorKind::TimedOut] { + assert!( + can_retry(&std::io::Error::from(kind)), + "{kind:?} can be retried globally" + ); + } + for kind in [ + std::io::ErrorKind::OutOfMemory, + std::io::ErrorKind::ConnectionReset, + std::io::ErrorKind::UnexpectedEof, + ] { + assert!( + !can_retry(&std::io::Error::from(kind)), + "{kind:?} needs explicit retry policy" + ); + } + assert!(can_retry(&RetryableError::new(message("try again")))); +} + +#[test] +fn lenient_retry_policy_preserves_the_previous_io_kinds() { + for kind in [ + std::io::ErrorKind::Interrupted, + std::io::ErrorKind::UnexpectedEof, + std::io::ErrorKind::OutOfMemory, + std::io::ErrorKind::TimedOut, + std::io::ErrorKind::BrokenPipe, + std::io::ErrorKind::AddrInUse, + std::io::ErrorKind::ConnectionAborted, + std::io::ErrorKind::ConnectionReset, + std::io::ErrorKind::ConnectionRefused, + ] { + assert!( + can_retry_lenient(&std::io::Error::from(kind)), + "{kind:?} is retryable under the lenient policy" + ); + } + + assert!( + !Error::from_error(std::io::Error::from(std::io::ErrorKind::PermissionDenied)).can_retry_lenient(), + "the lenient policy still rejects permanent I/O errors" + ); + assert!( + Error::from_error(RetryableError::new(message("try again"))).can_retry_lenient(), + "the lenient policy includes explicitly retryable errors" + ); + let allocation_failure = Vec::::new() + .try_reserve(usize::MAX) + .expect_err("the maximum capacity cannot be reserved"); + assert!( + !Error::from_error(allocation_failure).can_retry_lenient(), + "only I/O OutOfMemory errors are covered by the historical policy" + ); +} + +#[test] +fn unknown_errors_are_omitted() { + assert_eq!(Error::from_error(message("unknown")).classify().count(), 0); +} diff --git a/gix-error/tests/error/error.rs b/gix-error/tests/error/error.rs index ad285255e21..2e1f3a6d52e 100644 --- a/gix-error/tests/error/error.rs +++ b/gix-error/tests/error/error.rs @@ -27,29 +27,29 @@ fn from_exn_error_tree() { insta::assert_compact_debug_snapshot!(&err, "compact Debug renders the complete tree with caller locations", @" topmost, at gix-error/tests/error/error.rs:25 | - └─ E6, at gix-error/tests/error/main.rs:25 + └─ E6, at gix-error/tests/error/main.rs:26 | - └─ E5, at gix-error/tests/error/main.rs:17 + └─ E5, at gix-error/tests/error/main.rs:18 | | - | └─ E3, at gix-error/tests/error/main.rs:9 + | └─ E3, at gix-error/tests/error/main.rs:10 | | | - | | └─ E1, at gix-error/tests/error/main.rs:8 + | | └─ E1, at gix-error/tests/error/main.rs:9 | | - | └─ E10, at gix-error/tests/error/main.rs:12 + | └─ E10, at gix-error/tests/error/main.rs:13 | | | - | | └─ E9, at gix-error/tests/error/main.rs:11 + | | └─ E9, at gix-error/tests/error/main.rs:12 | | - | └─ E12, at gix-error/tests/error/main.rs:15 + | └─ E12, at gix-error/tests/error/main.rs:16 | | - | └─ E11, at gix-error/tests/error/main.rs:14 + | └─ E11, at gix-error/tests/error/main.rs:15 | - └─ E4, at gix-error/tests/error/main.rs:20 + └─ E4, at gix-error/tests/error/main.rs:21 | | - | └─ E2, at gix-error/tests/error/main.rs:19 + | └─ E2, at gix-error/tests/error/main.rs:20 | - └─ E8, at gix-error/tests/error/main.rs:23 + └─ E8, at gix-error/tests/error/main.rs:24 | - └─ E7, at gix-error/tests/error/main.rs:22 + └─ E7, at gix-error/tests/error/main.rs:23 "); insta::assert_debug_snapshot!(err, "pretty Debug renders the complete tree without caller locations", @r" topmost @@ -104,18 +104,18 @@ fn from_exn_error_tree() { @r#" [ "topmost, at gix-error/tests/error/error.rs:25", - "E6, at gix-error/tests/error/main.rs:25", - "E5, at gix-error/tests/error/main.rs:17", - "E4, at gix-error/tests/error/main.rs:20", - "E8, at gix-error/tests/error/main.rs:23", - "E3, at gix-error/tests/error/main.rs:9", - "E10, at gix-error/tests/error/main.rs:12", - "E12, at gix-error/tests/error/main.rs:15", - "E2, at gix-error/tests/error/main.rs:19", - "E7, at gix-error/tests/error/main.rs:22", - "E1, at gix-error/tests/error/main.rs:8", - "E9, at gix-error/tests/error/main.rs:11", - "E11, at gix-error/tests/error/main.rs:14", + "E6, at gix-error/tests/error/main.rs:26", + "E5, at gix-error/tests/error/main.rs:18", + "E4, at gix-error/tests/error/main.rs:21", + "E8, at gix-error/tests/error/main.rs:24", + "E3, at gix-error/tests/error/main.rs:10", + "E10, at gix-error/tests/error/main.rs:13", + "E12, at gix-error/tests/error/main.rs:16", + "E2, at gix-error/tests/error/main.rs:20", + "E7, at gix-error/tests/error/main.rs:23", + "E1, at gix-error/tests/error/main.rs:9", + "E9, at gix-error/tests/error/main.rs:12", + "E11, at gix-error/tests/error/main.rs:15", ] "# ); diff --git a/gix-error/tests/error/exn.rs b/gix-error/tests/error/exn.rs index 2f4ac0a7652..775a695895b 100644 --- a/gix-error/tests/error/exn.rs +++ b/gix-error/tests/error/exn.rs @@ -359,29 +359,29 @@ fn error_tree() { └─ E7 "); insta::assert_compact_debug_snapshot!(&err, "tree errors retain caller locations", @" - E6, at gix-error/tests/error/main.rs:25 + E6, at gix-error/tests/error/main.rs:26 | - └─ E5, at gix-error/tests/error/main.rs:17 + └─ E5, at gix-error/tests/error/main.rs:18 | | - | └─ E3, at gix-error/tests/error/main.rs:9 + | └─ E3, at gix-error/tests/error/main.rs:10 | | | - | | └─ E1, at gix-error/tests/error/main.rs:8 + | | └─ E1, at gix-error/tests/error/main.rs:9 | | - | └─ E10, at gix-error/tests/error/main.rs:12 + | └─ E10, at gix-error/tests/error/main.rs:13 | | | - | | └─ E9, at gix-error/tests/error/main.rs:11 + | | └─ E9, at gix-error/tests/error/main.rs:12 | | - | └─ E12, at gix-error/tests/error/main.rs:15 + | └─ E12, at gix-error/tests/error/main.rs:16 | | - | └─ E11, at gix-error/tests/error/main.rs:14 + | └─ E11, at gix-error/tests/error/main.rs:15 | - └─ E4, at gix-error/tests/error/main.rs:20 + └─ E4, at gix-error/tests/error/main.rs:21 | | - | └─ E2, at gix-error/tests/error/main.rs:19 + | └─ E2, at gix-error/tests/error/main.rs:20 | - └─ E8, at gix-error/tests/error/main.rs:23 + └─ E8, at gix-error/tests/error/main.rs:24 | - └─ E7, at gix-error/tests/error/main.rs:22 + └─ E7, at gix-error/tests/error/main.rs:23 "); insta::assert_debug_snapshot!(err.frame().iter_frames().map(ToString::to_string).collect::>(), "frame iteration is breadth-first", @r#" [ diff --git a/gix-error/tests/error/main.rs b/gix-error/tests/error/main.rs index 365dba1b2b2..7b824b6c3f3 100644 --- a/gix-error/tests/error/main.rs +++ b/gix-error/tests/error/main.rs @@ -1,3 +1,4 @@ +mod classification; mod error; mod exn; diff --git a/gix-features/Cargo.toml b/gix-features/Cargo.toml index e5db6f06876..2c19c23fd50 100644 --- a/gix-features/Cargo.toml +++ b/gix-features/Cargo.toml @@ -8,7 +8,7 @@ version = "0.49.1" authors = ["Sebastian Thiel "] license = "MIT OR Apache-2.0" edition = "2024" -rust-version = "1.85" +rust-version = "1.88" include = ["/src/**/*", "/LICENSE-*"] [lib] diff --git a/gix-fetchhead/Cargo.toml b/gix-fetchhead/Cargo.toml index 2ced4d57b25..4302c17a69e 100644 --- a/gix-fetchhead/Cargo.toml +++ b/gix-fetchhead/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0" description = "A crate of the gitoxide project to read and write .git/FETCH_HEAD" authors = ["Sebastian Thiel "] edition = "2024" -rust-version = "1.85" +rust-version = "1.88" include = ["/src/**/*", "/LICENSE-*"] [lib] diff --git a/gix-filter/Cargo.toml b/gix-filter/Cargo.toml index 123e1ee2e70..d0c0816020d 100644 --- a/gix-filter/Cargo.toml +++ b/gix-filter/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0" description = "A crate of the gitoxide project implementing git filters" authors = ["Sebastian Thiel "] edition = "2024" -rust-version = "1.85" +rust-version = "1.88" include = [ "/src/**/*", "/LICENSE-*", diff --git a/gix-filter/src/pipeline/convert.rs b/gix-filter/src/pipeline/convert.rs index 759fa61133b..608aa91b350 100644 --- a/gix-filter/src/pipeline/convert.rs +++ b/gix-filter/src/pipeline/convert.rs @@ -128,23 +128,23 @@ impl Pipeline { }, )?; - if let Some(driver) = driver { - if let Some(mut read) = self.processes.apply( + if let Some(driver) = driver + && let Some(mut read) = self.processes.apply( driver, &mut src, driver::Operation::Clean, self.context.with_path(bstr_rela_path.as_ref()), - )? { - if !apply_ident_filter && encoding.is_none() && !would_convert_eol { - // Note that this is not typically a benefit in terms of saving memory as most filters - // aren't expected to make the output file larger. It's more about who is waiting for the filter's - // output to arrive, which won't be us now. For `git-lfs` it definitely won't matter though. - return Ok(ToGitOutcome::Process(read)); - } - self.bufs.clear(); - read.read_to_end(&mut self.bufs.src)?; - in_src_buffer = true; + )? + { + if !apply_ident_filter && encoding.is_none() && !would_convert_eol { + // Note that this is not typically a benefit in terms of saving memory as most filters + // aren't expected to make the output file larger. It's more about who is waiting for the filter's + // output to arrive, which won't be us now. For `git-lfs` it definitely won't matter though. + return Ok(ToGitOutcome::Process(read)); } + self.bufs.clear(); + read.read_to_end(&mut self.bufs.src)?; + in_src_buffer = true; } if !in_src_buffer && (apply_ident_filter || encoding.is_some() || would_convert_eol) { self.bufs.clear(); diff --git a/gix-fs/Cargo.toml b/gix-fs/Cargo.toml index a4883d75e36..b1d80b42516 100644 --- a/gix-fs/Cargo.toml +++ b/gix-fs/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0" description = "A crate providing file system specific utilities to `gitoxide`" authors = ["Sebastian Thiel "] edition = "2024" -rust-version = "1.85" +rust-version = "1.88" include = ["/src/**/*", "/LICENSE-*"] [lib] diff --git a/gix-fs/src/stack.rs b/gix-fs/src/stack.rs index 771a5e83dd2..47b266129e3 100644 --- a/gix-fs/src/stack.rs +++ b/gix-fs/src/stack.rs @@ -218,14 +218,14 @@ impl Stack { self.current_is_directory = parent_is_directory; return Err(err); } - if self.current_is_directory { - if let Err(err) = delegate.push_directory(self) { - self.current.pop(); - self.current_relative.pop(); - self.valid_components -= 1; - self.current_is_directory = parent_is_directory; - return Err(err); - } + if self.current_is_directory + && let Err(err) = delegate.push_directory(self) + { + self.current.pop(); + self.current_relative.pop(); + self.valid_components -= 1; + self.current_is_directory = parent_is_directory; + return Err(err); } } Ok(()) diff --git a/gix-fsck/Cargo.toml b/gix-fsck/Cargo.toml index 721c2323af3..f3e00274026 100644 --- a/gix-fsck/Cargo.toml +++ b/gix-fsck/Cargo.toml @@ -9,7 +9,7 @@ license = "MIT OR Apache-2.0" description = "Verifies the connectivity and validity of objects in the database" edition = "2024" include = ["/src/**/*", "/LICENSE-*"] -rust-version = "1.85" +rust-version = "1.88" [lib] doctest = false diff --git a/gix-glob/Cargo.toml b/gix-glob/Cargo.toml index 29cc5452fef..1c0c0f94939 100644 --- a/gix-glob/Cargo.toml +++ b/gix-glob/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0" description = "A crate of the gitoxide project dealing with pattern matching" authors = ["Sebastian Thiel "] edition = "2024" -rust-version = "1.85" +rust-version = "1.88" include = ["/src/**/*", "/LICENSE-*"] [lib] diff --git a/gix-hash/Cargo.toml b/gix-hash/Cargo.toml index 5774c6c0aa6..85c9eef98a7 100644 --- a/gix-hash/Cargo.toml +++ b/gix-hash/Cargo.toml @@ -9,7 +9,7 @@ repository = "https://github.com/GitoxideLabs/gitoxide" license = "MIT OR Apache-2.0" edition = "2024" include = ["/src/**/*", "/LICENSE-*"] -rust-version = "1.85" +rust-version = "1.88" [lib] doctest = true diff --git a/gix-hash/src/change_id.rs b/gix-hash/src/change_id.rs index 4a3084e5b86..4a0db086f81 100644 --- a/gix-hash/src/change_id.rs +++ b/gix-hash/src/change_id.rs @@ -131,7 +131,7 @@ pub(crate) fn reverse_hex_to_hex(reverse_hex: &[u8], hex: &mut [u8]) -> Result<( } fn encode_reverse_hex<'a>(id: &oid, buf: &'a mut [u8]) -> &'a str { - for (byte, pair) in id.as_bytes().iter().zip(buf.chunks_exact_mut(2)) { + for (byte, pair) in id.as_bytes().iter().zip(buf.as_chunks_mut::<2>().0) { pair[0] = REVERSE_HEX[usize::from(byte >> 4)]; pair[1] = REVERSE_HEX[usize::from(byte & 0x0f)]; } diff --git a/gix-hash/src/prefix.rs b/gix-hash/src/prefix.rs index ff75599150b..d5f06f18c55 100644 --- a/gix-hash/src/prefix.rs +++ b/gix-hash/src/prefix.rs @@ -144,7 +144,7 @@ impl Prefix { let kind = crate::Kind::from_hex_len(hex_len).expect("hex-len is already checked"); let mut bytes = ObjectId::null(kind); let dst = &mut bytes.as_mut_slice()[..hex_len.div_ceil(2)]; - let decode_result = if hex_len % 2 == 0 { + let decode_result = if hex_len.is_multiple_of(2) { faster_hex::hex_decode(value.as_bytes(), dst) } else { let mut hex = crate::Kind::hex_buf(); diff --git a/gix-hashtable/Cargo.toml b/gix-hashtable/Cargo.toml index 351e412fe15..5c03f9cb6fb 100644 --- a/gix-hashtable/Cargo.toml +++ b/gix-hashtable/Cargo.toml @@ -9,7 +9,7 @@ description = "A crate that provides hashtable based data structures optimized t authors = ["Pascal Kuthe "] edition = "2024" include = ["/src/**/*", "/LICENSE-*"] -rust-version = "1.85" +rust-version = "1.88" [lib] doctest = true diff --git a/gix-ignore/Cargo.toml b/gix-ignore/Cargo.toml index e40b5f81f08..20e77eca8be 100644 --- a/gix-ignore/Cargo.toml +++ b/gix-ignore/Cargo.toml @@ -9,7 +9,7 @@ description = "A crate of the gitoxide project dealing .gitignore files" authors = ["Sebastian Thiel "] edition = "2024" include = ["/src/**/*", "/LICENSE-*"] -rust-version = "1.85" +rust-version = "1.88" [lib] doctest = true diff --git a/gix-imara-diff/Cargo.toml b/gix-imara-diff/Cargo.toml index 588673ba231..57cccd8a4bb 100644 --- a/gix-imara-diff/Cargo.toml +++ b/gix-imara-diff/Cargo.toml @@ -6,7 +6,7 @@ name = "gix-imara-diff" version = "0.2.5" edition = "2024" authors = ["pascalkuthe ", "Sebastian Thiel "] -rust-version = "1.85" +rust-version = "1.88" license = "Apache-2.0" description = "A high performance library for computing diffs, maintained as a modified copy of upstream imara-diff for gitoxide." diff --git a/gix-index/Cargo.toml b/gix-index/Cargo.toml index 36af2737b67..459a26150de 100644 --- a/gix-index/Cargo.toml +++ b/gix-index/Cargo.toml @@ -9,7 +9,7 @@ description = "A work-in-progress crate of the gitoxide project dedicated implem authors = ["Sebastian Thiel "] edition = "2024" include = ["/src/**/*", "/LICENSE-*", "/README.md"] -rust-version = "1.85" +rust-version = "1.88" [lib] diff --git a/gix-index/src/access/mod.rs b/gix-index/src/access/mod.rs index 8f655fb63a7..cc5b6db566e 100644 --- a/gix-index/src/access/mod.rs +++ b/gix-index/src/access/mod.rs @@ -411,12 +411,12 @@ impl State { .walk_entry_stages(low_entry.path(self), low, Ordering::Less) .unwrap_or(low); } - if let Some(high_entry) = self.entries.get(high) { - if high_entry.stage_raw() != 0 { - high = self - .walk_entry_stages(high_entry.path(self), high, Ordering::Less) - .unwrap_or(high); - } + if let Some(high_entry) = self.entries.get(high) + && high_entry.stage_raw() != 0 + { + high = self + .walk_entry_stages(high_entry.path(self), high, Ordering::Less) + .unwrap_or(high); } (low != high).then_some(low..high) } diff --git a/gix-index/src/extension/tree/verify.rs b/gix-index/src/extension/tree/verify.rs index cff91e2e17c..5ae094a5c75 100644 --- a/gix-index/src/extension/tree/verify.rs +++ b/gix-index/src/extension/tree/verify.rs @@ -69,14 +69,14 @@ impl Tree { entries = entries .checked_add(child.num_entries.unwrap_or(0)) .ok_or(Error::EntriesCountOverflow)?; - if let Some(prev) = prev { - if prev.name.cmp(&child.name) != Ordering::Less { - return Err(Error::OutOfOrder { - parent_id, - previous_path: prev.name.as_bstr().into(), - current_path: child.name.as_bstr().into(), - }); - } + if let Some(prev) = prev + && prev.name.cmp(&child.name) != Ordering::Less + { + return Err(Error::OutOfOrder { + parent_id, + previous_path: prev.name.as_bstr().into(), + current_path: child.name.as_bstr().into(), + }); } prev = Some(child); } @@ -106,13 +106,13 @@ impl Tree { // This is actually needed here as it's a mut ref, which isn't copy. We do a re-borrow here. let actual_num_entries = verify_recursive(child.id, &child.children, object_buf.as_deref_mut(), objects)?; - if let Some((actual, num_entries)) = actual_num_entries.zip(child.num_entries) { - if actual > num_entries { - return Err(Error::EntriesCount { - actual, - expected: num_entries, - }); - } + if let Some((actual, num_entries)) = actual_num_entries.zip(child.num_entries) + && actual > num_entries + { + return Err(Error::EntriesCount { + actual, + expected: num_entries, + }); } } Ok(entries.into()) @@ -127,13 +127,13 @@ impl Tree { let mut buf = Vec::new(); let declared_entries = verify_recursive(self.id, &self.children, use_objects.then_some(&mut buf), &objects)?; - if let Some((actual, num_entries)) = declared_entries.zip(self.num_entries) { - if actual > num_entries { - return Err(Error::EntriesCount { - actual, - expected: num_entries, - }); - } + if let Some((actual, num_entries)) = declared_entries.zip(self.num_entries) + && actual > num_entries + { + return Err(Error::EntriesCount { + actual, + expected: num_entries, + }); } Ok(()) @@ -144,14 +144,14 @@ impl Tree { /// This is a cheap heuristic: it doesn't prove each cached subtree count matches its actual path range, /// but no TREE node can describe more entries than the entire index contains. pub(crate) fn verify_entries_count(&self, num_index_entries: usize) -> Result<(), Error> { - if let Some(actual) = self.num_entries { - if actual as usize > num_index_entries { - return Err(Error::EntriesCountExceedsIndex { - name: self.name.as_bstr().into(), - actual, - expected: num_index_entries, - }); - } + if let Some(actual) = self.num_entries + && actual as usize > num_index_entries + { + return Err(Error::EntriesCountExceedsIndex { + name: self.name.as_bstr().into(), + actual, + expected: num_index_entries, + }); } for child in &self.children { diff --git a/gix-index/src/init.rs b/gix-index/src/init.rs index b1d6519cd18..ad52a892aac 100644 --- a/gix-index/src/init.rs +++ b/gix-index/src/init.rs @@ -142,10 +142,10 @@ pub mod from_tree { self.path.push(b'/'); } self.path.push_str(name); - if self.invalid_path.is_none() { - if let Err(err) = gix_validate::path::component(name, None, self.validate) { - self.invalid_path = Some((self.path.clone(), err)); - } + if self.invalid_path.is_none() + && let Err(err) = gix_validate::path::component(name, None, self.validate) + { + self.invalid_path = Some((self.path.clone(), err)); } } diff --git a/gix-index/src/verify.rs b/gix-index/src/verify.rs index 84f52a0f91d..03be4cbe08c 100644 --- a/gix-index/src/verify.rs +++ b/gix-index/src/verify.rs @@ -42,16 +42,16 @@ impl State { let _span = gix_features::trace::coarse!("gix_index::File::verify_entries()"); let mut previous = None::<&crate::Entry>; for (idx, entry) in self.entries.iter().enumerate() { - if let Some(prev) = previous { - if prev.cmp(entry, self) != Ordering::Less { - return Err(entries::Error::OutOfOrder { - current_index: idx, - current_path: entry.path(self).into(), - current_stage: entry.flags.stage() as u8, - previous_path: prev.path(self).into(), - previous_stage: prev.flags.stage() as u8, - }); - } + if let Some(prev) = previous + && prev.cmp(entry, self) != Ordering::Less + { + return Err(entries::Error::OutOfOrder { + current_index: idx, + current_path: entry.path(self).into(), + current_stage: entry.flags.stage() as u8, + previous_path: prev.path(self).into(), + previous_stage: prev.flags.stage() as u8, + }); } previous = Some(entry); } diff --git a/gix-lfs/Cargo.toml b/gix-lfs/Cargo.toml index 3101e6fab99..2df481702bd 100644 --- a/gix-lfs/Cargo.toml +++ b/gix-lfs/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0" description = "A crate of the gitoxide project dealing with handling git large file support" authors = ["Sebastian Thiel "] edition = "2024" -rust-version = "1.85" +rust-version = "1.88" include = ["/src/**/*", "/LICENSE-*"] [lib] diff --git a/gix-lock/Cargo.toml b/gix-lock/Cargo.toml index eb42581771f..4c860c0e4fb 100644 --- a/gix-lock/Cargo.toml +++ b/gix-lock/Cargo.toml @@ -9,7 +9,7 @@ description = "A git-style lock-file implementation" authors = ["Sebastian Thiel "] edition = "2024" include = ["/src/**/*", "/LICENSE-*", "/README.md"] -rust-version = "1.85" +rust-version = "1.88" [lib] doctest = true diff --git a/gix-macros/Cargo.toml b/gix-macros/Cargo.toml index b9bd7f70df8..c931adeb1e7 100644 --- a/gix-macros/Cargo.toml +++ b/gix-macros/Cargo.toml @@ -13,7 +13,7 @@ authors = [ repository = "https://github.com/GitoxideLabs/gitoxide" license = "MIT OR Apache-2.0" include = ["/src/**/*", "/LICENSE-*"] -rust-version = "1.85" +rust-version = "1.88" [lib] proc-macro = true diff --git a/gix-macros/src/momo.rs b/gix-macros/src/momo.rs index c16841faf8a..307ee25fb0b 100644 --- a/gix-macros/src/momo.rs +++ b/gix-macros/src/momo.rs @@ -125,19 +125,17 @@ fn parse_bounds(bounds: &Punctuated) -> Option) -> Option HashMap { let mut ty_conversions = HashMap::new(); for gp in decl.generics.params.iter() { - if let GenericParam::Type(tp) = gp { - if let Some(conversion) = parse_bounds(&tp.bounds) { - ty_conversions.insert(tp.ident.clone(), conversion); - } + if let GenericParam::Type(tp) = gp + && let Some(conversion) = parse_bounds(&tp.bounds) + { + ty_conversions.insert(tp.ident.clone(), conversion); } } if let Some(ref wc) = decl.generics.where_clause { for wp in wc.predicates.iter() { - if let WherePredicate::Type(pt) = wp { - if let Some(ident) = parse_bounded_type(&pt.bounded_ty) { - if let Some(conversion) = parse_bounds(&pt.bounds) { - ty_conversions.insert(ident, conversion); - } - } + if let WherePredicate::Type(pt) = wp + && let Some(ident) = parse_bounded_type(&pt.bounded_ty) + && let Some(conversion) = parse_bounds(&pt.bounds) + { + ty_conversions.insert(ident, conversion); } } } diff --git a/gix-mailmap/Cargo.toml b/gix-mailmap/Cargo.toml index 9e7206fcad2..06cd2ec74c5 100644 --- a/gix-mailmap/Cargo.toml +++ b/gix-mailmap/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0" description = "A crate of the gitoxide project for parsing mailmap files" authors = ["Sebastian Thiel "] edition = "2024" -rust-version = "1.85" +rust-version = "1.88" include = ["/src/**/*", "/LICENSE-*"] [lib] diff --git a/gix-merge/Cargo.toml b/gix-merge/Cargo.toml index 55a87299d4e..a8446a22009 100644 --- a/gix-merge/Cargo.toml +++ b/gix-merge/Cargo.toml @@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0" description = "A crate of the gitoxide project implementing merge algorithms" authors = ["Sebastian Thiel "] edition = "2024" -rust-version = "1.85" +rust-version = "1.88" include = ["/src/**/*", "/LICENSE-*"] [lints] diff --git a/gix-merge/src/blob/platform/prepare_merge.rs b/gix-merge/src/blob/platform/prepare_merge.rs index 78681df1794..9742b425ca5 100644 --- a/gix-merge/src/blob/platform/prepare_merge.rs +++ b/gix-merge/src/blob/platform/prepare_merge.rs @@ -68,15 +68,14 @@ impl Platform { self.find_driver_by_name(name) } }; - if let attributes::StateRef::Value(value) = marker_size_attr.assignment.state { - if let Some(value) = u8::from_str(value.as_bstr().to_str_lossy().as_ref()) + if let attributes::StateRef::Value(value) = marker_size_attr.assignment.state + && let Some(value) = u8::from_str(value.as_bstr().to_str_lossy().as_ref()) .ok() .and_then(NonZeroU8::new) - { - match &mut options.text.conflict { - Conflict::Keep { marker_size, .. } => *marker_size = value, - Conflict::ResolveWithOurs | Conflict::ResolveWithTheirs | Conflict::ResolveWithUnion => {} - } + { + match &mut options.text.conflict { + Conflict::Keep { marker_size, .. } => *marker_size = value, + Conflict::ResolveWithOurs | Conflict::ResolveWithTheirs | Conflict::ResolveWithUnion => {} } } if let Some(recursive_driver_name) = match driver { diff --git a/gix-merge/src/tree/function/resolve.rs b/gix-merge/src/tree/function/resolve.rs index 8e3f2058399..cd691d6c22d 100644 --- a/gix-merge/src/tree/function/resolve.rs +++ b/gix-merge/src/tree/function/resolve.rs @@ -133,15 +133,15 @@ where let mut conflicts = Vec::new(); let mut failed_on_first_conflict = false; let mut should_fail_on_conflict = |mut conflict: Conflict| -> bool { - if resolve_tree_conflicts.is_some() { - if let Err(failure) = conflict.resolution { - conflict.resolution = Ok(Resolution::Forced(failure)); - } + if resolve_tree_conflicts.is_some() + && let Err(failure) = conflict.resolution + { + conflict.resolution = Ok(Resolution::Forced(failure)); } - if let Some(how) = options.fail_on_conflict { - if conflict.resolution.is_err() || conflict.is_unresolved(how) { - failed_on_first_conflict = true; - } + if let Some(how) = options.fail_on_conflict + && (conflict.resolution.is_err() || conflict.is_unresolved(how)) + { + failed_on_first_conflict = true; } conflicts.push(conflict); failed_on_first_conflict @@ -1662,8 +1662,8 @@ where } }; - if let Some(resolution) = resolution { - if should_fail_on_conflict(Conflict::with_resolution( + if let Some(resolution) = resolution + && should_fail_on_conflict(Conflict::with_resolution( Resolution::OursModifiedTheirsModifiedThenBlobContentMerge { merged_blob: ContentMerge { resolution, @@ -1688,9 +1688,9 @@ where ConflictIndexEntryPathHint::RenamedOrTheirs, ), ], - )) { - break 'outer; - } + )) + { + break 'outer; } if let Some(addition) = our_addition { push_deferred((addition, Some(theirs_idx)), our_changes); @@ -1884,8 +1884,8 @@ where editor.remove(toc(source_location))?; pick_mut(side, our_tree, their_tree).remove_change(source_location.as_bstr()); - if let Some(resolution) = resolution { - if should_fail_on_conflict(Conflict::with_resolution( + if let Some(resolution) = resolution + && should_fail_on_conflict(Conflict::with_resolution( Resolution::OursModifiedTheirsModifiedThenBlobContentMerge { merged_blob: ContentMerge { resolution, @@ -1894,9 +1894,9 @@ where }, (ours, theirs, Original, outer_side), [None, index_entry(our_mode, our_id), index_entry(their_mode, their_id)], - )) { - break 'outer; - } + )) + { + break 'outer; } // Because this constellation can only be found by the lookup tree, there is diff --git a/gix-negotiate/Cargo.toml b/gix-negotiate/Cargo.toml index 0b77078ec5d..baaf5c641bc 100644 --- a/gix-negotiate/Cargo.toml +++ b/gix-negotiate/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0" description = "A crate of the gitoxide project implementing negotiation algorithms" authors = ["Sebastian Thiel "] edition = "2024" -rust-version = "1.85" +rust-version = "1.88" include = ["/src/**/*", "/LICENSE-*"] [lib] diff --git a/gix-negotiate/src/consecutive.rs b/gix-negotiate/src/consecutive.rs index adf157206f2..5fa4b15fae9 100644 --- a/gix-negotiate/src/consecutive.rs +++ b/gix-negotiate/src/consecutive.rs @@ -63,22 +63,22 @@ impl Algorithm { .is_none_or(|commit| !commit.data.flags.contains(Flags::SEEN)) { self.add_to_queue(id, Flags::SEEN, graph)?; - } else if matches!(ancestors, Ancestors::AllUnseen) || generation < 2 { - if let Some(commit) = graph.get_or_insert_commit(id, |_| {})? { - for parent_id in commit.parents.clone() { - let mut prev_flags = Flags::default(); - if let Some(parent) = graph - .get_or_insert_commit(parent_id, |data| { - prev_flags = data.flags; - data.flags |= Flags::COMMON; - })? - .filter(|_| !prev_flags.contains(Flags::COMMON)) - { - if prev_flags.contains(Flags::SEEN) && !prev_flags.contains(Flags::POPPED) { - self.non_common_revs -= 1; - } - queue.insert(parent.commit_time, (parent_id, generation + 1)); + } else if (matches!(ancestors, Ancestors::AllUnseen) || generation < 2) + && let Some(commit) = graph.get_or_insert_commit(id, |_| {})? + { + for parent_id in commit.parents.clone() { + let mut prev_flags = Flags::default(); + if let Some(parent) = graph + .get_or_insert_commit(parent_id, |data| { + prev_flags = data.flags; + data.flags |= Flags::COMMON; + })? + .filter(|_| !prev_flags.contains(Flags::COMMON)) + { + if prev_flags.contains(Flags::SEEN) && !prev_flags.contains(Flags::POPPED) { + self.non_common_revs -= 1; } + queue.insert(parent.commit_time, (parent_id, generation + 1)); } } } @@ -127,15 +127,14 @@ impl Negotiator for Algorithm { if graph .get(&parent_id) .is_none_or(|commit| !commit.data.flags.contains(Flags::SEEN)) + && let Err(err) = self.add_to_queue(parent_id, mark, graph) { - if let Err(err) = self.add_to_queue(parent_id, mark, graph) { - return Some(Err(err)); - } + return Some(Err(err)); } - if mark.contains(Flags::COMMON) { - if let Err(err) = self.mark_common(parent_id, Mark::AncestorsOnly, Ancestors::AllUnseen, graph) { - return Some(Err(err)); - } + if mark.contains(Flags::COMMON) + && let Err(err) = self.mark_common(parent_id, Mark::AncestorsOnly, Ancestors::AllUnseen, graph) + { + return Some(Err(err)); } } diff --git a/gix-note/Cargo.toml b/gix-note/Cargo.toml index 3065d5ba524..79f525abd9d 100644 --- a/gix-note/Cargo.toml +++ b/gix-note/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0" description = "A crate of the gitoxide project dealing with git notes" authors = ["Sebastian Thiel "] edition = "2024" -rust-version = "1.85" +rust-version = "1.88" include = ["/src/**/*", "/LICENSE-*"] [lib] diff --git a/gix-object/Cargo.toml b/gix-object/Cargo.toml index c116b78b162..df36a5e35d4 100644 --- a/gix-object/Cargo.toml +++ b/gix-object/Cargo.toml @@ -9,7 +9,7 @@ repository = "https://github.com/GitoxideLabs/gitoxide" license = "MIT OR Apache-2.0" edition = "2024" include = ["/src/**/*", "/LICENSE-*"] -rust-version = "1.85" +rust-version = "1.88" [lib] doctest = true diff --git a/gix-object/src/commit/message/decode.rs b/gix-object/src/commit/message/decode.rs index 3ef600a6112..dee5f24f948 100644 --- a/gix-object/src/commit/message/decode.rs +++ b/gix-object/src/commit/message/decode.rs @@ -4,11 +4,11 @@ use crate::bstr::{BStr, ByteSlice}; pub fn message_title_and_body(input: &[u8]) -> (&BStr, Option<&BStr>) { let mut pos = 0; while pos < input.len() { - if let Some(first_len) = newline_len(&input[pos..]) { - if let Some(second_len) = newline_len(&input[pos + first_len..]) { - let body = &input[pos + first_len + second_len..]; - return (input[..pos].as_bstr(), (!body.is_empty()).then(|| body.as_bstr())); - } + if let Some(first_len) = newline_len(&input[pos..]) + && let Some(second_len) = newline_len(&input[pos + first_len..]) + { + let body = &input[pos + first_len + second_len..]; + return (input[..pos].as_bstr(), (!body.is_empty()).then(|| body.as_bstr())); } pos += 1; } diff --git a/gix-object/src/commit/message/mod.rs b/gix-object/src/commit/message/mod.rs index e6dee6daece..df0c6ce049a 100644 --- a/gix-object/src/commit/message/mod.rs +++ b/gix-object/src/commit/message/mod.rs @@ -96,12 +96,12 @@ pub(crate) fn summary(message: &BStr) -> Cow<'_, BStr> { let mut out = BString::default(); let mut previous_pos = None; loop { - if let Some(previous_pos) = previous_pos { - if previous_pos + 1 == pos { - let len_after_trim = out.trim_end().len(); - out.resize(len_after_trim, 0); - break out.into(); - } + if let Some(previous_pos) = previous_pos + && previous_pos + 1 == pos + { + let len_after_trim = out.trim_end().len(); + out.resize(len_after_trim, 0); + break out.into(); } let message_to_newline = &message[previous_pos.map_or(0, |p| p + 1)..pos]; diff --git a/gix-object/src/commit/ref_iter.rs b/gix-object/src/commit/ref_iter.rs index c28d46584d2..9132e473ada 100644 --- a/gix-object/src/commit/ref_iter.rs +++ b/gix-object/src/commit/ref_iter.rs @@ -64,13 +64,13 @@ impl<'a> CommitRefIter<'a> { }; for token in raw_tokens { let token = token?; - if let Token::ExtraHeader((name, value)) = &token.token { - if *name == signature_field_name(hash_kind) { - // keep track of the signature range alongside the signature data, - // because all but the signature is the signed data. - signature_and_range = Some((value.clone(), token.token_range)); - break; - } + if let Token::ExtraHeader((name, value)) = &token.token + && *name == signature_field_name(hash_kind) + { + // keep track of the signature range alongside the signature data, + // because all but the signature is the signed data. + signature_and_range = Some((value.clone(), token.token_range)); + break; } } diff --git a/gix-odb/Cargo.toml b/gix-odb/Cargo.toml index 0947de1db11..362aa1a88f6 100644 --- a/gix-odb/Cargo.toml +++ b/gix-odb/Cargo.toml @@ -9,7 +9,7 @@ license = "MIT OR Apache-2.0" description = "Implements various git object databases" edition = "2024" include = ["/src/**/*", "/LICENSE-*"] -rust-version = "1.85" +rust-version = "1.88" autotests = false [lib] diff --git a/gix-odb/src/alternate/mod.rs b/gix-odb/src/alternate/mod.rs index c19703115aa..d10086b06c0 100644 --- a/gix-odb/src/alternate/mod.rs +++ b/gix-odb/src/alternate/mod.rs @@ -51,16 +51,16 @@ pub fn resolve(objects_directory: PathBuf, current_dir: &std::path::Path) -> Res while let Some((parent_idx, dir)) = dirs.pop() { let dir_canonicalized = gix_path::realpath_opts(&dir, current_dir, MAX_SYMLINKS)?; if let Some(seen_idx) = seen.iter().position(|(seen_dir, _)| *seen_dir == dir_canonicalized) { - if let Some(parent_idx) = parent_idx { - if chain(&seen, parent_idx).any(|ancestor| ancestor == seen_idx) { - let mut cycle: Vec<_> = chain(&seen, parent_idx) - .take_while(|ancestor| *ancestor != seen_idx) - .map(|idx| seen[idx].0.clone()) - .collect(); - cycle.push(seen[seen_idx].0.clone()); - cycle.reverse(); - return Err(Error::Cycle(cycle)); - } + if let Some(parent_idx) = parent_idx + && chain(&seen, parent_idx).any(|ancestor| ancestor == seen_idx) + { + let mut cycle: Vec<_> = chain(&seen, parent_idx) + .take_while(|ancestor| *ancestor != seen_idx) + .map(|idx| seen[idx].0.clone()) + .collect(); + cycle.push(seen[seen_idx].0.clone()); + cycle.reverse(); + return Err(Error::Cycle(cycle)); } continue; } diff --git a/gix-odb/src/cache.rs b/gix-odb/src/cache.rs index e85127c5e77..ac2d90e8631 100644 --- a/gix-odb/src/cache.rs +++ b/gix-odb/src/cache.rs @@ -235,10 +235,10 @@ mod impls { buffer: &'a mut Vec, pack_cache: &mut dyn gix_pack::cache::DecodeEntry, ) -> Result, Option)>, gix_object::find::Error> { - if let Some(mut obj_cache) = self.object_cache.as_ref().map(RefCell::borrow_mut) { - if let Some(kind) = obj_cache.get(&id.as_ref().to_owned(), buffer) { - return Ok(Some((Data::new(buffer, kind, id.kind()), None))); - } + if let Some(mut obj_cache) = self.object_cache.as_ref().map(RefCell::borrow_mut) + && let Some(kind) = obj_cache.get(&id.as_ref().to_owned(), buffer) + { + return Ok(Some((Data::new(buffer, kind, id.kind()), None))); } let possibly_obj = self.inner.try_find_cached(id.as_ref(), buffer, pack_cache)?; if let (Some(mut obj_cache), Some((obj, _location))) = diff --git a/gix-odb/src/store_impls/dynamic/find.rs b/gix-odb/src/store_impls/dynamic/find.rs index c612a76d527..ac5de05dea6 100644 --- a/gix-odb/src/store_impls/dynamic/find.rs +++ b/gix-odb/src/store_impls/dynamic/find.rs @@ -100,14 +100,13 @@ where id: r.original_id.to_owned(), }); } - } else if !self.ignore_replacements { - if let Ok(pos) = self + } else if !self.ignore_replacements + && let Ok(pos) = self .store .replacements .binary_search_by(|(map_this, _)| map_this.as_ref().cmp(id)) - { - id = self.store.replacements[pos].1.as_ref(); - } + { + id = self.store.replacements[pos].1.as_ref(); } 'outer: loop { diff --git a/gix-odb/src/store_impls/dynamic/header.rs b/gix-odb/src/store_impls/dynamic/header.rs index d34550495b1..8e568bd624f 100644 --- a/gix-odb/src/store_impls/dynamic/header.rs +++ b/gix-odb/src/store_impls/dynamic/header.rs @@ -26,14 +26,13 @@ where id: r.original_id.to_owned(), }); } - } else if !self.ignore_replacements { - if let Ok(pos) = self + } else if !self.ignore_replacements + && let Ok(pos) = self .store .replacements .binary_search_by(|(map_this, _)| map_this.as_ref().cmp(id)) - { - id = self.store.replacements[pos].1.as_ref(); - } + { + id = self.store.replacements[pos].1.as_ref(); } 'outer: loop { diff --git a/gix-odb/src/store_impls/loose/iter.rs b/gix-odb/src/store_impls/loose/iter.rs index bb12623affa..9f180c9e961 100644 --- a/gix-odb/src/store_impls/loose/iter.rs +++ b/gix-odb/src/store_impls/loose/iter.rs @@ -17,19 +17,19 @@ impl loose::Iter { let p = e.path(); let mut ci = p.components(); let (c2, c1) = (ci.next_back(), ci.next_back()); - if let (Some(Normal(c1)), Some(Normal(c2))) = (c1, c2) { - if c1.len() == 2 && c2.len() == self.hash_hex_len - 2 { - if let (Some(c1), Some(c2)) = (c1.to_str(), c2.to_str()) { - let mut buf = gix_hash::Kind::hex_buf(); - { - let (first_byte, rest) = buf[..self.hash_hex_len].split_at_mut(2); - first_byte.copy_from_slice(c1.as_bytes()); - rest.copy_from_slice(c2.as_bytes()); - } - if let Ok(b) = gix_hash::ObjectId::from_hex(&buf[..self.hash_hex_len]) { - return Some(Ok(b)); - } - } + if let (Some(Normal(c1)), Some(Normal(c2))) = (c1, c2) + && c1.len() == 2 + && c2.len() == self.hash_hex_len - 2 + && let (Some(c1), Some(c2)) = (c1.to_str(), c2.to_str()) + { + let mut buf = gix_hash::Kind::hex_buf(); + { + let (first_byte, rest) = buf[..self.hash_hex_len].split_at_mut(2); + first_byte.copy_from_slice(c1.as_bytes()); + rest.copy_from_slice(c2.as_bytes()); + } + if let Ok(b) = gix_hash::ObjectId::from_hex(&buf[..self.hash_hex_len]) { + return Some(Ok(b)); } } } diff --git a/gix-pack/Cargo.toml b/gix-pack/Cargo.toml index f3856edeb72..309520da6fe 100644 --- a/gix-pack/Cargo.toml +++ b/gix-pack/Cargo.toml @@ -9,7 +9,7 @@ license = "MIT OR Apache-2.0" description = "Implements git packs and related data structures" edition = "2024" include = ["/src/**/*", "/LICENSE-*"] -rust-version = "1.85" +rust-version = "1.88" [lib] doctest = false diff --git a/gix-pack/src/cache/delta/traverse/mod.rs b/gix-pack/src/cache/delta/traverse/mod.rs index 4991706afdf..fab2fbe11eb 100644 --- a/gix-pack/src/cache/delta/traverse/mod.rs +++ b/gix-pack/src/cache/delta/traverse/mod.rs @@ -183,10 +183,10 @@ where )?; } - if let Some(ref_delta_children) = ref_delta_children { - if let Some((base_id, _children)) = threading::lock(&ref_delta_children).first_key_value() { - return Err(Error::UnresolvedRefDelta { base_id: *base_id }); - } + if let Some(ref_delta_children) = ref_delta_children + && let Some((base_id, _children)) = threading::lock(&ref_delta_children).first_key_value() + { + return Err(Error::UnresolvedRefDelta { base_id: *base_id }); } object_progress.show_throughput(start); diff --git a/gix-pack/src/cache/delta/traverse/resolve.rs b/gix-pack/src/cache/delta/traverse/resolve.rs index 4d6f60bf954..df8e8a37a55 100644 --- a/gix-pack/src/cache/delta/traverse/resolve.rs +++ b/gix-pack/src/cache/delta/traverse/resolve.rs @@ -549,15 +549,13 @@ where // This might be a leaf, while its base buffer now is also exclusively available, // and if so, keep the larger buffer. - if let Some(parent) = parent { - if let Ok(parent) = OwnShared::try_unwrap(parent) { - if reusable - .as_ref() - .is_none_or(|reusable| parent.bytes.capacity() > reusable.capacity()) - { - reusable = Some(parent.bytes); - } - } + if let Some(parent) = parent + && let Ok(parent) = OwnShared::try_unwrap(parent) + && reusable + .as_ref() + .is_none_or(|reusable| parent.bytes.capacity() > reusable.capacity()) + { + reusable = Some(parent.bytes); } if let Some(reusable) = reusable { *fully_resolved_delta_bytes = reusable; diff --git a/gix-pack/src/data/input/bytes_to_entries.rs b/gix-pack/src/data/input/bytes_to_entries.rs index 198c80c1369..7b9e7b8b7bf 100644 --- a/gix-pack/src/data/input/bytes_to_entries.rs +++ b/gix-pack/src/data/input/bytes_to_entries.rs @@ -171,10 +171,10 @@ where fn try_read_trailer(&mut self) -> Result, input::Error> { Ok(if self.objects_left == 0 { let mut id = gix_hash::ObjectId::null(self.object_hash); - if let Err(err) = self.read.read_exact(id.as_mut_slice()) { - if self.mode != input::Mode::Restore { - return Err(input::Error::Io(err.into())); - } + if let Err(err) = self.read.read_exact(id.as_mut_slice()) + && self.mode != input::Mode::Restore + { + return Err(input::Error::Io(err.into())); } if let Some(hash) = self.hash.take() { diff --git a/gix-pack/src/data/output/entry/iter_from_counts.rs b/gix-pack/src/data/output/entry/iter_from_counts.rs index 857dd0fe81a..2147e755c4b 100644 --- a/gix-pack/src/data/output/entry/iter_from_counts.rs +++ b/gix-pack/src/data/output/entry/iter_from_counts.rs @@ -166,10 +166,10 @@ pub(crate) mod function { .and_then(|l| db.entry_by_location(l).map(|pe| (l, pe))) { Some((location, pack_entry)) => { - if let Some((cached_pack_id, _)) = &pack_offsets_to_id { - if *cached_pack_id != location.pack_id { - pack_offsets_to_id = None; - } + if let Some((cached_pack_id, _)) = &pack_offsets_to_id + && *cached_pack_id != location.pack_id + { + pack_offsets_to_id = None; } let pack_range = counts_range_by_pack_id[counts_range_by_pack_id .binary_search_by_key(&location.pack_id, |e| e.0) diff --git a/gix-pack/src/index/access.rs b/gix-pack/src/index/access.rs index 3fba18e3bf7..e956b879a53 100644 --- a/gix-pack/src/index/access.rs +++ b/gix-pack/src/index/access.rs @@ -54,10 +54,14 @@ where .chunks_exact(self.hash_len) .take(self.num_objects as usize); let crcs = self.data[self.offset_crc32_v2()..] - .chunks_exact(N32_SIZE) + .as_chunks::() + .0 + .iter() .take(self.num_objects as usize); let offsets = self.data[self.offset_pack_offset_v2()..] - .chunks_exact(N32_SIZE) + .as_chunks::() + .0 + .iter() .take(self.num_objects as usize); assert_eq!(oids.len(), crcs.len()); assert_eq!(crcs.len(), offsets.len()); @@ -170,7 +174,11 @@ where index::Version::V1 => self.iter().map(|e| e.pack_offset).collect(), index::Version::V2 => { let offset32_start = &self.data[self.offset_pack_offset_v2()..]; - let offsets32 = offset32_start.chunks_exact(N32_SIZE).take(self.num_objects as usize); + let offsets32 = offset32_start + .as_chunks::() + .0 + .iter() + .take(self.num_objects as usize); assert_eq!(self.num_objects as usize, offsets32.len()); let pack_offset_64_start = self.offset_pack_offset64_v2(); offsets32 diff --git a/gix-pack/src/index/init.rs b/gix-pack/src/index/init.rs index 770e19f1d62..aa1b01318e4 100644 --- a/gix-pack/src/index/init.rs +++ b/gix-pack/src/index/init.rs @@ -101,7 +101,7 @@ fn read_fan(d: &[u8]) -> ([u32; FAN_LEN], usize) { assert!(d.len() >= FAN_LEN * N32_SIZE); let mut fan = [0; FAN_LEN]; - for (c, f) in d.chunks_exact(N32_SIZE).zip(fan.iter_mut()) { + for (c, f) in d.as_chunks::().0.iter().zip(fan.iter_mut()) { *f = crate::read_u32(c); } (fan, FAN_LEN * N32_SIZE) @@ -154,7 +154,9 @@ fn validate_size(data: &[u8], kind: Version, num_objects: u32, hash_len: usize) }); } let (large_offsets, max_large_offset_index) = data[offset32_start..offset32_end] - .chunks_exact(N32_SIZE) + .as_chunks::() + .0 + .iter() .filter_map(|offset| { let offset = crate::read_u32(offset); (offset & (1 << 31) != 0).then_some((offset ^ (1 << 31)) as usize) diff --git a/gix-pack/src/multi_index/chunk.rs b/gix-pack/src/multi_index/chunk.rs index 1c0583b31f6..27e9a9b5bc1 100644 --- a/gix-pack/src/multi_index/chunk.rs +++ b/gix-pack/src/multi_index/chunk.rs @@ -78,10 +78,10 @@ pub mod index_names { })? .to_owned(); - if let Some(previous) = out.last() { - if previous >= &path { - return Err(decode::Error::NotOrderedAlphabetically); - } + if let Some(previous) = out.last() + && previous >= &path + { + return Err(decode::Error::NotOrderedAlphabetically); } out.push(path); @@ -157,8 +157,8 @@ pub mod fanout { return None; } let mut out = [0; 256]; - for (c, f) in chunk.chunks_exact(4).zip(out.iter_mut()) { - *f = u32::from_be_bytes(c.try_into().unwrap()); + for (c, f) in chunk.as_chunks::<4>().0.iter().zip(out.iter_mut()) { + *f = u32::from_be_bytes(*c); } out.into() } @@ -284,7 +284,7 @@ pub mod large_offsets { } /// Returns true if the `offsets` range seems to be properly aligned for the data we expect. pub fn is_valid(offset: &Range) -> bool { - (offset.end - offset.start) % 8 == 0 + (offset.end - offset.start).is_multiple_of(8) } pub(crate) fn write( diff --git a/gix-packetline/Cargo.toml b/gix-packetline/Cargo.toml index 43008025d1f..468de540681 100644 --- a/gix-packetline/Cargo.toml +++ b/gix-packetline/Cargo.toml @@ -9,7 +9,7 @@ description = "A crate of the gitoxide project implementing the pkt-line seriali authors = ["Sebastian Thiel "] edition = "2024" include = ["/src/**/*", "/LICENSE-*"] -rust-version = "1.85" +rust-version = "1.88" [lib] doctest = true diff --git a/gix-packetline/src/async_io/read.rs b/gix-packetline/src/async_io/read.rs index 501fa664187..999f269c978 100644 --- a/gix-packetline/src/async_io/read.rs +++ b/gix-packetline/src/async_io/read.rs @@ -100,16 +100,14 @@ where let stopped_at = delimiters.iter().find(|l| **l == line).copied(); buf.clear(); return (true, stopped_at, None); - } else if fail_on_err_lines { - if let Some(err) = line.check_error() { - let err = err.0.as_bstr().to_owned(); - buf.clear(); - return ( - true, - None, - Some(Err(io::Error::other(crate::read::Error { message: err }))), - ); - } + } else if fail_on_err_lines && let Some(err) = line.check_error() { + let err = err.0.as_bstr().to_owned(); + buf.clear(); + return ( + true, + None, + Some(Err(io::Error::other(crate::read::Error { message: err }))), + ); } let len = line.as_slice().map_or(U16_HEX_BYTES, |s| s.len() + U16_HEX_BYTES); if buf_resize { diff --git a/gix-packetline/src/blocking_io/read.rs b/gix-packetline/src/blocking_io/read.rs index 4d8b966d4fd..9806656e942 100644 --- a/gix-packetline/src/blocking_io/read.rs +++ b/gix-packetline/src/blocking_io/read.rs @@ -96,16 +96,14 @@ where let stopped_at = delimiters.iter().find(|l| **l == line).copied(); buf.clear(); return (true, stopped_at, None); - } else if fail_on_err_lines { - if let Some(err) = line.check_error() { - let err = err.0.as_bstr().to_owned(); - buf.clear(); - return ( - true, - None, - Some(Err(io::Error::other(crate::read::Error { message: err }))), - ); - } + } else if fail_on_err_lines && let Some(err) = line.check_error() { + let err = err.0.as_bstr().to_owned(); + buf.clear(); + return ( + true, + None, + Some(Err(io::Error::other(crate::read::Error { message: err }))), + ); } let len = line.as_slice().map_or(U16_HEX_BYTES, |s| s.len() + U16_HEX_BYTES); if buf_resize { diff --git a/gix-path/Cargo.toml b/gix-path/Cargo.toml index afc6bb1f6b5..aa2fd7997aa 100644 --- a/gix-path/Cargo.toml +++ b/gix-path/Cargo.toml @@ -9,7 +9,7 @@ description = "A crate of the gitoxide project dealing paths and their conversio authors = ["Sebastian Thiel "] edition = "2024" include = ["/src/**/*", "/LICENSE-*"] -rust-version = "1.85" +rust-version = "1.88" [lib] doctest = true diff --git a/gix-path/src/convert.rs b/gix-path/src/convert.rs index c92ad3225e1..5a67699cead 100644 --- a/gix-path/src/convert.rs +++ b/gix-path/src/convert.rs @@ -367,14 +367,12 @@ pub fn relativize_with_prefix<'a>(relative_path: &'a Path, prefix: &Path) -> Cow let mut rpc = relative_path.components().peekable(); let mut equal_thus_far = true; for pcomp in prefix.components() { - if equal_thus_far { - if let (Component::Normal(pname), Some(Component::Normal(rpname))) = (pcomp, rpc.peek()) { - if &pname == rpname { - rpc.next(); - continue; - } else { - equal_thus_far = false; - } + if equal_thus_far && let (Component::Normal(pname), Some(Component::Normal(rpname))) = (pcomp, rpc.peek()) { + if &pname == rpname { + rpc.next(); + continue; + } else { + equal_thus_far = false; } } buf.push(Component::ParentDir); diff --git a/gix-pathspec/Cargo.toml b/gix-pathspec/Cargo.toml index 11f1fc120f0..bb003ee5466 100644 --- a/gix-pathspec/Cargo.toml +++ b/gix-pathspec/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0" description = "A crate of the gitoxide project dealing magical pathspecs" authors = ["Sebastian Thiel "] edition = "2024" -rust-version = "1.85" +rust-version = "1.88" include = ["/src/**/*", "/LICENSE-*", "/README.md"] [lib] diff --git a/gix-pathspec/src/search/matching.rs b/gix-pathspec/src/search/matching.rs index a1648be6919..d1e0b3ff884 100644 --- a/gix-pathspec/src/search/matching.rs +++ b/gix-pathspec/src/search/matching.rs @@ -216,13 +216,13 @@ impl Search { let mut is_match = pattern.always_matches(); if !is_match { let plen = relative_path.len(); - if leading && rightmost_idx > plen { - if let Some(idx) = pattern.path[..plen] + if leading + && rightmost_idx > plen + && let Some(idx) = pattern.path[..plen] .rfind_byte(b'/') .or_else(|| pattern.path[plen..].find_byte(b'/').map(|idx| idx + plen)) - { - rightmost_idx = idx; - } + { + rightmost_idx = idx; } if let Some(relative_path) = relative_path.get(..rightmost_idx) { let pattern_path = pattern.path[..rightmost_idx].as_bstr(); diff --git a/gix-prompt/Cargo.toml b/gix-prompt/Cargo.toml index 0ef1b4beac5..024ed207923 100644 --- a/gix-prompt/Cargo.toml +++ b/gix-prompt/Cargo.toml @@ -9,7 +9,7 @@ description = "A crate of the gitoxide project for handling prompts in the termi authors = ["Sebastian Thiel "] edition = "2024" include = ["/src/**/*", "/LICENSE-*", "/README.md"] -rust-version = "1.85" +rust-version = "1.88" [lib] doctest = false diff --git a/gix-prompt/src/types.rs b/gix-prompt/src/types.rs index 705ed89476f..06e955c15f4 100644 --- a/gix-prompt/src/types.rs +++ b/gix-prompt/src/types.rs @@ -61,10 +61,10 @@ impl Options { if let Some(askpass) = use_git_askpass.then(|| std::env::var_os("GIT_ASKPASS")).flatten() { self.askpass = Some(askpass.into()); } - if self.askpass.is_none() { - if let Some(askpass) = use_ssh_askpass.then(|| std::env::var_os("SSH_ASKPASS")).flatten() { - self.askpass = Some(askpass.into()); - } + if self.askpass.is_none() + && let Some(askpass) = use_ssh_askpass.then(|| std::env::var_os("SSH_ASKPASS")).flatten() + { + self.askpass = Some(askpass.into()); } self.mode = use_git_terminal_prompt .then(|| { diff --git a/gix-protocol/Cargo.toml b/gix-protocol/Cargo.toml index d0b8c60297f..e0c2de19e89 100644 --- a/gix-protocol/Cargo.toml +++ b/gix-protocol/Cargo.toml @@ -9,7 +9,7 @@ description = "A crate of the gitoxide project for implementing git protocols" authors = ["Sebastian Thiel "] edition = "2024" include = ["/src/**/*", "/LICENSE-*", "!/tests/**/*"] -rust-version = "1.85" +rust-version = "1.88" [lib] doctest = false diff --git a/gix-protocol/src/command.rs b/gix-protocol/src/command.rs index 7a3019b451b..ab128e0a04e 100644 --- a/gix-protocol/src/command.rs +++ b/gix-protocol/src/command.rs @@ -158,14 +158,13 @@ mod with_io { // Echo the server's object format in every v2 command. // A stateless transport like HTTP sends each command as its own request, so without this, // the server assumes SHA1 and aborts any command against a SHA-256 repository. - if matches!(version, gix_transport::Protocol::V2) { - if let Some(object_format) = server_capabilities + if matches!(version, gix_transport::Protocol::V2) + && let Some(object_format) = server_capabilities .capability("object-format") .and_then(|c| c.value()) .and_then(|value| value.to_str().ok()) - { - features.push(("object-format", Some(object_format.to_owned()))); - } + { + features.push(("object-format", Some(object_format.to_owned()))); } features } diff --git a/gix-protocol/src/fetch/function.rs b/gix-protocol/src/fetch/function.rs index a9b6e90c54a..45900056dfa 100644 --- a/gix-protocol/src/fetch/function.rs +++ b/gix-protocol/src/fetch/function.rs @@ -164,10 +164,10 @@ where } drop(reader); - if let Some(shallow_lock) = shallow_lock { - if !previous_response.shallow_updates().is_empty() { - gix_shallow::write(shallow_lock, shallow_commits, previous_response.shallow_updates())?; - } + if let Some(shallow_lock) = shallow_lock + && !previous_response.shallow_updates().is_empty() + { + gix_shallow::write(shallow_lock, shallow_commits, previous_response.shallow_updates())?; } Ok(Some(Outcome { last_response: previous_response, diff --git a/gix-quote/Cargo.toml b/gix-quote/Cargo.toml index 75f1927c317..34eb150f6ec 100644 --- a/gix-quote/Cargo.toml +++ b/gix-quote/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0" description = "A crate of the gitoxide project dealing with various quotations used by git" authors = ["Sebastian Thiel "] edition = "2024" -rust-version = "1.85" +rust-version = "1.88" include = ["/src/**/*", "/LICENSE-*"] [lib] diff --git a/gix-rebase/Cargo.toml b/gix-rebase/Cargo.toml index c5f064ec912..a42e8738368 100644 --- a/gix-rebase/Cargo.toml +++ b/gix-rebase/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0" description = "A crate of the gitoxide project dealing rebases" authors = ["Sebastian Thiel "] edition = "2024" -rust-version = "1.85" +rust-version = "1.88" include = ["/src/**/*", "/LICENSE-*"] [lib] diff --git a/gix-ref/Cargo.toml b/gix-ref/Cargo.toml index d7e6e7db357..dc64b8258f1 100644 --- a/gix-ref/Cargo.toml +++ b/gix-ref/Cargo.toml @@ -9,7 +9,7 @@ description = "A crate to handle git references" authors = ["Sebastian Thiel "] edition = "2024" include = ["/src/**/*", "/LICENSE-*"] -rust-version = "1.85" +rust-version = "1.88" [lib] doctest = false diff --git a/gix-ref/src/store/file/find.rs b/gix-ref/src/store/file/find.rs index 267aea51434..82d657bc66f 100644 --- a/gix-ref/src/store/file/find.rs +++ b/gix-ref/src/store/file/find.rs @@ -177,23 +177,23 @@ impl file::Store { match content_buf { None => { - if let Some(packed) = packed { - if let Some(full_name) = packed::find::transform_full_name_for_lookup(full_name) { - let full_name_backing; - let full_name = match &self.namespace { - Some(namespace) => { - full_name_backing = namespace.to_owned().into_namespaced_name(full_name); - full_name_backing.as_ref() - } - None => full_name, - }; - if let Some(packed_ref) = packed.try_find_full_name(full_name)? { - let mut res: Reference = packed_ref.into(); - if let Some(namespace) = &self.namespace { - res.strip_namespace(namespace); - } - return Ok(Some(res)); + if let Some(packed) = packed + && let Some(full_name) = packed::find::transform_full_name_for_lookup(full_name) + { + let full_name_backing; + let full_name = match &self.namespace { + Some(namespace) => { + full_name_backing = namespace.to_owned().into_namespaced_name(full_name); + full_name_backing.as_ref() + } + None => full_name, + }; + if let Some(packed_ref) = packed.try_find_full_name(full_name)? { + let mut res: Reference = packed_ref.into(); + if let Some(namespace) = &self.namespace { + res.strip_namespace(namespace); } + return Ok(Some(res)); } } Ok(None) diff --git a/gix-ref/src/store/file/loose/iter.rs b/gix-ref/src/store/file/loose/iter.rs index 300541e91a1..fdef9ab2529 100644 --- a/gix-ref/src/store/file/loose/iter.rs +++ b/gix-ref/src/store/file/loose/iter.rs @@ -62,15 +62,15 @@ impl Iterator for SortedLoosePaths { else { continue; }; - if let Some(prefix) = &self.prefix { - if !full_name.starts_with(prefix) { - continue; - } + if let Some(prefix) = &self.prefix + && !full_name.starts_with(prefix) + { + continue; } - if let Some(suffix) = &self.suffix { - if !full_name.ends_with(suffix) { - continue; - } + if let Some(suffix) = &self.suffix + && !full_name.ends_with(suffix) + { + continue; } if gix_validate::reference::name_partial(full_name.as_bstr()).is_ok() { let name = FullName(full_name); diff --git a/gix-ref/src/store/file/transaction/commit.rs b/gix-ref/src/store/file/transaction/commit.rs index 018dc144f18..1d87caa7292 100644 --- a/gix-ref/src/store/file/transaction/commit.rs +++ b/gix-ref/src/store/file/transaction/commit.rs @@ -92,24 +92,22 @@ impl Transaction<'_, '_> { change.lock = lock; continue; } - if update_ref { - if let Some(Err(err)) = lock.map(gix_lock::Marker::commit) { - // TODO: when Kind::IsADirectory becomes stable, use that. - let err = if err.instance.resource_path().is_dir() { - gix_tempfile::remove_dir::empty_depth_first(err.instance.resource_path()) - .map_err(std::io::Error::other) - .and_then(|_| err.instance.commit().map_err(|err| err.error)) - .err() - } else { - Some(err.error) - }; + if update_ref && let Some(Err(err)) = lock.map(gix_lock::Marker::commit) { + // TODO: when Kind::IsADirectory becomes stable, use that. + let err = if err.instance.resource_path().is_dir() { + gix_tempfile::remove_dir::empty_depth_first(err.instance.resource_path()) + .map_err(std::io::Error::other) + .and_then(|_| err.instance.commit().map_err(|err| err.error)) + .err() + } else { + Some(err.error) + }; - if let Some(err) = err { - return Err(Error::LockCommit { - source: err, - full_name: change.name(), - }); - } + if let Some(err) = err { + return Err(Error::LockCommit { + source: err, + full_name: change.name(), + }); } } } @@ -162,13 +160,13 @@ impl Transaction<'_, '_> { if take_lock_and_delete { let lock = change.lock.take(); let reference_path = self.store.reference_path(change.update.name.as_ref()); - if let Err(err) = std::fs::remove_file(reference_path) { - if err.kind() != std::io::ErrorKind::NotFound { - return Err(Error::DeleteReference { - err, - full_name: change.name(), - }); - } + if let Err(err) = std::fs::remove_file(reference_path) + && err.kind() != std::io::ErrorKind::NotFound + { + return Err(Error::DeleteReference { + err, + full_name: change.name(), + }); } drop(lock); } diff --git a/gix-ref/src/store/file/transaction/prepare.rs b/gix-ref/src/store/file/transaction/prepare.rs index cbf52ca781d..28dfda7bac6 100644 --- a/gix-ref/src/store/file/transaction/prepare.rs +++ b/gix-ref/src/store/file/transaction/prepare.rs @@ -302,18 +302,17 @@ impl Transaction<'_, '_> { Some(n) => n, None => continue, }; - if let Some(ref mut num_updates) = maybe_updates_for_packed_refs { - if let Change::Update { + if let Some(ref mut num_updates) = maybe_updates_for_packed_refs + && let Change::Update { new: Target::Object(_), .. } = edit.update.change - { - edits_for_packed_transaction.push(RefEdit { - name, - ..edit.update.clone() - }); - *num_updates += 1; - continue; - } + { + edits_for_packed_transaction.push(RefEdit { + name, + ..edit.update.clone() + }); + *num_updates += 1; + continue; } match edit.update.change { Change::Update { diff --git a/gix-ref/src/store/packed/iter.rs b/gix-ref/src/store/packed/iter.rs index 1dca8b63a75..aa2ef319f2e 100644 --- a/gix-ref/src/store/packed/iter.rs +++ b/gix-ref/src/store/packed/iter.rs @@ -36,11 +36,11 @@ impl<'a> Iterator for packed::Iter<'a> { match decode::reference(&mut self.cursor, self.object_hash) { Ok(reference) => { self.current_line += 1; - if let Some(ref prefix) = self.prefix { - if !reference.name.as_bstr().starts_with_str(prefix) { - self.cursor = &[]; - return None; - } + if let Some(ref prefix) = self.prefix + && !reference.name.as_bstr().starts_with_str(prefix) + { + self.cursor = &[]; + return None; } Some(Ok(reference)) } diff --git a/gix-ref/src/transaction/ext.rs b/gix-ref/src/transaction/ext.rs index c08b51d49a2..8129a4e611d 100644 --- a/gix-ref/src/transaction/ext.rs +++ b/gix-ref/src/transaction/ext.rs @@ -82,14 +82,7 @@ where } => { let current_mode = *mode; *mode = RefLog::Only; - RefEdit { - change: Change::Delete { - expected: previous.clone(), - log: current_mode, - }, - name: referent, - deref: true, - } + RefEdit::delete_with_log(referent, previous.clone(), current_mode).with_deref(true) } Change::Update { log, expected, new } => { let current = std::mem::replace( @@ -101,15 +94,7 @@ where }, ); let next = std::mem::replace(expected, PreviousValue::Any); - RefEdit { - change: Change::Update { - expected: next, - new: new.clone(), - log: current, - }, - name: referent, - deref: true, - } + RefEdit::update_with_log(referent, new.clone(), next, current).with_deref(true) } }, )); diff --git a/gix-ref/src/transaction/mod.rs b/gix-ref/src/transaction/mod.rs index 47d05010807..cdb597a1c13 100644 --- a/gix-ref/src/transaction/mod.rs +++ b/gix-ref/src/transaction/mod.rs @@ -121,6 +121,71 @@ pub struct RefEdit { pub deref: bool, } +/// Lifecycle +impl RefEdit { + /// Create an edit that applies `change` to `name` without dereferencing symbolic references. + pub fn new(name: FullName, change: Change) -> Self { + RefEdit { + change, + name, + deref: false, + } + } + + /// Create an update that sets `name` to `new` if its current state satisfies `expected`, recording + /// `reflog_message` with standard reference-log handling and without dereferencing symbolic references. + pub fn update( + name: FullName, + new: impl Into, + expected: PreviousValue, + reflog_message: impl Into, + ) -> Self { + RefEdit::update_with_log( + name, + new, + expected, + LogChange { + message: reflog_message.into(), + ..Default::default() + }, + ) + } + + /// Create an update that sets `name` to `new` if its current state satisfies `expected`, using `log` to configure + /// reference-log handling and without dereferencing symbolic references. + pub fn update_with_log(name: FullName, new: impl Into, expected: PreviousValue, log: LogChange) -> Self { + RefEdit::new( + name, + Change::Update { + log, + expected, + new: new.into(), + }, + ) + } + + /// Create a deletion of `name` and its reference log if its current state satisfies `expected`, without + /// dereferencing symbolic references. + pub fn delete(name: FullName, expected: PreviousValue) -> Self { + RefEdit::delete_with_log(name, expected, RefLog::AndReference) + } + + /// Create a deletion of `name` if its current state satisfies `expected`, using `log` to configure reference-log + /// handling and without dereferencing symbolic references. + pub fn delete_with_log(name: FullName, expected: PreviousValue, log: RefLog) -> Self { + RefEdit::new(name, Change::Delete { expected, log }) + } +} + +/// Builders +impl RefEdit { + /// Set whether symbolic references are dereferenced before applying the edit. + pub fn with_deref(mut self, deref: bool) -> Self { + self.deref = deref; + self + } +} + /// The way to deal with the Reflog in deletions. #[derive(PartialEq, Eq, Debug, Hash, Ord, PartialOrd, Clone, Copy)] pub enum RefLog { diff --git a/gix-ref/tests/refs/file/store/mod.rs b/gix-ref/tests/refs/file/store/mod.rs index 5f41be2d8ac..096209080c4 100644 --- a/gix-ref/tests/refs/file/store/mod.rs +++ b/gix-ref/tests/refs/file/store/mod.rs @@ -4,7 +4,7 @@ use gix_ref::{ Target, file::transaction::PackedRefs, store::WriteReflog, - transaction::{Change, LogChange, PreviousValue, RefEdit}, + transaction::{PreviousValue, RefEdit}, }; use crate::file::{ @@ -119,15 +119,7 @@ fn precompose_unicode_journey() -> crate::Result { store_decomposed .loose_iter()? .filter_map(|r| r.ok().filter(|r| r.kind() == gix_ref::Kind::Object)) - .map(|r| RefEdit { - change: Change::Update { - log: LogChange::default(), - expected: PreviousValue::MustExistAndMatch(r.target.clone()), - new: r.target, - }, - name: r.name, - deref: false, - }), + .map(|r| RefEdit::update(r.name, r.target.clone(), PreviousValue::MustExistAndMatch(r.target), "")), Fail::Immediately, Fail::Immediately, )? @@ -180,15 +172,12 @@ fn precompose_unicode_journey() -> crate::Result { .transaction() .prepare( // A symref pointing to a decomposed name. - Some(RefEdit { - change: Change::Update { - log: LogChange::default(), - expected: PreviousValue::MustNotExist, - new: Target::Symbolic(decomposed_ref.clone().try_into().expect("valid name")), - }, - name: "HEAD".try_into().expect("valid name"), - deref: false, - }), + Some(RefEdit::update( + "HEAD".try_into().expect("valid name"), + Target::Symbolic(decomposed_ref.clone().try_into().expect("valid name")), + PreviousValue::MustNotExist, + "", + )), Fail::Immediately, Fail::Immediately, )? diff --git a/gix-ref/tests/refs/file/transaction/mod.rs b/gix-ref/tests/refs/file/transaction/mod.rs index e61980f4eae..8c58c9bd3f4 100644 --- a/gix-ref/tests/refs/file/transaction/mod.rs +++ b/gix-ref/tests/refs/file/transaction/mod.rs @@ -3,7 +3,7 @@ pub(crate) mod prepare_and_commit { use gix_object::bstr::BString; use gix_ref::{ Target, file, - transaction::{Change, LogChange, PreviousValue, RefEdit, RefLog}, + transaction::{LogChange, PreviousValue, RefEdit, RefLog}, }; use crate::hex_to_id; @@ -42,42 +42,29 @@ pub(crate) mod prepare_and_commit { } pub(crate) fn create_at(name: &str) -> RefEdit { - RefEdit { - change: Change::Update { - log: LogChange { - mode: RefLog::AndReference, - force_create_reflog: true, - message: "log peeled".into(), - }, - expected: PreviousValue::MustNotExist, - new: Target::Object(hex_to_id("e69de29bb2d1d6434b8b29ae775ad8c2e48c5391")), + RefEdit::update_with_log( + name.try_into().expect("valid"), + hex_to_id("e69de29bb2d1d6434b8b29ae775ad8c2e48c5391"), + PreviousValue::MustNotExist, + LogChange { + mode: RefLog::AndReference, + force_create_reflog: true, + message: "log peeled".into(), }, - name: name.try_into().expect("valid"), - deref: false, - } + ) } fn create_symbolic_at(name: &str, symbolic_target: &str) -> RefEdit { - RefEdit { - change: Change::Update { - log: LogChange::default(), - expected: PreviousValue::MustNotExist, - new: Target::Symbolic(symbolic_target.try_into().expect("valid target name")), - }, - name: name.try_into().expect("valid"), - deref: false, - } + RefEdit::update( + name.try_into().expect("valid"), + Target::Symbolic(symbolic_target.try_into().expect("valid target name")), + PreviousValue::MustNotExist, + "", + ) } fn delete_at(name: &str) -> RefEdit { - RefEdit { - change: Change::Delete { - expected: PreviousValue::Any, - log: RefLog::AndReference, - }, - name: name.try_into().expect("valid name"), - deref: false, - } + RefEdit::delete(name.try_into().expect("valid name"), PreviousValue::Any) } mod create_or_update; diff --git a/gix-ref/tests/refs/file/transaction/prepare_and_commit/create_or_update/collisions.rs b/gix-ref/tests/refs/file/transaction/prepare_and_commit/create_or_update/collisions.rs index 89477f8bb03..8e77e278f66 100644 --- a/gix-ref/tests/refs/file/transaction/prepare_and_commit/create_or_update/collisions.rs +++ b/gix-ref/tests/refs/file/transaction/prepare_and_commit/create_or_update/collisions.rs @@ -3,7 +3,7 @@ use gix_lock::acquire::Fail; use gix_ref::{ Target, file::transaction::PackedRefs, - transaction::{Change, LogChange, PreviousValue, RefEdit}, + transaction::{PreviousValue, RefEdit}, }; use crate::{ @@ -140,26 +140,20 @@ fn conflicting_creation_into_packed_refs() -> crate::Result { )) .prepare( [ - RefEdit { - change: Change::Update { - log: LogChange::default(), - expected: PreviousValue::Any, - new: Target::Object(null), - }, - name: "refs/a".try_into().expect("valid"), - deref: false, - }, - RefEdit { - change: Change::Update { - log: LogChange::default(), - expected: PreviousValue::MustExistAndMatch(Target::Object(hex_to_id( - "e69de29bb2d1d6434b8b29ae775ad8c2e48c5391", - ))), - new: Target::Object(null), - }, - name: "refs/A".try_into().expect("valid"), - deref: false, - }, + RefEdit::update( + "refs/a".try_into().expect("valid"), + Target::Object(null), + PreviousValue::Any, + "", + ), + RefEdit::update( + "refs/A".try_into().expect("valid"), + Target::Object(null), + PreviousValue::MustExistAndMatch(Target::Object(hex_to_id( + "e69de29bb2d1d6434b8b29ae775ad8c2e48c5391", + ))), + "", + ), ], Fail::Immediately, Fail::Immediately, @@ -206,15 +200,12 @@ fn conflicting_creation_into_packed_refs() -> crate::Result { store .transaction() .prepare( - [RefEdit { - change: Change::Update { - log: LogChange::default(), - expected: PreviousValue::Any, - new: Target::Symbolic("refs/heads/does-not-matter".try_into().expect("valid")), - }, - name: "refs/a".try_into().expect("valid"), - deref: false, - }], + [RefEdit::update( + "refs/a".try_into().expect("valid"), + Target::Symbolic("refs/heads/does-not-matter".try_into().expect("valid")), + PreviousValue::Any, + "", + )], Fail::Immediately, Fail::Immediately, )? diff --git a/gix-ref/tests/refs/file/transaction/prepare_and_commit/create_or_update/mod.rs b/gix-ref/tests/refs/file/transaction/prepare_and_commit/create_or_update/mod.rs index 2b365d10084..5205c34c9e2 100644 --- a/gix-ref/tests/refs/file/transaction/prepare_and_commit/create_or_update/mod.rs +++ b/gix-ref/tests/refs/file/transaction/prepare_and_commit/create_or_update/mod.rs @@ -73,15 +73,12 @@ fn reference_with_equally_named_empty_or_non_empty_directory_already_in_place_ca let edits = store .transaction() .prepare( - Some(RefEdit { - change: Change::Update { - log: LogChange::default(), - expected: PreviousValue::MustNotExist, - new: Target::Symbolic("refs/heads/main".try_into().unwrap()), - }, - name: "HEAD".try_into()?, - deref: false, - }), + Some(RefEdit::update( + "HEAD".try_into()?, + Target::Symbolic("refs/heads/main".try_into().unwrap()), + PreviousValue::MustNotExist, + "", + )), Fail::Immediately, Fail::Immediately, )? @@ -113,15 +110,12 @@ fn reference_with_old_value_must_exist_when_creating_it() -> crate::Result { let new_target = Target::Object(crate::fixture_hash_kind().null()); let res = store.transaction().prepare( - Some(RefEdit { - change: Change::Update { - log: LogChange::default(), - new: new_target.clone(), - expected: PreviousValue::MustExist, - }, - name: "HEAD".try_into()?, - deref: false, - }), + Some(RefEdit::update( + "HEAD".try_into()?, + new_target.clone(), + PreviousValue::MustExist, + "", + )), Fail::Immediately, Fail::Immediately, ); @@ -143,17 +137,12 @@ fn reference_with_explicit_value_must_match_the_value_on_update() -> crate::Resu let target = head.target; let res = store.transaction().prepare( - Some(RefEdit { - change: Change::Update { - log: LogChange::default(), - new: Target::Object(crate::fixture_hash_kind().null()), - expected: PreviousValue::MustExistAndMatch(Target::Object(hex_to_id( - "28ce6a8b26aa170e1de65536fe8abe1832bd3242", - ))), - }, - name: "HEAD".try_into()?, - deref: false, - }), + Some(RefEdit::update( + "HEAD".try_into()?, + Target::Object(crate::fixture_hash_kind().null()), + PreviousValue::MustExistAndMatch(Target::Object(hex_to_id("28ce6a8b26aa170e1de65536fe8abe1832bd3242"))), + "", + )), Fail::Immediately, Fail::Immediately, ); @@ -175,15 +164,12 @@ fn the_existing_must_match_constraint_allow_non_existing_references_to_be_create let edits = store .transaction() .prepare( - Some(RefEdit { - change: Change::Update { - log: LogChange::default(), - new: Target::Object(crate::fixture_hash_kind().null()), - expected: expected.clone(), - }, - name: "refs/heads/new".try_into()?, - deref: false, - }), + Some(RefEdit::update( + "refs/heads/new".try_into()?, + Target::Object(crate::fixture_hash_kind().null()), + expected.clone(), + "", + )), Fail::Immediately, Fail::Immediately, )? @@ -191,15 +177,14 @@ fn the_existing_must_match_constraint_allow_non_existing_references_to_be_create assert_eq!( edits, - vec![RefEdit { - change: Change::Update { + vec![RefEdit::new( + "refs/heads/new".try_into()?, + Change::Update { log: LogChange::default(), new: Target::Object(crate::fixture_hash_kind().null()), expected, }, - name: "refs/heads/new".try_into()?, - deref: false, - }] + )] ); Ok(()) } @@ -212,17 +197,12 @@ fn the_existing_must_match_constraint_requires_existing_references_to_have_the_g let target = head.target; let res = store.transaction().prepare( - Some(RefEdit { - change: Change::Update { - log: LogChange::default(), - new: Target::Object(crate::fixture_hash_kind().null()), - expected: PreviousValue::ExistingMustMatch(Target::Object(hex_to_id( - "28ce6a8b26aa170e1de65536fe8abe1832bd3242", - ))), - }, - name: "HEAD".try_into()?, - deref: false, - }), + Some(RefEdit::update( + "HEAD".try_into()?, + Target::Object(crate::fixture_hash_kind().null()), + PreviousValue::ExistingMustMatch(Target::Object(hex_to_id("28ce6a8b26aa170e1de65536fe8abe1832bd3242"))), + "", + )), Fail::Immediately, Fail::Immediately, ); @@ -283,15 +263,12 @@ fn reference_with_must_exist_constraint_must_exist_already_with_any_value() -> c let edits = store .transaction() .prepare( - Some(RefEdit { - change: Change::Update { - log: LogChange::default(), - new: new_target.clone(), - expected: PreviousValue::MustExist, - }, - name: "HEAD".try_into()?, - deref: false, - }), + Some(RefEdit::update( + "HEAD".try_into()?, + new_target.clone(), + PreviousValue::MustExist, + "", + )), Fail::Immediately, Fail::Immediately, )? @@ -299,15 +276,12 @@ fn reference_with_must_exist_constraint_must_exist_already_with_any_value() -> c assert_eq!( edits, - vec![RefEdit { - change: Change::Update { - log: LogChange::default(), - new: new_target, - expected: PreviousValue::MustExistAndMatch(target) - }, - name: "HEAD".try_into()?, - deref: false, - }] + vec![RefEdit::update( + "HEAD".try_into()?, + new_target, + PreviousValue::MustExistAndMatch(target), + "", + )] ); assert_eq!( @@ -329,15 +303,12 @@ fn reference_with_must_not_exist_constraint_may_exist_already_if_the_new_value_m let edits = store .transaction() .prepare( - Some(RefEdit { - change: Change::Update { - log: LogChange::default(), - new: target.clone(), - expected: PreviousValue::MustNotExist, - }, - name: "HEAD".try_into()?, - deref: false, - }), + Some(RefEdit::update( + "HEAD".try_into()?, + target.clone(), + PreviousValue::MustNotExist, + "", + )), Fail::Immediately, Fail::Immediately, )? @@ -345,15 +316,12 @@ fn reference_with_must_not_exist_constraint_may_exist_already_if_the_new_value_m assert_eq!( edits, - vec![RefEdit { - change: Change::Update { - log: LogChange::default(), - new: target.clone(), - expected: PreviousValue::MustExistAndMatch(target) - }, - name: "HEAD".try_into()?, - deref: false, - }] + vec![RefEdit::update( + "HEAD".try_into()?, + target.clone(), + PreviousValue::MustExistAndMatch(target), + "", + )] ); assert_eq!( @@ -406,15 +374,14 @@ fn symbolic_reference_writes_reflog_if_previous_value_is_set() -> crate::Result let edits = store .transaction() .prepare( - Some(RefEdit { - change: Change::Update { + Some(RefEdit::new( + "refs/heads/symbolic".try_into()?, + Change::Update { log, new: new_head_value, expected: PreviousValue::ExistingMustMatch(Target::Object(new_oid)), }, - name: "refs/heads/symbolic".try_into()?, - deref: false, - }), + )), Fail::Immediately, Fail::Immediately, )? @@ -452,15 +419,12 @@ fn windows_device_name_is_illegal_with_enabled_windows_protections() -> crate::R let err = store .transaction() .prepare( - Some(RefEdit { - change: Change::Update { - log: log_ignored.clone(), - new: new.clone(), - expected: PreviousValue::Any, - }, - name: invalid_name.try_into()?, - deref: false, - }), + Some(RefEdit::update_with_log( + invalid_name.try_into()?, + new.clone(), + PreviousValue::Any, + log_ignored.clone(), + )), Fail::Immediately, Fail::Immediately, ) @@ -477,15 +441,14 @@ fn windows_device_name_is_illegal_with_enabled_windows_protections() -> crate::R { store.prohibit_windows_device_names = false; let _prepared_transaction = store.transaction().prepare( - Some(RefEdit { - change: Change::Update { + Some(RefEdit::new( + "refs/heads/CON".try_into()?, + Change::Update { log: log_ignored.clone(), new, expected: PreviousValue::Any, }, - name: "refs/heads/CON".try_into()?, - deref: false, - }), + )), Fail::Immediately, Fail::Immediately, )?; @@ -516,19 +479,12 @@ fn windows_device_name_check_runs_before_lock_acquisition() -> crate::Result { let err = store .transaction() .prepare( - Some(RefEdit { - change: Change::Update { - log: LogChange { - mode: RefLog::AndReference, - force_create_reflog: false, - message: "ignored".into(), - }, - new: Target::Object(hex_to_id("28ce6a8b26aa170e1de65536fe8abe1832bd3242")), - expected: PreviousValue::Any, - }, - name: "refs/heads/CON".try_into()?, - deref: false, - }), + Some(RefEdit::update( + "refs/heads/CON".try_into()?, + Target::Object(hex_to_id("28ce6a8b26aa170e1de65536fe8abe1832bd3242")), + PreviousValue::Any, + "ignored", + )), Fail::Immediately, Fail::Immediately, ) @@ -553,15 +509,15 @@ fn lock_failure_on_symbolic_referent_is_reported_for_the_symbolic_ref() -> crate let err = store .transaction() .prepare( - Some(RefEdit { - change: Change::Update { - log: LogChange::default(), - new: Target::Object(hex_to_id("28ce6a8b26aa170e1de65536fe8abe1832bd3242")), - expected: PreviousValue::Any, - }, - name: "HEAD".try_into()?, - deref: true, - }), + Some( + RefEdit::update( + "HEAD".try_into()?, + Target::Object(hex_to_id("28ce6a8b26aa170e1de65536fe8abe1832bd3242")), + PreviousValue::Any, + "", + ) + .with_deref(true), + ), Fail::Immediately, Fail::Immediately, ) @@ -594,30 +550,24 @@ fn symbolic_head_missing_referent_then_update_referent() -> crate::Result { let edits = store .transaction() .prepare( - Some(RefEdit { - change: Change::Update { - log: log_ignored.clone(), - new: new_head_value.clone(), - expected: PreviousValue::MustNotExist, - }, - name: "HEAD".try_into()?, - deref: false, - }), + Some(RefEdit::update_with_log( + "HEAD".try_into()?, + new_head_value.clone(), + PreviousValue::MustNotExist, + log_ignored.clone(), + )), Fail::Immediately, Fail::Immediately, )? .commit(committer().to_ref(&mut buf))?; assert_eq!( edits, - vec![RefEdit { - change: Change::Update { - log: log_ignored.clone(), - new: new_head_value.clone(), - expected: PreviousValue::MustNotExist, - }, - name: "HEAD".try_into()?, - deref: false, - }], + vec![RefEdit::update_with_log( + "HEAD".try_into()?, + new_head_value.clone(), + PreviousValue::MustNotExist, + log_ignored.clone(), + )], "no split was performed" ); @@ -646,15 +596,10 @@ fn symbolic_head_missing_referent_then_update_referent() -> crate::Result { let edits = store .transaction() .prepare( - Some(RefEdit { - change: Change::Update { - log: log.clone(), - new: new.clone(), - expected: PreviousValue::Any, - }, - name: "HEAD".try_into()?, - deref: true, - }), + Some( + RefEdit::update_with_log("HEAD".try_into()?, new.clone(), PreviousValue::Any, log.clone()) + .with_deref(true), + ), Fail::Immediately, Fail::Immediately, )? @@ -663,28 +608,18 @@ fn symbolic_head_missing_referent_then_update_referent() -> crate::Result { assert_eq!( edits, vec![ - RefEdit { - change: Change::Update { - log: { - let mut l = log.clone(); - l.mode = RefLog::Only; - l - }, - new: new.clone(), - expected: PreviousValue::MustExistAndMatch(new_head_value.clone()), - }, - name: "HEAD".try_into()?, - deref: false, - }, - RefEdit { - change: Change::Update { - log, - new: new.clone(), - expected: PreviousValue::Any, // there is no previous value, so we can't put `MustExistAndMatch` here. + RefEdit::update_with_log( + "HEAD".try_into()?, + new.clone(), + PreviousValue::MustExistAndMatch(new_head_value.clone()), + { + let mut l = log.clone(); + l.mode = RefLog::Only; + l }, - name: referent.try_into()?, - deref: false, - } + ), + // There is no previous value, so we can't put `MustExistAndMatch` here. + RefEdit::update_with_log(referent.try_into()?, new.clone(), PreviousValue::Any, log) ] ); @@ -740,19 +675,12 @@ fn write_reference_to_which_head_points_to_does_not_update_heads_reflog_even_tho let edits = store .transaction() .prepare( - Some(RefEdit { - change: Change::Update { - log: LogChange { - mode: RefLog::AndReference, - force_create_reflog: false, - message: "".into(), - }, - expected: PreviousValue::MustExist, - new: Target::Object(new_id), - }, - name: referent.as_bstr().try_into()?, - deref: false, - }), + Some(RefEdit::update( + referent.as_bstr().try_into()?, + Target::Object(new_id), + PreviousValue::MustExist, + "", + )), Fail::Immediately, Fail::Immediately, )? @@ -761,21 +689,12 @@ fn write_reference_to_which_head_points_to_does_not_update_heads_reflog_even_tho assert_eq!(edits.len(), 1, "HEAD wasn't update"); assert_eq!( edits, - vec![RefEdit { - change: Change::Update { - log: LogChange { - mode: RefLog::AndReference, - force_create_reflog: false, - message: "".into(), - }, - expected: PreviousValue::MustExistAndMatch(Target::Object(hex_to_id( - "02a7a22d90d7c02fb494ed25551850b868e634f0" - ))), - new: Target::Object(new_id), - }, - name: referent.as_bstr().try_into()?, - deref: false, - }] + vec![RefEdit::update( + referent.as_bstr().try_into()?, + Target::Object(new_id), + PreviousValue::MustExistAndMatch(Target::Object(hex_to_id("02a7a22d90d7c02fb494ed25551850b868e634f0"))), + "", + )] ); assert_eq!( reflog_lines(&store, "HEAD")?, @@ -806,19 +725,12 @@ fn packed_refs_are_looked_up_when_checking_existing_values() -> crate::Result { let edits = store .transaction() .prepare( - Some(RefEdit { - change: Change::Update { - log: LogChange { - mode: RefLog::AndReference, - force_create_reflog: false, - message: "for pack".into(), - }, - expected: PreviousValue::MustExistAndMatch(Target::Object(old_id)), - new: Target::Object(new_id), - }, - name: "refs/heads/main".try_into()?, - deref: false, - }), + Some(RefEdit::update( + "refs/heads/main".try_into()?, + Target::Object(new_id), + PreviousValue::MustExistAndMatch(Target::Object(old_id)), + "for pack", + )), Fail::Immediately, Fail::Immediately, )? @@ -867,15 +779,7 @@ fn packed_refs_creation_with_packed_refs_mode_prune_removes_original_loose_refs( store .loose_iter()? .filter_map(|r| r.ok().filter(|r| r.kind() == gix_ref::Kind::Object)) - .map(|r| RefEdit { - change: Change::Update { - log: LogChange::default(), - expected: PreviousValue::MustExistAndMatch(r.target.clone()), - new: r.target, - }, - name: r.name, - deref: false, - }), + .map(|r| RefEdit::update(r.name, r.target.clone(), PreviousValue::MustExistAndMatch(r.target), "")), Fail::Immediately, Fail::Immediately, )? @@ -918,15 +822,10 @@ fn packed_refs_creation_with_packed_refs_mode_leave_keeps_original_loose_refs() let previous_reflog_entries = branch.log_iter(&store).all()?.expect("log").count(); let previous_packed_refs = packed.iter()?.filter_map(Result::ok).count(); - let edits = store.loose_iter()?.map(|r| r.expect("valid ref")).map(|r| RefEdit { - change: Change::Update { - log: LogChange::default(), - expected: PreviousValue::MustExistAndMatch(r.target.clone()), - new: r.target, - }, - name: r.name, - deref: false, - }); + let edits = store + .loose_iter()? + .map(|r| r.expect("valid ref")) + .map(|r| RefEdit::update(r.name, r.target.clone(), PreviousValue::MustExistAndMatch(r.target), "")); let edits = store .transaction() @@ -977,14 +876,10 @@ fn packed_refs_deletion_in_deletions_and_updates_mode() -> crate::Result { .transaction() .packed_refs(PackedRefs::DeletionsAndNonSymbolicUpdates(Box::new(odb))) .prepare( - Some(RefEdit { - change: Change::Delete { - expected: PreviousValue::MustExistAndMatch(Target::Object(old_id)), - log: RefLog::AndReference, - }, - name: "refs/heads/d1".try_into()?, - deref: false, - }), + Some(RefEdit::delete( + "refs/heads/d1".try_into()?, + PreviousValue::MustExistAndMatch(Target::Object(old_id)), + )), Fail::Immediately, Fail::Immediately, )? diff --git a/gix-ref/tests/refs/file/transaction/prepare_and_commit/delete.rs b/gix-ref/tests/refs/file/transaction/prepare_and_commit/delete.rs index 45f39c1ceef..c29dc4020c2 100644 --- a/gix-ref/tests/refs/file/transaction/prepare_and_commit/delete.rs +++ b/gix-ref/tests/refs/file/transaction/prepare_and_commit/delete.rs @@ -8,11 +8,10 @@ use crate::{ use gix_date::parse::TimeBuf; use gix_lock::acquire::Fail; use gix_ref::file::transaction::prepare::Error; -use gix_ref::transaction::LogChange; use gix_ref::{ FullName, Reference, Target, file::ReferenceExt, - transaction::{Change, PreviousValue, RefEdit, RefLog}, + transaction::{PreviousValue, RefEdit, RefLog}, }; #[test] @@ -21,14 +20,7 @@ fn delete_a_ref_which_is_gone_succeeds() -> crate::Result { let edits = store .transaction() .prepare( - Some(RefEdit { - change: Change::Delete { - expected: PreviousValue::Any, - log: RefLog::AndReference, - }, - name: "DOES_NOT_EXIST".try_into()?, - deref: false, - }), + Some(RefEdit::delete("DOES_NOT_EXIST".try_into()?, PreviousValue::Any)), Fail::Immediately, Fail::Immediately, )? @@ -41,14 +33,7 @@ fn delete_a_ref_which_is_gone_succeeds() -> crate::Result { fn delete_a_ref_which_is_gone_but_must_exist_fails() -> crate::Result { let (_keep, store) = empty_store()?; let res = store.transaction().prepare( - Some(RefEdit { - change: Change::Delete { - expected: PreviousValue::MustExist, - log: RefLog::AndReference, - }, - name: "DOES_NOT_EXIST".try_into()?, - deref: false, - }), + Some(RefEdit::delete("DOES_NOT_EXIST".try_into()?, PreviousValue::MustExist)), Fail::Immediately, Fail::Immediately, ); @@ -72,14 +57,7 @@ fn delete_ref_and_reflog_on_symbolic_no_deref() -> crate::Result { let edits = store .transaction() .prepare( - Some(RefEdit { - change: Change::Delete { - expected: PreviousValue::MustExist, - log: RefLog::AndReference, - }, - name: head.name.clone(), - deref: false, - }), + Some(RefEdit::delete(head.name.clone(), PreviousValue::MustExist)), Fail::Immediately, Fail::Immediately, )? @@ -87,14 +65,10 @@ fn delete_ref_and_reflog_on_symbolic_no_deref() -> crate::Result { assert_eq!( edits, - vec![RefEdit { - change: Change::Delete { - expected: PreviousValue::MustExistAndMatch(Target::Symbolic("refs/heads/main".try_into()?)), - log: RefLog::AndReference, - }, - name: head.name, - deref: false - }], + vec![RefEdit::delete( + head.name, + PreviousValue::MustExistAndMatch(Target::Symbolic("refs/heads/main".try_into()?)), + )], "the previous value was updated with the actual one" ); assert!( @@ -113,14 +87,14 @@ fn delete_ref_with_incorrect_previous_value_fails() -> crate::Result { assert!(head.log_exists(&store)); let res = store.transaction().prepare( - Some(RefEdit { - change: Change::Delete { - expected: PreviousValue::MustExistAndMatch(Target::Symbolic("refs/heads/main".try_into()?)), - log: RefLog::Only, - }, - name: head.name, - deref: true, - }), + Some( + RefEdit::delete_with_log( + head.name, + PreviousValue::MustExistAndMatch(Target::Symbolic("refs/heads/main".try_into()?)), + RefLog::Only, + ) + .with_deref(true), + ), Fail::Immediately, Fail::Immediately, ); @@ -154,14 +128,11 @@ fn delete_reflog_only_of_symbolic_no_deref() -> crate::Result { let edits = store .transaction() .prepare( - Some(RefEdit { - change: Change::Delete { - expected: PreviousValue::MustExistAndMatch(Target::Symbolic("refs/heads/main".try_into()?)), - log: RefLog::Only, - }, - name: head.name, - deref: false, - }), + Some(RefEdit::delete_with_log( + head.name, + PreviousValue::MustExistAndMatch(Target::Symbolic("refs/heads/main".try_into()?)), + RefLog::Only, + )), Fail::Immediately, Fail::Immediately, )? @@ -189,14 +160,7 @@ fn delete_reflog_only_of_symbolic_with_deref() -> crate::Result { let edits = store .transaction() .prepare( - Some(RefEdit { - change: Change::Delete { - expected: PreviousValue::MustExist, - log: RefLog::Only, - }, - name: head.name, - deref: true, - }), + Some(RefEdit::delete_with_log(head.name, PreviousValue::MustExist, RefLog::Only).with_deref(true)), Fail::Immediately, Fail::Immediately, )? @@ -225,23 +189,8 @@ fn rename_a_to_a_slash_b_in_one_transaction() -> crate::Result { .transaction() .prepare( [ - RefEdit { - change: Change::Delete { - expected: PreviousValue::MustExist, - log: RefLog::AndReference, - }, - name: old.name.clone(), - deref: true, - }, - RefEdit { - change: Change::Update { - expected: PreviousValue::MustNotExist, - log: LogChange::default(), - new: old.target.clone(), - }, - name: new_name.clone(), - deref: true, - }, + RefEdit::delete(old.name.clone(), PreviousValue::MustExist).with_deref(true), + RefEdit::update(new_name.clone(), old.target.clone(), PreviousValue::MustNotExist, "").with_deref(true), ], Fail::Immediately, Fail::Immediately, @@ -262,14 +211,7 @@ fn rename_a_to_a_slash_b_in_one_transaction() -> crate::Result { let edits = store .transaction() .prepare( - [RefEdit { - change: Change::Delete { - expected: PreviousValue::MustExist, - log: RefLog::AndReference, - }, - name: old.name, - deref: true, - }], + [RefEdit::delete(old.name, PreviousValue::MustExist).with_deref(true)], Fail::Immediately, Fail::Immediately, )? @@ -279,15 +221,7 @@ fn rename_a_to_a_slash_b_in_one_transaction() -> crate::Result { let edits = store .transaction() .prepare( - [RefEdit { - change: Change::Update { - expected: PreviousValue::MustNotExist, - log: LogChange::default(), - new: old.target, - }, - name: new_name.clone(), - deref: true, - }], + [RefEdit::update(new_name.clone(), old.target, PreviousValue::MustNotExist, "").with_deref(true)], Fail::Immediately, Fail::Immediately, )? @@ -308,14 +242,7 @@ fn delete_broken_ref_that_must_exist_fails_as_it_is_no_valid_ref() -> crate::Res assert!(store.try_find_loose("HEAD").is_err(), "the ref is truly broken"); let res = store.transaction().prepare( - Some(RefEdit { - change: Change::Delete { - expected: PreviousValue::MustExist, - log: RefLog::AndReference, - }, - name: "HEAD".try_into()?, - deref: true, - }), + Some(RefEdit::delete("HEAD".try_into()?, PreviousValue::MustExist).with_deref(true)), Fail::Immediately, Fail::Immediately, ); @@ -339,14 +266,7 @@ fn non_existing_can_be_deleted_with_the_may_exist_match_constraint() -> crate::R let edits = store .transaction() .prepare( - Some(RefEdit { - change: Change::Delete { - expected: previous_value.clone(), - log: RefLog::AndReference, - }, - name: "refs/heads/not-there".try_into()?, - deref: true, - }), + Some(RefEdit::delete("refs/heads/not-there".try_into()?, previous_value.clone()).with_deref(true)), Fail::Immediately, Fail::Immediately, )? @@ -354,14 +274,7 @@ fn non_existing_can_be_deleted_with_the_may_exist_match_constraint() -> crate::R assert_eq!( edits, - vec![RefEdit { - change: Change::Delete { - expected: previous_value, - log: RefLog::AndReference, - }, - name: "refs/heads/not-there".try_into()?, - deref: false, - }] + vec![RefEdit::delete("refs/heads/not-there".try_into()?, previous_value,)] ); Ok(()) } @@ -376,31 +289,14 @@ fn delete_broken_ref_that_may_not_exist_works_even_in_deref_mode() -> crate::Res let edits = store .transaction() .prepare( - Some(RefEdit { - change: Change::Delete { - expected: PreviousValue::Any, - log: RefLog::AndReference, - }, - name: "HEAD".try_into()?, - deref: true, - }), + Some(RefEdit::delete("HEAD".try_into()?, PreviousValue::Any).with_deref(true)), Fail::Immediately, Fail::Immediately, )? .commit(committer().to_ref(&mut TimeBuf::default()))?; assert!(store.try_find_loose("HEAD")?.is_none(), "the ref was deleted"); - assert_eq!( - edits, - vec![RefEdit { - change: Change::Delete { - expected: PreviousValue::Any, - log: RefLog::AndReference, - }, - name: "HEAD".try_into()?, - deref: false, - }] - ); + assert_eq!(edits, vec![RefEdit::delete("HEAD".try_into()?, PreviousValue::Any,)]); Ok(()) } @@ -418,14 +314,11 @@ fn store_write_mode_has_no_effect_and_reflogs_are_always_deleted() -> crate::Res let edits = store .transaction() .prepare( - Some(RefEdit { - change: Change::Delete { - expected: PreviousValue::Any, - log: RefLog::Only, - }, - name: "HEAD".try_into()?, - deref: false, - }), + Some(RefEdit::delete_with_log( + "HEAD".try_into()?, + PreviousValue::Any, + RefLog::Only, + )), Fail::Immediately, Fail::Immediately, )? @@ -454,14 +347,10 @@ fn packed_refs_are_consulted_when_determining_previous_value_of_ref_to_be_delete let edits = store .transaction() .prepare( - Some(RefEdit { - change: Change::Delete { - expected: PreviousValue::MustExistAndMatch(Target::Object(old_id)), - log: RefLog::AndReference, - }, - name: "refs/heads/main".try_into()?, - deref: false, - }), + Some(RefEdit::delete( + "refs/heads/main".try_into()?, + PreviousValue::MustExistAndMatch(Target::Object(old_id)), + )), Fail::Immediately, Fail::Immediately, )? @@ -488,14 +377,10 @@ fn a_loose_ref_with_old_value_check_and_outdated_packed_refs_value_deletes_both_ let edits = store .transaction() .prepare( - Some(RefEdit { - change: Change::Delete { - expected: PreviousValue::MustExistAndMatch(Target::Object(branch_id)), - log: RefLog::AndReference, - }, - name: branch.name, - deref: false, - }), + Some(RefEdit::delete( + branch.name, + PreviousValue::MustExistAndMatch(Target::Object(branch_id)), + )), Fail::Immediately, Fail::Immediately, )? @@ -522,18 +407,14 @@ fn all_contained_references_deletes_the_packed_ref_file_too() -> crate::Result { .prepare( store.open_packed_buffer()?.expect("packed-refs").iter()?.map(|r| { let r = r.expect("valid ref"); - RefEdit { - change: Change::Delete { - expected: match mode { - "must-exist" => PreviousValue::MustExistAndMatch(Target::Object(r.target())), - "may-exist" => PreviousValue::ExistingMustMatch(Target::Object(r.target())), - _ => unimplemented!("unknown mode: {}", mode), - }, - log: RefLog::AndReference, + RefEdit::delete( + r.name.into(), + match mode { + "must-exist" => PreviousValue::MustExistAndMatch(Target::Object(r.target())), + "may-exist" => PreviousValue::ExistingMustMatch(Target::Object(r.target())), + _ => unimplemented!("unknown mode: {}", mode), }, - name: r.name.into(), - deref: false, - } + ) }), Fail::Immediately, Fail::Immediately, diff --git a/gix-ref/tests/refs/file/worktree.rs b/gix-ref/tests/refs/file/worktree.rs index 401b0e9b2e1..2f85c95d0e9 100644 --- a/gix-ref/tests/refs/file/worktree.rs +++ b/gix-ref/tests/refs/file/worktree.rs @@ -237,31 +237,20 @@ mod writable { let edits = t .prepare( vec![ - RefEdit { - change: change_with_id(new_id_main), - name: "main-worktree/refs/heads/new".try_into()?, - deref: false, - }, - RefEdit { - change: change_with_id(new_id_linked), - name: "worktrees/w1/refs/worktree/private".try_into()?, - deref: false, - }, - RefEdit { - change: change_with_id(new_id_linked), - name: "worktrees/w1/refs/bisect/good".try_into()?, - deref: false, - }, - RefEdit { - change: change_with_id(new_id_main), - name: "refs/bisect/good".try_into()?, - deref: false, - }, - RefEdit { - change: change_with_id(new_id_linked), - name: "worktrees/w1/refs/heads/shared".try_into()?, - deref: false, - }, + RefEdit::new("main-worktree/refs/heads/new".try_into()?, change_with_id(new_id_main)), + RefEdit::new( + "worktrees/w1/refs/worktree/private".try_into()?, + change_with_id(new_id_linked), + ), + RefEdit::new( + "worktrees/w1/refs/bisect/good".try_into()?, + change_with_id(new_id_linked), + ), + RefEdit::new("refs/bisect/good".try_into()?, change_with_id(new_id_main)), + RefEdit::new( + "worktrees/w1/refs/heads/shared".try_into()?, + change_with_id(new_id_linked), + ), ], Fail::Immediately, Fail::Immediately, @@ -434,16 +423,8 @@ mod writable { matches!( store.transaction().prepare( vec![ - RefEdit { - change: change_with_id(new_id_main), - name: "main-worktree/refs/heads/foo".try_into()?, - deref: false, - }, - RefEdit { - change: change_with_id(new_id_main), - name: "refs/heads/foo".try_into()?, - deref: false, - }, + RefEdit::new("main-worktree/refs/heads/foo".try_into()?, change_with_id(new_id_main),), + RefEdit::new("refs/heads/foo".try_into()?, change_with_id(new_id_main),), ], Fail::Immediately, Fail::Immediately, @@ -456,16 +437,11 @@ mod writable { assert!(matches!( store.transaction().prepare( vec![ - RefEdit { - change: change_with_id(new_id_main), - name: "refs/heads/new-shared".try_into()?, - deref: false, - }, - RefEdit { - change: change_with_id(new_id_main), - name: "worktrees/w1/refs/heads/new-shared".try_into()?, - deref: false, - }, + RefEdit::new("refs/heads/new-shared".try_into()?, change_with_id(new_id_main),), + RefEdit::new( + "worktrees/w1/refs/heads/new-shared".try_into()?, + change_with_id(new_id_main), + ), ], Fail::Immediately, Fail::Immediately, @@ -501,16 +477,8 @@ mod writable { matches!( store.transaction().prepare( vec![ - RefEdit { - change: change_with_id(new_id), - name: conflicting_name.try_into()?, - deref: false, - }, - RefEdit { - change: change_with_id(new_id), - name: "refs/heads/shared".try_into()?, - deref: false, - }, + RefEdit::new(conflicting_name.try_into()?, change_with_id(new_id),), + RefEdit::new("refs/heads/shared".try_into()?, change_with_id(new_id),), ], Fail::Immediately, Fail::Immediately, @@ -529,31 +497,14 @@ mod writable { let edits = t .prepare( vec![ - RefEdit { - change: change_with_id(new_id_main), - name: "main-worktree/refs/heads/new".try_into()?, - deref: false, - }, - RefEdit { - change: change_with_id(new_id_main), - name: "main-worktree/refs/bisect/good".try_into()?, - deref: false, - }, - RefEdit { - change: change_with_id(new_id), - name: "refs/bisect/good".try_into()?, - deref: false, - }, - RefEdit { - change: change_with_id(new_id), - name: "refs/worktree/private".try_into()?, - deref: false, - }, - RefEdit { - change: change_with_id(new_id), - name: "refs/heads/shared".try_into()?, - deref: false, - }, + RefEdit::new("main-worktree/refs/heads/new".try_into()?, change_with_id(new_id_main)), + RefEdit::new( + "main-worktree/refs/bisect/good".try_into()?, + change_with_id(new_id_main), + ), + RefEdit::new("refs/bisect/good".try_into()?, change_with_id(new_id)), + RefEdit::new("refs/worktree/private".try_into()?, change_with_id(new_id)), + RefEdit::new("refs/heads/shared".try_into()?, change_with_id(new_id)), ], Fail::Immediately, Fail::Immediately, diff --git a/gix-ref/tests/refs/transaction.rs b/gix-ref/tests/refs/transaction.rs index 4016d391fdd..9bfee397d06 100644 --- a/gix-ref/tests/refs/transaction.rs +++ b/gix-ref/tests/refs/transaction.rs @@ -1,10 +1,74 @@ +mod refedit { + #[test] + fn constructors_apply_common_defaults() -> crate::Result { + use gix_ref::{ + FullName, Target, + transaction::{Change, LogChange, PreviousValue, RefEdit, RefLog}, + }; + + let update_name: FullName = "refs/heads/update".try_into()?; + let new_id = crate::fixture_hash_kind().null(); + assert_eq!( + RefEdit::update( + update_name.clone(), + new_id, + PreviousValue::MustNotExist, + "update message", + ), + RefEdit { + change: Change::Update { + log: LogChange { + message: "update message".into(), + ..Default::default() + }, + expected: PreviousValue::MustNotExist, + new: Target::Object(new_id), + }, + name: update_name, + deref: false, + }, + "updates use standard reference-log handling without dereferencing" + ); + + let delete_name: FullName = "refs/heads/delete".try_into()?; + assert_eq!( + RefEdit::delete(delete_name.clone(), PreviousValue::MustExist), + RefEdit { + change: Change::Delete { + expected: PreviousValue::MustExist, + log: RefLog::AndReference, + }, + name: delete_name, + deref: false, + }, + "deletions remove the reference and its log without dereferencing" + ); + + let custom_name: FullName = "HEAD".try_into()?; + let custom_change = Change::Delete { + expected: PreviousValue::Any, + log: RefLog::Only, + }; + assert_eq!( + RefEdit::new(custom_name.clone(), custom_change.clone()).with_deref(true), + RefEdit { + change: custom_change, + name: custom_name, + deref: true, + }, + "general edits retain custom changes and configurable dereferencing" + ); + Ok(()) + } +} + mod refedit_ext { use std::{cell::RefCell, collections::BTreeMap}; use gix_object::bstr::{BString, ByteSlice}; use gix_ref::{ PartialNameRef, Target, - transaction::{Change, PreviousValue, RefEdit, RefEditsExt, RefLog}, + transaction::{PreviousValue, RefEdit, RefEditsExt}, }; #[derive(Default)] @@ -31,14 +95,7 @@ mod refedit_ext { } fn named_edit(name: &str) -> RefEdit { - RefEdit { - change: Change::Delete { - expected: PreviousValue::Any, - log: RefLog::AndReference, - }, - name: name.try_into().expect("valid name"), - deref: false, - } + RefEdit::delete(name.try_into().expect("valid name"), PreviousValue::Any) } #[test] @@ -46,22 +103,8 @@ mod refedit_ext { let store = MockStore::with(Some(("HEAD", Target::Symbolic("refs/heads/main".try_into()?)))); let mut edits = vec![ - RefEdit { - change: Change::Delete { - expected: PreviousValue::Any, - log: RefLog::AndReference, - }, - name: "HEAD".try_into()?, - deref: true, - }, - RefEdit { - change: Change::Delete { - expected: PreviousValue::Any, - log: RefLog::AndReference, - }, - name: "refs/heads/main".try_into()?, - deref: false, - }, + RefEdit::delete("HEAD".try_into()?, PreviousValue::Any).with_deref(true), + RefEdit::delete("refs/heads/main".try_into()?, PreviousValue::Any), ]; let err = edits @@ -100,7 +143,7 @@ mod refedit_ext { use gix_ref::{ PartialNameRef, Target, - transaction::{Change, LogChange, PreviousValue, RefEdit, RefEditsExt, RefLog}, + transaction::{LogChange, PreviousValue, RefEdit, RefEditsExt, RefLog}, }; use crate::{hex_to_id, transaction::refedit_ext::MockStore}; @@ -116,30 +159,17 @@ mod refedit_ext { Target::Object(gix_hash::Kind::Sha1.null()), ))); let mut edits = vec![ - RefEdit { - change: Change::Delete { - expected: PreviousValue::Any, - log: RefLog::AndReference, - }, - name: "SYMBOLIC_PROBABLY_BUT_DEREF_IS_FALSE_SO_IGNORED".try_into()?, - deref: false, - }, - RefEdit { - change: Change::Delete { - expected: PreviousValue::Any, - log: RefLog::AndReference, - }, - name: "refs/heads/anything-but-not-symbolic".try_into()?, - deref: true, - }, - RefEdit { - change: Change::Delete { - expected: PreviousValue::Any, - log: RefLog::AndReference, - }, - name: "refs/heads/does-not-exist-and-deref-is-ignored".try_into()?, - deref: true, - }, + RefEdit::delete( + "SYMBOLIC_PROBABLY_BUT_DEREF_IS_FALSE_SO_IGNORED".try_into()?, + PreviousValue::Any, + ), + RefEdit::delete("refs/heads/anything-but-not-symbolic".try_into()?, PreviousValue::Any) + .with_deref(true), + RefEdit::delete( + "refs/heads/does-not-exist-and-deref-is-ignored".try_into()?, + PreviousValue::Any, + ) + .with_deref(true), ]; edits.extend_with_splits_of_symbolic_refs(&mut |n| store.find_existing(n), &mut |_, _| { @@ -184,27 +214,18 @@ mod refedit_ext { } let mut edits = vec![ - RefEdit { - change: Change::Delete { - expected: PreviousValue::Any, - log: RefLog::AndReference, - }, - name: "refs/heads/delete-symbolic-1".try_into()?, - deref: true, - }, - RefEdit { - change: Change::Update { - expected: PreviousValue::MustNotExist, - log: LogChange { - mode: RefLog::AndReference, - force_create_reflog: true, - message: "the log message".into(), - }, - new: Target::Object(gix_hash::Kind::Sha1.null()), + RefEdit::delete("refs/heads/delete-symbolic-1".try_into()?, PreviousValue::Any).with_deref(true), + RefEdit::update_with_log( + "refs/heads/update-symbolic-1".try_into()?, + gix_hash::Kind::Sha1.null(), + PreviousValue::MustNotExist, + LogChange { + mode: RefLog::AndReference, + force_create_reflog: true, + message: "the log message".into(), }, - name: "refs/heads/update-symbolic-1".try_into()?, - deref: true, - }, + ) + .with_deref(true), ]; let store = Cycler::default(); @@ -258,23 +279,14 @@ mod refedit_ext { l }; let mut edits = vec![ - RefEdit { - change: Change::Delete { - expected: PreviousValue::Any, - log: RefLog::AndReference, - }, - name: "refs/heads/delete-symbolic-1".try_into()?, - deref: true, - }, - RefEdit { - change: Change::Update { - expected: PreviousValue::MustNotExist, - log: log.clone(), - new: Target::Object(gix_hash::Kind::Sha1.null()), - }, - name: "refs/heads/update-symbolic-1".try_into()?, - deref: true, - }, + RefEdit::delete("refs/heads/delete-symbolic-1".try_into()?, PreviousValue::Any).with_deref(true), + RefEdit::update_with_log( + "refs/heads/update-symbolic-1".try_into()?, + gix_hash::Kind::Sha1.null(), + PreviousValue::MustNotExist, + log.clone(), + ) + .with_deref(true), ]; let mut indices = Vec::new(); @@ -291,57 +303,35 @@ mod refedit_ext { assert_eq!( edits, vec![ - RefEdit { - change: Change::Delete { - expected: PreviousValue::Any, - log: RefLog::Only, - }, - name: "refs/heads/delete-symbolic-1".try_into()?, - deref: false, - }, - RefEdit { - change: Change::Update { - expected: PreviousValue::Any, - log: log_only.clone(), - new: Target::Object(gix_hash::Kind::Sha1.null()), - }, - name: "refs/heads/update-symbolic-1".try_into()?, - deref: false, - }, - RefEdit { - change: Change::Delete { - expected: PreviousValue::Any, - log: RefLog::Only, - }, - name: "refs/heads/delete-symbolic-2".try_into()?, - deref: false, - }, - RefEdit { - change: Change::Update { - expected: PreviousValue::Any, - log: log_only, - new: Target::Object(gix_hash::Kind::Sha1.null()), - }, - name: "refs/heads/update-symbolic-2".try_into()?, - deref: false, - }, - RefEdit { - change: Change::Delete { - expected: PreviousValue::Any, - log: RefLog::AndReference, - }, - name: "refs/heads/delete-symbolic-3".try_into()?, - deref: false, - }, - RefEdit { - change: Change::Update { - expected: PreviousValue::MustNotExist, - log, - new: Target::Object(gix_hash::Kind::Sha1.null()), - }, - name: "refs/heads/update-symbolic-3".try_into()?, - deref: false, - }, + RefEdit::delete_with_log( + "refs/heads/delete-symbolic-1".try_into()?, + PreviousValue::Any, + RefLog::Only, + ), + RefEdit::update_with_log( + "refs/heads/update-symbolic-1".try_into()?, + gix_hash::Kind::Sha1.null(), + PreviousValue::Any, + log_only.clone(), + ), + RefEdit::delete_with_log( + "refs/heads/delete-symbolic-2".try_into()?, + PreviousValue::Any, + RefLog::Only, + ), + RefEdit::update_with_log( + "refs/heads/update-symbolic-2".try_into()?, + gix_hash::Kind::Sha1.null(), + PreviousValue::Any, + log_only, + ), + RefEdit::delete("refs/heads/delete-symbolic-3".try_into()?, PreviousValue::Any), + RefEdit::update_with_log( + "refs/heads/update-symbolic-3".try_into()?, + gix_hash::Kind::Sha1.null(), + PreviousValue::MustNotExist, + log, + ), ] ); Ok(()) diff --git a/gix-ref/tests/transaction_fd_limit.rs b/gix-ref/tests/transaction_fd_limit.rs index 30d302f23e0..d98417084ff 100644 --- a/gix-ref/tests/transaction_fd_limit.rs +++ b/gix-ref/tests/transaction_fd_limit.rs @@ -2,8 +2,8 @@ use gix_lock::acquire::Fail; use gix_ref::{ - Target, file, - transaction::{Change, LogChange, PreviousValue, RefEdit, RefLog}, + file, + transaction::{LogChange, PreviousValue, RefEdit, RefLog}, }; /// Preparing a transaction must retain only a `gix_lock::Marker` per edit, not an open file descriptor. @@ -20,18 +20,17 @@ fn large_transactions_hold_a_constant_number_of_file_descriptors() -> gix_testto let dir = gix_testtools::tempfile::TempDir::new()?; let object_hash = gix_testtools::object_hash(); let store = file::Store::at(dir.path().into(), object_hash); - let edits = (0..20).map(|i| RefEdit { - change: Change::Update { - log: LogChange { + let edits = (0..20).map(|i| { + RefEdit::update_with_log( + format!("refs/heads/fd-{i:02}").try_into().expect("valid ref name"), + object_hash.empty_blob(), + PreviousValue::MustNotExist, + LogChange { mode: RefLog::AndReference, force_create_reflog: true, message: "log peeled".into(), }, - expected: PreviousValue::MustNotExist, - new: Target::Object(object_hash.empty_blob()), - }, - name: format!("refs/heads/fd-{i:02}").try_into().expect("valid ref name"), - deref: false, + ) }); let applied = store diff --git a/gix-refspec/Cargo.toml b/gix-refspec/Cargo.toml index ea3c040dc53..ed56f1b2664 100644 --- a/gix-refspec/Cargo.toml +++ b/gix-refspec/Cargo.toml @@ -9,7 +9,7 @@ description = "A crate of the gitoxide project for parsing and representing refs authors = ["Sebastian Thiel "] edition = "2024" include = ["/src/**/*", "/LICENSE-*", "/README.md"] -rust-version = "1.85" +rust-version = "1.88" [lib] doctest = true diff --git a/gix-refspec/src/parse.rs b/gix-refspec/src/parse.rs index 2f3bac92bd9..767b06b1790 100644 --- a/gix-refspec/src/parse.rs +++ b/gix-refspec/src/parse.rs @@ -114,10 +114,10 @@ pub(crate) mod function { } }; - if let Some(spec) = src.as_mut() { - if *spec == "@" { - *spec = "HEAD".into(); - } + if let Some(spec) = src.as_mut() + && *spec == "@" + { + *spec = "HEAD".into(); } let (src, src_had_pattern) = validated(src, operation == Operation::Push && dst.is_some())?; let (dst, dst_had_pattern) = validated(dst, false)?; diff --git a/gix-revision/Cargo.toml b/gix-revision/Cargo.toml index be8b43679bd..795c86aed97 100644 --- a/gix-revision/Cargo.toml +++ b/gix-revision/Cargo.toml @@ -9,7 +9,7 @@ description = "A crate of the gitoxide project dealing with finding names for re authors = ["Sebastian Thiel "] edition = "2024" include = ["/src/**/*", "/LICENSE-*", "/README.md"] -rust-version = "1.85" +rust-version = "1.88" [lib] doctest = false diff --git a/gix-revwalk/Cargo.toml b/gix-revwalk/Cargo.toml index 3ccbf81da10..10d18eeef35 100644 --- a/gix-revwalk/Cargo.toml +++ b/gix-revwalk/Cargo.toml @@ -9,7 +9,7 @@ description = "A crate providing utilities for walking the revision graph" authors = ["Sebastian Thiel "] edition = "2024" include = ["/src/**/*", "/LICENSE-*"] -rust-version = "1.85" +rust-version = "1.88" [lib] doctest = false diff --git a/gix-revwalk/src/graph/mod.rs b/gix-revwalk/src/graph/mod.rs index ce428136267..76501ede34e 100644 --- a/gix-revwalk/src/graph/mod.rs +++ b/gix-revwalk/src/graph/mod.rs @@ -366,13 +366,13 @@ fn try_lookup<'graph, 'cache>( cache: Option<&'cache gix_commitgraph::Graph>, buf: &'graph mut Vec, ) -> Result>, gix_object::find::existing_iter::Error> { - if let Some(cache) = cache { - if let Some(pos) = cache.lookup(id) { - return Ok(Some(LazyCommit { - object_hash: id.kind(), - backing: Either::Right((cache, pos)), - })); - } + if let Some(cache) = cache + && let Some(pos) = cache.lookup(id) + { + return Ok(Some(LazyCommit { + object_hash: id.kind(), + backing: Either::Right((cache, pos)), + })); } Ok( match objects diff --git a/gix-sec/Cargo.toml b/gix-sec/Cargo.toml index 5c39ad668ed..e2dee1e3424 100644 --- a/gix-sec/Cargo.toml +++ b/gix-sec/Cargo.toml @@ -9,7 +9,7 @@ description = "A crate of the gitoxide project providing a shared trust model" authors = ["Sebastian Thiel "] edition = "2024" include = ["/src/**/*", "/LICENSE-*"] -rust-version = "1.85" +rust-version = "1.88" [lib] doctest = false diff --git a/gix-sequencer/Cargo.toml b/gix-sequencer/Cargo.toml index cb5f724e395..c616239ec01 100644 --- a/gix-sequencer/Cargo.toml +++ b/gix-sequencer/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0" description = "A crate of the gitoxide project handling sequences of human-aided operations" authors = ["Sebastian Thiel "] edition = "2024" -rust-version = "1.85" +rust-version = "1.88" include = ["/src/**/*", "/LICENSE-*"] [lib] diff --git a/gix-shallow/Cargo.toml b/gix-shallow/Cargo.toml index 8c781e132bf..50dd8d51be7 100644 --- a/gix-shallow/Cargo.toml +++ b/gix-shallow/Cargo.toml @@ -9,7 +9,7 @@ license = "MIT OR Apache-2.0" description = "Handle files specifying the shallow boundary" edition = "2024" include = ["/src/**/*", "/LICENSE-*"] -rust-version = "1.85" +rust-version = "1.88" [lib] doctest = true diff --git a/gix-shallow/src/lib.rs b/gix-shallow/src/lib.rs index e130cc0ea02..31c5bd745d1 100644 --- a/gix-shallow/src/lib.rs +++ b/gix-shallow/src/lib.rs @@ -88,10 +88,10 @@ pub mod write { } } if shallow_commits.is_empty() { - if let Err(err) = std::fs::remove_file(file.resource_path()) { - if err.kind() != std::io::ErrorKind::NotFound { - return Err(err.into()); - } + if let Err(err) = std::fs::remove_file(file.resource_path()) + && err.kind() != std::io::ErrorKind::NotFound + { + return Err(err.into()); } drop(file); return Ok(()); diff --git a/gix-status/Cargo.toml b/gix-status/Cargo.toml index 7106385709d..9460bb11bbd 100644 --- a/gix-status/Cargo.toml +++ b/gix-status/Cargo.toml @@ -9,7 +9,7 @@ description = "A crate of the gitoxide project dealing with 'git status'-like fu authors = ["Sebastian Thiel ", "Pascal Kuthe "] edition = "2024" include = ["/src/**/*", "/LICENSE-*"] -rust-version = "1.85" +rust-version = "1.88" [lib] doctest = false diff --git a/gix-submodule/Cargo.toml b/gix-submodule/Cargo.toml index 8336e75d904..740e40d1be3 100644 --- a/gix-submodule/Cargo.toml +++ b/gix-submodule/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0" description = "A crate of the gitoxide project dealing git submodules" authors = ["Sebastian Thiel "] edition = "2024" -rust-version = "1.85" +rust-version = "1.88" include = ["/src/**/*", "/LICENSE-*"] [lib] diff --git a/gix-submodule/src/access.rs b/gix-submodule/src/access.rs index 950ed6445bf..db0dd6b7a2c 100644 --- a/gix-submodule/src/access.rs +++ b/gix-submodule/src/access.rs @@ -180,13 +180,13 @@ impl File { None => return Ok(None), }; - if let Update::Command(cmd) = &value { - if value_is_from_modules_file.unwrap_or_default() { - return Err(config::update::Error::CommandForbiddenInModulesConfiguration { - submodule: name.to_owned(), - actual: cmd.to_owned(), - }); - } + if let Update::Command(cmd) = &value + && value_is_from_modules_file.unwrap_or_default() + { + return Err(config::update::Error::CommandForbiddenInModulesConfiguration { + submodule: name.to_owned(), + actual: cmd.to_owned(), + }); } Ok(Some(value)) } diff --git a/gix-tempfile/Cargo.toml b/gix-tempfile/Cargo.toml index 603d50cf84c..6654ef5a9d8 100644 --- a/gix-tempfile/Cargo.toml +++ b/gix-tempfile/Cargo.toml @@ -9,7 +9,7 @@ description = "A tempfile implementation with a global registry to assure cleanu authors = ["Sebastian Thiel "] edition = "2024" include = ["/src/**/*", "/LICENSE-*", "/README.md"] -rust-version = "1.85" +rust-version = "1.88" [[example]] name = "delete-tempfiles-on-sigterm" diff --git a/gix-tempfile/src/registry.rs b/gix-tempfile/src/registry.rs index a0447925384..0d56e87b104 100644 --- a/gix-tempfile/src/registry.rs +++ b/gix-tempfile/src/registry.rs @@ -21,10 +21,10 @@ pub fn cleanup_tempfiles_signal_safe() { for idx in 0..one_past_last_index { if let Some(entry) = REGISTRY.try_entry(idx) { entry.and_modify(|tempfile| { - if tempfile.as_ref().is_some_and(|tf| tf.owning_process_id == current_pid) { - if let Some(tempfile) = tempfile.take() { - tempfile.drop_without_deallocation(); - } + if tempfile.as_ref().is_some_and(|tf| tf.owning_process_id == current_pid) + && let Some(tempfile) = tempfile.take() + { + tempfile.drop_without_deallocation(); } }); } diff --git a/gix-tix/src/edit/rebase.rs b/gix-tix/src/edit/rebase.rs index 590d4b92dad..6bfd76531d8 100644 --- a/gix-tix/src/edit/rebase.rs +++ b/gix-tix/src/edit/rebase.rs @@ -13,7 +13,7 @@ use gix::{ prelude::ObjectIdExt, refs::{ Category, Target, - transaction::{Change, LogChange, PreviousValue, RefEdit, RefLog}, + transaction::{LogChange, PreviousValue, RefEdit, RefLog}, }, }; @@ -3022,64 +3022,43 @@ fn update_refs( .context("an unborn HEAD must point to a branch")? .to_owned(); let new = inserted.context("an unborn insertion must create a commit")?; - edits.push(RefEdit { - name: name.clone(), - deref: false, - change: Change::Update { - log: log_change(), - expected: PreviousValue::MustNotExist, - new: Target::Object(new), - }, - }); - rollback.push(RefEdit { + edits.push(RefEdit::update_with_log( + name.clone(), + new, + PreviousValue::MustNotExist, + log_change(), + )); + rollback.push(RefEdit::delete( name, - deref: false, - change: Change::Delete { - expected: PreviousValue::MustExistAndMatch(Target::Object(new)), - log: RefLog::AndReference, - }, - }); + PreviousValue::MustExistAndMatch(Target::Object(new)), + )); } let mut reserved = HashSet::new(); for id in pins { let name = pin_name(repo, *id, &reserved)?; reserved.insert(name.clone()); - edits.push(RefEdit { - name: name.clone(), - deref: false, - change: Change::Update { - log: log_change(), - expected: PreviousValue::MustNotExist, - new: Target::Object(*id), - }, - }); - rollback.push(RefEdit { + edits.push(RefEdit::update_with_log( + name.clone(), + *id, + PreviousValue::MustNotExist, + log_change(), + )); + rollback.push(RefEdit::delete( name, - deref: false, - change: Change::Delete { - expected: PreviousValue::MustExistAndMatch(Target::Object(*id)), - log: RefLog::AndReference, - }, - }); + PreviousValue::MustExistAndMatch(Target::Object(*id)), + )); } for (name, target) in delete_refs { - edits.push(RefEdit { - name: name.clone(), - deref: false, - change: Change::Delete { - expected: PreviousValue::MustExistAndMatch(target.clone()), - log: RefLog::AndReference, - }, - }); - rollback.push(RefEdit { - name: name.clone(), - deref: false, - change: Change::Update { - log: log_change(), - expected: PreviousValue::MustNotExist, - new: target.clone(), - }, - }); + edits.push(RefEdit::delete( + name.clone(), + PreviousValue::MustExistAndMatch(target.clone()), + )); + rollback.push(RefEdit::update_with_log( + name.clone(), + target.clone(), + PreviousValue::MustNotExist, + log_change(), + )); } if edits.is_empty() { return Ok(UpdatedRefs::default()); @@ -3149,26 +3128,16 @@ fn is_missing_ref(mut err: &(dyn std::error::Error + 'static)) -> bool { } fn ref_edit(name: gix::refs::FullName, old: Option, new: Option) -> RefEdit { - RefEdit { - name, - deref: false, - change: match (old, new) { - (Some(old), Some(new)) => Change::Update { - log: log_change(), - expected: PreviousValue::MustExistAndMatch(Target::Object(old)), - new: Target::Object(new), - }, - (Some(old), None) => Change::Delete { - expected: PreviousValue::MustExistAndMatch(Target::Object(old)), - log: RefLog::AndReference, - }, - (None, Some(new)) => Change::Update { - log: log_change(), - expected: PreviousValue::MustNotExist, - new: Target::Object(new), - }, - (None, None) => unreachable!("unchanged absent refs are filtered before editing"), - }, + match (old, new) { + (Some(old), Some(new)) => RefEdit::update_with_log( + name, + new, + PreviousValue::MustExistAndMatch(Target::Object(old)), + log_change(), + ), + (Some(old), None) => RefEdit::delete(name, PreviousValue::MustExistAndMatch(Target::Object(old))), + (None, Some(new)) => RefEdit::update_with_log(name, new, PreviousValue::MustNotExist, log_change()), + (None, None) => unreachable!("unchanged absent refs are filtered before editing"), } } diff --git a/gix-tix/src/edit/stash.rs b/gix-tix/src/edit/stash.rs index 8b0eff13bc9..e57ba1ff3d7 100644 --- a/gix-tix/src/edit/stash.rs +++ b/gix-tix/src/edit/stash.rs @@ -11,7 +11,7 @@ use gix::{ bstr::{BStr, ByteSlice}, refs::{ Target, - transaction::{Change, LogChange, PreviousValue, RefEdit, RefLog}, + transaction::{PreviousValue, RefEdit}, }, }; @@ -108,30 +108,11 @@ pub(super) fn rewrite_edits( } fn create_edit(name: gix::refs::FullName, target: Target) -> RefEdit { - RefEdit { - change: Change::Update { - log: LogChange { - mode: RefLog::AndReference, - force_create_reflog: false, - message: "tix commit stash rewrite".into(), - }, - expected: PreviousValue::MustNotExist, - new: target, - }, - name, - deref: false, - } + RefEdit::update(name, target, PreviousValue::MustNotExist, "tix commit stash rewrite") } fn delete_edit(name: gix::refs::FullName, target: Target) -> RefEdit { - RefEdit { - change: Change::Delete { - expected: PreviousValue::MustExistAndMatch(target), - log: RefLog::AndReference, - }, - name, - deref: false, - } + RefEdit::delete(name, PreviousValue::MustExistAndMatch(target)) } #[tracing::instrument(skip_all, fields(commit_id = %id))] @@ -249,19 +230,12 @@ pub(super) fn save( anyhow::bail!("git stash push did not create a new stash"); } let target = Target::Object(id); - if let Err(err) = repo.edit_references([RefEdit { - change: Change::Update { - log: LogChange { - mode: RefLog::AndReference, - force_create_reflog: false, - message: reflog_message.into(), - }, - expected: PreviousValue::MustNotExist, - new: target.clone(), - }, - name: name.clone(), - deref: false, - }]) { + if let Err(err) = repo.edit_references([RefEdit::update( + name.clone(), + target.clone(), + PreviousValue::MustNotExist, + reflog_message, + )]) { drop(repo); let restore = Command::new("git") .arg("-C") @@ -337,14 +311,10 @@ pub(super) fn apply(repository_path: &Path, bare: bool, workdir: &Path, stash: S .arg(stash.name.as_bstr().to_str_lossy().as_ref()) .output() .context("could not launch git stash apply")?; - let deletion = repo.edit_references([RefEdit { - change: Change::Delete { - expected: PreviousValue::MustExistAndMatch(stash.target), - log: RefLog::AndReference, - }, - name: stash.name.clone(), - deref: false, - }]); + let deletion = repo.edit_references([RefEdit::delete( + stash.name.clone(), + PreviousValue::MustExistAndMatch(stash.target), + )]); let mut notice = if output.status.success() { format!("restored {}", stash.name.shorten()) } else { diff --git a/gix-tix/src/edit/time_travel.rs b/gix-tix/src/edit/time_travel.rs index 72c934aa0bd..af053501de2 100644 --- a/gix-tix/src/edit/time_travel.rs +++ b/gix-tix/src/edit/time_travel.rs @@ -12,7 +12,7 @@ use gix::{ bstr::ByteSlice, refs::{ Target, - transaction::{Change, LogChange, PreviousValue, RefEdit, RefLog}, + transaction::{PreviousValue, RefEdit}, }, }; @@ -643,19 +643,7 @@ pub(crate) fn attach_reporting( } fn checked_ref_edit(name: gix::refs::FullName, old: Target, new: Target, message: &str) -> RefEdit { - RefEdit { - name, - deref: false, - change: Change::Update { - log: LogChange { - mode: RefLog::AndReference, - force_create_reflog: false, - message: message.into(), - }, - expected: PreviousValue::MustExistAndMatch(old), - new, - }, - } + RefEdit::update(name, new, PreviousValue::MustExistAndMatch(old), message) } fn cleanup_new_pins( @@ -1050,19 +1038,7 @@ fn create_or_update_head_pin_reporting( PreviousValue::MustExistAndMatch(reference.target().into_owned()) }); let target = Target::Symbolic(branch.clone()); - let edit = RefEdit { - change: Change::Update { - log: LogChange { - mode: RefLog::AndReference, - force_create_reflog: false, - message: "tix remember HEAD branch".into(), - }, - expected, - new: target.clone(), - }, - name: name.clone(), - deref: false, - }; + let edit = RefEdit::update(name.clone(), target.clone(), expected, "tix remember HEAD branch"); let applied = repository .edit_references([edit]) .context("could not remember the branch HEAD was attached to")?; @@ -1186,19 +1162,12 @@ pub(crate) fn create_pin_reporting( suffix_len = hex.len() + 1; } }; - let edit = RefEdit { - change: Change::Update { - log: LogChange { - mode: RefLog::AndReference, - force_create_reflog: false, - message: reflog_message.into(), - }, - expected: PreviousValue::MustNotExist, - new: target.clone(), - }, - name: name.clone(), - deref: false, - }; + let edit = RefEdit::update( + name.clone(), + target.clone(), + PreviousValue::MustNotExist, + reflog_message, + ); let applied = repository.edit_references([edit]).context("could not create tix pin")?; let changes = super::undo::changes_from_edits(applied)?; Ok((history::Pin { name, target, id }, changes)) @@ -1271,14 +1240,7 @@ pub(crate) fn toggle_pin_reporting( } fn delete_pin_edit(pin: &history::Pin) -> RefEdit { - RefEdit { - change: Change::Delete { - expected: PreviousValue::MustExistAndMatch(pin.target.clone()), - log: RefLog::AndReference, - }, - name: pin.name.clone(), - deref: false, - } + RefEdit::delete(pin.name.clone(), PreviousValue::MustExistAndMatch(pin.target.clone())) } fn delete_deferred_refs( @@ -1293,14 +1255,7 @@ fn delete_deferred_refs( .context("could not reopen repository to finish reference deletions")?; let edits: Vec<_> = refs .iter() - .map(|(name, old)| RefEdit { - name: name.clone(), - deref: false, - change: Change::Delete { - expected: PreviousValue::MustExistAndMatch(Target::Object(*old)), - log: RefLog::AndReference, - }, - }) + .map(|(name, old)| RefEdit::delete(name.clone(), PreviousValue::MustExistAndMatch(Target::Object(*old)))) .collect(); let applied = repository .edit_references(edits) @@ -1333,19 +1288,12 @@ fn checkout_reference( checkout_detached(workdir, selected)?; open_repository(repository_path, bare, false) .context("could not reopen repository to attach HEAD")? - .edit_reference(RefEdit { - name: "HEAD".try_into().expect("valid reference name"), - deref: false, - change: Change::Update { - log: LogChange { - mode: RefLog::AndReference, - force_create_reflog: false, - message: "tix attach HEAD".into(), - }, - expected: PreviousValue::MustExistAndMatch(Target::Object(selected)), - new: Target::Symbolic(name.clone()), - }, - }) + .edit_reference(RefEdit::update( + "HEAD".try_into().expect("valid reference name"), + name.clone(), + PreviousValue::MustExistAndMatch(Target::Object(selected)), + "tix attach HEAD", + )) .context("could not attach HEAD to the selected reference")?; Ok(()) } diff --git a/gix-tix/src/edit/undo.rs b/gix-tix/src/edit/undo.rs index 1316d446e74..a4aea076e1c 100644 --- a/gix-tix/src/edit/undo.rs +++ b/gix-tix/src/edit/undo.rs @@ -179,14 +179,10 @@ pub(crate) fn clear(repo: &gix::Repository) -> Result<()> { else { continue; }; - edits.push(RefEdit { - name: reference.name().to_owned(), - deref: false, - change: Change::Delete { - expected: PreviousValue::MustExistAndMatch(reference.target().into_owned()), - log: RefLog::AndReference, - }, - }); + edits.push(RefEdit::delete( + reference.name().to_owned(), + PreviousValue::MustExistAndMatch(reference.target().into_owned()), + )); } if edits.is_empty() { return Ok(()); @@ -542,25 +538,18 @@ fn checked_edit(change: &RefChange) -> Result { log: log_change(), }, }; - Ok(RefEdit { - name: change.name.clone(), - deref: false, - change: tx_change, - }) + Ok(RefEdit::new(change.name.clone(), tx_change)) } fn queue_update(name: &str, old: Option, new: ObjectId) -> Result { - Ok(RefEdit { - name: name.try_into().context("the undo queue reference name is invalid")?, - deref: false, - change: Change::Update { - expected: old.map_or(PreviousValue::MustNotExist, |id| { - PreviousValue::MustExistAndMatch(Target::Object(id)) - }), - new: Target::Object(new), - log: log_change(), - }, - }) + Ok(RefEdit::update_with_log( + name.try_into().context("the undo queue reference name is invalid")?, + new, + old.map_or(PreviousValue::MustNotExist, |id| { + PreviousValue::MustExistAndMatch(Target::Object(id)) + }), + log_change(), + )) } fn log_change() -> LogChange { diff --git a/gix-trace/Cargo.toml b/gix-trace/Cargo.toml index 098d0bfef34..e26df1c670d 100644 --- a/gix-trace/Cargo.toml +++ b/gix-trace/Cargo.toml @@ -8,7 +8,7 @@ version = "0.1.21" authors = ["Sebastian Thiel "] license = "MIT OR Apache-2.0" edition = "2024" -rust-version = "1.85" +rust-version = "1.88" include = ["/src/**/*", "/LICENSE-*"] [lib] diff --git a/gix-transport/Cargo.toml b/gix-transport/Cargo.toml index f8bac61bde8..137589a7e3a 100644 --- a/gix-transport/Cargo.toml +++ b/gix-transport/Cargo.toml @@ -9,7 +9,7 @@ description = "A crate of the gitoxide project dedicated to implementing the git authors = ["Sebastian Thiel "] edition = "2024" include = ["/src/**/*", "/LICENSE-*"] -rust-version = "1.85" +rust-version = "1.88" [lib] doctest = false diff --git a/gix-transport/src/client/blocking_io/http/curl/remote.rs b/gix-transport/src/client/blocking_io/http/curl/remote.rs index d98ae97e0b3..d9fe1bd8582 100644 --- a/gix-transport/src/client/blocking_io/http/curl/remote.rs +++ b/gix-transport/src/client/blocking_io/http/curl/remote.rs @@ -370,12 +370,11 @@ pub fn new() -> Worker { handle.cainfo(ca_info)?; } - if let Some(ref mut curl_options) = backend.as_ref().and_then(|backend| backend.lock().ok()) { - if let Some(opts) = curl_options.downcast_mut::() { - if let Some(enabled) = opts.schannel_check_revoke { - handle.ssl_options(curl::easy::SslOpt::new().no_revoke(!enabled))?; - } - } + if let Some(ref mut curl_options) = backend.as_ref().and_then(|backend| backend.lock().ok()) + && let Some(opts) = curl_options.downcast_mut::() + && let Some(enabled) = opts.schannel_check_revoke + { + handle.ssl_options(curl::easy::SslOpt::new().no_revoke(!enabled))?; } if let Some(ssl_version) = ssl_version { @@ -531,10 +530,9 @@ pub fn new() -> Worker { (Some(header), mut data) => { if let Err(TrySendError::Disconnected(err) | TrySendError::Full(err)) = header.channel.try_send(err) + && let Some(body) = data.take() { - if let Some(body) = data.take() { - body.channel.try_send(err).ok(); - } + body.channel.try_send(err).ok(); } } (None, Some(body)) => { diff --git a/gix-transport/src/client/blocking_io/http/reqwest/remote.rs b/gix-transport/src/client/blocking_io/http/reqwest/remote.rs index ac2c9cb6121..f60b431259d 100644 --- a/gix-transport/src/client/blocking_io/http/reqwest/remote.rs +++ b/gix-transport/src/client/blocking_io/http/reqwest/remote.rs @@ -150,13 +150,12 @@ impl Default for Remote { }; let mut req = req_builder.build()?; let mut has_configure_request = false; - if let Some(ref mut request_options) = config.backend.as_ref().and_then(|backend| backend.lock().ok()) { - if let Some(options) = request_options.downcast_mut::() { - if let Some(configure_request) = &mut options.configure_request { - has_configure_request = true; - configure_request(&mut req)?; - } - } + if let Some(ref mut request_options) = config.backend.as_ref().and_then(|backend| backend.lock().ok()) + && let Some(options) = request_options.downcast_mut::() + && let Some(configure_request) = &mut options.configure_request + { + has_configure_request = true; + configure_request(&mut req)?; } let follow = follow.get_or_insert(config.follow_redirects); @@ -180,11 +179,11 @@ impl Default for Remote { Err(err) => { // `error_for_status()` preserves the final URL for HTTP error responses. Capture it here so // authentication retries after redirected 401 responses use the redirected base URL. - if let Some(actual_url) = err.url().map(reqwest::Url::as_str) { - if actual_url != effective_url { - let new_base_url = redirect::base_url(actual_url, &base_url, url.clone())?; - *redirected_base_url_shared.lock() = Some(new_base_url); - } + if let Some(actual_url) = err.url().map(reqwest::Url::as_str) + && actual_url != effective_url + { + let new_base_url = redirect::base_url(actual_url, &base_url, url.clone())?; + *redirected_base_url_shared.lock() = Some(new_base_url); } let err = match err.status() { Some(status) => { diff --git a/gix-traverse/Cargo.toml b/gix-traverse/Cargo.toml index 15f7ef4b653..f42a4bc49fd 100644 --- a/gix-traverse/Cargo.toml +++ b/gix-traverse/Cargo.toml @@ -9,7 +9,7 @@ description = "A crate of the gitoxide project" authors = ["Sebastian Thiel "] edition = "2024" include = ["/src/**/*", "/LICENSE-*"] -rust-version = "1.85" +rust-version = "1.88" [lib] doctest = false diff --git a/gix-tui/Cargo.toml b/gix-tui/Cargo.toml index 7c99e0016fc..de03fa1da7f 100644 --- a/gix-tui/Cargo.toml +++ b/gix-tui/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0" description = "A crate of the gitoxide project dedicated to a terminal user interface to interact with git repositories" authors = ["Sebastian Thiel "] edition = "2024" -rust-version = "1.85" +rust-version = "1.88" include = ["/src/**/*", "/LICENSE-*"] [[bin]] diff --git a/gix-url/Cargo.toml b/gix-url/Cargo.toml index 13b69ebd8b6..3bec66e41a9 100644 --- a/gix-url/Cargo.toml +++ b/gix-url/Cargo.toml @@ -9,7 +9,7 @@ description = "A crate of the gitoxide project implementing parsing and serializ authors = ["Sebastian Thiel "] edition = "2024" include = ["/src/**/*", "/LICENSE-*", "/tests/baseline/**/*"] -rust-version = "1.85" +rust-version = "1.88" [lib] doctest = true diff --git a/gix-url/src/lib.rs b/gix-url/src/lib.rs index 83a0396efc8..ecdac4aa797 100644 --- a/gix-url/src/lib.rs +++ b/gix-url/src/lib.rs @@ -305,10 +305,10 @@ impl Url { path: BString, serialize_alternative_form: bool, ) -> Result { - if let Scheme::Helper(name) = &scheme { - if !parse::is_valid_remote_helper_name(name.as_bytes()) { - return Err(parse::Error::InvalidRemoteHelperName { name: name.clone() }); - } + if let Scheme::Helper(name) = &scheme + && !parse::is_valid_remote_helper_name(name.as_bytes()) + { + return Err(parse::Error::InvalidRemoteHelperName { name: name.clone() }); } let is_http = matches!(scheme, Scheme::Http | Scheme::Https); let mut parsed = parse( @@ -529,10 +529,10 @@ impl Url { /// public field mutation may return an error. pub fn write_to(&self, out: &mut dyn std::io::Write) -> std::io::Result<()> { if matches!(self.scheme, Scheme::Ext | Scheme::Helper(_)) { - if let Scheme::Helper(name) = &self.scheme { - if !parse::is_valid_remote_helper_name(name.as_bytes()) { - return Err(std::io::Error::other("invalid remote-helper name")); - } + if let Scheme::Helper(name) = &self.scheme + && !parse::is_valid_remote_helper_name(name.as_bytes()) + { + return Err(std::io::Error::other("invalid remote-helper name")); } if self.user.is_some() || self.password.is_some() || self.host.is_some() || self.port.is_some() { return Err(std::io::Error::other( diff --git a/gix-url/src/parse.rs b/gix-url/src/parse.rs index d56cd244f69..091050fe4a4 100644 --- a/gix-url/src/parse.rs +++ b/gix-url/src/parse.rs @@ -222,10 +222,10 @@ pub(crate) fn url(input: &BStr, protocol_end: usize) -> Result"] edition = "2024" -rust-version = "1.85" +rust-version = "1.88" include = ["/src/**/*", "/LICENSE-*"] [lib] diff --git a/gix-utils/src/str.rs b/gix-utils/src/str.rs index ecb84a3037d..79efa940951 100644 --- a/gix-utils/src/str.rs +++ b/gix-utils/src/str.rs @@ -20,13 +20,12 @@ pub fn precompose(s: Cow<'_, str>) -> Cow<'_, str> { /// Returns `true` if `ch` was composed into the starter, or `false` if it was appended unchanged. fn push(out: &mut Vec, starter: &mut Option, max_class: &mut u8, ch: char) -> bool { let class = char::canonical_combining_class(ch); - if let Some(starter) = *starter { - if *max_class == 0 || *max_class < class { - if let Some(composed) = char::compose(out[starter], ch) { - out[starter] = composed; - return true; - } - } + if let Some(starter) = *starter + && (*max_class == 0 || *max_class < class) + && let Some(composed) = char::compose(out[starter], ch) + { + out[starter] = composed; + return true; } if class == 0 { *starter = Some(out.len()); diff --git a/gix-validate/Cargo.toml b/gix-validate/Cargo.toml index 651c30d78be..d841a29de7e 100644 --- a/gix-validate/Cargo.toml +++ b/gix-validate/Cargo.toml @@ -9,7 +9,7 @@ description = "Validation functions for various kinds of names in git" authors = ["Sebastian Thiel "] edition = "2024" include = ["/src/**/*", "/LICENSE-*"] -rust-version = "1.85" +rust-version = "1.88" [lib] doctest = true diff --git a/gix-validate/src/path.rs b/gix-validate/src/path.rs index f551fee6200..1f5541d6c5f 100644 --- a/gix-validate/src/path.rs +++ b/gix-validate/src/path.rs @@ -125,10 +125,8 @@ pub fn component( return Err(component::Error::SymlinkedGitModules); } - if protect_windows { - if let Some(err) = check_win_devices_and_illegal_characters(input) { - return Err(err); - } + if protect_windows && let Some(err) = check_win_devices_and_illegal_characters(input) { + return Err(err); } } diff --git a/gix-worktree-state/Cargo.toml b/gix-worktree-state/Cargo.toml index d7dd7dc65ed..998df6c2206 100644 --- a/gix-worktree-state/Cargo.toml +++ b/gix-worktree-state/Cargo.toml @@ -9,7 +9,7 @@ description = "A crate of the gitoxide project implementing setting the worktree authors = ["Sebastian Thiel "] edition = "2024" include = ["/src/**/*", "/LICENSE-*"] -rust-version = "1.85" +rust-version = "1.88" [lib] doctest = false diff --git a/gix-worktree-stream/Cargo.toml b/gix-worktree-stream/Cargo.toml index dfeb0cc8137..6028f0fbddc 100644 --- a/gix-worktree-stream/Cargo.toml +++ b/gix-worktree-stream/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0" description = "generate a byte-stream from a git-tree" authors = ["Sebastian Thiel "] edition = "2024" -rust-version = "1.85" +rust-version = "1.88" include = ["/src/**/*", "/LICENSE-*"] [lib] diff --git a/gix-worktree/Cargo.toml b/gix-worktree/Cargo.toml index 6ad7a94b10e..c35d59ab801 100644 --- a/gix-worktree/Cargo.toml +++ b/gix-worktree/Cargo.toml @@ -9,7 +9,7 @@ description = "A crate of the gitoxide project for shared worktree related types authors = ["Sebastian Thiel "] edition = "2024" include = ["/src/**/*", "/LICENSE-*"] -rust-version = "1.85" +rust-version = "1.88" [lib] doctest = false diff --git a/gix-zlib/Cargo.toml b/gix-zlib/Cargo.toml index 495659d25b9..dd97e05516d 100644 --- a/gix-zlib/Cargo.toml +++ b/gix-zlib/Cargo.toml @@ -8,7 +8,7 @@ version = "0.1.0" authors = ["Sebastian Thiel "] license = "MIT OR Apache-2.0" edition = "2024" -rust-version = "1.85" +rust-version = "1.88" include = ["/src/**/*", "/LICENSE-*"] [lib] diff --git a/gix/Cargo.toml b/gix/Cargo.toml index 119fc8aac46..31aa32ac313 100644 --- a/gix/Cargo.toml +++ b/gix/Cargo.toml @@ -9,9 +9,9 @@ version = "0.87.1" authors = ["Sebastian Thiel "] edition = "2024" include = ["/src/**/*", "/LICENSE-*"] -# Rust 1.85 is required so hash-related dependencies can use Rust 2024 crates, +# Rust 1.88 is required so hash-related dependencies can use Rust 2024 crates, # notably `sha2` 0.11 and `hashbrown` 0.17. -rust-version = "1.85" +rust-version = "1.88" [lib] doctest = true diff --git a/gix/examples/clone.rs b/gix/examples/clone.rs index 294a0746f94..0251015fa0a 100644 --- a/gix/examples/clone.rs +++ b/gix/examples/clone.rs @@ -21,7 +21,7 @@ fn main() -> anyhow::Result<()> { println!("Url: {:?}", url.to_bstring()); let mut prepare_clone = gix::prepare_clone(url, &dst)?; - println!("Cloning {repo_url:?} into {dst:?}..."); + println!("Cloning {} into {}...", repo_url.display(), dst.display()); let (mut prepare_checkout, _) = prepare_clone.fetch_then_checkout(gix::progress::Discard, &gix::interrupt::IS_INTERRUPTED)?; diff --git a/gix/src/clone/fetch/util.rs b/gix/src/clone/fetch/util.rs index b151315203d..ebb8154e536 100644 --- a/gix/src/clone/fetch/util.rs +++ b/gix/src/clone/fetch/util.rs @@ -130,10 +130,7 @@ pub fn update_head( ref_name: Option<&PartialName>, revision: Option<&gix_refspec::RefSpec>, ) -> Result<(), Error> { - use gix_ref::{ - Target, - transaction::{PreviousValue, RefEdit}, - }; + use gix_ref::transaction::{PreviousValue, RefEdit}; let revision_head_id = revision .map(|revision| -> Result { let mapping = find_revision(ref_map, revision)?; @@ -192,25 +189,19 @@ pub fn update_head( )) .prepare( { - let mut edits = vec![RefEdit { - change: gix_ref::transaction::Change::Update { - log: reflog_message(), - expected: PreviousValue::Any, - new: Target::Symbolic(referent.clone()), - }, - name: head.clone(), - deref: false, - }]; + let mut edits = vec![RefEdit::update_with_log( + head.clone(), + referent.clone(), + PreviousValue::Any, + reflog_message(), + )]; if let Some(head_peeled_id) = head_peeled_id { - edits.push(RefEdit { - change: gix_ref::transaction::Change::Update { - log: reflog_message(), - expected: PreviousValue::Any, - new: Target::Object(head_peeled_id.to_owned()), - }, - name: referent.clone(), - deref: false, - }); + edits.push(RefEdit::update_with_log( + referent.clone(), + head_peeled_id.to_owned(), + PreviousValue::Any, + reflog_message(), + )); } edits }, @@ -228,33 +219,25 @@ pub fn update_head( if let Some(head_peeled_id) = head_peeled_id { let mut log = reflog_message(); log.mode = RefLog::Only; - repo.edit_reference(RefEdit { - change: gix_ref::transaction::Change::Update { - log, - expected: PreviousValue::Any, - new: Target::Object(head_peeled_id.to_owned()), - }, - name: head, - deref: false, - })?; + repo.edit_reference(RefEdit::update_with_log( + head, + head_peeled_id.to_owned(), + PreviousValue::Any, + log, + ))?; } setup_branch_config(repo, referent.as_ref(), head_peeled_id, remote_name)?; } None => { - repo.edit_reference(RefEdit { - change: gix_ref::transaction::Change::Update { - log: reflog_message(), - expected: PreviousValue::Any, - new: Target::Object( - head_peeled_id - .expect("detached heads always point to something") - .to_owned(), - ), - }, - name: head, - deref: false, - })?; + repo.edit_reference(RefEdit::update_with_log( + head, + head_peeled_id + .expect("detached heads always point to something") + .to_owned(), + PreviousValue::Any, + reflog_message(), + ))?; } } Ok(()) diff --git a/gix/src/discover.rs b/gix/src/discover.rs index 2b9381daebb..7979c68ea77 100644 --- a/gix/src/discover.rs +++ b/gix/src/discover.rs @@ -91,10 +91,9 @@ impl ThreadSafeRepository { if let Some(cross_fs) = std::env::var_os("GIT_DISCOVERY_ACROSS_FILESYSTEM") .and_then(|v| Vec::from_os_string(v).ok().map(BString::from)) + && let Ok(b) = gix_config::Boolean::try_from(cross_fs) { - if let Ok(b) = gix_config::Boolean::try_from(cross_fs) { - opts.cross_fs = b.into(); - } + opts.cross_fs = b.into(); } opts } diff --git a/gix/src/init.rs b/gix/src/init.rs index c4b842d01bd..b537c021c4a 100644 --- a/gix/src/init.rs +++ b/gix/src/init.rs @@ -2,7 +2,7 @@ use std::path::Path; use gix_ref::{ - Category, FullName, Target, + Category, FullName, store::WriteReflog, transaction::{PreviousValue, RefEdit}, }; @@ -98,15 +98,12 @@ impl ThreadSafeRepository { let mut repo = repo.to_thread_local(); let prev_write_reflog = repo.refs.write_reflog; repo.refs.write_reflog = WriteReflog::Disable; - repo.edit_reference(RefEdit { - change: gix_ref::transaction::Change::Update { - log: Default::default(), - expected: PreviousValue::Any, - new: Target::Symbolic(sym_ref), - }, - name: "HEAD".try_into().expect("valid"), - deref: false, - })?; + repo.edit_reference(RefEdit::update( + "HEAD".try_into().expect("valid"), + sym_ref, + PreviousValue::Any, + "", + ))?; repo.refs.write_reflog = prev_write_reflog; } diff --git a/gix/src/open/repository.rs b/gix/src/open/repository.rs index ab9a8818d09..5dc4bf47c1d 100644 --- a/gix/src/open/repository.rs +++ b/gix/src/open/repository.rs @@ -198,25 +198,25 @@ impl ThreadSafeRepository { if repo_config.precompose_unicode { git_dir = gix_utils::str::precompose_path(git_dir.into()).into_owned(); - if let Some(common_dir) = common_dir.as_mut() { - if let Cow::Owned(precomposed) = gix_utils::str::precompose_path((&*common_dir).into()) { - *common_dir = precomposed; - } + if let Some(common_dir) = common_dir.as_mut() + && let Cow::Owned(precomposed) = gix_utils::str::precompose_path((&*common_dir).into()) + { + *common_dir = precomposed; } - if let Some(worktree_dir) = worktree_dir.as_mut() { - if let Cow::Owned(precomposed) = gix_utils::str::precompose_path((&*worktree_dir).into()) { - *worktree_dir = precomposed; - } + if let Some(worktree_dir) = worktree_dir.as_mut() + && let Cow::Owned(precomposed) = gix_utils::str::precompose_path((&*worktree_dir).into()) + { + *worktree_dir = precomposed; } } let common_dir_ref = common_dir.as_deref().unwrap_or(&git_dir); let current_dir = { let current_dir_ref = current_dir.as_mut().expect("BUG: current_dir must be set by caller"); - if repo_config.precompose_unicode { - if let Cow::Owned(precomposed) = gix_utils::str::precompose_path((&*current_dir_ref).into()) { - *current_dir_ref = precomposed; - } + if repo_config.precompose_unicode + && let Cow::Owned(precomposed) = gix_utils::str::precompose_path((&*current_dir_ref).into()) + { + *current_dir_ref = precomposed; } current_dir_ref.as_path() }; diff --git a/gix/src/reference/edits.rs b/gix/src/reference/edits.rs index a6210ca7a01..c10fcd13c46 100644 --- a/gix/src/reference/edits.rs +++ b/gix/src/reference/edits.rs @@ -51,7 +51,7 @@ pub mod set_target_id { /// pub mod delete { - use gix_ref::transaction::{Change, PreviousValue, RefEdit, RefLog}; + use gix_ref::transaction::{PreviousValue, RefEdit}; use crate::Reference; @@ -60,14 +60,10 @@ pub mod delete { /// Note that this instance remains available in memory but probably shouldn't be used anymore. pub fn delete(&self) -> Result<(), crate::reference::edit::Error> { self.repo - .edit_reference(RefEdit { - change: Change::Delete { - expected: PreviousValue::MustExistAndMatch(self.inner.target.clone()), - log: RefLog::AndReference, - }, - name: self.inner.name.clone(), - deref: false, - }) + .edit_reference(RefEdit::delete( + self.inner.name.clone(), + PreviousValue::MustExistAndMatch(self.inner.target.clone()), + )) .map(|_| ()) } } diff --git a/gix/src/remote/connection/fetch/receive_pack.rs b/gix/src/remote/connection/fetch/receive_pack.rs index e580f6db8fd..6ff2e0fc75d 100644 --- a/gix/src/remote/connection/fetch/receive_pack.rs +++ b/gix/src/remote/connection/fetch/receive_pack.rs @@ -230,12 +230,11 @@ where self.write_packed_refs, )?; - if let Some(bundle) = write_pack_bundle.as_mut() { - if !update_refs.edits.is_empty() || bundle.index.num_objects == 0 { - if let Some(path) = bundle.keep_path.take() { - std::fs::remove_file(&path).map_err(|err| Error::RemovePackKeepFile { path, source: err })?; - } - } + if let Some(bundle) = write_pack_bundle.as_mut() + && (!update_refs.edits.is_empty() || bundle.index.num_objects == 0) + && let Some(path) = bundle.keep_path.take() + { + std::fs::remove_file(&path).map_err(|err| Error::RemovePackKeepFile { path, source: err })?; } let out = Outcome { diff --git a/gix/src/remote/connection/fetch/update_refs/mod.rs b/gix/src/remote/connection/fetch/update_refs/mod.rs index fac23639553..4c72f937adb 100644 --- a/gix/src/remote/connection/fetch/update_refs/mod.rs +++ b/gix/src/remote/connection/fetch/update_refs/mod.rs @@ -2,7 +2,7 @@ use gix_object::Exists; use gix_ref::{ Target, TargetRef, - transaction::{Change, LogChange, PreviousValue, RefEdit, RefLog}, + transaction::{Change, PreviousValue, RefEdit}, }; use crate::{ @@ -104,18 +104,19 @@ pub(crate) fn update( ) { // `None` only if unborn. let remote_id = remote.as_id(); - if matches!(dry_run, fetch::DryRun::No) && !remote_id.is_none_or(|id| repo.objects.exists(id)) { - if let Some(remote_id) = remote_id.filter(|id| !repo.objects.exists(id)) { - let update = if is_implicit_tag { - Mode::ImplicitTagNotSentByRemote.into() - } else { - // Assure the ODB is not to blame for the missing object. - repo.try_find_object(remote_id)?; - Mode::RejectedSourceObjectNotFound { id: remote_id.into() }.into() - }; - updates.push(update); - continue; - } + if matches!(dry_run, fetch::DryRun::No) + && !remote_id.is_none_or(|id| repo.objects.exists(id)) + && let Some(remote_id) = remote_id.filter(|id| !repo.objects.exists(id)) + { + let update = if is_implicit_tag { + Mode::ImplicitTagNotSentByRemote.into() + } else { + // Assure the ODB is not to blame for the missing object. + repo.try_find_object(remote_id)?; + Mode::RejectedSourceObjectNotFound { id: remote_id.into() }.into() + }; + updates.push(update); + continue; } let (mode, edit_index, type_change) = match local { Some(name) => { @@ -268,21 +269,9 @@ pub(crate) fn update( let anticipated_update_index = updates.len(); edit_indices_to_validate.push((anticipated_update_index, edit_index)); } - let edit = RefEdit { - change: Change::Update { - log: LogChange { - mode: RefLog::AndReference, - force_create_reflog: false, - message: message.compose(reflog_message), - }, - expected: previous_value, - new, - }, - name, - // We must not deref symrefs or we will overwrite their destination, which might be checked out - // and we don't check for that case. - deref: false, - }; + // We must not deref symrefs or we will overwrite their destination, which might be checked out + // and we don't check for that case. + let edit = RefEdit::update(name, new, previous_value, message.compose(reflog_message)); edits.push(edit); (mode, Some(edit_index), type_change) } diff --git a/gix/src/remote/connection/fetch/update_refs/tests.rs b/gix/src/remote/connection/fetch/update_refs/tests.rs index 55b3ac8e73b..cec52444205 100644 --- a/gix/src/remote/connection/fetch/update_refs/tests.rs +++ b/gix/src/remote/connection/fetch/update_refs/tests.rs @@ -56,7 +56,7 @@ mod update { } use gix_ref::{ Target, TargetRef, - transaction::{Change, LogChange, PreviousValue, RefEdit, RefLog}, + transaction::{Change, PreviousValue, RefEdit}, }; use crate::{ @@ -315,21 +315,12 @@ mod update { assert_eq!(out.edits.len(), 1, "we are OK with updating unborn refs"); assert_eq!( out.edits[0], - RefEdit { - change: Change::Update { - log: LogChange { - mode: RefLog::AndReference, - force_create_reflog: false, - message: "action: change unborn ref".into(), - }, - expected: PreviousValue::MustExistAndMatch(Target::Symbolic( - "refs/heads/main".try_into().expect("valid"), - )), - new: Target::Symbolic("refs/heads/main".try_into().expect("valid")), - }, - name: "refs/heads/existing-unborn-symbolic".try_into().expect("valid"), - deref: false, - } + RefEdit::update( + "refs/heads/existing-unborn-symbolic".try_into().expect("valid"), + Target::Symbolic("refs/heads/main".try_into().expect("valid")), + PreviousValue::MustExistAndMatch(Target::Symbolic("refs/heads/main".try_into().expect("valid"),)), + "action: change unborn ref", + ) ); let (mappings, specs) = mapping_from_spec("HEAD:refs/heads/existing-unborn-symbolic-other", &repo); @@ -359,21 +350,12 @@ mod update { ); assert_eq!( out.edits[0], - RefEdit { - change: Change::Update { - log: LogChange { - mode: RefLog::AndReference, - force_create_reflog: false, - message: "action: change unborn ref".into(), - }, - expected: PreviousValue::MustExistAndMatch(Target::Symbolic( - "refs/heads/other".try_into().expect("valid"), - )), - new: Target::Symbolic("refs/heads/main".try_into().expect("valid")), - }, - name: "refs/heads/existing-unborn-symbolic-other".try_into().expect("valid"), - deref: false, - } + RefEdit::update( + "refs/heads/existing-unborn-symbolic-other".try_into().expect("valid"), + Target::Symbolic("refs/heads/main".try_into().expect("valid")), + PreviousValue::MustExistAndMatch(Target::Symbolic("refs/heads/other".try_into().expect("valid"),)), + "action: change unborn ref", + ) ); Ok(()) } @@ -407,19 +389,12 @@ mod update { let target = Target::Object(peeled_id(&remote_repo, "refs/heads/symbolic")); assert_eq!( out.edits[0], - RefEdit { - change: Change::Update { - log: LogChange { - mode: RefLog::AndReference, - force_create_reflog: false, - message: "action: storing head".into(), - }, - expected: PreviousValue::ExistingMustMatch(target.clone()), - new: target, - }, - name: "refs/heads/new".try_into().expect("valid"), - deref: false, - }, + RefEdit::update( + "refs/heads/new".try_into().expect("valid"), + target.clone(), + PreviousValue::ExistingMustMatch(target), + "action: storing head", + ), "we create local-refs whose targets aren't present yet, even though the remote knows them.\ This leaves the caller with assuring all refs are mentioned in mappings." ); @@ -501,19 +476,12 @@ mod update { type_change: None, edit_index: Some(0), }, - Some(RefEdit { - change: Change::Update { - log: LogChange { - mode: RefLog::AndReference, - force_create_reflog: false, - message: "action: storing head".into(), - }, - expected: PreviousValue::ExistingMustMatch(Target::Object(main_id)), - new: Target::Object(main_id), - }, - name: "refs/heads/HEAD".try_into().expect("valid"), - deref: false, - }), + Some(RefEdit::update( + "refs/heads/HEAD".try_into().expect("valid"), + main_id, + PreviousValue::ExistingMustMatch(Target::Object(main_id)), + "action: storing head", + )), ), ( // attempt to overwrite checked out branch fails @@ -537,21 +505,12 @@ mod update { type_change: Some(TypeChange::SymbolicToDirect), edit_index: Some(0), }, - Some(RefEdit { - change: Change::Update { - log: LogChange { - mode: RefLog::AndReference, - force_create_reflog: false, - message: "action: no update will be performed".into(), - }, - expected: PreviousValue::MustExistAndMatch(Target::Symbolic( - "refs/heads/main".try_into().expect("valid"), - )), - new: Target::Object(main_id), - }, - name: "refs/heads/symbolic".try_into().expect("valid"), - deref: false, - }), + Some(RefEdit::update( + "refs/heads/symbolic".try_into().expect("valid"), + main_id, + PreviousValue::MustExistAndMatch(Target::Symbolic("refs/heads/main".try_into().expect("valid"))), + "action: no update will be performed", + )), ), ( // unmapped symbolic refs are peeled, so the direct ref remains direct @@ -562,19 +521,12 @@ mod update { type_change: None, edit_index: Some(0), }, - Some(RefEdit { - change: Change::Update { - log: LogChange { - mode: RefLog::AndReference, - force_create_reflog: false, - message: "action: no update will be performed".into(), - }, - expected: PreviousValue::MustExistAndMatch(Target::Object(main_id)), - new: Target::Object(main_id), - }, - name: "refs/remotes/origin/a".try_into().expect("valid"), - deref: false, - }), + Some(RefEdit::update( + "refs/remotes/origin/a".try_into().expect("valid"), + main_id, + PreviousValue::MustExistAndMatch(Target::Object(main_id)), + "action: no update will be performed", + )), ), ( // symbolic refs with unmapped targets are peeled, even if source and destination names match @@ -585,21 +537,12 @@ mod update { type_change: Some(TypeChange::SymbolicToDirect), edit_index: Some(0), }, - Some(RefEdit { - change: Change::Update { - log: LogChange { - mode: RefLog::AndReference, - force_create_reflog: false, - message: "action: no update will be performed".into(), - }, - expected: PreviousValue::MustExistAndMatch(Target::Symbolic( - "refs/heads/main".try_into().expect("valid"), - )), - new: Target::Object(main_id), - }, - name: "refs/heads/symbolic".try_into().expect("valid"), - deref: false, - }), + Some(RefEdit::update( + "refs/heads/symbolic".try_into().expect("valid"), + main_id, + PreviousValue::MustExistAndMatch(Target::Symbolic("refs/heads/main".try_into().expect("valid"))), + "action: no update will be performed", + )), ), ] { let (mappings, specs) = mapping_from_spec(&format!("{source}:{destination}"), &repo); diff --git a/gix/src/remote/connection/ref_map.rs b/gix/src/remote/connection/ref_map.rs index fe3d0127894..1a5afe55026 100644 --- a/gix/src/remote/connection/ref_map.rs +++ b/gix/src/remote/connection/ref_map.rs @@ -127,10 +127,10 @@ where }: Options, ) -> Result { let _span = gix_trace::coarse!("remote::Connection::ref_map()"); - if let Some(tag_spec) = self.remote.fetch_tags.to_refspec().map(|spec| spec.to_owned()) { - if !extra_refspecs.contains(&tag_spec) { - extra_refspecs.push(tag_spec); - } + if let Some(tag_spec) = self.remote.fetch_tags.to_refspec().map(|spec| spec.to_owned()) + && !extra_refspecs.contains(&tag_spec) + { + extra_refspecs.push(tag_spec); } let mut credentials_storage; let url = self.transport.inner.to_url(); diff --git a/gix/src/repository/branch.rs b/gix/src/repository/branch.rs index 72e45f565bb..4db1d55d51b 100644 --- a/gix/src/repository/branch.rs +++ b/gix/src/repository/branch.rs @@ -1,6 +1,6 @@ use gix_ref::{ Category, FullName, - transaction::{Change, PreviousValue, RefEdit, RefLog}, + transaction::{PreviousValue, RefEdit}, }; /// Delete local branches. @@ -104,14 +104,7 @@ impl crate::Repository { let edits: Vec<_> = names .iter() - .map(|name| RefEdit { - change: Change::Delete { - expected: PreviousValue::Any, - log: RefLog::AndReference, - }, - name: name.clone(), - deref: false, - }) + .map(|name| RefEdit::delete(name.clone(), PreviousValue::Any)) .collect(); let config_path = self.common_dir().join("config"); diff --git a/gix/src/repository/freelist.rs b/gix/src/repository/freelist.rs index 9755f3d9e88..9e4af730889 100644 --- a/gix/src/repository/freelist.rs +++ b/gix/src/repository/freelist.rs @@ -56,10 +56,10 @@ impl crate::Repository { /// it to be reclaimed. #[inline] pub(crate) fn reuse_buffer(&self, data: &mut Vec) { - if data.capacity() > 0 { - if let Some(bufs) = self.bufs.as_ref() { - bufs.borrow_mut().push(std::mem::take(data)); - } + if data.capacity() > 0 + && let Some(bufs) = self.bufs.as_ref() + { + bufs.borrow_mut().push(std::mem::take(data)); } } } diff --git a/gix/src/repository/init.rs b/gix/src/repository/init.rs index af52090f46d..26b1e064137 100644 --- a/gix/src/repository/init.rs +++ b/gix/src/repository/init.rs @@ -52,12 +52,11 @@ impl crate::Repository { pub fn reload(&mut self) -> Result<&mut Self, crate::open::Error> { let mut git_dir = self.git_dir().to_owned(); let options = self.options.clone().open_path_as_is(true); - if git_dir.is_relative() { - if let Some((prev_cwd, cwd)) = options.current_dir.as_ref().zip(std::env::current_dir().ok()) { - if *prev_cwd != cwd { - git_dir = prev_cwd.join(git_dir); - } - } + if git_dir.is_relative() + && let Some((prev_cwd, cwd)) = options.current_dir.as_ref().zip(std::env::current_dir().ok()) + && *prev_cwd != cwd + { + git_dir = prev_cwd.join(git_dir); } *self = crate::ThreadSafeRepository::open_opts(git_dir, options)?.to_thread_local(); Ok(self) diff --git a/gix/src/repository/object.rs b/gix/src/repository/object.rs index cced33331af..ebc2ef9aea7 100644 --- a/gix/src/repository/object.rs +++ b/gix/src/repository/object.rs @@ -4,10 +4,7 @@ use std::ops::DerefMut; use gix_hash::ObjectId; use gix_object::{Exists, Find, FindExt, Write}; use gix_odb::{Header, HeaderExt}; -use gix_ref::{ - FullName, - transaction::{LogChange, PreviousValue, RefLog}, -}; +use gix_ref::{FullName, transaction::PreviousValue}; use smallvec::SmallVec; use crate::repository::{new_commit, new_commit_as}; @@ -390,10 +387,7 @@ impl crate::Repository { tree: ObjectId, parents: SmallVec<[ObjectId; 1]>, ) -> Result, commit::Error> { - use gix_ref::{ - Target, - transaction::{Change, RefEdit}, - }; + use gix_ref::{Target, transaction::RefEdit}; // TODO: possibly use CommitRef to save a few allocations (but will have to allocate for object ids anyway. // This can be made vastly more efficient though if we wanted to, so we lie in the API @@ -408,33 +402,26 @@ impl crate::Repository { }; let commit_id = self.write_object(&commit)?; + let expected = match commit.parents.first().map(|p| Target::Object(*p)) { + Some(previous) => { + if reference.as_bstr() == "HEAD" { + PreviousValue::MustExistAndMatch(previous) + } else { + PreviousValue::ExistingMustMatch(previous) + } + } + None => PreviousValue::MustNotExist, + }; self.edit_references_as( - Some(RefEdit { - change: Change::Update { - log: LogChange { - mode: RefLog::AndReference, - force_create_reflog: false, - message: crate::reference::log::message( - "commit", - commit.message.as_ref(), - commit.parents.len(), - ), - }, - expected: match commit.parents.first().map(|p| Target::Object(*p)) { - Some(previous) => { - if reference.as_bstr() == "HEAD" { - PreviousValue::MustExistAndMatch(previous) - } else { - PreviousValue::ExistingMustMatch(previous) - } - } - None => PreviousValue::MustNotExist, - }, - new: Target::Object(commit_id.inner), - }, - name: reference, - deref: true, - }), + Some( + RefEdit::update( + reference, + commit_id.inner, + expected, + crate::reference::log::message("commit", commit.message.as_ref(), commit.parents.len()), + ) + .with_deref(true), + ), Some(committer), )?; Ok(commit_id) diff --git a/gix/src/repository/reference.rs b/gix/src/repository/reference.rs index afd1303fecf..82ae7bf3b6e 100644 --- a/gix/src/repository/reference.rs +++ b/gix/src/repository/reference.rs @@ -1,7 +1,7 @@ use gix_hash::ObjectId; use gix_ref::{ FullName, PartialNameRef, Target, - transaction::{Change, LogChange, PreviousValue, RefEdit, RefLog}, + transaction::{PreviousValue, RefEdit}, }; use crate::{Reference, bstr::BString, ext::ReferenceExt, reference}; @@ -19,15 +19,12 @@ impl crate::Repository { constraint: PreviousValue, ) -> Result, reference::edit::Error> { let id = target.into(); - let mut edits = self.edit_reference(RefEdit { - change: Change::Update { - log: Default::default(), - expected: constraint, - new: Target::Object(id), - }, - name: format!("refs/tags/{}", name.as_ref()).try_into()?, - deref: false, - })?; + let mut edits = self.edit_reference(RefEdit::update( + format!("refs/tags/{}", name.as_ref()).try_into()?, + id, + constraint, + "", + ))?; assert_eq!(edits.len(), 1, "reference splits should ever happen"); let edit = edits.pop().expect("exactly one item"); Ok(Reference { @@ -102,19 +99,7 @@ impl crate::Repository { constraint: PreviousValue, log_message: BString, ) -> Result, reference::edit::Error> { - let mut edits = self.edit_reference(RefEdit { - change: Change::Update { - log: LogChange { - mode: RefLog::AndReference, - force_create_reflog: false, - message: log_message, - }, - expected: constraint, - new: Target::Object(id), - }, - name, - deref: false, - })?; + let mut edits = self.edit_reference(RefEdit::update(name, id, constraint, log_message))?; assert_eq!( edits.len(), 1, diff --git a/gix/src/revision/spec/parse/delegate/mod.rs b/gix/src/revision/spec/parse/delegate/mod.rs index 619e060433e..d2d14530e0c 100644 --- a/gix/src/revision/spec/parse/delegate/mod.rs +++ b/gix/src/revision/spec/parse/delegate/mod.rs @@ -222,8 +222,8 @@ impl Delegate<'_> { fn follow_refs_to_objects_if_needed_delay_errors(&mut self) { let repo = self.repo; for (r, obj) in self.refs.iter().zip(self.objs.iter_mut()) { - if let (Some(ref_), obj_opt @ None) = (r, obj) { - if let Some(id) = ref_.target.try_id().map(ToOwned::to_owned).or_else(|| { + if let (Some(ref_), obj_opt @ None) = (r, obj) + && let Some(id) = ref_.target.try_id().map(ToOwned::to_owned).or_else(|| { match ref_.clone().attach(repo).peel_to_id() { Err(err) => { self.delayed_errors.push( @@ -238,11 +238,11 @@ impl Delegate<'_> { } Ok(id) => Some(id.detach()), } - }) { - let objs = obj_opt.get_or_insert_with(Vec::new); - if !objs.contains(&id) { - objs.push(id); - } + }) + { + let objs = obj_opt.get_or_insert_with(Vec::new); + if !objs.contains(&id) { + objs.push(id); } } } diff --git a/gix/src/revision/walk.rs b/gix/src/revision/walk.rs index f39b7b70959..3b0b01f6a0b 100644 --- a/gix/src/revision/walk.rs +++ b/gix/src/revision/walk.rs @@ -234,10 +234,10 @@ impl Platform<'_> { for id in ids.into_iter() { let id = id.into(); if !self.boundary.contains(&id) { - if let Some(time) = self.repo.find_commit(id).ok().and_then(|c| c.time().ok()) { - if cutoff.is_none() || cutoff > Some(time.seconds) { - cutoff = time.seconds.into(); - } + if let Some(time) = self.repo.find_commit(id).ok().and_then(|c| c.time().ok()) + && (cutoff.is_none() || cutoff > Some(time.seconds)) + { + cutoff = time.seconds.into(); } self.boundary.push(id); } @@ -308,11 +308,11 @@ impl<'repo> Platform<'repo> { grafted_parents_to_skip.remove(idx); return false; } - if commits.binary_search(&id).is_ok() { - if let Ok(commit) = repo.objects.find_commit_iter(&id, &mut buf) { - grafted_parents_to_skip.extend(commit.parent_ids()); - grafted_parents_to_skip.sort(); - } + if commits.binary_search(&id).is_ok() + && let Ok(commit) = repo.objects.find_commit_iter(&id, &mut buf) + { + grafted_parents_to_skip.extend(commit.parent_ids()); + grafted_parents_to_skip.sort(); } true } diff --git a/gix/tests/gix/repository/branch.rs b/gix/tests/gix/repository/branch.rs index 65f16b77001..51c5f87162c 100644 --- a/gix/tests/gix/repository/branch.rs +++ b/gix/tests/gix/repository/branch.rs @@ -2,7 +2,7 @@ use std::io::Write; use gix::refs::{ FullName, Target, - transaction::{Change, LogChange, PreviousValue, RefEdit, RefLog}, + transaction::{LogChange, PreviousValue, RefEdit, RefLog}, }; fn refname(value: &str) -> FullName { @@ -20,19 +20,16 @@ fn deletes_a_batch_and_all_of_its_local_config_without_inspecting_commits() -> c PreviousValue::MustNotExist, "create test branch", )?; - repo.edit_reference(RefEdit { - change: Change::Update { - log: LogChange { - mode: RefLog::AndReference, - force_create_reflog: true, - message: "create broken symbolic test branch".into(), - }, - expected: PreviousValue::MustNotExist, - new: Target::Symbolic(refname("refs/heads/missing-target")), + repo.edit_reference(RefEdit::update_with_log( + symbolic.clone(), + Target::Symbolic(refname("refs/heads/missing-target")), + PreviousValue::MustNotExist, + LogChange { + mode: RefLog::AndReference, + force_create_reflog: true, + message: "create broken symbolic test branch".into(), }, - name: symbolic.clone(), - deref: false, - })?; + ))?; let included_path = repo.common_dir().join("included-config"); std::fs::write(&included_path, b"[branch \"delete-direct\"]\n\tremote = elsewhere\n")?; diff --git a/gix/tests/gix/repository/note.rs b/gix/tests/gix/repository/note.rs index 0cc6cf68c16..5d85b2969aa 100644 --- a/gix/tests/gix/repository/note.rs +++ b/gix/tests/gix/repository/note.rs @@ -66,7 +66,7 @@ fn query_and_mutate_a_configured_notes_ref() -> crate::Result { fn mutations_follow_symbolic_references_to_their_direct_target() -> crate::Result { use gix::refs::{ FullName, Target, TargetRef, - transaction::{Change, LogChange, PreviousValue, RefEdit, RefLog}, + transaction::{PreviousValue, RefEdit}, }; fn full_name(name: &str) -> FullName { @@ -74,19 +74,12 @@ fn mutations_follow_symbolic_references_to_their_direct_target() -> crate::Resul } fn create_symbolic_ref(repo: &gix::Repository, name: &str, target: &str) -> crate::Result { - repo.edit_reference(RefEdit { - change: Change::Update { - log: LogChange { - mode: RefLog::AndReference, - force_create_reflog: false, - message: "create symbolic notes reference".into(), - }, - expected: PreviousValue::MustNotExist, - new: Target::Symbolic(full_name(target)), - }, - name: full_name(name), - deref: false, - })?; + repo.edit_reference(RefEdit::update( + full_name(name), + Target::Symbolic(full_name(target)), + PreviousValue::MustNotExist, + "create symbolic notes reference", + ))?; Ok(()) } diff --git a/src/plumbing/main.rs b/src/plumbing/main.rs index 7a69eb59951..af6520d79a2 100644 --- a/src/plumbing/main.rs +++ b/src/plumbing/main.rs @@ -539,7 +539,9 @@ pub fn main() -> Result<()> { add_paths: add_path, prefix, files: add_virtual_file - .chunks_exact(2) + .as_chunks::<2>() + .0 + .iter() .map(|c| (c[0].clone(), c[1].clone())) .collect(), format: format.map(|f| match f { diff --git a/tests/it/Cargo.toml b/tests/it/Cargo.toml index 40958546105..ae63f605473 100644 --- a/tests/it/Cargo.toml +++ b/tests/it/Cargo.toml @@ -8,7 +8,7 @@ authors = ["Sebastian Thiel "] edition = "2024" license = "MIT OR Apache-2.0" publish = false -rust-version = "1.85" +rust-version = "1.88" [[bin]] name = "it" diff --git a/tests/it/src/commands/env.rs b/tests/it/src/commands/env.rs index ed0cf5a9909..b02b661a8b5 100644 --- a/tests/it/src/commands/env.rs +++ b/tests/it/src/commands/env.rs @@ -6,6 +6,7 @@ pub(super) mod function { Ok(()) } + #[allow(clippy::unnecessary_debug_formatting, reason = "preserve non-UTF-8 bytes")] fn repr(text: &std::ffi::OsStr) -> String { text.to_str() .filter(|s| !s.chars().any(|c| c == '"' || c == '\n')) diff --git a/tests/tools/Cargo.toml b/tests/tools/Cargo.toml index d3139631768..0a02aa79429 100644 --- a/tests/tools/Cargo.toml +++ b/tests/tools/Cargo.toml @@ -8,7 +8,7 @@ authors = ["Sebastian Thiel "] edition = "2024" license = "MIT OR Apache-2.0" include = ["/src/**/*", "/LICENSE-*"] -rust-version = "1.85" +rust-version = "1.88" [[bin]] name = "jtt"