From 0e9a18ed6921116cca6e48345d6937ad7120e83e Mon Sep 17 00:00:00 2001 From: Niklas Wimmer Date: Thu, 10 Aug 2023 18:46:55 +0200 Subject: [PATCH 0001/1077] Improve error printing for gix-url baseline test Makes sure to always include the expected and (if available) actual URL in the panic message. This makes reasoning of failed baseline test much easier. --- gix-url/tests/baseline/main.rs | 57 ++++++++++++++++++++-------------- 1 file changed, 33 insertions(+), 24 deletions(-) diff --git a/gix-url/tests/baseline/main.rs b/gix-url/tests/baseline/main.rs index 7843e6e18fe..9d2fbcc0f39 100644 --- a/gix-url/tests/baseline/main.rs +++ b/gix-url/tests/baseline/main.rs @@ -1,3 +1,5 @@ +use std::any::Any; + use bstr::ByteSlice; use libtest_mimic::{Arguments, Failed, Trial}; @@ -16,35 +18,42 @@ fn get_baseline_test_cases() -> Vec { baseline::URLS .iter() .map(|(url, expected)| { - Trial::test( - format!("baseline {}", url.to_str().expect("url is valid utf-8")), - move || { - std::panic::catch_unwind(|| { - assert_urls_equal(expected, &gix_url::parse(url).expect("valid urls can be parsed")) - }) - .map_err(|err| { - // Succeeds whenever `panic!` was given a string literal (for example if - // `assert!` is given a string literal). - match err.downcast_ref::<&str>() { - Some(panic_message) => panic_message.into(), - None => { - // Succeeds whenever `panic!` was given an owned String (for - // example when using the `format!` syntax and always for - // `assert_*!` macros). - match err.downcast_ref::() { - Some(panic_message) => panic_message.into(), - None => Failed::without_message(), - } - } - } - }) - }, - ) + Trial::test(format!("{}", url.to_str().expect("url is valid utf-8")), move || { + let actual = std::panic::catch_unwind(|| gix_url::parse(url).expect("valid urls can be parsed")) + .map_err(|panic| match downcast_panic_to_str(&panic) { + Some(s) => format!("{s}\nexpected: {expected:?}").into(), + None => Failed::without_message(), + })?; + + std::panic::catch_unwind(|| assert_urls_equal(expected, &actual)).map_err(|panic| { + match downcast_panic_to_str(&panic) { + Some(s) => format!("{s}\nexpected: {expected:?}\nactual: {actual:?}").into(), + None => Failed::without_message(), + } + }) + }) .with_ignored_flag(true /* currently most of these fail */) }) .collect::<_>() } +fn downcast_panic_to_str<'a>(panic: &'a Box) -> Option<&'a str> { + // Succeeds whenever `panic!` was given a string literal (for example if + // `assert!` is given a string literal). + match panic.downcast_ref::<&'static str>() { + Some(s) => Some(s), + None => { + // Succeeds whenever `panic!` was given an owned String (for + // example when using the `format!` syntax and always for + // `assert_*!` macros). + match panic.downcast_ref::() { + Some(s) => Some(s), + None => None, + } + } + } +} + fn assert_urls_equal(expected: &baseline::GitDiagUrl<'_>, actual: &gix_url::Url) { assert_eq!( gix_url::Scheme::from(expected.protocol.to_str().unwrap()), From f18bfd8d81a56e9a68d465c49ef2da192de6c279 Mon Sep 17 00:00:00 2001 From: Niklas Wimmer Date: Thu, 10 Aug 2023 19:06:49 +0200 Subject: [PATCH 0002/1077] Fix wrong assertion in gix-url baseline test This change does not affect the number of passing tests, because all tests that were affected by this wrong assertion now fail for some other reason. --- gix-url/tests/baseline/main.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/gix-url/tests/baseline/main.rs b/gix-url/tests/baseline/main.rs index 9d2fbcc0f39..7b8e8f42252 100644 --- a/gix-url/tests/baseline/main.rs +++ b/gix-url/tests/baseline/main.rs @@ -62,7 +62,7 @@ fn assert_urls_equal(expected: &baseline::GitDiagUrl<'_>, actual: &gix_url::Url) match expected.host { baseline::GitDiagHost::NonSsh { host_and_port } => match host_and_port { - Some(host_and_port) => { + Some(host_and_port) if !host_and_port.is_empty() => { assert!(actual.host().is_some()); let mut gix_host_and_port = String::with_capacity(host_and_port.len()); @@ -81,7 +81,7 @@ fn assert_urls_equal(expected: &baseline::GitDiagUrl<'_>, actual: &gix_url::Url) assert_eq!(host_and_port, gix_host_and_port); } - None => { + _ => { assert!(actual.host().is_none()); assert!(actual.port.is_none()); } From 3faac3648b4d39bff4a05602b481bf8e6d71b77e Mon Sep 17 00:00:00 2001 From: Niklas Wimmer Date: Thu, 17 Aug 2023 13:00:31 +0200 Subject: [PATCH 0003/1077] Add support for "git+ssh" and "ssh+git" urls Doubles the amount of baseline tests that pass :) --- gix-url/src/scheme.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/gix-url/src/scheme.rs b/gix-url/src/scheme.rs index 1c5f045262e..a50b735c7be 100644 --- a/gix-url/src/scheme.rs +++ b/gix-url/src/scheme.rs @@ -24,7 +24,8 @@ pub enum Scheme { impl<'a> From<&'a str> for Scheme { fn from(value: &'a str) -> Self { match value { - "ssh" => Scheme::Ssh, + // "ssh+git" and "git+ssh" are legacy, but Git still allows them and so should we + "ssh" | "ssh+git" | "git+ssh" => Scheme::Ssh, "file" => Scheme::File, "git" => Scheme::Git, "http" => Scheme::Http, From 14facd98632b44eb350c33a5aa425d2e68d25889 Mon Sep 17 00:00:00 2001 From: Niklas Wimmer Date: Sat, 19 Aug 2023 10:59:33 +0200 Subject: [PATCH 0004/1077] Rewrite gix-url parsing This change is intentionally kept very simple and does not try to immediately fix all now failing tests. When comparing the test output of this implementation with the previous there are a few things worth mentioning: - all previously passing baseline tests still do so - the new implementation correctly classifies paths starting with a `/` or `./` but containing a `:` as file paths - the new implementation correctly classifies paths containing just letters before the first `:` as scp paths - the new implementation fails all tests that check the returned errors for invalid paths - the new implementation seems to fail for some windows paths The next step is to evaluate the now failing tests, and either remove/rewrite them if they are based on flawed assumptions (looking at you 'ssh_alias_needs_username_to_not_be_considered_a_filepath') or fix the new implementation to make them pass again. We can then work on making the baseline tests pass. The change also keeps the previous parsing logic around and just removes it from the module graph, to allow for local comparisons of the two implementations during development. --- gix-url/src/lib.rs | 2 + gix-url/src/parse/mod.rs | 123 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 125 insertions(+) create mode 100644 gix-url/src/parse/mod.rs diff --git a/gix-url/src/lib.rs b/gix-url/src/lib.rs index 1d90689ae61..cb35752a0cb 100644 --- a/gix-url/src/lib.rs +++ b/gix-url/src/lib.rs @@ -12,6 +12,8 @@ use bstr::{BStr, BString}; use std::borrow::Cow; /// +#[path = "parse/mod.rs"] +// #[path = "parse.rs"] pub mod parse; #[doc(inline)] pub use parse::parse; diff --git a/gix-url/src/parse/mod.rs b/gix-url/src/parse/mod.rs new file mode 100644 index 00000000000..36e1b3b7d4f --- /dev/null +++ b/gix-url/src/parse/mod.rs @@ -0,0 +1,123 @@ +use std::convert::Infallible; + +use bstr::{BStr, BString, ByteSlice}; + +#[derive(Debug, thiserror::Error)] +#[allow(missing_docs)] +pub enum Error { + #[error("Could not decode URL as UTF8")] + Utf8(#[from] std::str::Utf8Error), + #[error(transparent)] + Url(#[from] url::ParseError), + #[error("URLs need to specify the path to the repository")] + MissingResourceLocation, + #[error("file URLs require an absolute or relative path to the repository")] + MissingRepositoryPath, + #[error("\"{url}\" is not a valid local path")] + NotALocalFile { url: BString }, + #[error("Relative URLs are not permitted: {url:?}")] + RelativeUrl { url: String }, +} + +impl From for Error { + fn from(_: Infallible) -> Self { + unreachable!("Cannot actually happen, but it seems there can't be a blanket impl for this") + } +} + +enum InputScheme { + Url { protocol_end: usize }, + Scp { colon: usize }, + Local, +} + +fn find_scheme(input: &BStr) -> InputScheme { + // TODO: url's may only contain `:/`, we should additionally check if the characters used for + // protocol are all valid + if let Some(protocol_end) = input.find("://") { + return InputScheme::Url { protocol_end }; + } + + if let Some(colon) = input.find_byte(b':') { + // allow user to select files containing a `:` by passing them as absolute or relative path + // this is behavior explicitly mentioned by the scp and git manuals + if !&input[..colon].contains(&b'/') { + // TODO: implement windows specific checks + return InputScheme::Scp { colon }; + } + } + + InputScheme::Local +} + +/// Parse the given `bytes` as a [git url](crate::Url). +/// +/// # Note +/// +/// We cannot and should never have to deal with UTF-16 encoded windows strings, so bytes input is acceptable. +/// For file-paths, we don't expect UTF8 encoding either. +pub fn parse(input: &BStr) -> Result { + match find_scheme(input) { + InputScheme::Url { .. } => parse_url(input), + InputScheme::Scp { colon } => parse_scp(input, colon), + InputScheme::Local => parse_local(input), + } +} + +fn parse_url(input: &BStr) -> Result { + let url = url::Url::parse(std::str::from_utf8(input)?)?; + + Ok(crate::Url { + serialize_alternative_form: false, + scheme: url.scheme().into(), + password: url.password().map(Into::into), + user: if url.username().is_empty() && url.password().is_none() { + None + } else { + Some(url.username().into()) + }, + host: url.host_str().map(Into::into), + port: url.port(), + path: url.path().into(), + }) +} + +fn parse_scp(input: &BStr, colon: usize) -> Result { + let input = std::str::from_utf8(input)?; + + // TODO: this incorrectly splits at IPv6 addresses, check for `[]` before splitting + let (host, path) = input.split_at(colon); + let path = &path[1..]; // remove leading `:` + + // The path returned by the parsed url often has the wrong number of leading `/` characters but + // should never differ in any other way (ssh URLs should not contain a query or fragment part). + // To avoid the various off-by-one errors caused by the `/` characters, we keep using the path + // determined above and can therefore skip parsing it here as well. + let url = url::Url::parse(&format!("ssh://{host}"))?; + + Ok(crate::Url { + serialize_alternative_form: true, + scheme: url.scheme().into(), + password: url.password().map(Into::into), + user: if url.username().is_empty() && url.password().is_none() { + None + } else { + Some(url.username().into()) + }, + host: url.host_str().map(Into::into), + port: url.port(), + path: path.into(), + }) +} + +fn parse_local(input: &BStr) -> Result { + Ok(crate::Url { + serialize_alternative_form: true, + scheme: crate::scheme::Scheme::File, + password: None, + user: None, + host: None, + port: None, + path: input.into(), + }) +} From dd1a1257d66d2f280be0adfce0a100a6a83e1c65 Mon Sep 17 00:00:00 2001 From: Niklas Wimmer Date: Wed, 23 Aug 2023 18:31:53 +0200 Subject: [PATCH 0005/1077] remove!: url parsing error MissingResourceLocation The `MissingResourceLocation` error variant was previously returned if the input URL had either scheme ssh (no matter if URL or SCP format) or git and the URL contained no or an empty path section. In the future we will instead return the `MissingRepositoryPath` error in such a case. The only benefit of such a seperation is that it allows the caller to infer the kind of URL we tried to parse. A future commit will add a new field to the `MissingRepositoryPath` error variant which will clearly communicate this information and can therefore be used instead for this purpose. --- gix-url/src/parse/mod.rs | 2 -- gix-url/tests/parse/invalid.rs | 6 +++--- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/gix-url/src/parse/mod.rs b/gix-url/src/parse/mod.rs index 36e1b3b7d4f..5cce12740ae 100644 --- a/gix-url/src/parse/mod.rs +++ b/gix-url/src/parse/mod.rs @@ -9,8 +9,6 @@ pub enum Error { Utf8(#[from] std::str::Utf8Error), #[error(transparent)] Url(#[from] url::ParseError), - #[error("URLs need to specify the path to the repository")] - MissingResourceLocation, #[error("file URLs require an absolute or relative path to the repository")] MissingRepositoryPath, #[error("\"{url}\" is not a valid local path")] diff --git a/gix-url/tests/parse/invalid.rs b/gix-url/tests/parse/invalid.rs index 0f4c462e4e4..bdaa010099a 100644 --- a/gix-url/tests/parse/invalid.rs +++ b/gix-url/tests/parse/invalid.rs @@ -12,12 +12,12 @@ fn relative_path_due_to_double_colon() { #[test] fn ssh_missing_path() { - assert_failure("ssh://host.xz", Error::MissingResourceLocation) + assert_failure("ssh://host.xz", Error::MissingRepositoryPath) } #[test] fn git_missing_path() { - assert_failure("git://host.xz", Error::MissingResourceLocation) + assert_failure("git://host.xz", Error::MissingRepositoryPath) } #[test] @@ -39,7 +39,7 @@ fn empty() { #[test] fn missing_port_despite_indication() { - assert_failure("ssh://host.xz:", Error::MissingResourceLocation) + assert_failure("ssh://host.xz:", Error::MissingRepositoryPath) } #[test] From fb0b8a769a8992e8079c66fea7d4708d9db0323d Mon Sep 17 00:00:00 2001 From: Niklas Wimmer Date: Wed, 23 Aug 2023 19:00:28 +0200 Subject: [PATCH 0006/1077] remove!: url parsing error NotALocalFile The `NotALocalFile` error variant was previously returned if the input url contained a colon but the slice after that character contained no slash character (`/` or `\`). This behavior is wrong. SCP like URLs may not need a slash character to specify the repositories location. Similarly, a local directory that contains a colon in its name is a valid repository path as well. The new implementation correctly parses such URLs. --- gix-url/src/parse/mod.rs | 2 -- gix-url/tests/parse/file.rs | 11 +++++++++++ gix-url/tests/parse/invalid.rs | 5 ----- gix-url/tests/parse/ssh.rs | 10 ++++++++++ 4 files changed, 21 insertions(+), 7 deletions(-) diff --git a/gix-url/src/parse/mod.rs b/gix-url/src/parse/mod.rs index 5cce12740ae..fc5a0f42c5c 100644 --- a/gix-url/src/parse/mod.rs +++ b/gix-url/src/parse/mod.rs @@ -11,8 +11,6 @@ pub enum Error { Url(#[from] url::ParseError), #[error("file URLs require an absolute or relative path to the repository")] MissingRepositoryPath, - #[error("\"{url}\" is not a valid local path")] - NotALocalFile { url: BString }, #[error("Relative URLs are not permitted: {url:?}")] RelativeUrl { url: String }, } diff --git a/gix-url/tests/parse/file.rs b/gix-url/tests/parse/file.rs index e086fd6d799..62696fe391f 100644 --- a/gix-url/tests/parse/file.rs +++ b/gix-url/tests/parse/file.rs @@ -142,6 +142,17 @@ fn url_from_absolute_path() -> crate::Result { Ok(()) } +#[test] +fn url_from_relative_path_with_colon_in_name() -> crate::Result { + let url = assert_url( + "./weird/directory/na:me", + url_alternate(Scheme::File, None, None, None, b"./weird/directory/na:me"), + )? + .to_bstring(); + assert_eq!(url, "./weird/directory/na:me"); + Ok(()) +} + mod windows { use gix_url::Scheme; diff --git a/gix-url/tests/parse/invalid.rs b/gix-url/tests/parse/invalid.rs index bdaa010099a..6bd7fff43ba 100644 --- a/gix-url/tests/parse/invalid.rs +++ b/gix-url/tests/parse/invalid.rs @@ -41,8 +41,3 @@ fn empty() { fn missing_port_despite_indication() { assert_failure("ssh://host.xz:", Error::MissingRepositoryPath) } - -#[test] -fn strange() { - assert_failure("file:..", "\"file:..\" is not a valid local path") -} diff --git a/gix-url/tests/parse/ssh.rs b/gix-url/tests/parse/ssh.rs index e54186b961d..f1f433f350a 100644 --- a/gix-url/tests/parse/ssh.rs +++ b/gix-url/tests/parse/ssh.rs @@ -177,3 +177,13 @@ fn strange_windows_paths_yield_meaningful_results() -> crate::Result { assert_eq!(url, "user@host.xz:42:C:/strange/absolute/path"); Ok(()) } + +// Git does not care that the host is named `file`, it still treats it as an SCP url. +// I btw tested this, yes you can really clone a repository from there, just `git init` +// in the directory above your home directory on the remote machine. +#[test] +fn strange() -> crate::Result { + let url = assert_url("file:..", url_alternate(Scheme::Ssh, None, "file", None, b".."))?.to_bstring(); + assert_eq!(url, "file:.."); + Ok(()) +} From 313a7b3ddc5786af1f120fa99dd659d725b6845a Mon Sep 17 00:00:00 2001 From: Niklas Wimmer Date: Sun, 20 Aug 2023 13:54:04 +0200 Subject: [PATCH 0007/1077] chore!: restructure gix-url parsing error variants All error variants now own a copy of the input which is used in their display implementation. I noticed that URL parsing errors are almost never acted upon but only wrapped and bubbled up to the user. It therefore makes sense to ensure the message for this error is informative enough by default. If an error can be thrown for different types of URLs it now also includes a kind field. With this field the caller can determine what kind of URL we tried to parse. Additionally, this information is used for the error message too. For testing the assert_matches crate was added which implements the unstable feature with the same name in stable rust. It makes testing the invalid variants much more convenient. BREAKING because public fields of some error variants are now no longer available --- Cargo.lock | 7 ++++ gix-url/Cargo.toml | 1 + gix-url/src/parse/mod.rs | 66 ++++++++++++++++++++++++++++------ gix-url/tests/parse/invalid.rs | 29 ++++++++------- gix-url/tests/parse/mod.rs | 9 ++--- 5 files changed, 81 insertions(+), 31 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index a31149bf25a..4e1d523b01a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -126,6 +126,12 @@ version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711" +[[package]] +name = "assert_matches" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b34d609dfbaf33d6889b2b7106d3ca345eacad44200913df5ba02bfd31d2ba9" + [[package]] name = "async-attributes" version = "1.1.2" @@ -2432,6 +2438,7 @@ version = "0.0.0" name = "gix-url" version = "0.24.0" dependencies = [ + "assert_matches", "bstr", "document-features", "gix-features 0.35.0", diff --git a/gix-url/Cargo.toml b/gix-url/Cargo.toml index ab363daed01..3903828b9d5 100644 --- a/gix-url/Cargo.toml +++ b/gix-url/Cargo.toml @@ -33,6 +33,7 @@ home = "0.5.3" document-features = { version = "0.2.0", optional = true } [dev-dependencies] +assert_matches = "1.5.0" gix-testtools = { path = "../tests/tools" } libtest-mimic = "0.6.1" diff --git a/gix-url/src/parse/mod.rs b/gix-url/src/parse/mod.rs index fc5a0f42c5c..2a3ba670ca4 100644 --- a/gix-url/src/parse/mod.rs +++ b/gix-url/src/parse/mod.rs @@ -5,13 +5,21 @@ use bstr::{BStr, BString, ByteSlice}; #[derive(Debug, thiserror::Error)] #[allow(missing_docs)] pub enum Error { - #[error("Could not decode URL as UTF8")] - Utf8(#[from] std::str::Utf8Error), - #[error(transparent)] - Url(#[from] url::ParseError), - #[error("file URLs require an absolute or relative path to the repository")] - MissingRepositoryPath, - #[error("Relative URLs are not permitted: {url:?}")] + #[error("{} \"{url}\" is not valid UTF-8", .kind.get_error_str())] + Utf8 { + url: BString, + kind: UrlKind, + source: std::str::Utf8Error, + }, + #[error("{} {url:?} can not be parsed as valid URL", .kind.get_error_str())] + Url { + url: String, + kind: UrlKind, + source: url::ParseError, + }, + #[error("{} \"{url}\" does not specify a path to a repository", .kind.get_error_str())] + MissingRepositoryPath { url: BString, kind: UrlKind }, + #[error("URL {url:?} is relative which is not allowed in this context")] RelativeUrl { url: String }, } @@ -21,6 +29,27 @@ impl From for Error { } } +/// +#[derive(Debug)] +pub enum UrlKind { + /// + Url, + /// + Scp, + /// + Local, +} + +impl UrlKind { + fn get_error_str(&self) -> &'static str { + match self { + UrlKind::Url => "URL", + UrlKind::Scp => "SCP-like target", + UrlKind::Local => "local path", + } + } +} + enum InputScheme { Url { protocol_end: usize }, Scp { colon: usize }, @@ -61,7 +90,16 @@ pub fn parse(input: &BStr) -> Result { } fn parse_url(input: &BStr) -> Result { - let url = url::Url::parse(std::str::from_utf8(input)?)?; + let input = std::str::from_utf8(input).map_err(|source| Error::Utf8 { + url: input.to_owned(), + kind: UrlKind::Url, + source, + })?; + let url = url::Url::parse(input).map_err(|source| Error::Url { + url: input.to_owned(), + kind: UrlKind::Url, + source, + })?; Ok(crate::Url { serialize_alternative_form: false, @@ -79,7 +117,11 @@ fn parse_url(input: &BStr) -> Result { } fn parse_scp(input: &BStr, colon: usize) -> Result { - let input = std::str::from_utf8(input)?; + let input = std::str::from_utf8(input).map_err(|source| Error::Utf8 { + url: input.to_owned(), + kind: UrlKind::Scp, + source, + })?; // TODO: this incorrectly splits at IPv6 addresses, check for `[]` before splitting let (host, path) = input.split_at(colon); @@ -89,7 +131,11 @@ fn parse_scp(input: &BStr, colon: usize) -> Result { // should never differ in any other way (ssh URLs should not contain a query or fragment part). // To avoid the various off-by-one errors caused by the `/` characters, we keep using the path // determined above and can therefore skip parsing it here as well. - let url = url::Url::parse(&format!("ssh://{host}"))?; + let url = url::Url::parse(&format!("ssh://{host}")).map_err(|source| Error::Url { + url: input.to_owned(), + kind: UrlKind::Scp, + source, + })?; Ok(crate::Url { serialize_alternative_form: true, diff --git a/gix-url/tests/parse/invalid.rs b/gix-url/tests/parse/invalid.rs index 6bd7fff43ba..9d01e4246a6 100644 --- a/gix-url/tests/parse/invalid.rs +++ b/gix-url/tests/parse/invalid.rs @@ -1,43 +1,42 @@ -use gix_url::parse::Error; +use assert_matches::assert_matches; -use crate::parse::assert_failure; +use gix_url::parse::Error::*; + +use crate::parse::parse; #[test] fn relative_path_due_to_double_colon() { - assert_failure( - "invalid:://host.xz/path/to/repo.git/", - "Relative URLs are not permitted: \"invalid:://host.xz/path/to/repo.git/\"", - ) + assert_matches!(parse("invalid:://host.xz/path/to/repo.git/"), Err(RelativeUrl { .. })) } #[test] fn ssh_missing_path() { - assert_failure("ssh://host.xz", Error::MissingRepositoryPath) + assert_matches!(parse("ssh://host.xz"), Err(MissingRepositoryPath { .. })) } #[test] fn git_missing_path() { - assert_failure("git://host.xz", Error::MissingRepositoryPath) + assert_matches!(parse("git://host.xz"), Err(MissingRepositoryPath { .. })) } #[test] fn file_missing_path() { - assert_failure("file://", Error::MissingRepositoryPath); + assert_matches!(parse("file://"), Err(MissingRepositoryPath { .. })); } #[test] fn empty() { - assert_failure("", Error::MissingRepositoryPath); - assert_failure("file://..", Error::MissingRepositoryPath); - assert_failure("file://.", Error::MissingRepositoryPath); + assert_matches!(parse(""), Err(MissingRepositoryPath { .. })); + assert_matches!(parse("file://.."), Err(MissingRepositoryPath { .. })); + assert_matches!(parse("file://."), Err(MissingRepositoryPath { .. })); #[cfg(not(windows))] { - assert_failure("file://.\\", Error::MissingRepositoryPath); + assert_matches!(parse("file://.\\"), Err(MissingRepositoryPath { .. })); } - assert_failure("file://a", Error::MissingRepositoryPath); + assert_matches!(parse("file://a"), Err(MissingRepositoryPath { .. })); } #[test] fn missing_port_despite_indication() { - assert_failure("ssh://host.xz:", Error::MissingRepositoryPath) + assert_matches!(parse("ssh://host.xz:"), Err(MissingRepositoryPath { .. })) } diff --git a/gix-url/tests/parse/mod.rs b/gix-url/tests/parse/mod.rs index de803a04b0c..19f5d3b4f3b 100644 --- a/gix-url/tests/parse/mod.rs +++ b/gix-url/tests/parse/mod.rs @@ -1,4 +1,4 @@ -use bstr::ByteSlice; +use bstr::{BStr, ByteSlice}; use gix_url::Scheme; fn assert_url(url: &str, expected: gix_url::Url) -> Result { @@ -22,11 +22,8 @@ fn assert_url_roundtrip(url: &str, expected: gix_url::Url) -> crate::Result { Ok(()) } -fn assert_failure(url: &str, expected_err: impl ToString) { - assert_eq!( - gix_url::parse(url.into()).unwrap_err().to_string(), - expected_err.to_string() - ); +fn parse<'a>(input: impl Into<&'a BStr>) -> Result { + gix_url::parse(input.into()) } fn url<'a, 'b>( From d3746df5dd402d8a461c2b07eaa0f8d8803fadf8 Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Tue, 22 Aug 2023 11:59:27 +0200 Subject: [PATCH 0008/1077] make `gix-url` publishable by adding baseline test --- gix-revision/fuzz/Cargo.lock | 18 +++++++++--------- gix-url/Cargo.toml | 2 +- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/gix-revision/fuzz/Cargo.lock b/gix-revision/fuzz/Cargo.lock index 0e1697f3a6b..c2805a426e4 100644 --- a/gix-revision/fuzz/Cargo.lock +++ b/gix-revision/fuzz/Cargo.lock @@ -70,7 +70,7 @@ dependencies = [ [[package]] name = "gix-actor" -version = "0.24.2" +version = "0.25.0" dependencies = [ "bstr", "btoi", @@ -89,7 +89,7 @@ dependencies = [ [[package]] name = "gix-commitgraph" -version = "0.18.2" +version = "0.19.0" dependencies = [ "bstr", "gix-chunk", @@ -101,7 +101,7 @@ dependencies = [ [[package]] name = "gix-date" -version = "0.7.2" +version = "0.7.3" dependencies = [ "bstr", "itoa", @@ -111,7 +111,7 @@ dependencies = [ [[package]] name = "gix-features" -version = "0.32.1" +version = "0.33.0" dependencies = [ "gix-hash", "gix-trace", @@ -121,7 +121,7 @@ dependencies = [ [[package]] name = "gix-hash" -version = "0.11.4" +version = "0.12.0" dependencies = [ "faster-hex", "thiserror", @@ -129,7 +129,7 @@ dependencies = [ [[package]] name = "gix-hashtable" -version = "0.2.4" +version = "0.3.0" dependencies = [ "gix-hash", "hashbrown", @@ -138,7 +138,7 @@ dependencies = [ [[package]] name = "gix-object" -version = "0.34.0" +version = "0.35.0" dependencies = [ "bstr", "btoi", @@ -155,7 +155,7 @@ dependencies = [ [[package]] name = "gix-revision" -version = "0.19.0" +version = "0.20.0" dependencies = [ "bstr", "gix-date", @@ -179,7 +179,7 @@ dependencies = [ [[package]] name = "gix-revwalk" -version = "0.5.0" +version = "0.6.0" dependencies = [ "gix-commitgraph", "gix-date", diff --git a/gix-url/Cargo.toml b/gix-url/Cargo.toml index 57d5ef0f1a2..2892ab53cea 100644 --- a/gix-url/Cargo.toml +++ b/gix-url/Cargo.toml @@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0" description = "A crate of the gitoxide project implementing parsing and serialization of gix-url" authors = ["Sebastian Thiel "] edition = "2021" -include = ["src/**/*", "LICENSE-*", "CHANGELOG.md"] +include = ["src/**/*", "LICENSE-*", "CHANGELOG.md", "tests/baseline/**/*"] rust-version = "1.65" [lib] From 6c62e748240ac0980fc23fdf30f8477dea8b9bc3 Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Tue, 22 Aug 2023 11:59:57 +0200 Subject: [PATCH 0009/1077] Release gix-url v0.22.0, gix-credentials v0.18.0, gix-diff v0.34.0, gix-discover v0.23.0, gix-ignore v0.6.0, gix-bitmap v0.2.7, gix-index v0.22.0, gix-mailmap v0.17.0, gix-negotiate v0.6.0, gix-pack v0.41.0, gix-odb v0.51.0, gix-pathspec v0.1.0, gix-packetline v0.16.5, gix-transport v0.35.0, gix-protocol v0.38.0, gix-revision v0.20.0, gix-refspec v0.16.0, gix-submodule v0.2.0, gix-worktree v0.24.0, gix-worktree-state v0.1.0, gix v0.52.0, gitoxide-core v0.31.0, gitoxide v0.29.0 --- gitoxide-core/CHANGELOG.md | 3 ++- gix-bitmap/CHANGELOG.md | 3 ++- gix-credentials/CHANGELOG.md | 3 ++- gix-diff/CHANGELOG.md | 3 ++- gix-discover/CHANGELOG.md | 3 ++- gix-ignore/CHANGELOG.md | 3 ++- gix-index/CHANGELOG.md | 3 ++- gix-mailmap/CHANGELOG.md | 3 ++- gix-negotiate/CHANGELOG.md | 3 ++- gix-odb/CHANGELOG.md | 3 ++- gix-pack/CHANGELOG.md | 3 ++- gix-packetline/CHANGELOG.md | 3 ++- gix-pathspec/CHANGELOG.md | 5 ++++- gix-protocol/CHANGELOG.md | 3 ++- gix-refspec/CHANGELOG.md | 3 ++- gix-revision/CHANGELOG.md | 4 +++- gix-submodule/CHANGELOG.md | 3 ++- gix-transport/CHANGELOG.md | 3 ++- gix-url/CHANGELOG.md | 4 +++- gix-worktree-state/CHANGELOG.md | 3 ++- gix-worktree/CHANGELOG.md | 3 ++- gix/CHANGELOG.md | 3 ++- 22 files changed, 48 insertions(+), 22 deletions(-) diff --git a/gitoxide-core/CHANGELOG.md b/gitoxide-core/CHANGELOG.md index 5a5bc3e03d2..43fc8dca7fd 100644 --- a/gitoxide-core/CHANGELOG.md +++ b/gitoxide-core/CHANGELOG.md @@ -21,7 +21,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - - 24 commits contributed to the release over the course of 29 calendar days. + - 25 commits contributed to the release over the course of 29 calendar days. - 30 days passed between releases. - 5 commits were understood as [conventional](https://www.conventionalcommits.org). - 0 issues like '(#ID)' were seen in commit messages @@ -33,6 +33,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
view details * **Uncategorized** + - Release gix-date v0.7.3, gix-hash v0.12.0, gix-features v0.33.0, gix-actor v0.25.0, gix-object v0.35.0, gix-path v0.9.0, gix-glob v0.11.0, gix-quote v0.4.7, gix-attributes v0.17.0, gix-command v0.2.9, gix-packetline-blocking v0.16.5, gix-filter v0.3.0, gix-fs v0.5.0, gix-commitgraph v0.19.0, gix-hashtable v0.3.0, gix-revwalk v0.6.0, gix-traverse v0.31.0, gix-worktree-stream v0.3.0, gix-archive v0.3.0, gix-config-value v0.13.0, gix-tempfile v8.0.0, gix-lock v8.0.0, gix-ref v0.35.0, gix-sec v0.9.0, gix-config v0.28.0, gix-prompt v0.6.0, gix-url v0.22.0, gix-credentials v0.18.0, gix-diff v0.34.0, gix-discover v0.23.0, gix-ignore v0.6.0, gix-bitmap v0.2.7, gix-index v0.22.0, gix-mailmap v0.17.0, gix-negotiate v0.6.0, gix-pack v0.41.0, gix-odb v0.51.0, gix-pathspec v0.1.0, gix-packetline v0.16.5, gix-transport v0.35.0, gix-protocol v0.38.0, gix-revision v0.20.0, gix-refspec v0.16.0, gix-submodule v0.2.0, gix-worktree v0.24.0, gix-worktree-state v0.1.0, gix v0.52.0, gitoxide-core v0.31.0, gitoxide v0.29.0, safety bump 41 crates ([`30b2761`](https://github.com/Byron/gitoxide/commit/30b27615047692d3ced1b2d9c2ac15a80f79fbee)) - Update changelogs prior to release ([`f23ea88`](https://github.com/Byron/gitoxide/commit/f23ea8828f2d9ba7559973daca388c9591bcc5fc)) - `gix index entries` with tracing ([`ec1e550`](https://github.com/Byron/gitoxide/commit/ec1e5506ebb34ab5269b67d426ec1d57f2037d29)) - `gix submodule` subcommand for simple submodule listing and information retrieval ([`1ccbe16`](https://github.com/Byron/gitoxide/commit/1ccbe16117d58b68b25a8e3e66676a61a07dd49c)) diff --git a/gix-bitmap/CHANGELOG.md b/gix-bitmap/CHANGELOG.md index 470af678e8b..06daba4a341 100644 --- a/gix-bitmap/CHANGELOG.md +++ b/gix-bitmap/CHANGELOG.md @@ -17,7 +17,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - - 2 commits contributed to the release over the course of 4 calendar days. + - 3 commits contributed to the release over the course of 4 calendar days. - 30 days passed between releases. - 1 commit was understood as [conventional](https://www.conventionalcommits.org). - 0 issues like '(#ID)' were seen in commit messages @@ -29,6 +29,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
view details * **Uncategorized** + - Release gix-date v0.7.3, gix-hash v0.12.0, gix-features v0.33.0, gix-actor v0.25.0, gix-object v0.35.0, gix-path v0.9.0, gix-glob v0.11.0, gix-quote v0.4.7, gix-attributes v0.17.0, gix-command v0.2.9, gix-packetline-blocking v0.16.5, gix-filter v0.3.0, gix-fs v0.5.0, gix-commitgraph v0.19.0, gix-hashtable v0.3.0, gix-revwalk v0.6.0, gix-traverse v0.31.0, gix-worktree-stream v0.3.0, gix-archive v0.3.0, gix-config-value v0.13.0, gix-tempfile v8.0.0, gix-lock v8.0.0, gix-ref v0.35.0, gix-sec v0.9.0, gix-config v0.28.0, gix-prompt v0.6.0, gix-url v0.22.0, gix-credentials v0.18.0, gix-diff v0.34.0, gix-discover v0.23.0, gix-ignore v0.6.0, gix-bitmap v0.2.7, gix-index v0.22.0, gix-mailmap v0.17.0, gix-negotiate v0.6.0, gix-pack v0.41.0, gix-odb v0.51.0, gix-pathspec v0.1.0, gix-packetline v0.16.5, gix-transport v0.35.0, gix-protocol v0.38.0, gix-revision v0.20.0, gix-refspec v0.16.0, gix-submodule v0.2.0, gix-worktree v0.24.0, gix-worktree-state v0.1.0, gix v0.52.0, gitoxide-core v0.31.0, gitoxide v0.29.0, safety bump 41 crates ([`30b2761`](https://github.com/Byron/gitoxide/commit/30b27615047692d3ced1b2d9c2ac15a80f79fbee)) - Update changelogs prior to release ([`f23ea88`](https://github.com/Byron/gitoxide/commit/f23ea8828f2d9ba7559973daca388c9591bcc5fc)) - Don't call crate 'WIP' in manifest anymore. ([`229bd48`](https://github.com/Byron/gitoxide/commit/229bd4899213f749a7cc124aa2b82a1368fba40f))
diff --git a/gix-credentials/CHANGELOG.md b/gix-credentials/CHANGELOG.md index 1b8635117b3..98bed82d6d8 100644 --- a/gix-credentials/CHANGELOG.md +++ b/gix-credentials/CHANGELOG.md @@ -17,7 +17,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - - 4 commits contributed to the release over the course of 18 calendar days. + - 5 commits contributed to the release over the course of 18 calendar days. - 30 days passed between releases. - 1 commit was understood as [conventional](https://www.conventionalcommits.org). - 0 issues like '(#ID)' were seen in commit messages @@ -29,6 +29,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
view details * **Uncategorized** + - Release gix-date v0.7.3, gix-hash v0.12.0, gix-features v0.33.0, gix-actor v0.25.0, gix-object v0.35.0, gix-path v0.9.0, gix-glob v0.11.0, gix-quote v0.4.7, gix-attributes v0.17.0, gix-command v0.2.9, gix-packetline-blocking v0.16.5, gix-filter v0.3.0, gix-fs v0.5.0, gix-commitgraph v0.19.0, gix-hashtable v0.3.0, gix-revwalk v0.6.0, gix-traverse v0.31.0, gix-worktree-stream v0.3.0, gix-archive v0.3.0, gix-config-value v0.13.0, gix-tempfile v8.0.0, gix-lock v8.0.0, gix-ref v0.35.0, gix-sec v0.9.0, gix-config v0.28.0, gix-prompt v0.6.0, gix-url v0.22.0, gix-credentials v0.18.0, gix-diff v0.34.0, gix-discover v0.23.0, gix-ignore v0.6.0, gix-bitmap v0.2.7, gix-index v0.22.0, gix-mailmap v0.17.0, gix-negotiate v0.6.0, gix-pack v0.41.0, gix-odb v0.51.0, gix-pathspec v0.1.0, gix-packetline v0.16.5, gix-transport v0.35.0, gix-protocol v0.38.0, gix-revision v0.20.0, gix-refspec v0.16.0, gix-submodule v0.2.0, gix-worktree v0.24.0, gix-worktree-state v0.1.0, gix v0.52.0, gitoxide-core v0.31.0, gitoxide v0.29.0, safety bump 41 crates ([`30b2761`](https://github.com/Byron/gitoxide/commit/30b27615047692d3ced1b2d9c2ac15a80f79fbee)) - Update changelogs prior to release ([`f23ea88`](https://github.com/Byron/gitoxide/commit/f23ea8828f2d9ba7559973daca388c9591bcc5fc)) - Don't call crate 'WIP' in manifest anymore. ([`229bd48`](https://github.com/Byron/gitoxide/commit/229bd4899213f749a7cc124aa2b82a1368fba40f)) - Merge branch 'dev-on-linux' ([`6b4a303`](https://github.com/Byron/gitoxide/commit/6b4a30330fe49fc97daa73f55bf56580cc0597aa)) diff --git a/gix-diff/CHANGELOG.md b/gix-diff/CHANGELOG.md index 5fe2fdea428..7c707f4a78f 100644 --- a/gix-diff/CHANGELOG.md +++ b/gix-diff/CHANGELOG.md @@ -15,7 +15,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - - 5 commits contributed to the release over the course of 15 calendar days. + - 6 commits contributed to the release over the course of 15 calendar days. - 30 days passed between releases. - 1 commit was understood as [conventional](https://www.conventionalcommits.org). - 0 issues like '(#ID)' were seen in commit messages @@ -27,6 +27,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
view details * **Uncategorized** + - Release gix-date v0.7.3, gix-hash v0.12.0, gix-features v0.33.0, gix-actor v0.25.0, gix-object v0.35.0, gix-path v0.9.0, gix-glob v0.11.0, gix-quote v0.4.7, gix-attributes v0.17.0, gix-command v0.2.9, gix-packetline-blocking v0.16.5, gix-filter v0.3.0, gix-fs v0.5.0, gix-commitgraph v0.19.0, gix-hashtable v0.3.0, gix-revwalk v0.6.0, gix-traverse v0.31.0, gix-worktree-stream v0.3.0, gix-archive v0.3.0, gix-config-value v0.13.0, gix-tempfile v8.0.0, gix-lock v8.0.0, gix-ref v0.35.0, gix-sec v0.9.0, gix-config v0.28.0, gix-prompt v0.6.0, gix-url v0.22.0, gix-credentials v0.18.0, gix-diff v0.34.0, gix-discover v0.23.0, gix-ignore v0.6.0, gix-bitmap v0.2.7, gix-index v0.22.0, gix-mailmap v0.17.0, gix-negotiate v0.6.0, gix-pack v0.41.0, gix-odb v0.51.0, gix-pathspec v0.1.0, gix-packetline v0.16.5, gix-transport v0.35.0, gix-protocol v0.38.0, gix-revision v0.20.0, gix-refspec v0.16.0, gix-submodule v0.2.0, gix-worktree v0.24.0, gix-worktree-state v0.1.0, gix v0.52.0, gitoxide-core v0.31.0, gitoxide v0.29.0, safety bump 41 crates ([`30b2761`](https://github.com/Byron/gitoxide/commit/30b27615047692d3ced1b2d9c2ac15a80f79fbee)) - Update changelogs prior to release ([`f23ea88`](https://github.com/Byron/gitoxide/commit/f23ea8828f2d9ba7559973daca388c9591bcc5fc)) - More cleanup of test crates ([`73c685a`](https://github.com/Byron/gitoxide/commit/73c685a67debcfa26a940f37bbca69cb3a4af57e)) - Merge branch 'worktree-organization' ([`8d0d8e0`](https://github.com/Byron/gitoxide/commit/8d0d8e005d7f11924a6717954d892aae5cec45e7)) diff --git a/gix-discover/CHANGELOG.md b/gix-discover/CHANGELOG.md index 0a4efe82964..c19c0456362 100644 --- a/gix-discover/CHANGELOG.md +++ b/gix-discover/CHANGELOG.md @@ -26,7 +26,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - - 7 commits contributed to the release over the course of 18 calendar days. + - 8 commits contributed to the release over the course of 18 calendar days. - 30 days passed between releases. - 2 commits were understood as [conventional](https://www.conventionalcommits.org). - 1 unique issue was worked on: [#980](https://github.com/Byron/gitoxide/issues/980) @@ -40,6 +40,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 * **[#980](https://github.com/Byron/gitoxide/issues/980)** - `bare()` can now make sure it detects bare repos, at an expense. ([`169228b`](https://github.com/Byron/gitoxide/commit/169228b12f826135d27fd674acbca932b2691a91)) * **Uncategorized** + - Release gix-date v0.7.3, gix-hash v0.12.0, gix-features v0.33.0, gix-actor v0.25.0, gix-object v0.35.0, gix-path v0.9.0, gix-glob v0.11.0, gix-quote v0.4.7, gix-attributes v0.17.0, gix-command v0.2.9, gix-packetline-blocking v0.16.5, gix-filter v0.3.0, gix-fs v0.5.0, gix-commitgraph v0.19.0, gix-hashtable v0.3.0, gix-revwalk v0.6.0, gix-traverse v0.31.0, gix-worktree-stream v0.3.0, gix-archive v0.3.0, gix-config-value v0.13.0, gix-tempfile v8.0.0, gix-lock v8.0.0, gix-ref v0.35.0, gix-sec v0.9.0, gix-config v0.28.0, gix-prompt v0.6.0, gix-url v0.22.0, gix-credentials v0.18.0, gix-diff v0.34.0, gix-discover v0.23.0, gix-ignore v0.6.0, gix-bitmap v0.2.7, gix-index v0.22.0, gix-mailmap v0.17.0, gix-negotiate v0.6.0, gix-pack v0.41.0, gix-odb v0.51.0, gix-pathspec v0.1.0, gix-packetline v0.16.5, gix-transport v0.35.0, gix-protocol v0.38.0, gix-revision v0.20.0, gix-refspec v0.16.0, gix-submodule v0.2.0, gix-worktree v0.24.0, gix-worktree-state v0.1.0, gix v0.52.0, gitoxide-core v0.31.0, gitoxide v0.29.0, safety bump 41 crates ([`30b2761`](https://github.com/Byron/gitoxide/commit/30b27615047692d3ced1b2d9c2ac15a80f79fbee)) - Update changelogs prior to release ([`f23ea88`](https://github.com/Byron/gitoxide/commit/f23ea8828f2d9ba7559973daca388c9591bcc5fc)) - Merge pull request #988 from not-my-profile/fix-gix-config-sub ([`7735047`](https://github.com/Byron/gitoxide/commit/7735047198bd7cc5059ca338f5c2147dd273f711)) - Fix incorrect s/git-config/gix-config/ ([`c51c8da`](https://github.com/Byron/gitoxide/commit/c51c8daee1ab54130ae3ed83ce67d08f01c4881a)) diff --git a/gix-ignore/CHANGELOG.md b/gix-ignore/CHANGELOG.md index d8cc2d94311..942d63821b7 100644 --- a/gix-ignore/CHANGELOG.md +++ b/gix-ignore/CHANGELOG.md @@ -17,7 +17,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - - 8 commits contributed to the release over the course of 18 calendar days. + - 9 commits contributed to the release over the course of 18 calendar days. - 30 days passed between releases. - 1 commit was understood as [conventional](https://www.conventionalcommits.org). - 0 issues like '(#ID)' were seen in commit messages @@ -29,6 +29,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
view details * **Uncategorized** + - Release gix-date v0.7.3, gix-hash v0.12.0, gix-features v0.33.0, gix-actor v0.25.0, gix-object v0.35.0, gix-path v0.9.0, gix-glob v0.11.0, gix-quote v0.4.7, gix-attributes v0.17.0, gix-command v0.2.9, gix-packetline-blocking v0.16.5, gix-filter v0.3.0, gix-fs v0.5.0, gix-commitgraph v0.19.0, gix-hashtable v0.3.0, gix-revwalk v0.6.0, gix-traverse v0.31.0, gix-worktree-stream v0.3.0, gix-archive v0.3.0, gix-config-value v0.13.0, gix-tempfile v8.0.0, gix-lock v8.0.0, gix-ref v0.35.0, gix-sec v0.9.0, gix-config v0.28.0, gix-prompt v0.6.0, gix-url v0.22.0, gix-credentials v0.18.0, gix-diff v0.34.0, gix-discover v0.23.0, gix-ignore v0.6.0, gix-bitmap v0.2.7, gix-index v0.22.0, gix-mailmap v0.17.0, gix-negotiate v0.6.0, gix-pack v0.41.0, gix-odb v0.51.0, gix-pathspec v0.1.0, gix-packetline v0.16.5, gix-transport v0.35.0, gix-protocol v0.38.0, gix-revision v0.20.0, gix-refspec v0.16.0, gix-submodule v0.2.0, gix-worktree v0.24.0, gix-worktree-state v0.1.0, gix v0.52.0, gitoxide-core v0.31.0, gitoxide v0.29.0, safety bump 41 crates ([`30b2761`](https://github.com/Byron/gitoxide/commit/30b27615047692d3ced1b2d9c2ac15a80f79fbee)) - Update changelogs prior to release ([`f23ea88`](https://github.com/Byron/gitoxide/commit/f23ea8828f2d9ba7559973daca388c9591bcc5fc)) - Don't call crate 'WIP' in manifest anymore. ([`229bd48`](https://github.com/Byron/gitoxide/commit/229bd4899213f749a7cc124aa2b82a1368fba40f)) - Merge branch 'pathspec-matching' ([`9f4dfe0`](https://github.com/Byron/gitoxide/commit/9f4dfe0f0b948280692916b596923959ea2fd9da)) diff --git a/gix-index/CHANGELOG.md b/gix-index/CHANGELOG.md index a52864f283e..8cbbe1ed442 100644 --- a/gix-index/CHANGELOG.md +++ b/gix-index/CHANGELOG.md @@ -26,7 +26,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - - 10 commits contributed to the release over the course of 18 calendar days. + - 11 commits contributed to the release over the course of 18 calendar days. - 30 days passed between releases. - 3 commits were understood as [conventional](https://www.conventionalcommits.org). - 0 issues like '(#ID)' were seen in commit messages @@ -38,6 +38,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
view details * **Uncategorized** + - Release gix-date v0.7.3, gix-hash v0.12.0, gix-features v0.33.0, gix-actor v0.25.0, gix-object v0.35.0, gix-path v0.9.0, gix-glob v0.11.0, gix-quote v0.4.7, gix-attributes v0.17.0, gix-command v0.2.9, gix-packetline-blocking v0.16.5, gix-filter v0.3.0, gix-fs v0.5.0, gix-commitgraph v0.19.0, gix-hashtable v0.3.0, gix-revwalk v0.6.0, gix-traverse v0.31.0, gix-worktree-stream v0.3.0, gix-archive v0.3.0, gix-config-value v0.13.0, gix-tempfile v8.0.0, gix-lock v8.0.0, gix-ref v0.35.0, gix-sec v0.9.0, gix-config v0.28.0, gix-prompt v0.6.0, gix-url v0.22.0, gix-credentials v0.18.0, gix-diff v0.34.0, gix-discover v0.23.0, gix-ignore v0.6.0, gix-bitmap v0.2.7, gix-index v0.22.0, gix-mailmap v0.17.0, gix-negotiate v0.6.0, gix-pack v0.41.0, gix-odb v0.51.0, gix-pathspec v0.1.0, gix-packetline v0.16.5, gix-transport v0.35.0, gix-protocol v0.38.0, gix-revision v0.20.0, gix-refspec v0.16.0, gix-submodule v0.2.0, gix-worktree v0.24.0, gix-worktree-state v0.1.0, gix v0.52.0, gitoxide-core v0.31.0, gitoxide v0.29.0, safety bump 41 crates ([`30b2761`](https://github.com/Byron/gitoxide/commit/30b27615047692d3ced1b2d9c2ac15a80f79fbee)) - Update changelogs prior to release ([`f23ea88`](https://github.com/Byron/gitoxide/commit/f23ea8828f2d9ba7559973daca388c9591bcc5fc)) - More cleanup of test crates ([`73c685a`](https://github.com/Byron/gitoxide/commit/73c685a67debcfa26a940f37bbca69cb3a4af57e)) - Split tests off into their own crate to allow feature toggles. ([`93feea2`](https://github.com/Byron/gitoxide/commit/93feea269eebd114e866e6f29f4a73c0096df9e0)) diff --git a/gix-mailmap/CHANGELOG.md b/gix-mailmap/CHANGELOG.md index c5fcb552453..01f463e5cbc 100644 --- a/gix-mailmap/CHANGELOG.md +++ b/gix-mailmap/CHANGELOG.md @@ -17,7 +17,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - - 3 commits contributed to the release over the course of 15 calendar days. + - 4 commits contributed to the release over the course of 15 calendar days. - 30 days passed between releases. - 1 commit was understood as [conventional](https://www.conventionalcommits.org). - 0 issues like '(#ID)' were seen in commit messages @@ -29,6 +29,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
view details * **Uncategorized** + - Release gix-date v0.7.3, gix-hash v0.12.0, gix-features v0.33.0, gix-actor v0.25.0, gix-object v0.35.0, gix-path v0.9.0, gix-glob v0.11.0, gix-quote v0.4.7, gix-attributes v0.17.0, gix-command v0.2.9, gix-packetline-blocking v0.16.5, gix-filter v0.3.0, gix-fs v0.5.0, gix-commitgraph v0.19.0, gix-hashtable v0.3.0, gix-revwalk v0.6.0, gix-traverse v0.31.0, gix-worktree-stream v0.3.0, gix-archive v0.3.0, gix-config-value v0.13.0, gix-tempfile v8.0.0, gix-lock v8.0.0, gix-ref v0.35.0, gix-sec v0.9.0, gix-config v0.28.0, gix-prompt v0.6.0, gix-url v0.22.0, gix-credentials v0.18.0, gix-diff v0.34.0, gix-discover v0.23.0, gix-ignore v0.6.0, gix-bitmap v0.2.7, gix-index v0.22.0, gix-mailmap v0.17.0, gix-negotiate v0.6.0, gix-pack v0.41.0, gix-odb v0.51.0, gix-pathspec v0.1.0, gix-packetline v0.16.5, gix-transport v0.35.0, gix-protocol v0.38.0, gix-revision v0.20.0, gix-refspec v0.16.0, gix-submodule v0.2.0, gix-worktree v0.24.0, gix-worktree-state v0.1.0, gix v0.52.0, gitoxide-core v0.31.0, gitoxide v0.29.0, safety bump 41 crates ([`30b2761`](https://github.com/Byron/gitoxide/commit/30b27615047692d3ced1b2d9c2ac15a80f79fbee)) - Update changelogs prior to release ([`f23ea88`](https://github.com/Byron/gitoxide/commit/f23ea8828f2d9ba7559973daca388c9591bcc5fc)) - Don't call crate 'WIP' in manifest anymore. ([`229bd48`](https://github.com/Byron/gitoxide/commit/229bd4899213f749a7cc124aa2b82a1368fba40f)) - Release gix-glob v0.10.2, gix-date v0.7.2, gix-validate v0.8.0, gix-object v0.34.0, gix-ref v0.34.0, gix-config v0.27.0, gix-commitgraph v0.18.2, gix-revwalk v0.5.0, gix-revision v0.19.0, gix-refspec v0.15.0, gix-submodule v0.1.0, safety bump 18 crates ([`4604f83`](https://github.com/Byron/gitoxide/commit/4604f83ef238dc07c85aaeae097399b67f3cfd0c)) diff --git a/gix-negotiate/CHANGELOG.md b/gix-negotiate/CHANGELOG.md index 8c4ddbab9e1..6e5c0cd96ad 100644 --- a/gix-negotiate/CHANGELOG.md +++ b/gix-negotiate/CHANGELOG.md @@ -13,7 +13,7 @@ A maintenance release without user-facing changes. - - 4 commits contributed to the release over the course of 18 calendar days. + - 5 commits contributed to the release over the course of 18 calendar days. - 30 days passed between releases. - 0 commits were understood as [conventional](https://www.conventionalcommits.org). - 0 issues like '(#ID)' were seen in commit messages @@ -25,6 +25,7 @@ A maintenance release without user-facing changes.
view details * **Uncategorized** + - Release gix-date v0.7.3, gix-hash v0.12.0, gix-features v0.33.0, gix-actor v0.25.0, gix-object v0.35.0, gix-path v0.9.0, gix-glob v0.11.0, gix-quote v0.4.7, gix-attributes v0.17.0, gix-command v0.2.9, gix-packetline-blocking v0.16.5, gix-filter v0.3.0, gix-fs v0.5.0, gix-commitgraph v0.19.0, gix-hashtable v0.3.0, gix-revwalk v0.6.0, gix-traverse v0.31.0, gix-worktree-stream v0.3.0, gix-archive v0.3.0, gix-config-value v0.13.0, gix-tempfile v8.0.0, gix-lock v8.0.0, gix-ref v0.35.0, gix-sec v0.9.0, gix-config v0.28.0, gix-prompt v0.6.0, gix-url v0.22.0, gix-credentials v0.18.0, gix-diff v0.34.0, gix-discover v0.23.0, gix-ignore v0.6.0, gix-bitmap v0.2.7, gix-index v0.22.0, gix-mailmap v0.17.0, gix-negotiate v0.6.0, gix-pack v0.41.0, gix-odb v0.51.0, gix-pathspec v0.1.0, gix-packetline v0.16.5, gix-transport v0.35.0, gix-protocol v0.38.0, gix-revision v0.20.0, gix-refspec v0.16.0, gix-submodule v0.2.0, gix-worktree v0.24.0, gix-worktree-state v0.1.0, gix v0.52.0, gitoxide-core v0.31.0, gitoxide v0.29.0, safety bump 41 crates ([`30b2761`](https://github.com/Byron/gitoxide/commit/30b27615047692d3ced1b2d9c2ac15a80f79fbee)) - Update changelogs prior to release ([`f23ea88`](https://github.com/Byron/gitoxide/commit/f23ea8828f2d9ba7559973daca388c9591bcc5fc)) - Release gix-glob v0.10.2, gix-date v0.7.2, gix-validate v0.8.0, gix-object v0.34.0, gix-ref v0.34.0, gix-config v0.27.0, gix-commitgraph v0.18.2, gix-revwalk v0.5.0, gix-revision v0.19.0, gix-refspec v0.15.0, gix-submodule v0.1.0, safety bump 18 crates ([`4604f83`](https://github.com/Byron/gitoxide/commit/4604f83ef238dc07c85aaeae097399b67f3cfd0c)) - Merge branch 'dev-on-linux' ([`6b4a303`](https://github.com/Byron/gitoxide/commit/6b4a30330fe49fc97daa73f55bf56580cc0597aa)) diff --git a/gix-odb/CHANGELOG.md b/gix-odb/CHANGELOG.md index 61b8e611700..05901c8a45a 100644 --- a/gix-odb/CHANGELOG.md +++ b/gix-odb/CHANGELOG.md @@ -17,7 +17,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - - 6 commits contributed to the release over the course of 18 calendar days. + - 7 commits contributed to the release over the course of 18 calendar days. - 19 days passed between releases. - 1 commit was understood as [conventional](https://www.conventionalcommits.org). - 0 issues like '(#ID)' were seen in commit messages @@ -29,6 +29,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
view details * **Uncategorized** + - Release gix-date v0.7.3, gix-hash v0.12.0, gix-features v0.33.0, gix-actor v0.25.0, gix-object v0.35.0, gix-path v0.9.0, gix-glob v0.11.0, gix-quote v0.4.7, gix-attributes v0.17.0, gix-command v0.2.9, gix-packetline-blocking v0.16.5, gix-filter v0.3.0, gix-fs v0.5.0, gix-commitgraph v0.19.0, gix-hashtable v0.3.0, gix-revwalk v0.6.0, gix-traverse v0.31.0, gix-worktree-stream v0.3.0, gix-archive v0.3.0, gix-config-value v0.13.0, gix-tempfile v8.0.0, gix-lock v8.0.0, gix-ref v0.35.0, gix-sec v0.9.0, gix-config v0.28.0, gix-prompt v0.6.0, gix-url v0.22.0, gix-credentials v0.18.0, gix-diff v0.34.0, gix-discover v0.23.0, gix-ignore v0.6.0, gix-bitmap v0.2.7, gix-index v0.22.0, gix-mailmap v0.17.0, gix-negotiate v0.6.0, gix-pack v0.41.0, gix-odb v0.51.0, gix-pathspec v0.1.0, gix-packetline v0.16.5, gix-transport v0.35.0, gix-protocol v0.38.0, gix-revision v0.20.0, gix-refspec v0.16.0, gix-submodule v0.2.0, gix-worktree v0.24.0, gix-worktree-state v0.1.0, gix v0.52.0, gitoxide-core v0.31.0, gitoxide v0.29.0, safety bump 41 crates ([`30b2761`](https://github.com/Byron/gitoxide/commit/30b27615047692d3ced1b2d9c2ac15a80f79fbee)) - Remove version specifications from dev dependencies ([`e80ed04`](https://github.com/Byron/gitoxide/commit/e80ed04f1cc065c5f4ddf196e780a8a8511a8069)) - Update changelogs prior to release ([`f23ea88`](https://github.com/Byron/gitoxide/commit/f23ea8828f2d9ba7559973daca388c9591bcc5fc)) - Reorganize tests to get rid of feature toggles that are for internal testing only ([`01c6ef6`](https://github.com/Byron/gitoxide/commit/01c6ef62e260246f1623bdf05f49c03eff14ac69)) diff --git a/gix-pack/CHANGELOG.md b/gix-pack/CHANGELOG.md index 3327052419f..290174894bb 100644 --- a/gix-pack/CHANGELOG.md +++ b/gix-pack/CHANGELOG.md @@ -20,7 +20,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - - 4 commits contributed to the release over the course of 15 calendar days. + - 5 commits contributed to the release over the course of 15 calendar days. - 29 days passed between releases. - 1 commit was understood as [conventional](https://www.conventionalcommits.org). - 0 issues like '(#ID)' were seen in commit messages @@ -32,6 +32,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
view details * **Uncategorized** + - Release gix-date v0.7.3, gix-hash v0.12.0, gix-features v0.33.0, gix-actor v0.25.0, gix-object v0.35.0, gix-path v0.9.0, gix-glob v0.11.0, gix-quote v0.4.7, gix-attributes v0.17.0, gix-command v0.2.9, gix-packetline-blocking v0.16.5, gix-filter v0.3.0, gix-fs v0.5.0, gix-commitgraph v0.19.0, gix-hashtable v0.3.0, gix-revwalk v0.6.0, gix-traverse v0.31.0, gix-worktree-stream v0.3.0, gix-archive v0.3.0, gix-config-value v0.13.0, gix-tempfile v8.0.0, gix-lock v8.0.0, gix-ref v0.35.0, gix-sec v0.9.0, gix-config v0.28.0, gix-prompt v0.6.0, gix-url v0.22.0, gix-credentials v0.18.0, gix-diff v0.34.0, gix-discover v0.23.0, gix-ignore v0.6.0, gix-bitmap v0.2.7, gix-index v0.22.0, gix-mailmap v0.17.0, gix-negotiate v0.6.0, gix-pack v0.41.0, gix-odb v0.51.0, gix-pathspec v0.1.0, gix-packetline v0.16.5, gix-transport v0.35.0, gix-protocol v0.38.0, gix-revision v0.20.0, gix-refspec v0.16.0, gix-submodule v0.2.0, gix-worktree v0.24.0, gix-worktree-state v0.1.0, gix v0.52.0, gitoxide-core v0.31.0, gitoxide v0.29.0, safety bump 41 crates ([`30b2761`](https://github.com/Byron/gitoxide/commit/30b27615047692d3ced1b2d9c2ac15a80f79fbee)) - Update changelogs prior to release ([`f23ea88`](https://github.com/Byron/gitoxide/commit/f23ea8828f2d9ba7559973daca388c9591bcc5fc)) - More cleanup of test crates ([`73c685a`](https://github.com/Byron/gitoxide/commit/73c685a67debcfa26a940f37bbca69cb3a4af57e)) - Split tests off into their own crate to allow feature toggles. ([`93feea2`](https://github.com/Byron/gitoxide/commit/93feea269eebd114e866e6f29f4a73c0096df9e0)) diff --git a/gix-packetline/CHANGELOG.md b/gix-packetline/CHANGELOG.md index f007a3f49e4..7c23e441eb6 100644 --- a/gix-packetline/CHANGELOG.md +++ b/gix-packetline/CHANGELOG.md @@ -21,7 +21,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - - 4 commits contributed to the release over the course of 5 calendar days. + - 5 commits contributed to the release over the course of 5 calendar days. - 30 days passed between releases. - 2 commits were understood as [conventional](https://www.conventionalcommits.org). - 0 issues like '(#ID)' were seen in commit messages @@ -33,6 +33,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
view details * **Uncategorized** + - Release gix-date v0.7.3, gix-hash v0.12.0, gix-features v0.33.0, gix-actor v0.25.0, gix-object v0.35.0, gix-path v0.9.0, gix-glob v0.11.0, gix-quote v0.4.7, gix-attributes v0.17.0, gix-command v0.2.9, gix-packetline-blocking v0.16.5, gix-filter v0.3.0, gix-fs v0.5.0, gix-commitgraph v0.19.0, gix-hashtable v0.3.0, gix-revwalk v0.6.0, gix-traverse v0.31.0, gix-worktree-stream v0.3.0, gix-archive v0.3.0, gix-config-value v0.13.0, gix-tempfile v8.0.0, gix-lock v8.0.0, gix-ref v0.35.0, gix-sec v0.9.0, gix-config v0.28.0, gix-prompt v0.6.0, gix-url v0.22.0, gix-credentials v0.18.0, gix-diff v0.34.0, gix-discover v0.23.0, gix-ignore v0.6.0, gix-bitmap v0.2.7, gix-index v0.22.0, gix-mailmap v0.17.0, gix-negotiate v0.6.0, gix-pack v0.41.0, gix-odb v0.51.0, gix-pathspec v0.1.0, gix-packetline v0.16.5, gix-transport v0.35.0, gix-protocol v0.38.0, gix-revision v0.20.0, gix-refspec v0.16.0, gix-submodule v0.2.0, gix-worktree v0.24.0, gix-worktree-state v0.1.0, gix v0.52.0, gitoxide-core v0.31.0, gitoxide v0.29.0, safety bump 41 crates ([`30b2761`](https://github.com/Byron/gitoxide/commit/30b27615047692d3ced1b2d9c2ac15a80f79fbee)) - Update changelogs prior to release ([`f23ea88`](https://github.com/Byron/gitoxide/commit/f23ea8828f2d9ba7559973daca388c9591bcc5fc)) - Don't call crate 'WIP' in manifest anymore. ([`229bd48`](https://github.com/Byron/gitoxide/commit/229bd4899213f749a7cc124aa2b82a1368fba40f)) - Merge branch 'faster-hex' ([`4a4fa0f`](https://github.com/Byron/gitoxide/commit/4a4fa0fcdaa6e14b51d3f03f5d7c5b65042667bf)) diff --git a/gix-pathspec/CHANGELOG.md b/gix-pathspec/CHANGELOG.md index 23c56ec72e0..6ec2a9316d4 100644 --- a/gix-pathspec/CHANGELOG.md +++ b/gix-pathspec/CHANGELOG.md @@ -9,6 +9,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 + + ### Chore @@ -68,7 +70,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - - 167 commits contributed to the release over the course of 523 calendar days. + - 168 commits contributed to the release over the course of 523 calendar days. - 12 commits were understood as [conventional](https://www.conventionalcommits.org). - 5 unique issues were worked on: [#301](https://github.com/Byron/gitoxide/issues/301), [#415](https://github.com/Byron/gitoxide/issues/415), [#427](https://github.com/Byron/gitoxide/issues/427), [#450](https://github.com/Byron/gitoxide/issues/450), [#691](https://github.com/Byron/gitoxide/issues/691) @@ -104,6 +106,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 * **[#691](https://github.com/Byron/gitoxide/issues/691)** - Set `rust-version` to 1.64 ([`55066ce`](https://github.com/Byron/gitoxide/commit/55066ce5fd71209abb5d84da2998b903504584bb)) * **Uncategorized** + - Release gix-date v0.7.3, gix-hash v0.12.0, gix-features v0.33.0, gix-actor v0.25.0, gix-object v0.35.0, gix-path v0.9.0, gix-glob v0.11.0, gix-quote v0.4.7, gix-attributes v0.17.0, gix-command v0.2.9, gix-packetline-blocking v0.16.5, gix-filter v0.3.0, gix-fs v0.5.0, gix-commitgraph v0.19.0, gix-hashtable v0.3.0, gix-revwalk v0.6.0, gix-traverse v0.31.0, gix-worktree-stream v0.3.0, gix-archive v0.3.0, gix-config-value v0.13.0, gix-tempfile v8.0.0, gix-lock v8.0.0, gix-ref v0.35.0, gix-sec v0.9.0, gix-config v0.28.0, gix-prompt v0.6.0, gix-url v0.22.0, gix-credentials v0.18.0, gix-diff v0.34.0, gix-discover v0.23.0, gix-ignore v0.6.0, gix-bitmap v0.2.7, gix-index v0.22.0, gix-mailmap v0.17.0, gix-negotiate v0.6.0, gix-pack v0.41.0, gix-odb v0.51.0, gix-pathspec v0.1.0, gix-packetline v0.16.5, gix-transport v0.35.0, gix-protocol v0.38.0, gix-revision v0.20.0, gix-refspec v0.16.0, gix-submodule v0.2.0, gix-worktree v0.24.0, gix-worktree-state v0.1.0, gix v0.52.0, gitoxide-core v0.31.0, gitoxide v0.29.0, safety bump 41 crates ([`30b2761`](https://github.com/Byron/gitoxide/commit/30b27615047692d3ced1b2d9c2ac15a80f79fbee)) - Update changelogs prior to release ([`f23ea88`](https://github.com/Byron/gitoxide/commit/f23ea8828f2d9ba7559973daca388c9591bcc5fc)) - Just fmt ([`0d258f4`](https://github.com/Byron/gitoxide/commit/0d258f40afcd848509e2b0c7c264e9f346ed1726)) - Don't call crate 'WIP' in manifest anymore. ([`229bd48`](https://github.com/Byron/gitoxide/commit/229bd4899213f749a7cc124aa2b82a1368fba40f)) diff --git a/gix-protocol/CHANGELOG.md b/gix-protocol/CHANGELOG.md index 94ef0c48df6..ac8b8832460 100644 --- a/gix-protocol/CHANGELOG.md +++ b/gix-protocol/CHANGELOG.md @@ -17,7 +17,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - - 3 commits contributed to the release over the course of 15 calendar days. + - 4 commits contributed to the release over the course of 15 calendar days. - 19 days passed between releases. - 1 commit was understood as [conventional](https://www.conventionalcommits.org). - 0 issues like '(#ID)' were seen in commit messages @@ -29,6 +29,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
view details * **Uncategorized** + - Release gix-date v0.7.3, gix-hash v0.12.0, gix-features v0.33.0, gix-actor v0.25.0, gix-object v0.35.0, gix-path v0.9.0, gix-glob v0.11.0, gix-quote v0.4.7, gix-attributes v0.17.0, gix-command v0.2.9, gix-packetline-blocking v0.16.5, gix-filter v0.3.0, gix-fs v0.5.0, gix-commitgraph v0.19.0, gix-hashtable v0.3.0, gix-revwalk v0.6.0, gix-traverse v0.31.0, gix-worktree-stream v0.3.0, gix-archive v0.3.0, gix-config-value v0.13.0, gix-tempfile v8.0.0, gix-lock v8.0.0, gix-ref v0.35.0, gix-sec v0.9.0, gix-config v0.28.0, gix-prompt v0.6.0, gix-url v0.22.0, gix-credentials v0.18.0, gix-diff v0.34.0, gix-discover v0.23.0, gix-ignore v0.6.0, gix-bitmap v0.2.7, gix-index v0.22.0, gix-mailmap v0.17.0, gix-negotiate v0.6.0, gix-pack v0.41.0, gix-odb v0.51.0, gix-pathspec v0.1.0, gix-packetline v0.16.5, gix-transport v0.35.0, gix-protocol v0.38.0, gix-revision v0.20.0, gix-refspec v0.16.0, gix-submodule v0.2.0, gix-worktree v0.24.0, gix-worktree-state v0.1.0, gix v0.52.0, gitoxide-core v0.31.0, gitoxide v0.29.0, safety bump 41 crates ([`30b2761`](https://github.com/Byron/gitoxide/commit/30b27615047692d3ced1b2d9c2ac15a80f79fbee)) - Update changelogs prior to release ([`f23ea88`](https://github.com/Byron/gitoxide/commit/f23ea8828f2d9ba7559973daca388c9591bcc5fc)) - Don't call crate 'WIP' in manifest anymore. ([`229bd48`](https://github.com/Byron/gitoxide/commit/229bd4899213f749a7cc124aa2b82a1368fba40f)) - Release gix-glob v0.10.2, gix-date v0.7.2, gix-validate v0.8.0, gix-object v0.34.0, gix-ref v0.34.0, gix-config v0.27.0, gix-commitgraph v0.18.2, gix-revwalk v0.5.0, gix-revision v0.19.0, gix-refspec v0.15.0, gix-submodule v0.1.0, safety bump 18 crates ([`4604f83`](https://github.com/Byron/gitoxide/commit/4604f83ef238dc07c85aaeae097399b67f3cfd0c)) diff --git a/gix-refspec/CHANGELOG.md b/gix-refspec/CHANGELOG.md index 9d15cf52439..67e7af0e8e3 100644 --- a/gix-refspec/CHANGELOG.md +++ b/gix-refspec/CHANGELOG.md @@ -17,7 +17,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - - 2 commits contributed to the release over the course of 4 calendar days. + - 3 commits contributed to the release over the course of 4 calendar days. - 15 days passed between releases. - 1 commit was understood as [conventional](https://www.conventionalcommits.org). - 0 issues like '(#ID)' were seen in commit messages @@ -29,6 +29,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
view details * **Uncategorized** + - Release gix-date v0.7.3, gix-hash v0.12.0, gix-features v0.33.0, gix-actor v0.25.0, gix-object v0.35.0, gix-path v0.9.0, gix-glob v0.11.0, gix-quote v0.4.7, gix-attributes v0.17.0, gix-command v0.2.9, gix-packetline-blocking v0.16.5, gix-filter v0.3.0, gix-fs v0.5.0, gix-commitgraph v0.19.0, gix-hashtable v0.3.0, gix-revwalk v0.6.0, gix-traverse v0.31.0, gix-worktree-stream v0.3.0, gix-archive v0.3.0, gix-config-value v0.13.0, gix-tempfile v8.0.0, gix-lock v8.0.0, gix-ref v0.35.0, gix-sec v0.9.0, gix-config v0.28.0, gix-prompt v0.6.0, gix-url v0.22.0, gix-credentials v0.18.0, gix-diff v0.34.0, gix-discover v0.23.0, gix-ignore v0.6.0, gix-bitmap v0.2.7, gix-index v0.22.0, gix-mailmap v0.17.0, gix-negotiate v0.6.0, gix-pack v0.41.0, gix-odb v0.51.0, gix-pathspec v0.1.0, gix-packetline v0.16.5, gix-transport v0.35.0, gix-protocol v0.38.0, gix-revision v0.20.0, gix-refspec v0.16.0, gix-submodule v0.2.0, gix-worktree v0.24.0, gix-worktree-state v0.1.0, gix v0.52.0, gitoxide-core v0.31.0, gitoxide v0.29.0, safety bump 41 crates ([`30b2761`](https://github.com/Byron/gitoxide/commit/30b27615047692d3ced1b2d9c2ac15a80f79fbee)) - Update changelogs prior to release ([`f23ea88`](https://github.com/Byron/gitoxide/commit/f23ea8828f2d9ba7559973daca388c9591bcc5fc)) - Don't call crate 'WIP' in manifest anymore. ([`229bd48`](https://github.com/Byron/gitoxide/commit/229bd4899213f749a7cc124aa2b82a1368fba40f))
diff --git a/gix-revision/CHANGELOG.md b/gix-revision/CHANGELOG.md index 6820d2463f6..f99bd98febf 100644 --- a/gix-revision/CHANGELOG.md +++ b/gix-revision/CHANGELOG.md @@ -37,7 +37,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - - 11 commits contributed to the release over the course of 14 calendar days. + - 13 commits contributed to the release over the course of 14 calendar days. - 15 days passed between releases. - 6 commits were understood as [conventional](https://www.conventionalcommits.org). - 0 issues like '(#ID)' were seen in commit messages @@ -49,6 +49,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
view details * **Uncategorized** + - Make `gix-url` publishable by adding baseline test ([`d3746df`](https://github.com/Byron/gitoxide/commit/d3746df5dd402d8a461c2b07eaa0f8d8803fadf8)) + - Release gix-date v0.7.3, gix-hash v0.12.0, gix-features v0.33.0, gix-actor v0.25.0, gix-object v0.35.0, gix-path v0.9.0, gix-glob v0.11.0, gix-quote v0.4.7, gix-attributes v0.17.0, gix-command v0.2.9, gix-packetline-blocking v0.16.5, gix-filter v0.3.0, gix-fs v0.5.0, gix-commitgraph v0.19.0, gix-hashtable v0.3.0, gix-revwalk v0.6.0, gix-traverse v0.31.0, gix-worktree-stream v0.3.0, gix-archive v0.3.0, gix-config-value v0.13.0, gix-tempfile v8.0.0, gix-lock v8.0.0, gix-ref v0.35.0, gix-sec v0.9.0, gix-config v0.28.0, gix-prompt v0.6.0, gix-url v0.22.0, gix-credentials v0.18.0, gix-diff v0.34.0, gix-discover v0.23.0, gix-ignore v0.6.0, gix-bitmap v0.2.7, gix-index v0.22.0, gix-mailmap v0.17.0, gix-negotiate v0.6.0, gix-pack v0.41.0, gix-odb v0.51.0, gix-pathspec v0.1.0, gix-packetline v0.16.5, gix-transport v0.35.0, gix-protocol v0.38.0, gix-revision v0.20.0, gix-refspec v0.16.0, gix-submodule v0.2.0, gix-worktree v0.24.0, gix-worktree-state v0.1.0, gix v0.52.0, gitoxide-core v0.31.0, gitoxide v0.29.0, safety bump 41 crates ([`30b2761`](https://github.com/Byron/gitoxide/commit/30b27615047692d3ced1b2d9c2ac15a80f79fbee)) - Update changelogs prior to release ([`f23ea88`](https://github.com/Byron/gitoxide/commit/f23ea8828f2d9ba7559973daca388c9591bcc5fc)) - Add tracing support to `describt()`. ([`f4a9a6b`](https://github.com/Byron/gitoxide/commit/f4a9a6b574ad4521d475e9088073c0f15d56d079)) - Switch `nom` to `winnow` in remaining uses in `gix-object`, `gix-ref`, and `gix-actor` for ~20% more performance. ([`ef54aab`](https://github.com/Byron/gitoxide/commit/ef54aab9e5521add4154ee8d902d62612a9d8d4a)) diff --git a/gix-submodule/CHANGELOG.md b/gix-submodule/CHANGELOG.md index 05baf648010..3493beb66f0 100644 --- a/gix-submodule/CHANGELOG.md +++ b/gix-submodule/CHANGELOG.md @@ -35,7 +35,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - - 10 commits contributed to the release over the course of 4 calendar days. + - 11 commits contributed to the release over the course of 4 calendar days. - 15 days passed between releases. - 6 commits were understood as [conventional](https://www.conventionalcommits.org). - 0 issues like '(#ID)' were seen in commit messages @@ -47,6 +47,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
view details * **Uncategorized** + - Release gix-date v0.7.3, gix-hash v0.12.0, gix-features v0.33.0, gix-actor v0.25.0, gix-object v0.35.0, gix-path v0.9.0, gix-glob v0.11.0, gix-quote v0.4.7, gix-attributes v0.17.0, gix-command v0.2.9, gix-packetline-blocking v0.16.5, gix-filter v0.3.0, gix-fs v0.5.0, gix-commitgraph v0.19.0, gix-hashtable v0.3.0, gix-revwalk v0.6.0, gix-traverse v0.31.0, gix-worktree-stream v0.3.0, gix-archive v0.3.0, gix-config-value v0.13.0, gix-tempfile v8.0.0, gix-lock v8.0.0, gix-ref v0.35.0, gix-sec v0.9.0, gix-config v0.28.0, gix-prompt v0.6.0, gix-url v0.22.0, gix-credentials v0.18.0, gix-diff v0.34.0, gix-discover v0.23.0, gix-ignore v0.6.0, gix-bitmap v0.2.7, gix-index v0.22.0, gix-mailmap v0.17.0, gix-negotiate v0.6.0, gix-pack v0.41.0, gix-odb v0.51.0, gix-pathspec v0.1.0, gix-packetline v0.16.5, gix-transport v0.35.0, gix-protocol v0.38.0, gix-revision v0.20.0, gix-refspec v0.16.0, gix-submodule v0.2.0, gix-worktree v0.24.0, gix-worktree-state v0.1.0, gix v0.52.0, gitoxide-core v0.31.0, gitoxide v0.29.0, safety bump 41 crates ([`30b2761`](https://github.com/Byron/gitoxide/commit/30b27615047692d3ced1b2d9c2ac15a80f79fbee)) - Update changelogs prior to release ([`f23ea88`](https://github.com/Byron/gitoxide/commit/f23ea8828f2d9ba7559973daca388c9591bcc5fc)) - `Modules::is_active()` now counts everything that doesn't match `submodule.active` (if present) as inactive. ([`e0d9b09`](https://github.com/Byron/gitoxide/commit/e0d9b09d02f88536b93ab6a31fddf9483881c5c1)) - Just fmt ([`0d258f4`](https://github.com/Byron/gitoxide/commit/0d258f40afcd848509e2b0c7c264e9f346ed1726)) diff --git a/gix-transport/CHANGELOG.md b/gix-transport/CHANGELOG.md index 540139e7df5..17b0277903b 100644 --- a/gix-transport/CHANGELOG.md +++ b/gix-transport/CHANGELOG.md @@ -17,7 +17,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - - 6 commits contributed to the release over the course of 9 calendar days. + - 7 commits contributed to the release over the course of 9 calendar days. - 19 days passed between releases. - 1 commit was understood as [conventional](https://www.conventionalcommits.org). - 0 issues like '(#ID)' were seen in commit messages @@ -29,6 +29,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
view details * **Uncategorized** + - Release gix-date v0.7.3, gix-hash v0.12.0, gix-features v0.33.0, gix-actor v0.25.0, gix-object v0.35.0, gix-path v0.9.0, gix-glob v0.11.0, gix-quote v0.4.7, gix-attributes v0.17.0, gix-command v0.2.9, gix-packetline-blocking v0.16.5, gix-filter v0.3.0, gix-fs v0.5.0, gix-commitgraph v0.19.0, gix-hashtable v0.3.0, gix-revwalk v0.6.0, gix-traverse v0.31.0, gix-worktree-stream v0.3.0, gix-archive v0.3.0, gix-config-value v0.13.0, gix-tempfile v8.0.0, gix-lock v8.0.0, gix-ref v0.35.0, gix-sec v0.9.0, gix-config v0.28.0, gix-prompt v0.6.0, gix-url v0.22.0, gix-credentials v0.18.0, gix-diff v0.34.0, gix-discover v0.23.0, gix-ignore v0.6.0, gix-bitmap v0.2.7, gix-index v0.22.0, gix-mailmap v0.17.0, gix-negotiate v0.6.0, gix-pack v0.41.0, gix-odb v0.51.0, gix-pathspec v0.1.0, gix-packetline v0.16.5, gix-transport v0.35.0, gix-protocol v0.38.0, gix-revision v0.20.0, gix-refspec v0.16.0, gix-submodule v0.2.0, gix-worktree v0.24.0, gix-worktree-state v0.1.0, gix v0.52.0, gitoxide-core v0.31.0, gitoxide v0.29.0, safety bump 41 crates ([`30b2761`](https://github.com/Byron/gitoxide/commit/30b27615047692d3ced1b2d9c2ac15a80f79fbee)) - Update changelogs prior to release ([`f23ea88`](https://github.com/Byron/gitoxide/commit/f23ea8828f2d9ba7559973daca388c9591bcc5fc)) - Don't call crate 'WIP' in manifest anymore. ([`229bd48`](https://github.com/Byron/gitoxide/commit/229bd4899213f749a7cc124aa2b82a1368fba40f)) - Merge branch 'fix-redirect' ([`e83c38f`](https://github.com/Byron/gitoxide/commit/e83c38fcc32687dff2ea79bbfae154c5b577e07a)) diff --git a/gix-url/CHANGELOG.md b/gix-url/CHANGELOG.md index 9728372c085..70a8ea6a3fc 100644 --- a/gix-url/CHANGELOG.md +++ b/gix-url/CHANGELOG.md @@ -22,7 +22,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - - 18 commits contributed to the release over the course of 17 calendar days. + - 20 commits contributed to the release over the course of 17 calendar days. - 30 days passed between releases. - 2 commits were understood as [conventional](https://www.conventionalcommits.org). - 0 issues like '(#ID)' were seen in commit messages @@ -34,6 +34,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
view details * **Uncategorized** + - Make `gix-url` publishable by adding baseline test ([`d3746df`](https://github.com/Byron/gitoxide/commit/d3746df5dd402d8a461c2b07eaa0f8d8803fadf8)) + - Release gix-date v0.7.3, gix-hash v0.12.0, gix-features v0.33.0, gix-actor v0.25.0, gix-object v0.35.0, gix-path v0.9.0, gix-glob v0.11.0, gix-quote v0.4.7, gix-attributes v0.17.0, gix-command v0.2.9, gix-packetline-blocking v0.16.5, gix-filter v0.3.0, gix-fs v0.5.0, gix-commitgraph v0.19.0, gix-hashtable v0.3.0, gix-revwalk v0.6.0, gix-traverse v0.31.0, gix-worktree-stream v0.3.0, gix-archive v0.3.0, gix-config-value v0.13.0, gix-tempfile v8.0.0, gix-lock v8.0.0, gix-ref v0.35.0, gix-sec v0.9.0, gix-config v0.28.0, gix-prompt v0.6.0, gix-url v0.22.0, gix-credentials v0.18.0, gix-diff v0.34.0, gix-discover v0.23.0, gix-ignore v0.6.0, gix-bitmap v0.2.7, gix-index v0.22.0, gix-mailmap v0.17.0, gix-negotiate v0.6.0, gix-pack v0.41.0, gix-odb v0.51.0, gix-pathspec v0.1.0, gix-packetline v0.16.5, gix-transport v0.35.0, gix-protocol v0.38.0, gix-revision v0.20.0, gix-refspec v0.16.0, gix-submodule v0.2.0, gix-worktree v0.24.0, gix-worktree-state v0.1.0, gix v0.52.0, gitoxide-core v0.31.0, gitoxide v0.29.0, safety bump 41 crates ([`30b2761`](https://github.com/Byron/gitoxide/commit/30b27615047692d3ced1b2d9c2ac15a80f79fbee)) - Update changelogs prior to release ([`f23ea88`](https://github.com/Byron/gitoxide/commit/f23ea8828f2d9ba7559973daca388c9591bcc5fc)) - Merge branch 'gix-url-fixture-tests' ([`1b957c5`](https://github.com/Byron/gitoxide/commit/1b957c524cae288ac2063f6ba7e4d10d523eb8f3)) - For now, ignore baseline tests as most of them fail. ([`c0be6ab`](https://github.com/Byron/gitoxide/commit/c0be6aba49d734d166f279933220b02989c584de)) diff --git a/gix-worktree-state/CHANGELOG.md b/gix-worktree-state/CHANGELOG.md index 9bd4adfeb8e..2e10ddeb546 100644 --- a/gix-worktree-state/CHANGELOG.md +++ b/gix-worktree-state/CHANGELOG.md @@ -24,7 +24,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - - 10 commits contributed to the release over the course of 2 calendar days. + - 11 commits contributed to the release over the course of 2 calendar days. - 2 commits were understood as [conventional](https://www.conventionalcommits.org). - 0 issues like '(#ID)' were seen in commit messages @@ -35,6 +35,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
view details * **Uncategorized** + - Release gix-date v0.7.3, gix-hash v0.12.0, gix-features v0.33.0, gix-actor v0.25.0, gix-object v0.35.0, gix-path v0.9.0, gix-glob v0.11.0, gix-quote v0.4.7, gix-attributes v0.17.0, gix-command v0.2.9, gix-packetline-blocking v0.16.5, gix-filter v0.3.0, gix-fs v0.5.0, gix-commitgraph v0.19.0, gix-hashtable v0.3.0, gix-revwalk v0.6.0, gix-traverse v0.31.0, gix-worktree-stream v0.3.0, gix-archive v0.3.0, gix-config-value v0.13.0, gix-tempfile v8.0.0, gix-lock v8.0.0, gix-ref v0.35.0, gix-sec v0.9.0, gix-config v0.28.0, gix-prompt v0.6.0, gix-url v0.22.0, gix-credentials v0.18.0, gix-diff v0.34.0, gix-discover v0.23.0, gix-ignore v0.6.0, gix-bitmap v0.2.7, gix-index v0.22.0, gix-mailmap v0.17.0, gix-negotiate v0.6.0, gix-pack v0.41.0, gix-odb v0.51.0, gix-pathspec v0.1.0, gix-packetline v0.16.5, gix-transport v0.35.0, gix-protocol v0.38.0, gix-revision v0.20.0, gix-refspec v0.16.0, gix-submodule v0.2.0, gix-worktree v0.24.0, gix-worktree-state v0.1.0, gix v0.52.0, gitoxide-core v0.31.0, gitoxide v0.29.0, safety bump 41 crates ([`30b2761`](https://github.com/Byron/gitoxide/commit/30b27615047692d3ced1b2d9c2ac15a80f79fbee)) - Update changelogs prior to release ([`f23ea88`](https://github.com/Byron/gitoxide/commit/f23ea8828f2d9ba7559973daca388c9591bcc5fc)) - `checkout()` now creates empty directories for submodules. ([`fc0529e`](https://github.com/Byron/gitoxide/commit/fc0529eaa805e696f7297ba8cf0179c5fac7c677)) - More cleanup of test crates ([`73c685a`](https://github.com/Byron/gitoxide/commit/73c685a67debcfa26a940f37bbca69cb3a4af57e)) diff --git a/gix-worktree/CHANGELOG.md b/gix-worktree/CHANGELOG.md index 5f2ecaa25b7..a869a1dd626 100644 --- a/gix-worktree/CHANGELOG.md +++ b/gix-worktree/CHANGELOG.md @@ -40,7 +40,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - - 18 commits contributed to the release over the course of 18 calendar days. + - 19 commits contributed to the release over the course of 18 calendar days. - 19 days passed between releases. - 6 commits were understood as [conventional](https://www.conventionalcommits.org). - 0 issues like '(#ID)' were seen in commit messages @@ -52,6 +52,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
view details * **Uncategorized** + - Release gix-date v0.7.3, gix-hash v0.12.0, gix-features v0.33.0, gix-actor v0.25.0, gix-object v0.35.0, gix-path v0.9.0, gix-glob v0.11.0, gix-quote v0.4.7, gix-attributes v0.17.0, gix-command v0.2.9, gix-packetline-blocking v0.16.5, gix-filter v0.3.0, gix-fs v0.5.0, gix-commitgraph v0.19.0, gix-hashtable v0.3.0, gix-revwalk v0.6.0, gix-traverse v0.31.0, gix-worktree-stream v0.3.0, gix-archive v0.3.0, gix-config-value v0.13.0, gix-tempfile v8.0.0, gix-lock v8.0.0, gix-ref v0.35.0, gix-sec v0.9.0, gix-config v0.28.0, gix-prompt v0.6.0, gix-url v0.22.0, gix-credentials v0.18.0, gix-diff v0.34.0, gix-discover v0.23.0, gix-ignore v0.6.0, gix-bitmap v0.2.7, gix-index v0.22.0, gix-mailmap v0.17.0, gix-negotiate v0.6.0, gix-pack v0.41.0, gix-odb v0.51.0, gix-pathspec v0.1.0, gix-packetline v0.16.5, gix-transport v0.35.0, gix-protocol v0.38.0, gix-revision v0.20.0, gix-refspec v0.16.0, gix-submodule v0.2.0, gix-worktree v0.24.0, gix-worktree-state v0.1.0, gix v0.52.0, gitoxide-core v0.31.0, gitoxide v0.29.0, safety bump 41 crates ([`30b2761`](https://github.com/Byron/gitoxide/commit/30b27615047692d3ced1b2d9c2ac15a80f79fbee)) - Update changelogs prior to release ([`f23ea88`](https://github.com/Byron/gitoxide/commit/f23ea8828f2d9ba7559973daca388c9591bcc5fc)) - More cleanup of test crates ([`73c685a`](https://github.com/Byron/gitoxide/commit/73c685a67debcfa26a940f37bbca69cb3a4af57e)) - Split tests off into their own crate to allow feature toggles. ([`93feea2`](https://github.com/Byron/gitoxide/commit/93feea269eebd114e866e6f29f4a73c0096df9e0)) diff --git a/gix/CHANGELOG.md b/gix/CHANGELOG.md index a1674eb920d..9e8b2740e44 100644 --- a/gix/CHANGELOG.md +++ b/gix/CHANGELOG.md @@ -46,7 +46,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - - 29 commits contributed to the release over the course of 18 calendar days. + - 30 commits contributed to the release over the course of 18 calendar days. - 19 days passed between releases. - 9 commits were understood as [conventional](https://www.conventionalcommits.org). - 0 issues like '(#ID)' were seen in commit messages @@ -58,6 +58,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
view details * **Uncategorized** + - Release gix-date v0.7.3, gix-hash v0.12.0, gix-features v0.33.0, gix-actor v0.25.0, gix-object v0.35.0, gix-path v0.9.0, gix-glob v0.11.0, gix-quote v0.4.7, gix-attributes v0.17.0, gix-command v0.2.9, gix-packetline-blocking v0.16.5, gix-filter v0.3.0, gix-fs v0.5.0, gix-commitgraph v0.19.0, gix-hashtable v0.3.0, gix-revwalk v0.6.0, gix-traverse v0.31.0, gix-worktree-stream v0.3.0, gix-archive v0.3.0, gix-config-value v0.13.0, gix-tempfile v8.0.0, gix-lock v8.0.0, gix-ref v0.35.0, gix-sec v0.9.0, gix-config v0.28.0, gix-prompt v0.6.0, gix-url v0.22.0, gix-credentials v0.18.0, gix-diff v0.34.0, gix-discover v0.23.0, gix-ignore v0.6.0, gix-bitmap v0.2.7, gix-index v0.22.0, gix-mailmap v0.17.0, gix-negotiate v0.6.0, gix-pack v0.41.0, gix-odb v0.51.0, gix-pathspec v0.1.0, gix-packetline v0.16.5, gix-transport v0.35.0, gix-protocol v0.38.0, gix-revision v0.20.0, gix-refspec v0.16.0, gix-submodule v0.2.0, gix-worktree v0.24.0, gix-worktree-state v0.1.0, gix v0.52.0, gitoxide-core v0.31.0, gitoxide v0.29.0, safety bump 41 crates ([`30b2761`](https://github.com/Byron/gitoxide/commit/30b27615047692d3ced1b2d9c2ac15a80f79fbee)) - Update changelogs prior to release ([`f23ea88`](https://github.com/Byron/gitoxide/commit/f23ea8828f2d9ba7559973daca388c9591bcc5fc)) - Make sure that submodule hashes aren't attached as the parent repo is the wrong one here. ([`c96f26b`](https://github.com/Byron/gitoxide/commit/c96f26b5c13581812753638a24d261c3f75dddcf)) - Properly isolate environment variable based tests into their own binary ([`c35ddab`](https://github.com/Byron/gitoxide/commit/c35ddab41ff6f18ad9cd11df44cfffee91563433)) From 015f12e8ca35d96173ea481fe31bf9097b001a89 Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Tue, 22 Aug 2023 15:28:42 +0200 Subject: [PATCH 0010/1077] remove `cargo-smart-release` - moved to https://github.com/Byron/cargo-smart-release --- cargo-smart-release/CHANGELOG.md | 2316 -------------- cargo-smart-release/Cargo.lock | 2693 ----------------- cargo-smart-release/Cargo.toml | 47 - cargo-smart-release/README.md | 106 - cargo-smart-release/build.rs | 17 - cargo-smart-release/src/bat.rs | 47 - cargo-smart-release/src/changelog/header.md | 7 - cargo-smart-release/src/changelog/init.rs | 129 - cargo-smart-release/src/changelog/merge.rs | 334 -- cargo-smart-release/src/changelog/mod.rs | 116 - cargo-smart-release/src/changelog/parse.rs | 520 ---- .../src/changelog/section/from_history.rs | 174 -- .../src/changelog/section/mod.rs | 38 - .../src/changelog/section/segment.rs | 143 - cargo-smart-release/src/changelog/tests.rs | 22 - cargo-smart-release/src/changelog/write.rs | 422 --- cargo-smart-release/src/cli/main-changelog.rs | 1 - .../src/cli/main-smart-release.rs | 1 - cargo-smart-release/src/cli/main.rs | 145 - cargo-smart-release/src/cli/options.rs | 213 -- cargo-smart-release/src/command/changelog.rs | 151 - cargo-smart-release/src/command/mod.rs | 52 - .../src/command/release/cargo.rs | 66 - .../src/command/release/git.rs | 117 - .../src/command/release/github.rs | 72 - .../src/command/release/manifest.rs | 618 ---- .../src/command/release/mod.rs | 527 ---- cargo-smart-release/src/commit/history.rs | 30 - cargo-smart-release/src/commit/message.rs | 200 -- cargo-smart-release/src/commit/mod.rs | 29 - cargo-smart-release/src/context.rs | 95 - cargo-smart-release/src/crates_index.rs | 24 - cargo-smart-release/src/git/history.rs | 280 -- cargo-smart-release/src/git/mod.rs | 114 - cargo-smart-release/src/lib.rs | 20 - cargo-smart-release/src/traverse.rs | 608 ---- cargo-smart-release/src/utils.rs | 306 -- cargo-smart-release/src/version.rs | 185 -- cargo-smart-release/tests/changelog/merge.rs | 418 --- cargo-smart-release/tests/changelog/mod.rs | 11 - cargo-smart-release/tests/changelog/parse.rs | 120 - .../tests/changelog/write_and_parse/mod.rs | 186 -- ...ll_section_types_round_trips_lossy-10.snap | 6 - ...ll_section_types_round_trips_lossy-11.snap | 33 - ...all_section_types_round_trips_lossy-2.snap | 50 - ...all_section_types_round_trips_lossy-3.snap | 10 - ...all_section_types_round_trips_lossy-4.snap | 6 - ...all_section_types_round_trips_lossy-5.snap | 28 - ...all_section_types_round_trips_lossy-6.snap | 10 - ...all_section_types_round_trips_lossy-7.snap | 12 - ...all_section_types_round_trips_lossy-8.snap | 39 - ...all_section_types_round_trips_lossy-9.snap | 10 - ...__all_section_types_round_trips_lossy.snap | 50 - ...__conventional_write_empty_messages-2.snap | 26 - ...__conventional_write_empty_messages-3.snap | 26 - ...__conventional_write_empty_messages-4.snap | 26 - ...__conventional_write_empty_messages-5.snap | 20 - ...__conventional_write_empty_messages-6.snap | 26 - ...se__conventional_write_empty_messages.snap | 25 - .../parse/known-section-unknown-content.md | 9 - ...nown-section-unknown-headline-with-link.md | 7 - .../unknown-known-unknown-known-unsorted.md | 13 - .../fixtures/tri-depth-workspace/Cargo.lock | 21 - .../fixtures/tri-depth-workspace/Cargo.toml | 2 - .../tri-depth-workspace/a/CHANGELOG.md | 6 - .../fixtures/tri-depth-workspace/a/Cargo.toml | 8 - .../fixtures/tri-depth-workspace/a/src/lib.rs | 7 - .../tri-depth-workspace/b/CHANGELOG.md | 9 - .../fixtures/tri-depth-workspace/b/Cargo.toml | 9 - .../fixtures/tri-depth-workspace/b/src/lib.rs | 7 - .../fixtures/tri-depth-workspace/c/Cargo.toml | 9 - .../tri-depth-workspace/c/src/main.rs | 3 - cargo-smart-release/tests/integration.rs | 3 - cargo-smart-release/tests/journey.sh | 196 -- .../a-dry-run-success-multi-crate | 1 - .../crate-a-released/.gitignore | 2 - .../crate-a-released/Cargo.lock | 21 - .../crate-a-released/Cargo.toml | 2 - .../crate-a-released/a/CHANGELOG.md | 27 - .../crate-a-released/a/Cargo.toml | 8 - .../crate-a-released/a/src/lib.rs | 7 - .../crate-a-released/b/CHANGELOG.md | 9 - .../crate-a-released/b/Cargo.toml | 9 - .../crate-a-released/b/src/lib.rs | 7 - .../crate-a-released/c/Cargo.toml | 9 - .../crate-a-released/c/src/main.rs | 3 - ...-dry-run-success-multi-crate-unconditional | 22 - .../a-dry-run-success-multi-crate | 12 - ...cess-multi-crate-auto-bump-breaking-change | 10 - ...uto-bump-breaking-change-dependant-publish | 24 - ...uto-bump-breaking-change-no-bump-on-demand | 15 - ...change-no-bump-on-demand-no-publish-stable | 15 - ...success-multi-crate-auto-bump-minor-change | 10 - ...un-success-multi-crate-auto-bump-no-change | 12 - ...-dry-run-success-multi-crate-unconditional | 18 - ...cess-multi-crate-auto-bump-breaking-change | 19 - ...success-multi-crate-auto-bump-minor-change | 19 - ...un-success-multi-crate-auto-bump-no-change | 19 - .../crate-a-released-force-bump/.gitignore | 1 - .../.package-cache | 0 .../crate-a-released-force-bump/Cargo.lock | 21 - .../crate-a-released-force-bump/Cargo.toml | 2 - .../a/CHANGELOG.md | 29 - .../crate-a-released-force-bump/a/Cargo.toml | 8 - .../crate-a-released-force-bump/a/src/lib.rs | 7 - .../b/CHANGELOG.md | 9 - .../crate-a-released-force-bump/b/Cargo.toml | 9 - .../crate-a-released-force-bump/b/src/lib.rs | 7 - .../crate-a-released-force-bump/c/Cargo.toml | 9 - .../crate-a-released-force-bump/c/src/main.rs | 3 - .../crate-a-released/.gitignore | 1 - .../crate-a-released/.package-cache | 0 .../crate-a-released/Cargo.lock | 21 - .../crate-a-released/Cargo.toml | 2 - .../crate-a-released/a/CHANGELOG.md | 27 - .../crate-a-released/a/Cargo.toml | 8 - .../crate-a-released/a/src/lib.rs | 7 - .../crate-a-released/b/CHANGELOG.md | 9 - .../crate-a-released/b/Cargo.toml | 9 - .../crate-a-released/b/src/lib.rs | 7 - .../crate-a-released/c/Cargo.toml | 9 - .../crate-a-released/c/src/main.rs | 3 - cargo-smart-release/tests/utilities.sh | 182 -- 123 files changed, 13122 deletions(-) delete mode 100644 cargo-smart-release/CHANGELOG.md delete mode 100644 cargo-smart-release/Cargo.lock delete mode 100644 cargo-smart-release/Cargo.toml delete mode 100644 cargo-smart-release/README.md delete mode 100644 cargo-smart-release/build.rs delete mode 100644 cargo-smart-release/src/bat.rs delete mode 100644 cargo-smart-release/src/changelog/header.md delete mode 100644 cargo-smart-release/src/changelog/init.rs delete mode 100644 cargo-smart-release/src/changelog/merge.rs delete mode 100644 cargo-smart-release/src/changelog/mod.rs delete mode 100644 cargo-smart-release/src/changelog/parse.rs delete mode 100644 cargo-smart-release/src/changelog/section/from_history.rs delete mode 100644 cargo-smart-release/src/changelog/section/mod.rs delete mode 100644 cargo-smart-release/src/changelog/section/segment.rs delete mode 100644 cargo-smart-release/src/changelog/tests.rs delete mode 100644 cargo-smart-release/src/changelog/write.rs delete mode 100644 cargo-smart-release/src/cli/main-changelog.rs delete mode 100644 cargo-smart-release/src/cli/main-smart-release.rs delete mode 100644 cargo-smart-release/src/cli/main.rs delete mode 100644 cargo-smart-release/src/cli/options.rs delete mode 100644 cargo-smart-release/src/command/changelog.rs delete mode 100644 cargo-smart-release/src/command/mod.rs delete mode 100644 cargo-smart-release/src/command/release/cargo.rs delete mode 100644 cargo-smart-release/src/command/release/git.rs delete mode 100644 cargo-smart-release/src/command/release/github.rs delete mode 100644 cargo-smart-release/src/command/release/manifest.rs delete mode 100644 cargo-smart-release/src/command/release/mod.rs delete mode 100644 cargo-smart-release/src/commit/history.rs delete mode 100644 cargo-smart-release/src/commit/message.rs delete mode 100644 cargo-smart-release/src/commit/mod.rs delete mode 100644 cargo-smart-release/src/context.rs delete mode 100644 cargo-smart-release/src/crates_index.rs delete mode 100644 cargo-smart-release/src/git/history.rs delete mode 100644 cargo-smart-release/src/git/mod.rs delete mode 100644 cargo-smart-release/src/lib.rs delete mode 100644 cargo-smart-release/src/traverse.rs delete mode 100644 cargo-smart-release/src/utils.rs delete mode 100644 cargo-smart-release/src/version.rs delete mode 100644 cargo-smart-release/tests/changelog/merge.rs delete mode 100644 cargo-smart-release/tests/changelog/mod.rs delete mode 100644 cargo-smart-release/tests/changelog/parse.rs delete mode 100644 cargo-smart-release/tests/changelog/write_and_parse/mod.rs delete mode 100644 cargo-smart-release/tests/changelog/write_and_parse/snapshots/integration__changelog__write_and_parse__all_section_types_round_trips_lossy-10.snap delete mode 100644 cargo-smart-release/tests/changelog/write_and_parse/snapshots/integration__changelog__write_and_parse__all_section_types_round_trips_lossy-11.snap delete mode 100644 cargo-smart-release/tests/changelog/write_and_parse/snapshots/integration__changelog__write_and_parse__all_section_types_round_trips_lossy-2.snap delete mode 100644 cargo-smart-release/tests/changelog/write_and_parse/snapshots/integration__changelog__write_and_parse__all_section_types_round_trips_lossy-3.snap delete mode 100644 cargo-smart-release/tests/changelog/write_and_parse/snapshots/integration__changelog__write_and_parse__all_section_types_round_trips_lossy-4.snap delete mode 100644 cargo-smart-release/tests/changelog/write_and_parse/snapshots/integration__changelog__write_and_parse__all_section_types_round_trips_lossy-5.snap delete mode 100644 cargo-smart-release/tests/changelog/write_and_parse/snapshots/integration__changelog__write_and_parse__all_section_types_round_trips_lossy-6.snap delete mode 100644 cargo-smart-release/tests/changelog/write_and_parse/snapshots/integration__changelog__write_and_parse__all_section_types_round_trips_lossy-7.snap delete mode 100644 cargo-smart-release/tests/changelog/write_and_parse/snapshots/integration__changelog__write_and_parse__all_section_types_round_trips_lossy-8.snap delete mode 100644 cargo-smart-release/tests/changelog/write_and_parse/snapshots/integration__changelog__write_and_parse__all_section_types_round_trips_lossy-9.snap delete mode 100644 cargo-smart-release/tests/changelog/write_and_parse/snapshots/integration__changelog__write_and_parse__all_section_types_round_trips_lossy.snap delete mode 100644 cargo-smart-release/tests/changelog/write_and_parse/snapshots/integration__changelog__write_and_parse__conventional_write_empty_messages-2.snap delete mode 100644 cargo-smart-release/tests/changelog/write_and_parse/snapshots/integration__changelog__write_and_parse__conventional_write_empty_messages-3.snap delete mode 100644 cargo-smart-release/tests/changelog/write_and_parse/snapshots/integration__changelog__write_and_parse__conventional_write_empty_messages-4.snap delete mode 100644 cargo-smart-release/tests/changelog/write_and_parse/snapshots/integration__changelog__write_and_parse__conventional_write_empty_messages-5.snap delete mode 100644 cargo-smart-release/tests/changelog/write_and_parse/snapshots/integration__changelog__write_and_parse__conventional_write_empty_messages-6.snap delete mode 100644 cargo-smart-release/tests/changelog/write_and_parse/snapshots/integration__changelog__write_and_parse__conventional_write_empty_messages.snap delete mode 100644 cargo-smart-release/tests/fixtures/changelog/parse/known-section-unknown-content.md delete mode 100644 cargo-smart-release/tests/fixtures/changelog/parse/known-section-unknown-headline-with-link.md delete mode 100644 cargo-smart-release/tests/fixtures/changelog/parse/unknown-known-unknown-known-unsorted.md delete mode 100644 cargo-smart-release/tests/fixtures/tri-depth-workspace/Cargo.lock delete mode 100644 cargo-smart-release/tests/fixtures/tri-depth-workspace/Cargo.toml delete mode 100644 cargo-smart-release/tests/fixtures/tri-depth-workspace/a/CHANGELOG.md delete mode 100644 cargo-smart-release/tests/fixtures/tri-depth-workspace/a/Cargo.toml delete mode 100644 cargo-smart-release/tests/fixtures/tri-depth-workspace/a/src/lib.rs delete mode 100644 cargo-smart-release/tests/fixtures/tri-depth-workspace/b/CHANGELOG.md delete mode 100644 cargo-smart-release/tests/fixtures/tri-depth-workspace/b/Cargo.toml delete mode 100644 cargo-smart-release/tests/fixtures/tri-depth-workspace/b/src/lib.rs delete mode 100644 cargo-smart-release/tests/fixtures/tri-depth-workspace/c/Cargo.toml delete mode 100644 cargo-smart-release/tests/fixtures/tri-depth-workspace/c/src/main.rs delete mode 100644 cargo-smart-release/tests/integration.rs delete mode 100755 cargo-smart-release/tests/journey.sh delete mode 100644 cargo-smart-release/tests/snapshots/triple-depth-workspace-changelog/a-dry-run-success-multi-crate delete mode 100644 cargo-smart-release/tests/snapshots/triple-depth-workspace-changelog/crate-a-released/.gitignore delete mode 100644 cargo-smart-release/tests/snapshots/triple-depth-workspace-changelog/crate-a-released/Cargo.lock delete mode 100644 cargo-smart-release/tests/snapshots/triple-depth-workspace-changelog/crate-a-released/Cargo.toml delete mode 100644 cargo-smart-release/tests/snapshots/triple-depth-workspace-changelog/crate-a-released/a/CHANGELOG.md delete mode 100644 cargo-smart-release/tests/snapshots/triple-depth-workspace-changelog/crate-a-released/a/Cargo.toml delete mode 100644 cargo-smart-release/tests/snapshots/triple-depth-workspace-changelog/crate-a-released/a/src/lib.rs delete mode 100644 cargo-smart-release/tests/snapshots/triple-depth-workspace-changelog/crate-a-released/b/CHANGELOG.md delete mode 100644 cargo-smart-release/tests/snapshots/triple-depth-workspace-changelog/crate-a-released/b/Cargo.toml delete mode 100644 cargo-smart-release/tests/snapshots/triple-depth-workspace-changelog/crate-a-released/b/src/lib.rs delete mode 100644 cargo-smart-release/tests/snapshots/triple-depth-workspace-changelog/crate-a-released/c/Cargo.toml delete mode 100644 cargo-smart-release/tests/snapshots/triple-depth-workspace-changelog/crate-a-released/c/src/main.rs delete mode 100644 cargo-smart-release/tests/snapshots/triple-depth-workspace/a-b-dry-run-success-multi-crate-unconditional delete mode 100644 cargo-smart-release/tests/snapshots/triple-depth-workspace/a-dry-run-success-multi-crate delete mode 100644 cargo-smart-release/tests/snapshots/triple-depth-workspace/a-dry-run-success-multi-crate-auto-bump-breaking-change delete mode 100644 cargo-smart-release/tests/snapshots/triple-depth-workspace/a-dry-run-success-multi-crate-auto-bump-breaking-change-dependant-publish delete mode 100644 cargo-smart-release/tests/snapshots/triple-depth-workspace/a-dry-run-success-multi-crate-auto-bump-breaking-change-no-bump-on-demand delete mode 100644 cargo-smart-release/tests/snapshots/triple-depth-workspace/a-dry-run-success-multi-crate-auto-bump-breaking-change-no-bump-on-demand-no-publish-stable delete mode 100644 cargo-smart-release/tests/snapshots/triple-depth-workspace/a-dry-run-success-multi-crate-auto-bump-minor-change delete mode 100644 cargo-smart-release/tests/snapshots/triple-depth-workspace/a-dry-run-success-multi-crate-auto-bump-no-change delete mode 100644 cargo-smart-release/tests/snapshots/triple-depth-workspace/a-dry-run-success-multi-crate-unconditional delete mode 100644 cargo-smart-release/tests/snapshots/triple-depth-workspace/c-dry-run-success-multi-crate-auto-bump-breaking-change delete mode 100644 cargo-smart-release/tests/snapshots/triple-depth-workspace/c-dry-run-success-multi-crate-auto-bump-minor-change delete mode 100644 cargo-smart-release/tests/snapshots/triple-depth-workspace/c-dry-run-success-multi-crate-auto-bump-no-change delete mode 100644 cargo-smart-release/tests/snapshots/triple-depth-workspace/crate-a-released-force-bump/.gitignore delete mode 100644 cargo-smart-release/tests/snapshots/triple-depth-workspace/crate-a-released-force-bump/.package-cache delete mode 100644 cargo-smart-release/tests/snapshots/triple-depth-workspace/crate-a-released-force-bump/Cargo.lock delete mode 100644 cargo-smart-release/tests/snapshots/triple-depth-workspace/crate-a-released-force-bump/Cargo.toml delete mode 100644 cargo-smart-release/tests/snapshots/triple-depth-workspace/crate-a-released-force-bump/a/CHANGELOG.md delete mode 100644 cargo-smart-release/tests/snapshots/triple-depth-workspace/crate-a-released-force-bump/a/Cargo.toml delete mode 100644 cargo-smart-release/tests/snapshots/triple-depth-workspace/crate-a-released-force-bump/a/src/lib.rs delete mode 100644 cargo-smart-release/tests/snapshots/triple-depth-workspace/crate-a-released-force-bump/b/CHANGELOG.md delete mode 100644 cargo-smart-release/tests/snapshots/triple-depth-workspace/crate-a-released-force-bump/b/Cargo.toml delete mode 100644 cargo-smart-release/tests/snapshots/triple-depth-workspace/crate-a-released-force-bump/b/src/lib.rs delete mode 100644 cargo-smart-release/tests/snapshots/triple-depth-workspace/crate-a-released-force-bump/c/Cargo.toml delete mode 100644 cargo-smart-release/tests/snapshots/triple-depth-workspace/crate-a-released-force-bump/c/src/main.rs delete mode 100644 cargo-smart-release/tests/snapshots/triple-depth-workspace/crate-a-released/.gitignore delete mode 100644 cargo-smart-release/tests/snapshots/triple-depth-workspace/crate-a-released/.package-cache delete mode 100644 cargo-smart-release/tests/snapshots/triple-depth-workspace/crate-a-released/Cargo.lock delete mode 100644 cargo-smart-release/tests/snapshots/triple-depth-workspace/crate-a-released/Cargo.toml delete mode 100644 cargo-smart-release/tests/snapshots/triple-depth-workspace/crate-a-released/a/CHANGELOG.md delete mode 100644 cargo-smart-release/tests/snapshots/triple-depth-workspace/crate-a-released/a/Cargo.toml delete mode 100644 cargo-smart-release/tests/snapshots/triple-depth-workspace/crate-a-released/a/src/lib.rs delete mode 100644 cargo-smart-release/tests/snapshots/triple-depth-workspace/crate-a-released/b/CHANGELOG.md delete mode 100644 cargo-smart-release/tests/snapshots/triple-depth-workspace/crate-a-released/b/Cargo.toml delete mode 100644 cargo-smart-release/tests/snapshots/triple-depth-workspace/crate-a-released/b/src/lib.rs delete mode 100644 cargo-smart-release/tests/snapshots/triple-depth-workspace/crate-a-released/c/Cargo.toml delete mode 100644 cargo-smart-release/tests/snapshots/triple-depth-workspace/crate-a-released/c/src/main.rs delete mode 100644 cargo-smart-release/tests/utilities.sh diff --git a/cargo-smart-release/CHANGELOG.md b/cargo-smart-release/CHANGELOG.md deleted file mode 100644 index 68c3a0c960d..00000000000 --- a/cargo-smart-release/CHANGELOG.md +++ /dev/null @@ -1,2316 +0,0 @@ -# Changelog - -All notable changes to this project will be documented in this file. - -The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), -and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). - -## 0.20.0 (2023-07-19) - - - - -### Chore - - - Add `clippy::redundant-closure-for-method-calls` lint - - inline format args - -### New Features - - - add --capitalize-commit option to capitalize commit message in cargo-smart-release - - add `vendored-openssl` feature toggle. - This should help the build on some platforms. - -### Bug Fixes - - - fix docs generation - URLs need to be escaped. Plus added doc build to CI without deps - -### Bug Fixes (BREAKING) - - - don't auto-publish stable crates by inverting `no-auto-publish-of-stable-crates` (to `auto-publish...`). - It turned out that I was happily publishing stable crates even without user-facing changes - as this was the default. - This will now stop, and is fine if stable crates are not exposing API of unstable crates. - -### Commit Statistics - - - - - 40 commits contributed to the release over the course of 83 calendar days. - - 82 days passed between releases. - - 6 commits were understood as [conventional](https://www.conventionalcommits.org). - - 0 issues like '(#ID)' were seen in commit messages - -### Commit Details - - - -
view details - - * **Uncategorized** - - Make sure smart-release can survive publishes ([`dd54d18`](https://github.com/Byron/gitoxide/commit/dd54d18f0374f8ed44624728e146d07747f6e678)) - - Release gix-prompt v0.5.3, gix v0.49.1, cargo-smart-release v0.20.0 ([`f069852`](https://github.com/Byron/gitoxide/commit/f0698522940c9ba4d45db5a44dce9f21ca29cb4e)) - - Adjust smart-release journey test to deal with the polarity changes of `--no-auto-publish-of-stable-crates` ([`abd74ea`](https://github.com/Byron/gitoxide/commit/abd74ea736bcf32fcc18caa409b31d5567156661)) - - Prepare changelogs prior to release ([`849f508`](https://github.com/Byron/gitoxide/commit/849f5081313c4a44bdaef6848758d0d9a5d1598b)) - - Merge branch 'smart-release-stability' ([`8629f56`](https://github.com/Byron/gitoxide/commit/8629f569cd5917b6c0c3fd928fde021e7976ee85)) - - Don't auto-publish stable crates by inverting `no-auto-publish-of-stable-crates` (to `auto-publish...`). ([`39bcb1d`](https://github.com/Byron/gitoxide/commit/39bcb1d1b2ea4cc9a75f97bc05db642b0a556f8d)) - - Adjust package versions (by cargo-smart-release) ([`c70e54f`](https://github.com/Byron/gitoxide/commit/c70e54f163c312c87753a506eeaad462e8579bfb)) - - Release gix-date v0.7.0, gix-trace v0.1.2, gix-actor v0.23.0, gix-commitgraph v0.17.1, gix-utils v0.1.4, gix-object v0.32.0, gix-ref v0.32.0, gix-config v0.25.0, gix-diff v0.32.0, gix-discover v0.21.0, gix-hashtable v0.2.3, gix-revwalk v0.3.0, gix-traverse v0.29.0, gix-index v0.20.0, gix-mailmap v0.15.0, gix-negotiate v0.4.0, gix-pack v0.39.0, gix-odb v0.49.0, gix-protocol v0.35.0, gix-revision v0.17.0, gix-refspec v0.13.0, gix-worktree v0.21.0, gix v0.48.0, safety bump 20 crates ([`27e8c18`](https://github.com/Byron/gitoxide/commit/27e8c18db5a9a21843381c116a8ed6d9f681b3f8)) - - Merge branch 'i64-times' ([`b407461`](https://github.com/Byron/gitoxide/commit/b407461d8991db67a5bdb2ab13f518f78a85ed40)) - - Adapt to changes in `gix-date` ([`fba45c6`](https://github.com/Byron/gitoxide/commit/fba45c68d57d5f73070a6949556a04187d42e427)) - - Release gix-date v0.6.0, gix-hash v0.11.3, gix-trace v0.1.1, gix-features v0.31.0, gix-actor v0.22.0, gix-path v0.8.2, gix-glob v0.9.0, gix-quote v0.4.5, gix-attributes v0.14.0, gix-chunk v0.4.3, gix-commitgraph v0.17.0, gix-config-value v0.12.2, gix-fs v0.3.0, gix-tempfile v7.0.0, gix-utils v0.1.3, gix-lock v7.0.0, gix-validate v0.7.6, gix-object v0.31.0, gix-ref v0.31.0, gix-sec v0.8.2, gix-config v0.24.0, gix-command v0.2.6, gix-prompt v0.5.2, gix-url v0.20.0, gix-credentials v0.16.0, gix-diff v0.31.0, gix-discover v0.20.0, gix-hashtable v0.2.2, gix-ignore v0.4.0, gix-bitmap v0.2.5, gix-revwalk v0.2.0, gix-traverse v0.28.0, gix-index v0.19.0, gix-mailmap v0.14.0, gix-negotiate v0.3.0, gix-pack v0.38.0, gix-odb v0.48.0, gix-packetline v0.16.3, gix-transport v0.33.0, gix-protocol v0.34.0, gix-revision v0.16.0, gix-refspec v0.12.0, gix-worktree v0.20.0, gix v0.47.0, gitoxide-core v0.29.0, gitoxide v0.27.0, safety bump 30 crates ([`ea9f942`](https://github.com/Byron/gitoxide/commit/ea9f9424e777f10da0e33bb9ffbbefd01c4c5a74)) - - Merge branch 'corpus' ([`aa16c8c`](https://github.com/Byron/gitoxide/commit/aa16c8ce91452a3e3063cf1cf0240b6014c4743f)) - - A build script to set a `gitoxide` version according to what's in git ([`83f6466`](https://github.com/Byron/gitoxide/commit/83f646674118ff6227a605dc17b0be7325481069)) - - Merge branch 'help-874-redundant-closures' ([`fe59956`](https://github.com/Byron/gitoxide/commit/fe59956ad667303a923d7cfd9ffd72283df41d78)) - - Add `clippy::redundant-closure-for-method-calls` lint ([`bcad5c2`](https://github.com/Byron/gitoxide/commit/bcad5c22049d56a25ef69d6c7a3344e78f9a1d4d)) - - Merge branch 'future-dates' ([`8d2e6a9`](https://github.com/Byron/gitoxide/commit/8d2e6a91ac92a033e9e3daad5cffa90263075536)) - - Adapt to changes in `gix-actor` ([`4a80e86`](https://github.com/Byron/gitoxide/commit/4a80e868f9530896616e649838e9be64b6d10036)) - - Adapt to changes in `gix-date` ([`d575336`](https://github.com/Byron/gitoxide/commit/d575336c26e6026e463cd06d88266bb2bdd3e162)) - - Release gix-attributes v0.13.1, gix-diff v0.30.1, gix-revwalk v0.1.0, gix-traverse v0.27.0, gix-index v0.18.0, gix-revision v0.15.2, gix-negotiate v0.2.1, gix-pack v0.37.0, gix-odb v0.47.0, gix-protocol v0.33.2, gix-worktree v0.19.0, gix v0.46.0, safety bump 7 crates ([`2560a2c`](https://github.com/Byron/gitoxide/commit/2560a2cc3e1d8c60cd812e15696fa4761d036e19)) - - Merge branch 'walk-with-commitgraph' ([`fdee9a2`](https://github.com/Byron/gitoxide/commit/fdee9a22873a13ae644d3dc92f8fe93f8f0266c0)) - - Adapt to changes in `gix` ([`20f73c8`](https://github.com/Byron/gitoxide/commit/20f73c8224ead1b423a1b6331c9cab65f769d46a)) - - Release gix-revision v0.15.1, gix v0.45.1 ([`11766a0`](https://github.com/Byron/gitoxide/commit/11766a0a82754fee9918ccdb8eaf92af6d2561ba)) - - `just fmt` ([`ffc1276`](https://github.com/Byron/gitoxide/commit/ffc1276e0c991ac33ce842f5dca0b45ac69680c0)) - - Merge branch 'auto-clippy' ([`dbf8aa1`](https://github.com/Byron/gitoxide/commit/dbf8aa19d19109195d0274928eae4b94f248cd88)) - - Autofix map-or-unwrap clippy lint (and manual fix what was left) ([`2087032`](https://github.com/Byron/gitoxide/commit/2087032b5956dcd82bce6ac57e530e8724b57f17)) - - Merge branch 'main' into auto-clippy ([`3ef5c90`](https://github.com/Byron/gitoxide/commit/3ef5c90aebce23385815f1df674c1d28d58b4b0d)) - - Auto-fix clippy to remove explicit iter looping ([`3eff567`](https://github.com/Byron/gitoxide/commit/3eff567c683b5c650c14792b68968cbdbc90ec5c)) - - Merge pull request #866 from nyurik/docs ([`e4aa014`](https://github.com/Byron/gitoxide/commit/e4aa014553db83ea830046a101ec67a8d443afb4)) - - Merge pull request #864 from nyurik/lint-fmt ([`279dc09`](https://github.com/Byron/gitoxide/commit/279dc09446f41d7f1d76350fbfafb444e53cd7da)) - - Include custom clippy settings ([`b057500`](https://github.com/Byron/gitoxide/commit/b057500dd3e6b75be3ebcd258cda0b946bedd9e1)) - - Fix docs generation ([`3d8d9f3`](https://github.com/Byron/gitoxide/commit/3d8d9f36206c7e8dcd2d38a085ad93a6295d3231)) - - Inline format args ([`dbc6cbb`](https://github.com/Byron/gitoxide/commit/dbc6cbb4363c2532f81b0bd6e351c4577bb9e9a3)) - - Merge branch 'consecutive-negotiation' ([`97b3f7e`](https://github.com/Byron/gitoxide/commit/97b3f7e2eaddea20c98f2f7ab6a0d2e2117b0793)) - - Release gix-commitgraph v0.15.0, gix-revision v0.14.0, gix-negotiate v0.1.0, safety bump 7 crates ([`92832ca`](https://github.com/Byron/gitoxide/commit/92832ca2899cd2f222f4c7b1cc9e766178f55806)) - - Merge branch 'capitalize-commit' ([`450212e`](https://github.com/Byron/gitoxide/commit/450212e9b39ff4d6d68587ca2801d606d91e654a)) - - Adjust CLI docs to match the existing conventions (more) ([`df0c982`](https://github.com/Byron/gitoxide/commit/df0c9821117e7ff42f7edd187c1c99c33f177cfe)) - - Cargo fmt ([`31b261d`](https://github.com/Byron/gitoxide/commit/31b261da128cf81b6da11bab1da5f43e2d1b1467)) - - Add --capitalize-commit option to capitalize commit message in cargo-smart-release ([`4a244a2`](https://github.com/Byron/gitoxide/commit/4a244a2c9d1007fa10afa6f5078747bd2b001eb5)) - - Add `vendored-openssl` feature toggle. ([`09aae21`](https://github.com/Byron/gitoxide/commit/09aae21add04b2edbaa1489f1b47cc0886da0062)) - - Add feature `vendored-openssl` which enables `crates-index/vendored-openssl` ([`a067f37`](https://github.com/Byron/gitoxide/commit/a067f3760ecf7ad1e5d8b6d383d0517e06bf5bb0)) -
- -## 0.19.0 (2023-04-27) - -### New Features - - - avoid panics in favor of error handling. That way more information can be provided which helps with a fix. - -### Commit Statistics - - - - - 3 commits contributed to the release. - - 1 commit was understood as [conventional](https://www.conventionalcommits.org). - - 0 issues like '(#ID)' were seen in commit messages - -### Commit Details - - - -
view details - - * **Uncategorized** - - Release cargo-smart-release v0.19.0 ([`a3cb773`](https://github.com/Byron/gitoxide/commit/a3cb773df10277e9ff5f4b579a2eb64cf62fac52)) - - Avoid panics in favor of error handling. That way more information can be provided which helps with a fix. ([`00471ae`](https://github.com/Byron/gitoxide/commit/00471ae75464ee14b93480b016858b6606e0b194)) - - Bump gix-path v0.8.0, safety bump 20 crates (gix set to 0.44.1 manually) ([`43ebaf2`](https://github.com/Byron/gitoxide/commit/43ebaf267557218865862538ffc7bdf00558492f)) -
- -## 0.18.0 (2023-04-27) - -### Documentation - - - fix minor typos - -### Bug Fixes - - - $HOME detection on windows - -### Commit Statistics - - - - - 21 commits contributed to the release over the course of 61 calendar days. - - 62 days passed between releases. - - 2 commits were understood as [conventional](https://www.conventionalcommits.org). - - 0 issues like '(#ID)' were seen in commit messages - -### Thanks Clippy - - - -[Clippy](https://github.com/rust-lang/rust-clippy) helped 1 time to make code idiomatic. - -### Commit Details - - - -
view details - - * **Uncategorized** - - Release cargo-smart-release v0.18.0 ([`44d2b67`](https://github.com/Byron/gitoxide/commit/44d2b67de5639d4ea3d08ab030ecfe4bdfc8cbfb)) - - Merge branch 'fix-823' ([`6ebd61e`](https://github.com/Byron/gitoxide/commit/6ebd61e548a36a04e413ac725a03e607a3588334)) - - Thanks clippy ([`14e64e7`](https://github.com/Byron/gitoxide/commit/14e64e74649cfb1f2f99da87015939af98fae5c8)) - - Release gix-utils v0.1.0, gix-hash v0.11.0, gix-date v0.5.0, gix-features v0.29.0, gix-actor v0.20.0, gix-object v0.29.0, gix-archive v0.1.0, gix-fs v0.1.0, safety bump 25 crates ([`8dbd0a6`](https://github.com/Byron/gitoxide/commit/8dbd0a60557a85acfa231800a058cbac0271a8cf)) - - Merge branch 'patch-1' ([`d0052c1`](https://github.com/Byron/gitoxide/commit/d0052c13cabcde8058177d2439053b50ea5adbfc)) - - Update to latest `bitflags` version. ([`594cca5`](https://github.com/Byron/gitoxide/commit/594cca51840c00654af05acc7f7c7d01fe699067)) - - Release gix-path v0.7.3, gix-config-value v0.10.2, gix-config v0.20.1, gix-discover v0.16.2, gix-index v0.15.1, gix-odb v0.43.1, gix-packetline v0.15.1, gix-protocol v0.30.2, gix-worktree v0.15.2, gix v0.43.1 ([`38eed1d`](https://github.com/Byron/gitoxide/commit/38eed1d06e7cbb8fbcd54b2cad3163ca45e0baf1)) - - Merge branch 'pascalkuthe/main' ([`d47cebe`](https://github.com/Byron/gitoxide/commit/d47cebe3b23080c45829cb307b867220e3af20db)) - - $HOME detection on windows ([`d1bd513`](https://github.com/Byron/gitoxide/commit/d1bd513f27e17787eb223f7b0521f954c518153e)) - - Merge pull request #798 from theduke/patch-1 ([`6deccbb`](https://github.com/Byron/gitoxide/commit/6deccbb22c38b2a2d009433fd4a1b45ac892ac11)) - - Fix minor typos ([`cc48c35`](https://github.com/Byron/gitoxide/commit/cc48c35d0ecf35824910c5b6ecc62fe9b2aff1b5)) - - Fix typo in README ([`889a3c3`](https://github.com/Byron/gitoxide/commit/889a3c3ce98110f3d2415f5d7f70142d583aaec3)) - - Release gix-tempfile v5.0.2, gix-validate v0.7.4, gix-config v0.20.0, gix-prompt v0.3.3, gix-diff v0.28.1, gix-discover v0.16.1, gix-pack v0.33.2, gix-transport v0.29.1, gix-protocol v0.30.1, gix-revision v0.12.1, gix-worktree v0.15.1, gix v0.43.0, safety bump gix v0.43.0 ([`5dc1f9f`](https://github.com/Byron/gitoxide/commit/5dc1f9f2bcb8b3e147115fcb6f76558e8f48ffef)) - - Release gix-features v0.28.1, gix-tempfile v5.0.1, gix-ref v0.27.1, gix-pack v0.33.1, gix-packetline v0.15.0, gix-transport v0.29.0, gix-protocol v0.30.0, gix v0.42.0, safety bump 3 crates ([`c1f1bfb`](https://github.com/Byron/gitoxide/commit/c1f1bfb8dc0e73993678353e4492d0614b642ed1)) - - Merge branch 'fix-cred-helper' ([`01277a6`](https://github.com/Byron/gitoxide/commit/01277a681e4997896e04567490c572b5af606f35)) - - Release gix-tempfile v5.0.0, gix-lock v5.0.0, gix-ref v0.27.0, gix-config v0.19.0, gix-url v0.16.0, gix-credentials v0.12.0, gix-discover v0.16.0, gix-index v0.15.0, gix-pack v0.33.0, gix-odb v0.43.0, gix-transport v0.28.0, gix-protocol v0.29.0, gix-worktree v0.15.0, gix v0.41.0, safety bump 12 crates ([`29a0870`](https://github.com/Byron/gitoxide/commit/29a087043d1feb2f127b065341c8028d0bd0301e)) - - Release gix v0.40.0 ([`18e72c9`](https://github.com/Byron/gitoxide/commit/18e72c988a58415080d4555bc869ae04df8d04fa)) - - Release gix-features v0.28.0, gix-actor v0.19.0, gix-object v0.28.0, gix-diff v0.28.0, gix-traverse v0.24.0, gix-pack v0.32.0, safety bump 20 crates ([`0f411e9`](https://github.com/Byron/gitoxide/commit/0f411e93ec812592bb9d3a52b751399dd86f76f7)) - - Prepare for git-tempfile release ([`56c005b`](https://github.com/Byron/gitoxide/commit/56c005b13c44376f71e61781e73c0bf93416d0e4)) - - Make fmt ([`8ef1cb2`](https://github.com/Byron/gitoxide/commit/8ef1cb293434c7b9e1fda4a6963368e0435920a9)) - - Release gix-object v0.26.4, gix-diff v0.26.3, gix v0.37.2, gix-commitgraph v0.13.1, gitoxide-core v0.25.0, gitoxide v0.23.0 ([`9982949`](https://github.com/Byron/gitoxide/commit/9982949cab401501d5ce3cba4e2ba900bc249c53)) -
- -## 0.17.0 (2023-02-23) - -### New Features - - - capitalize the first letter of reproduced commit messages. - That way they look more consistent with the rest of the text, which typically - is capitalized as well. - -### Commit Statistics - - - - - 8 commits contributed to the release over the course of 2 calendar days. - - 6 days passed between releases. - - 1 commit was understood as [conventional](https://www.conventionalcommits.org). - - 0 issues like '(#ID)' were seen in commit messages - -### Commit Details - - - -
view details - - * **Uncategorized** - - Release cargo-smart-release v0.17.0 ([`e083510`](https://github.com/Byron/gitoxide/commit/e0835109f14550214ee9a5910e3e9574f2f09a29)) - - Capitalize the first letter of reproduced commit messages. ([`eee2211`](https://github.com/Byron/gitoxide/commit/eee22110b7f0f3e4765043e4acc9c832c2b86549)) - - Refactor ([`dc6b5be`](https://github.com/Byron/gitoxide/commit/dc6b5be04bc7e0ecb36372efcce64c91272bb751)) - - Fix smart-release journey test expectation ([`3749b88`](https://github.com/Byron/gitoxide/commit/3749b88cdb0d13fab753cdcb1722639f4eb60b66)) - - Sentence case for changelog commit messages. ([`ce9406d`](https://github.com/Byron/gitoxide/commit/ce9406da15745138e058e645523fcffcc5691109)) - - Release gix-config v0.16.3, gix v0.37.1 ([`a3c283f`](https://github.com/Byron/gitoxide/commit/a3c283ff0e3f21cedb3ba7cd464fdfa0f5133af0)) - - Release gix-object v0.26.3, gix-diff v0.26.2, gix-traverse v0.22.2, gix v0.37.0, safety bump 3 crates ([`8b3e42f`](https://github.com/Byron/gitoxide/commit/8b3e42f69fe97fe5083eb845c323f10d7ac087b2)) - - Release gix-date v0.4.3, gix-hash v0.10.3, gix-features v0.26.5, gix-actor v0.17.2, gix-glob v0.5.5, gix-path v0.7.2, gix-quote v0.4.2, gix-attributes v0.8.3, gix-validate v0.7.3, gix-object v0.26.2, gix-ref v0.24.1, gix-config v0.16.2, gix-command v0.2.4, gix-url v0.13.3, gix-credentials v0.9.2, gix-discover v0.13.1, gix-index v0.12.4, gix-mailmap v0.9.3, gix-pack v0.30.3, gix-packetline v0.14.3, gix-transport v0.25.6, gix-protocol v0.26.4, gix-revision v0.10.4, gix-refspec v0.7.3, gix-worktree v0.12.3, gix v0.36.1 ([`9604783`](https://github.com/Byron/gitoxide/commit/96047839a20a657a559376b0b14c65aeab96acbd)) -
- -## 0.16.1 (2023-02-17) - -### Bug Fixes - - - enable local-offset support in the `time` crate and opt-in to it. - This should allow proper times for release dates like before as they - respect the local time, instead of defaulting to UTC-time. - -### Commit Statistics - - - - - 2 commits contributed to the release. - - 1 commit was understood as [conventional](https://www.conventionalcommits.org). - - 0 issues like '(#ID)' were seen in commit messages - -### Commit Details - - - -
view details - - * **Uncategorized** - - Release cargo-smart-release v0.16.1 ([`5228a7e`](https://github.com/Byron/gitoxide/commit/5228a7ecb900be16fc649e642b334873232e8f7f)) - - Enable local-offset support in the `time` crate and opt-in to it. ([`fe58a79`](https://github.com/Byron/gitoxide/commit/fe58a79edde7d916ce72badc40204c507d015ebf)) -
- -## 0.16.0 (2023-02-17) - -### New Features - - - rename tracking for crates in the crate-root. - Now it's possible to rename crates if they are directly at the crate root - without loosing their history. - -### Bug Fixes - - - assure we can track dependencies correctly. - Previously, if worktree crates would also be used as crates.io crates, - the dependency traversal would fail to find packages that come in from crates.io - as opposed to the workspace, and discard them, causing dependencies to be missed. - - Now we correctly ignore workspace dependencies from crates.io. - -### Commit Statistics - - - - - 47 commits contributed to the release over the course of 6 calendar days. - - 7 days passed between releases. - - 2 commits were understood as [conventional](https://www.conventionalcommits.org). - - 0 issues like '(#ID)' were seen in commit messages - -### Commit Details - - - -
view details - - * **Uncategorized** - - Release cargo-smart-release v0.16.0 ([`7f039e1`](https://github.com/Byron/gitoxide/commit/7f039e18e7eabf7179709340a10361e6d334cf6d)) - - Merge branch 'rename-crates' into inform-about-gix-rename ([`c9275b9`](https://github.com/Byron/gitoxide/commit/c9275b99ea43949306d93775d9d78c98fb86cfb1)) - - Release git-date v0.4.3, git-hash v0.10.3, git-features v0.26.5, git-actor v0.17.2, git-glob v0.5.4, git-path v0.7.2, git-quote v0.4.2, git-attributes v0.8.3, git-bitmap v0.2.2, git-chunk v0.4.2, git-command v0.2.4, git-commitgraph v0.13.1, git-config-value v0.10.2, git-tempfile v3.0.3, git-lock v3.0.3, git-validate v0.7.3, git-object v0.26.2, git-ref v0.24.1, git-sec v0.6.3, git-config v0.16.2, git-prompt v0.3.3, git-url v0.13.3, git-credentials v0.9.2, git-diff v0.26.2, git-discover v0.13.1, git-fetchhead v0.1.0, git-filter v0.1.0, git-hashtable v0.1.2, git-traverse v0.22.2, git-index v0.12.4, git-lfs v0.1.0, git-mailmap v0.9.3, git-note v0.1.0, git-pack v0.31.0, git-odb v0.41.0, git-packetline v0.14.3, git-pathspec v0.1.0, git-transport v0.25.5, git-protocol v0.26.4, git-rebase v0.1.0, git-revision v0.10.4, git-refspec v0.7.3, git-sequencer v0.1.0, git-submodule v0.1.0, git-tix v0.1.0, git-tui v0.1.0, git-worktree v0.12.3, safety bump 2 crates ([`90035a3`](https://github.com/Byron/gitoxide/commit/90035a332d0ba67584558db3605500fbcb424ddd)) - - Assure we can track dependencies correctly. ([`35a1df7`](https://github.com/Byron/gitoxide/commit/35a1df715e1e8e28fb98237908c964ddbb8981fa)) - - Rename `git-testtools` to `gix-testtools` ([`b65c33d`](https://github.com/Byron/gitoxide/commit/b65c33d256cfed65d11adeff41132e3e58754089)) - - Adjust to renaming of `git-pack` to `gix-pack` ([`1ee81ad`](https://github.com/Byron/gitoxide/commit/1ee81ad310285ee4aa118118a2be3810dbace574)) - - Adjust to renaming of `git-odb` to `gix-odb` ([`476e2ad`](https://github.com/Byron/gitoxide/commit/476e2ad1a64e9e3f0d7c8651d5bcbee36cd78241)) - - Adjust to renaming of `git-index` to `gix-index` ([`86db5e0`](https://github.com/Byron/gitoxide/commit/86db5e09fc58ce66b252dc13b8d7e2c48e4d5062)) - - Adjust to renaming of `git-diff` to `gix-diff` ([`49a163e`](https://github.com/Byron/gitoxide/commit/49a163ec8b18f0e5fcd05a315de16d5d8be7650e)) - - Adjust to renaming of `git-commitgraph` to `gix-commitgraph` ([`f1dd0a3`](https://github.com/Byron/gitoxide/commit/f1dd0a3366e31259af029da73228e8af2f414244)) - - Adjust to renaming of `git-mailmap` to `gix-mailmap` ([`2e28c56`](https://github.com/Byron/gitoxide/commit/2e28c56bb9f70de6f97439818118d3a25859698f)) - - Adjust to renaming of `git-discover` to `gix-discover` ([`53adfe1`](https://github.com/Byron/gitoxide/commit/53adfe1c34e9ea3b27067a97b5e7ac80b351c441)) - - Adjust to renaming of `git-chunk` to `gix-chunk` ([`59194e3`](https://github.com/Byron/gitoxide/commit/59194e3a07853eae0624ebc4907478d1de4f7599)) - - Adjust to renaming of `git-bitmap` to `gix-bitmap` ([`75f2a07`](https://github.com/Byron/gitoxide/commit/75f2a079b17489f62bc43e1f1d932307375c4f9d)) - - Adjust to renaming for `git-protocol` to `gix-protocol` ([`823795a`](https://github.com/Byron/gitoxide/commit/823795addea3810243cab7936cd8ec0137cbc224)) - - Adjust to renaming of `git-refspec` to `gix-refspec` ([`c958802`](https://github.com/Byron/gitoxide/commit/c9588020561577736faa065e7e5b5bb486ca8fe1)) - - Adjust to renaming of `git-revision` to `gix-revision` ([`ee0ee84`](https://github.com/Byron/gitoxide/commit/ee0ee84607c2ffe11ee75f27a31903db68afed02)) - - Adjust to renaming of `git-transport` to `gix-transport` ([`b2ccf71`](https://github.com/Byron/gitoxide/commit/b2ccf716dc4425bb96651d4d58806a3cc2da219e)) - - Adjust to renaming of `git-credentials` to `gix-credentials` ([`6b18abc`](https://github.com/Byron/gitoxide/commit/6b18abcf2856f02ab938d535a65e51ac282bf94a)) - - Adjust to renaming of `git-prompt` to `gix-prompt` ([`6a4654e`](https://github.com/Byron/gitoxide/commit/6a4654e0d10ab773dd219cb4b731c0fc1471c36d)) - - Adjust to renaming of `git-command` to `gix-command` ([`d26b8e0`](https://github.com/Byron/gitoxide/commit/d26b8e046496894ae06b0bbfdba77196976cd975)) - - Adjust to renaming of `git-packetline` to `gix-packetline` ([`5cbd22c`](https://github.com/Byron/gitoxide/commit/5cbd22cf42efb760058561c6c3bbcd4dab8c8be1)) - - Adjust to renaming of `git-worktree` to `gix-worktree` ([`73a1282`](https://github.com/Byron/gitoxide/commit/73a12821b3d9b66ec1714d07dd27eb7a73e3a544)) - - Adjust to renamining of `git-hashtable` to `gix-hashtable` ([`26a0c98`](https://github.com/Byron/gitoxide/commit/26a0c98d0a389b03e3dc7bfc758b37155e285244)) - - Adjust to renamining of `git-worktree` to `gix-worktree` ([`108bb1a`](https://github.com/Byron/gitoxide/commit/108bb1a634f4828853fb590e9fc125f79441dd38)) - - Adjust to renaming of `git-url` to `gix-url` ([`b50817a`](https://github.com/Byron/gitoxide/commit/b50817aadb143e19f61f64e19b19ec1107d980c6)) - - Adjust to renaming of `git-date` to `gix-date` ([`9a79ff2`](https://github.com/Byron/gitoxide/commit/9a79ff2d5cc74c1efad9f41e21095ae498cce00b)) - - Adjust to renamining of `git-attributes` to `gix-attributes` ([`4a8b3b8`](https://github.com/Byron/gitoxide/commit/4a8b3b812ac26f2a2aee8ce8ca81591273383c84)) - - Adjust to renaminig of `git-quote` to `gix-quote` ([`648025b`](https://github.com/Byron/gitoxide/commit/648025b7ca94411fdd0d90c53e5faede5fde6c8d)) - - Adjust to renaming of `git-config` to `gix-config` ([`3a861c8`](https://github.com/Byron/gitoxide/commit/3a861c8f049f6502d3bcbdac752659aa1aeda46a)) - - Adjust to renaming of `git-ref` to `gix-ref` ([`1f5f695`](https://github.com/Byron/gitoxide/commit/1f5f695407b034377d94b172465ff573562b3fc3)) - - Adjust to renaming of `git-lock` to `gix-lock` ([`2028e78`](https://github.com/Byron/gitoxide/commit/2028e7884ae1821edeec81612f501e88e4722b17)) - - Adjust to renaming of `git-tempfile` to `gix-tempfile` ([`b6cc3eb`](https://github.com/Byron/gitoxide/commit/b6cc3ebb5137084a6327af16a7d9364d8f092cc9)) - - Adjust to renaming of `git-object` to `gix-object` ([`fc86a1e`](https://github.com/Byron/gitoxide/commit/fc86a1e710ad7bf076c25cc6f028ddcf1a5a4311)) - - Adjust to renaming of `git-actor` to `gix-actor` ([`4dc9b44`](https://github.com/Byron/gitoxide/commit/4dc9b44dc52f2486ffa2040585c6897c1bf55df4)) - - Adjust to renaming of `git-validate` to `gix-validate` ([`5e40ad0`](https://github.com/Byron/gitoxide/commit/5e40ad078af3d08cbc2ca81ce755c0ed8a065b4f)) - - Adjust to renaming of `git-hash` to `gix-hash` ([`4a9d025`](https://github.com/Byron/gitoxide/commit/4a9d0257110c3efa61d08c8457c4545b200226d1)) - - Adjust to renaming of `git-features` to `gix-features` ([`e2dd68a`](https://github.com/Byron/gitoxide/commit/e2dd68a417aad229e194ff20dbbfd77668096ec6)) - - Adjust to renaming of `git-glob` to `gix-glob` ([`35b2a3a`](https://github.com/Byron/gitoxide/commit/35b2a3acbc8f2a03f151bc0a3863163844e0ca86)) - - Adjust to renaming of `git-sec` to `gix-sec` ([`eabbb92`](https://github.com/Byron/gitoxide/commit/eabbb923bd5a32fc80fa80f96cfdc2ab7bb2ed17)) - - Adapt to renaming of `git-path` to `gix-path` ([`d3bbcfc`](https://github.com/Byron/gitoxide/commit/d3bbcfccad80fc44ea8e7bf819f23adaca06ba2d)) - - Adjust to rename of `git-config-value` to `gix-config-value` ([`622b3e1`](https://github.com/Byron/gitoxide/commit/622b3e1d0bffa0f8db73697960f9712024fac430)) - - Show more debugging information if unreachable code is reached. ([`66f5341`](https://github.com/Byron/gitoxide/commit/66f53414efef6cfd6d03f830520964c9bdd23634)) - - Merge branch 'rename-crates' ([`6461c3d`](https://github.com/Byron/gitoxide/commit/6461c3da4d6daee857606d94294c3f87fc36965a)) - - Rename `git-repository` to `gix` ([`7bed2a9`](https://github.com/Byron/gitoxide/commit/7bed2a96604397fa990f427b1a970ddeb6f09f1c)) - - Release git-repository v0.35.0, safety bump 3 crates ([`abe1e91`](https://github.com/Byron/gitoxide/commit/abe1e91ae6b1bac5bcf767f51a4f242ae2633ecc)) - - Rename tracking for crates in the crate-root. ([`cd12023`](https://github.com/Byron/gitoxide/commit/cd1202388b1cd290211c2f9580d2acbdd82384f9)) -
- -## 0.15.0 (2023-02-09) - - - -### Chore - - - upgrade to clap 4.1 - -### Documentation - - - fix typos - -### Bug Fixes - - - handle worktree members which are also used as dependencies from crates.io. - Previously there would be an assertion error if worktree members - are not used only by path, but also by dependency to crates.io. - - Disable tag.gpgSign in test scripts - This is done for the same reason that commit.gpgsign is disabled for test - scripts. It prevents test failures if the user has tag.gpgsign enabled in - their global git config when invoking tests. - -### New Features (BREAKING) - - - upgrade edition to 2021 in most crates. - MSRV for this is 1.56, and we are now at 1.60 so should be compatible. - This isn't more than a patch release as it should break nobody - who is adhering to the MSRV, but let's be careful and mark it - breaking. - - Note that `gix-features` and `gix-pack` are still on edition 2018 - as they make use of a workaround to support (safe) mutable access - to non-overlapping entries in a slice which doesn't work anymore - in edition 2021. - -### Commit Statistics - - - - - 33 commits contributed to the release over the course of 92 calendar days. - - 94 days passed between releases. - - 5 commits were understood as [conventional](https://www.conventionalcommits.org). - - 1 unique issue was worked on: [#711](https://github.com/Byron/gitoxide/issues/711) - -### Thanks Clippy - - - -[Clippy](https://github.com/rust-lang/rust-clippy) helped 1 time to make code idiomatic. - -### Commit Details - - - -
view details - - * **[#711](https://github.com/Byron/gitoxide/issues/711)** - - Assure we get the latest version of the `time` crate ([`cb31cd1`](https://github.com/Byron/gitoxide/commit/cb31cd16bc4a6e749c298cfbc7e0dad05b11b96c)) - * **Uncategorized** - - Release cargo-smart-release v0.15.0 ([`83638c8`](https://github.com/Byron/gitoxide/commit/83638c8fe3cc5740c6a6034d8053869966148ef9)) - - Handle worktree members which are also used as dependencies from crates.io. ([`dc58041`](https://github.com/Byron/gitoxide/commit/dc580414cbc7593c3ccf257f1f62d7323a3a3424)) - - Release git-date v0.4.2, git-hash v0.10.2, git-features v0.26.2, git-actor v0.17.1, git-glob v0.5.3, git-path v0.7.1, git-quote v0.4.1, git-attributes v0.8.2, git-config-value v0.10.1, git-tempfile v3.0.2, git-lock v3.0.2, git-validate v0.7.2, git-object v0.26.1, git-ref v0.24.0, git-sec v0.6.2, git-config v0.16.0, git-command v0.2.3, git-prompt v0.3.2, git-url v0.13.2, git-credentials v0.9.1, git-diff v0.26.1, git-discover v0.13.0, git-hashtable v0.1.1, git-bitmap v0.2.1, git-traverse v0.22.1, git-index v0.12.3, git-mailmap v0.9.2, git-chunk v0.4.1, git-pack v0.30.2, git-odb v0.40.2, git-packetline v0.14.2, git-transport v0.25.4, git-protocol v0.26.3, git-revision v0.10.2, git-refspec v0.7.2, git-worktree v0.12.2, git-repository v0.34.0, safety bump 3 crates ([`c196d20`](https://github.com/Byron/gitoxide/commit/c196d206d57a310b1ce974a1cf0e7e6d6db5c4d6)) - - Merge branch 'Lioness100/main' ([`1e544e8`](https://github.com/Byron/gitoxide/commit/1e544e82455bf9ecb5e3c2146280eaf7ecd81f16)) - - Fix typos ([`39ed9ed`](https://github.com/Byron/gitoxide/commit/39ed9eda62b7718d5109135e5ad406fb1fe2978c)) - - Upgrade toml-edit and `cargo-toml` ([`a41ce60`](https://github.com/Byron/gitoxide/commit/a41ce6023a1f7ff8c4e167e44a3763ea953ea5db)) - - Break cyclical dev dependencies ([`1fea18f`](https://github.com/Byron/gitoxide/commit/1fea18f5f8b4189a23dc4fa3f041a672f6fbcfb3)) - - Upgrade to clap 4.1 ([`6396967`](https://github.com/Byron/gitoxide/commit/63969671df60b4e07e2d7d671c657639d055b0b8)) - - Release git-date v0.4.1, git-features v0.26.1, git-glob v0.5.2, git-attributes v0.8.1, git-tempfile v3.0.1, git-ref v0.23.1, git-sec v0.6.1, git-config v0.15.1, git-prompt v0.3.1, git-url v0.13.1, git-discover v0.12.1, git-index v0.12.2, git-mailmap v0.9.1, git-pack v0.30.1, git-odb v0.40.1, git-transport v0.25.3, git-protocol v0.26.2, git-revision v0.10.1, git-refspec v0.7.1, git-worktree v0.12.1, git-repository v0.33.0 ([`5b5b380`](https://github.com/Byron/gitoxide/commit/5b5b3809faa71c658db38b40dfc410224d08a367)) - - Merge branch 'patch-1' ([`b93f0c4`](https://github.com/Byron/gitoxide/commit/b93f0c49fc677b6c19aea332cbfc1445ce475375)) - - Thanks clippy ([`b34c9fe`](https://github.com/Byron/gitoxide/commit/b34c9fe58223862712eacc1cb7353e497a4b9778)) - - Upgrade env_logger ([`803d8e1`](https://github.com/Byron/gitoxide/commit/803d8e14b43a869db42f6345197e7e872c54679e)) - - Upgrade toml_edit ([`4d632d0`](https://github.com/Byron/gitoxide/commit/4d632d0b3b10a3f87c12c42fa21579da5c19dec2)) - - Upgrade `cargo_toml` ([`6504e93`](https://github.com/Byron/gitoxide/commit/6504e933dd4c82bfd3252e40e4ce30ee97d67563)) - - Release git-date v0.4.0, git-actor v0.17.0, git-object v0.26.0, git-traverse v0.22.0, git-index v0.12.0, safety bump 15 crates ([`0e3d0a5`](https://github.com/Byron/gitoxide/commit/0e3d0a56d7e6a60c6578138f2690b4fa54a2072d)) - - Release git-features v0.26.0, git-actor v0.16.0, git-attributes v0.8.0, git-object v0.25.0, git-ref v0.22.0, git-config v0.14.0, git-command v0.2.1, git-url v0.13.0, git-credentials v0.9.0, git-diff v0.25.0, git-discover v0.11.0, git-traverse v0.21.0, git-index v0.11.0, git-mailmap v0.8.0, git-pack v0.29.0, git-odb v0.39.0, git-transport v0.25.0, git-protocol v0.26.0, git-revision v0.9.0, git-refspec v0.6.0, git-worktree v0.11.0, git-repository v0.31.0, safety bump 24 crates ([`5ac9fbe`](https://github.com/Byron/gitoxide/commit/5ac9fbe265a5b61c533a2a6b3abfed2bdf7f89ad)) - - Release git-features v0.25.1, git-url v0.12.2, git-odb v0.38.1, git-transport v0.24.2, git-repository v0.30.2 ([`bb0a07b`](https://github.com/Byron/gitoxide/commit/bb0a07b5edd5f980989d1a92e74df7f183febe87)) - - Release git-url v0.12.1, git-transport v0.24.1, git-protocol v0.25.1, git-repository v0.30.1, git-commitgraph v0.12.0, gitoxide-core v0.22.0, gitoxide v0.20.0 ([`08ec3a9`](https://github.com/Byron/gitoxide/commit/08ec3a93d77a1018439a5c41c23729ffed27c5a5)) - - Merge branch 'fix/relative-scplike-urls' ([`b688592`](https://github.com/Byron/gitoxide/commit/b68859254a02b93e7ea90f4881323357cfd080a4)) - - Adapt to changes in `git-url` ([`2a7576c`](https://github.com/Byron/gitoxide/commit/2a7576c3a34351df47ac057588c605675ad591eb)) - - Release git-date v0.3.1, git-features v0.25.0, git-actor v0.15.0, git-glob v0.5.1, git-path v0.7.0, git-attributes v0.7.0, git-config-value v0.10.0, git-lock v3.0.1, git-validate v0.7.1, git-object v0.24.0, git-ref v0.21.0, git-sec v0.6.0, git-config v0.13.0, git-prompt v0.3.0, git-url v0.12.0, git-credentials v0.8.0, git-diff v0.24.0, git-discover v0.10.0, git-traverse v0.20.0, git-index v0.10.0, git-mailmap v0.7.0, git-pack v0.28.0, git-odb v0.38.0, git-packetline v0.14.1, git-transport v0.24.0, git-protocol v0.25.0, git-revision v0.8.0, git-refspec v0.5.0, git-worktree v0.10.0, git-repository v0.30.0, safety bump 26 crates ([`e6b9906`](https://github.com/Byron/gitoxide/commit/e6b9906c486b11057936da16ed6e0ec450a0fb83)) - - Adapt to changes in `git-repository` ([`c4f68bf`](https://github.com/Byron/gitoxide/commit/c4f68bf775b854625d901fe0bfcbdd38f656d408)) - - Adapt to changes in `git-config` ([`1c2e755`](https://github.com/Byron/gitoxide/commit/1c2e755e517b0f9fe8671187f5c30076ce43a3c9)) - - Merge branch 'main' into http-config ([`bcd9654`](https://github.com/Byron/gitoxide/commit/bcd9654e56169799eb706646da6ee1f4ef2021a9)) - - Release git-hash v0.10.0, git-features v0.24.0, git-date v0.3.0, git-actor v0.14.0, git-glob v0.5.0, git-path v0.6.0, git-quote v0.4.0, git-attributes v0.6.0, git-config-value v0.9.0, git-tempfile v3.0.0, git-lock v3.0.0, git-validate v0.7.0, git-object v0.23.0, git-ref v0.20.0, git-sec v0.5.0, git-config v0.12.0, git-command v0.2.0, git-prompt v0.2.0, git-url v0.11.0, git-credentials v0.7.0, git-diff v0.23.0, git-discover v0.9.0, git-bitmap v0.2.0, git-traverse v0.19.0, git-index v0.9.0, git-mailmap v0.6.0, git-chunk v0.4.0, git-pack v0.27.0, git-odb v0.37.0, git-packetline v0.14.0, git-transport v0.23.0, git-protocol v0.24.0, git-revision v0.7.0, git-refspec v0.4.0, git-worktree v0.9.0, git-repository v0.29.0, git-commitgraph v0.11.0, gitoxide-core v0.21.0, gitoxide v0.19.0, safety bump 28 crates ([`b2c301e`](https://github.com/Byron/gitoxide/commit/b2c301ef131ffe1871314e19f387cf10a8d2ac16)) - - Merge branch 'jpgrayson/main' ([`b242853`](https://github.com/Byron/gitoxide/commit/b242853abd790e5234b2f18b4aaeddb8f6f4d36f)) - - Disable tag.gpgSign in test scripts ([`1ce3190`](https://github.com/Byron/gitoxide/commit/1ce3190000f6211ce31468c7603d491bb5b90293)) - - Merge branch 'version2021' ([`0e4462d`](https://github.com/Byron/gitoxide/commit/0e4462df7a5166fe85c23a779462cdca8ee013e8)) - - Upgrade edition to 2021 in most crates. ([`3d8fa8f`](https://github.com/Byron/gitoxide/commit/3d8fa8fef9800b1576beab8a5bc39b821157a5ed)) - - Release git-glob v0.4.2, git-config-value v0.8.2, git-lock v2.2.0, git-ref v0.19.0, git-config v0.11.0, git-discover v0.8.0, git-index v0.8.0, git-transport v0.22.0, git-protocol v0.23.0, git-worktree v0.8.0, git-repository v0.28.0, gitoxide-core v0.20.0, gitoxide v0.18.0, safety bump 9 crates ([`0c253b1`](https://github.com/Byron/gitoxide/commit/0c253b15143dcedfe4c66d64ab1ea6e097030651)) - - Merge branch 'main' into http-config ([`7c5b37d`](https://github.com/Byron/gitoxide/commit/7c5b37d28e98f59a6847368a0d0166d2dbb4acc1)) - - Release git-diff v0.22.0, git-index v0.7.1, git-pack v0.26.0, git-odb v0.36.0, git-transport v0.21.2, git-repository v0.27.0, safety bump 6 crates ([`f0cab31`](https://github.com/Byron/gitoxide/commit/f0cab317bb0c2799fa80d16f3ae1b89d6aee4284)) -
- -## 0.14.0 (2022-11-06) - -### Bug Fixes - - - `where -> were` typo fix. - -### Commit Statistics - - - - - 7 commits contributed to the release over the course of 27 calendar days. - - 27 days passed between releases. - - 1 commit was understood as [conventional](https://www.conventionalcommits.org). - - 1 unique issue was worked on: [#560](https://github.com/Byron/gitoxide/issues/560) - -### Thanks Clippy - - - -[Clippy](https://github.com/rust-lang/rust-clippy) helped 1 time to make code idiomatic. - -### Commit Details - - - -
view details - - * **[#560](https://github.com/Byron/gitoxide/issues/560)** - - `where -> were` typo fix. ([`0eca94d`](https://github.com/Byron/gitoxide/commit/0eca94d84bd82f2083b41acdb316edce54365f11)) - * **Uncategorized** - - Release cargo-smart-release v0.14.0 ([`a1c68da`](https://github.com/Byron/gitoxide/commit/a1c68da4b0fa080a383cbbfa50fd54e8bb45330c)) - - Release git-features v0.23.1, git-glob v0.4.1, git-config-value v0.8.1, git-tempfile v2.0.6, git-object v0.22.1, git-ref v0.18.0, git-sec v0.4.2, git-config v0.10.0, git-prompt v0.1.1, git-url v0.10.1, git-credentials v0.6.1, git-diff v0.21.0, git-discover v0.7.0, git-index v0.7.0, git-pack v0.25.0, git-odb v0.35.0, git-transport v0.21.1, git-protocol v0.22.0, git-refspec v0.3.1, git-worktree v0.7.0, git-repository v0.26.0, git-commitgraph v0.10.0, gitoxide-core v0.19.0, gitoxide v0.17.0, safety bump 9 crates ([`d071583`](https://github.com/Byron/gitoxide/commit/d071583c5576fdf5f7717765ffed5681792aa81f)) - - Merge branch 'main' into write-sparse-index (upgrade to Rust 1.65) ([`5406630`](https://github.com/Byron/gitoxide/commit/5406630466145990b5adbdadb59151036993060d)) - - Thanks clippy ([`04cfa63`](https://github.com/Byron/gitoxide/commit/04cfa635a65ae34ad6d22391f2febd2ca7eabca9)) - - Merge branch 'main' into gix-clone ([`3b48317`](https://github.com/Byron/gitoxide/commit/3b48317d6a9f41765d4f2a9f0a49c31afcdb68b6)) - - Adapt to changes in `git-repository` ([`3ad7581`](https://github.com/Byron/gitoxide/commit/3ad758176739a137960ed4d69f7d28d33b7eb4e0)) -
- -## 0.13.0 (2022-10-10) - -### Bug Fixes - - - build complete history information to match with `did crate changed` queries - Previously it was possible see a crate was changed, but didn't receive a - version bump which would in turn halt the release process. - - The issue was an algorithm inability to find changes in the commitgraph - because it would not look at the correct tree, causing trees to be - missed entirely. This in turn caused it to not see changes that were - present and the mismatch in question. - - log errors if these log messages cause stopping the release process. - Previously it was possible see `log::warn` but have the process abort - with proclaimed errors which weren't obvious. Now they are `log::error` - as one would expect. - -### Commit Statistics - - - - - 26 commits contributed to the release over the course of 40 calendar days. - - 40 days passed between releases. - - 2 commits were understood as [conventional](https://www.conventionalcommits.org). - - 2 unique issues were worked on: [#450](https://github.com/Byron/gitoxide/issues/450), [#470](https://github.com/Byron/gitoxide/issues/470) - -### Thanks Clippy - - - -[Clippy](https://github.com/rust-lang/rust-clippy) helped 2 times to make code idiomatic. - -### Commit Details - - - -
view details - - * **[#450](https://github.com/Byron/gitoxide/issues/450)** - - Adjust to deal with changes to git-repository ([`b99b6bf`](https://github.com/Byron/gitoxide/commit/b99b6bfea47a4485496c2eb565693a6a53efe166)) - * **[#470](https://github.com/Byron/gitoxide/issues/470)** - - Adapt to changes in `git-repository` ([`5ec714f`](https://github.com/Byron/gitoxide/commit/5ec714fa687100d77b061516194bc9b96a03c9c0)) - * **Uncategorized** - - Release cargo-smart-release v0.13.0 ([`919ba0d`](https://github.com/Byron/gitoxide/commit/919ba0d102e7c730549bed9610a6079550a3aafc)) - - Release git-hash v0.9.11, git-features v0.23.0, git-actor v0.13.0, git-attributes v0.5.0, git-object v0.22.0, git-ref v0.17.0, git-sec v0.4.1, git-config v0.9.0, git-url v0.10.0, git-credentials v0.6.0, git-diff v0.20.0, git-discover v0.6.0, git-traverse v0.18.0, git-index v0.6.0, git-mailmap v0.5.0, git-pack v0.24.0, git-odb v0.34.0, git-packetline v0.13.1, git-transport v0.21.0, git-protocol v0.21.0, git-revision v0.6.0, git-refspec v0.3.0, git-worktree v0.6.0, git-repository v0.25.0, safety bump 24 crates ([`104d922`](https://github.com/Byron/gitoxide/commit/104d922add61ab21c534c24ce8ed37cddf3e275a)) - - Thanks clippy ([`65e1627`](https://github.com/Byron/gitoxide/commit/65e1627757d05b451d013fadc5bf902fbe0ced7c)) - - Merge branch 'fix-smart-release' ([`aa80b60`](https://github.com/Byron/gitoxide/commit/aa80b606e5570f327660cca42ea81581a6e9d5e3)) - - Build complete history information to match with `did crate changed` queries ([`118c196`](https://github.com/Byron/gitoxide/commit/118c19628e00dce0248ea975c5e93745c8058b5a)) - - Log errors if these log messages cause stopping the release process. ([`03f3ffc`](https://github.com/Byron/gitoxide/commit/03f3ffc0816659b03f4eb0b2f24154ab2f86b95a)) - - Probably improve logic of determining which conclusion to draw from version data. ([`d298391`](https://github.com/Byron/gitoxide/commit/d298391e4dfa3af2af87ef5ca0f5f7c3095339b0)) - - Merge branch 'main' into fetch-pack ([`d686020`](https://github.com/Byron/gitoxide/commit/d6860205db847b8a474756e92578195e1022481c)) - - Thanks clippy ([`b9937ad`](https://github.com/Byron/gitoxide/commit/b9937adc2c31095dde63397be7d56f1ea559b0f7)) - - Merge branch 'fix-git-features' ([`82fd251`](https://github.com/Byron/gitoxide/commit/82fd251ac80d07bc9da8a4d36e517aa35580d188)) - - Fix smart-release journey tests ([`309dff8`](https://github.com/Byron/gitoxide/commit/309dff834887e7fef3ecd55027797b115d97b041)) - - Use `git-repository` to obtain the current push url. ([`ce9e46c`](https://github.com/Byron/gitoxide/commit/ce9e46c8cca1f1b6a2da82aa3f37baad667cc42b)) - - Use `git-repository` to figure out the actual remote to push to. ([`83a677e`](https://github.com/Byron/gitoxide/commit/83a677eeddd3c2e90f93f6651623ad9b90461c9a)) - - Merge branch 'diff' ([`25a7726`](https://github.com/Byron/gitoxide/commit/25a7726377fbe400ea3c4927d04e9dec99802b7b)) - - Upgrade all dependencies, except for `windows` ([`2968181`](https://github.com/Byron/gitoxide/commit/29681819ffe53d3926d631dc482f71d6200cb549)) - - Make fmt ([`535e967`](https://github.com/Byron/gitoxide/commit/535e967666c6da657ff1b7eff7c64ab27cafb182)) - - Merge branch 'filter-refs-by-spec' ([`5c05198`](https://github.com/Byron/gitoxide/commit/5c051986bd89590a9287d85d84c713d83dfab83a)) - - Merge branch 'main' into filter-refs-by-spec ([`9aa1d3d`](https://github.com/Byron/gitoxide/commit/9aa1d3dc46d4b1c76af257f573aff3aeef2d3fa8)) - - Release git-features v0.22.4, git-url v0.8.0, safety bump 4 crates ([`1d4600a`](https://github.com/Byron/gitoxide/commit/1d4600ae51475c2e225f96c16c41e2c4a2b3f2aa)) - - Merge branch 'main' into index-from-tree ([`bc64b96`](https://github.com/Byron/gitoxide/commit/bc64b96a2ec781c72d1d4daad38aa7fb8b74f99b)) - - Merge branch 'main' into filter-refs-by-spec ([`51dc828`](https://github.com/Byron/gitoxide/commit/51dc8282fb77b519ff7d2c94c6bd73af306cfe8b)) - - Release git-diff v0.18.1, git-discover v0.4.2, git-traverse v0.16.4, git-repository v0.23.1 ([`2571831`](https://github.com/Byron/gitoxide/commit/2571831e5939bf4ea6f19537b0c1ccd71dc99088)) - - Merge branch 'main' into filter-refs-by-spec ([`56ba481`](https://github.com/Byron/gitoxide/commit/56ba481f4c48f74f10397feb1b6dc3d7dd3704fb)) - - Adjust journey tests expectations ([`992bfe5`](https://github.com/Byron/gitoxide/commit/992bfe5d0c230f169b1a62fa059c414a90b60f97)) -
- -## 0.12.1 (2022-08-31) - -### Fix - -- Use correct English in `Commit Details`, see [#513](https://github.com/Byron/gitoxide/issues/513) for details. - -### Commit Statistics - - - - - 5 commits contributed to the release. - - 0 commits were understood as [conventional](https://www.conventionalcommits.org). - - 1 unique issue was worked on: [#513](https://github.com/Byron/gitoxide/issues/513) - -### Commit Details - - - -
view details - - * **[#513](https://github.com/Byron/gitoxide/issues/513)** - - Prepare for release ([`673587d`](https://github.com/Byron/gitoxide/commit/673587de26a0aa031740a0d4e548968f0b9d2939)) - - Improve the English skills of cargo-smart-release and fix a typo. ([`a0835c5`](https://github.com/Byron/gitoxide/commit/a0835c5906eee1f7c9270fcbce5842c24c0f66e9)) - * **Uncategorized** - - Release cargo-smart-release v0.12.1 ([`b76999b`](https://github.com/Byron/gitoxide/commit/b76999bb9b8c79d0c59d1bc9aa9f87df960af4d8)) - - Update dependencies and assure we get the right version of `crates-index` ([`60a5272`](https://github.com/Byron/gitoxide/commit/60a527223965351f7c2164d4c827007fec4ec0ff)) - - Fix depreaction warning ([`47264d4`](https://github.com/Byron/gitoxide/commit/47264d41a65f00911a1b503a191b1974f4e222f8)) -
- -## 0.12.0 (2022-08-30) - -### Bug Fixes - - - Assure `git@github.com/user/repo` urls transform into https urls correctly. - -### Commit Statistics - - - - - 6 commits contributed to the release over the course of 6 calendar days. - - 6 days passed between releases. - - 1 commit was understood as [conventional](https://www.conventionalcommits.org). - - 1 unique issue was worked on: [#512](https://github.com/Byron/gitoxide/issues/512) - -### Commit Details - - - -
view details - - * **[#512](https://github.com/Byron/gitoxide/issues/512)** - - Assure `git@github.com/user/repo` urls transform into https urls correctly. ([`fcbea05`](https://github.com/Byron/gitoxide/commit/fcbea050d04f0b763adef80d9de829f171dda571)) - * **Uncategorized** - - Release cargo-smart-release v0.12.0 ([`5cfd1b6`](https://github.com/Byron/gitoxide/commit/5cfd1b6ce2cd21c435193a52f0f90a9e9fdc45fd)) - - Merge branch 'main' into filter-refs-by-spec ([`cef0b51`](https://github.com/Byron/gitoxide/commit/cef0b51ade2a3301fa09ede7a425aa1fe3527e78)) - - Release git-object v0.20.3, git-ref v0.15.4, git-config v0.7.1, git-diff v0.18.0, git-traverse v0.16.3, git-pack v0.22.0, git-odb v0.32.0, git-url v0.7.3, git-transport v0.19.3, git-protocol v0.19.1, git-refspec v0.1.1, git-repository v0.23.0, safety bump 6 crates ([`85a3bed`](https://github.com/Byron/gitoxide/commit/85a3bedd68d2e5f36592a2f691c977dc55298279)) - - Merge branch 'main' into filter-refs-by-spec ([`cfa1440`](https://github.com/Byron/gitoxide/commit/cfa144031dbcac2707ab0cec012bc35e78f9c475)) - - Merge branch 'fix-ci-installation' ([`9245083`](https://github.com/Byron/gitoxide/commit/92450839621a4d99cb22d08cbf9f9a89ff6b9e3f)) -
- -## 0.11.0 (2022-08-24) - - - -### Chore - - - remove default link to cargo doc everywhere - -### Bug Fixes - - - allow dependency edits to apply to `target..*dependencies`. - Previously these would be skipped, which would cause the publish to - abort due to invalid manifests - some dependencies would still refer - to an outdated but incompatible version. - - List any dependency update that is caused by other crates in preview. - Previously it was possible that crates there were about to be published - didn't show up in the list of crates that received a safety version - bump. - -### Commit Statistics - - - - - 42 commits contributed to the release over the course of 77 calendar days. - - 88 days passed between releases. - - 3 commits were understood as [conventional](https://www.conventionalcommits.org). - - 3 unique issues were worked on: [#331](https://github.com/Byron/gitoxide/issues/331), [#427](https://github.com/Byron/gitoxide/issues/427), [#450](https://github.com/Byron/gitoxide/issues/450) - -### Thanks Clippy - - - -[Clippy](https://github.com/rust-lang/rust-clippy) helped 3 times to make code idiomatic. - -### Commit Details - - - -
view details - - * **[#331](https://github.com/Byron/gitoxide/issues/331)** - - Make fmt ([`a7d7751`](https://github.com/Byron/gitoxide/commit/a7d7751822a1a8ac89930031707af57ad95d9cbd)) - * **[#427](https://github.com/Byron/gitoxide/issues/427)** - - Implement : parsing ([`74e7a46`](https://github.com/Byron/gitoxide/commit/74e7a46199d3ae13d8bc3616d285c238942c2cad)) - * **[#450](https://github.com/Byron/gitoxide/issues/450)** - - Adjust to changes in `git-url` ([`bb83843`](https://github.com/Byron/gitoxide/commit/bb838430ecbaa18921ef60af04ff684809572ce2)) - - Adapt to changes in `git-url` ([`60bfd6d`](https://github.com/Byron/gitoxide/commit/60bfd6d457d75fb4b342e08f329dadc8373de266)) - * **Uncategorized** - - Release git-date v0.1.0, git-actor v0.11.4, git-revision v0.4.3, git-repository v0.22.1, cargo-smart-release v0.11.0, git-commitgraph v0.8.2, gitoxide-core v0.17.0, gitoxide v0.15.0 ([`1fb931a`](https://github.com/Byron/gitoxide/commit/1fb931a7ea59f1cf895a6c1392fd8615b723c743)) - - Update changelogs prior to release ([`23cb58f`](https://github.com/Byron/gitoxide/commit/23cb58f02043e0e5027136fd6e8e724c03a2efbe)) - - Improve performance configuration of smart-release, allowing it to build on msvc by default ([`3923893`](https://github.com/Byron/gitoxide/commit/3923893c638d92c713def0a244f07b9718397fc3)) - - Release git-date v0.0.5, git-hash v0.9.8, git-features v0.22.2, git-actor v0.11.3, git-glob v0.3.2, git-quote v0.2.1, git-attributes v0.3.2, git-tempfile v2.0.4, git-lock v2.1.1, git-validate v0.5.5, git-object v0.20.2, git-ref v0.15.2, git-sec v0.3.1, git-config v0.7.0, git-credentials v0.4.0, git-diff v0.17.2, git-discover v0.4.1, git-bitmap v0.1.2, git-index v0.4.2, git-mailmap v0.3.2, git-chunk v0.3.1, git-traverse v0.16.2, git-pack v0.21.2, git-odb v0.31.2, git-packetline v0.12.7, git-url v0.7.2, git-transport v0.19.2, git-protocol v0.19.0, git-revision v0.4.2, git-refspec v0.1.0, git-worktree v0.4.2, git-repository v0.22.0, safety bump 4 crates ([`4974eca`](https://github.com/Byron/gitoxide/commit/4974eca96d525d1ee4f8cad79bb713af7a18bf9d)) - - Merge branch 'remote-ls-refs' ([`39d585d`](https://github.com/Byron/gitoxide/commit/39d585d9f9ac6f3ecf51359c8e37f0a50e21ed45)) - - Merge branch 'main' into remote-ls-refs ([`e2ee3de`](https://github.com/Byron/gitoxide/commit/e2ee3ded97e5c449933712883535b30d151c7c78)) - - Merge branch 'docsrs-show-features' ([`31c2351`](https://github.com/Byron/gitoxide/commit/31c235140cad212d16a56195763fbddd971d87ce)) - - Remove default link to cargo doc everywhere ([`533e887`](https://github.com/Byron/gitoxide/commit/533e887e80c5f7ede8392884562e1c5ba56fb9a8)) - - Merge branch 'main' into remote-ls-refs ([`c82bbfa`](https://github.com/Byron/gitoxide/commit/c82bbfaddc45bf9b5b55f056613046d977d9ef09)) - - Prepare for release of git-repository ([`8aa5389`](https://github.com/Byron/gitoxide/commit/8aa5389d5a1bdd3a07f1caa1c2f55c8af4f9844a)) - - Merge branch 'main' into remote-ls-refs ([`bd5f3e8`](https://github.com/Byron/gitoxide/commit/bd5f3e8db7e0bb4abfb7b0f79f585ab82c3a14ab)) - - Release git-date v0.0.3, git-actor v0.11.1, git-attributes v0.3.1, git-tempfile v2.0.3, git-object v0.20.1, git-ref v0.15.1, git-config v0.6.1, git-diff v0.17.1, git-discover v0.4.0, git-bitmap v0.1.1, git-index v0.4.1, git-mailmap v0.3.1, git-traverse v0.16.1, git-pack v0.21.1, git-odb v0.31.1, git-packetline v0.12.6, git-url v0.7.1, git-transport v0.19.1, git-protocol v0.18.1, git-revision v0.4.0, git-worktree v0.4.1, git-repository v0.21.0, safety bump 5 crates ([`c96473d`](https://github.com/Byron/gitoxide/commit/c96473dce21c3464aacbc0a62d520c1a33172611)) - - Merge branch 'main' into write-index-v2 ([`a938986`](https://github.com/Byron/gitoxide/commit/a938986877302c197d1aed087594c5605416fe5f)) - - Merge branch 'main' into remote-ls-refs ([`de61c4d`](https://github.com/Byron/gitoxide/commit/de61c4db7855d6925d66961f62ae3d12cc4acf78)) - - Thanks clippy ([`4bd747c`](https://github.com/Byron/gitoxide/commit/4bd747cb3e126fe5b1d540270cfbd731cffd42ef)) - - Merge pull request #2 from SidneyDouw/main ([`ce885ad`](https://github.com/Byron/gitoxide/commit/ce885ad4c3324c09c83751c32e014f246c748766)) - - Merge branch 'Byron:main' into main ([`9b9ea02`](https://github.com/Byron/gitoxide/commit/9b9ea0275f8ff5862f24cf5a4ca53bb1cd610709)) - - Merge branch 'main' into rev-parse-delegate ([`6da8250`](https://github.com/Byron/gitoxide/commit/6da82507588d3bc849217c11d9a1d398b67f2ed6)) - - Merge branch 'main' into pathspec ([`7b61506`](https://github.com/Byron/gitoxide/commit/7b615060712565f515515e35a3e8346278ad770c)) - - Merge branch 'kianmeng-fix-typos' ([`4e7b343`](https://github.com/Byron/gitoxide/commit/4e7b34349c0a01ad8686bbb4eb987e9338259d9c)) - - Fix typos ([`e9fcb70`](https://github.com/Byron/gitoxide/commit/e9fcb70e429edb2974afa3f58d181f3ef14c3da3)) - - Merge pull request #1 from Byron/main ([`085e76b`](https://github.com/Byron/gitoxide/commit/085e76b121291ed9bd324139105d2bd4117bedf8)) - - Fix build after changes to `git-url` and `git-config` ([`1f02420`](https://github.com/Byron/gitoxide/commit/1f0242034071ce317743df75cc685e7428b604b0)) - - Merge branch 'main' into pathspec ([`89ea12b`](https://github.com/Byron/gitoxide/commit/89ea12b558bcc056b892193ee8fb44b8664b5da4)) - - Merge branch 'main' into cont_include_if ([`daa71c3`](https://github.com/Byron/gitoxide/commit/daa71c3b753c6d76a3d652c29237906b3e28728f)) - - Thanks clippy ([`e1003d5`](https://github.com/Byron/gitoxide/commit/e1003d5fdee5d4439c0cf0286c67dec9b5e34f53)) - - Merge branch 'main' into cont_include_if ([`41ea8ba`](https://github.com/Byron/gitoxide/commit/41ea8ba78e74f5c988148367386a1f4f304cb951)) - - Release git-path v0.3.0, safety bump 14 crates ([`400c9be`](https://github.com/Byron/gitoxide/commit/400c9bec49e4ec5351dc9357b246e7677a63ea35)) - - Use clap 3.2.5 to be able to opt-in to deprecations ([`aaf1cde`](https://github.com/Byron/gitoxide/commit/aaf1cdedf7bd181977faa66ef21f7ee75627bf9f)) - - Thanks clippy ([`f6c2f94`](https://github.com/Byron/gitoxide/commit/f6c2f94a6270dd71523a90796fd0e3ac49b03a8f)) - - Fix smart-release journey tests ([`6c852b8`](https://github.com/Byron/gitoxide/commit/6c852b8896ce7ec8175faa05176fc30e0705df1d)) - - Adjust cargo-smart-release to use latest `git-repository` version ([`1e1fabd`](https://github.com/Byron/gitoxide/commit/1e1fabd31fbe11fb9a9422ceb474fd2724d0c320)) - - Allow dependency edits to apply to `target..*dependencies`. ([`376749c`](https://github.com/Byron/gitoxide/commit/376749cc49c6dafcc314b8435d6feac81482b3f5)) - - Make it possible (in theory) to find versions in `target` dependencies. ([`34d0744`](https://github.com/Byron/gitoxide/commit/34d074473c75a395501be20654373f70f7d2acb7)) - - List any dependency update that is caused by other crates in preview. ([`988c61e`](https://github.com/Byron/gitoxide/commit/988c61e07bdb52870794e70e94b925de7acb402e)) - - More useful debug output for `traverse::Dependency`. ([`0aff709`](https://github.com/Byron/gitoxide/commit/0aff7091adbedc53448b56d2363fad17408d8f4e)) - - Merge branch 'revspec-parsing' ([`a2c8969`](https://github.com/Byron/gitoxide/commit/a2c8969ba821fd387c39b14248074767f54749c8)) - - Also remove cargo-smart-release from workspace ([`8ef5197`](https://github.com/Byron/gitoxide/commit/8ef5197178f879bdd5d191dba331ac318626bfb5)) -
- -## 0.10.2 (2022-05-27) - -### Bug Fixes - - - Avoid running into the `default-members` trap with 'cargo publish'. - Default-members in a cargo workspace can override what's actually - published, so we have to be explicit about what to publish. - - This is only the case when there is more than one members in the - workspace, even though it would probably work as well if the package - would be specified with a single-crate workspace. - -### Commit Statistics - - - - - 4 commits contributed to the release over the course of 1 calendar day. - - 3 days passed between releases. - - 1 commit was understood as [conventional](https://www.conventionalcommits.org). - - 1 unique issue was worked on: [#429](https://github.com/Byron/gitoxide/issues/429) - -### Commit Details - - - -
view details - - * **[#429](https://github.com/Byron/gitoxide/issues/429)** - - Adjust changelogs prior to release ([`7397805`](https://github.com/Byron/gitoxide/commit/7397805fd032a752d6c2f2c2c28ac11ddecc7193)) - - Avoid running into the `default-members` trap with 'cargo publish'. ([`64b951c`](https://github.com/Byron/gitoxide/commit/64b951cade24c69d522a76ad217bea70a4afe45a)) - * **Uncategorized** - - Release git-sec v0.1.2, git-discover v0.1.3, cargo-smart-release v0.10.2 ([`6cd365e`](https://github.com/Byron/gitoxide/commit/6cd365e2cf6851f5cdecc22f3b1667440ad011b0)) - - Merge branch 'main' into SidneyDouw-pathspec ([`a22b1d8`](https://github.com/Byron/gitoxide/commit/a22b1d88a21311d44509018729c3ef1936cf052a)) -
- -## 0.10.1 (2022-05-23) - -### Bug Fixes - - - Correctly determine top-level crate name. - Previously it was possible to think the crate is part of a multi-crate - worktree even though it wasn't, causing changelogs to not pick up their - history as it would look for different tag names. - -### Commit Statistics - - - - - 2 commits contributed to the release. - - 1 day passed between releases. - - 1 commit was understood as [conventional](https://www.conventionalcommits.org). - - 0 issues like '(#ID)' were seen in commit messages - -### Commit Details - - - -
view details - - * **Uncategorized** - - Release git-path v0.1.3, git-discover v0.1.2, git-repository v0.18.1, cargo-smart-release v0.10.1 ([`b7399cc`](https://github.com/Byron/gitoxide/commit/b7399cc44ee419355a649a7b0ba7b352cd48b400)) - - Correctly determine top-level crate name. ([`33a2bd6`](https://github.com/Byron/gitoxide/commit/33a2bd6bd3faf597f020924e42082a714d3253b9)) -
- -## 0.10.0 (2022-05-21) - -### Bug Fixes - - - Don't assume crates are non-breaking just because they are in the user selection. - Crates showing up 'early' in our list could cause the entire - breakage-propagation to fail which led the crate to be ignored entirely - even when their dependees changed their version. This led to - inconsistent version requirements which would abort any cargo call. - -### Commit Statistics - - - - - 17 commits contributed to the release over the course of 46 calendar days. - - 48 days passed between releases. - - 1 commit was understood as [conventional](https://www.conventionalcommits.org). - - 3 unique issues were worked on: [#298](https://github.com/Byron/gitoxide/issues/298), [#301](https://github.com/Byron/gitoxide/issues/301), [#422](https://github.com/Byron/gitoxide/issues/422) - -### Commit Details - - - -
view details - - * **[#298](https://github.com/Byron/gitoxide/issues/298)** - - Adjust to changes in git-traverse ([`8240622`](https://github.com/Byron/gitoxide/commit/824062215865e6ec12afeb2d51b3c63f15291244)) - * **[#301](https://github.com/Byron/gitoxide/issues/301)** - - Adapt to changes in git-ref ([`21109ca`](https://github.com/Byron/gitoxide/commit/21109ca9ab21df0ab45f3be552e83114817e98d0)) - * **[#422](https://github.com/Byron/gitoxide/issues/422)** - - Don't assume crates are non-breaking just because they are in the user selection. ([`fcaa635`](https://github.com/Byron/gitoxide/commit/fcaa6353297fd1d4cb30ca3a873f76efb62e45e1)) - * **Uncategorized** - - Release git-path v0.1.2, git-sec v0.1.1, git-config v0.4.0, git-discover v0.1.1, git-pack v0.19.1, git-repository v0.18.0, cargo-smart-release v0.10.0, safety bump 2 crates ([`ceb6dff`](https://github.com/Byron/gitoxide/commit/ceb6dff13362a2b4318a551893217c1d11643b9f)) - - Merge branch 'main' into git_includeif ([`598c853`](https://github.com/Byron/gitoxide/commit/598c853087fcf8f77299aa5b9803bcec705c0cd0)) - - Merge branch 'refs-and-worktrees' ([`8131227`](https://github.com/Byron/gitoxide/commit/8131227ddff6f36919b6a0f7b33792ebde0f8ae9)) - - Merge branch 'main' into refs-and-worktrees ([`9cf0c7b`](https://github.com/Byron/gitoxide/commit/9cf0c7bd0cc5419137db5796f3a5b91bdf3dcc94)) - - Merge branch 'davidkna-remote-branch-name' ([`068a2de`](https://github.com/Byron/gitoxide/commit/068a2de764fabff949ff49a50594563cc625e343)) - - Adjust to changes in git-ref ([`0671586`](https://github.com/Byron/gitoxide/commit/06715861d3a1d236c310d71737ec1d1a5ca6c770)) - - Merge branch 'main' into git_includeif ([`05eb340`](https://github.com/Byron/gitoxide/commit/05eb34023933918c51c03cf2afd774db89cc5a33)) - - Adjust test expectations to match improved parsing in git-conventional ([`42abfed`](https://github.com/Byron/gitoxide/commit/42abfed32b2aa677b53f78f0b2756780aa61d2d4)) - - Merge branch 'main' into repo-status ([`4086335`](https://github.com/Byron/gitoxide/commit/40863353a739ec971b49410fbc2ba048b2762732)) - - Release git-glob v0.2.0, safety bump 3 crates ([`ab6bed7`](https://github.com/Byron/gitoxide/commit/ab6bed7e2aa19eeb9990441741008c430f373708)) - - Fix clippy - many false positives this time ([`045e6fa`](https://github.com/Byron/gitoxide/commit/045e6fae17077555c3e115992905c8046f2c5d0b)) - - Fix clippy - many false positives this time ([`099bd5b`](https://github.com/Byron/gitoxide/commit/099bd5b86fb80b26a73863b80ad60a0394458b6d)) - - Upgrade toml_edit for cargo-smart-release ([`fbacb77`](https://github.com/Byron/gitoxide/commit/fbacb778e3e982a74cd51350921cfcf074661df9)) - - Release git-config v0.2.1, git-diff v0.15.0, git-traverse v0.14.0, git-pack v0.18.0, git-odb v0.28.0, git-ref v0.12.1, git-revision v0.1.0, git-repository v0.16.0, gitoxide-core v0.14.0, gitoxide v0.12.0, safety bump 6 crates ([`b612021`](https://github.com/Byron/gitoxide/commit/b612021683ba709b693bd48aef3e2e3c2f5b9ead)) -
- -## 0.9.0 (2022-04-03) - - - - -A quality-of-life release which should make publishing of inter-dependent crates much more reliable. - -### New Features - - - Wait for previously published crates explicitly to avoid running into publish failures due to the previously published crate not present - even after 3 attempts. - -### Bug Fixes - - - improve headline parsing for git-conventional messages. - - It is now case-insensitive, which prevents it from getting tripped - up in some cases. - - Don't pass judgement on usefulness of certain kinds of git-conventional messages. - - Previously we would intentionally avoid writing out information about - refactors or chores as they are not deemed useful in a changelog. - - However, this can be confusing for anyone but the original author. - - We now write them as seen. - - Future iterations on this may consider adding more options - to configure which sections should go into the changelog. - -### Refactor (BREAKING) - - - clarify different repository types much better - -### Commit Statistics - - - - - 22 commits contributed to the release over the course of 69 calendar days. - - 69 days passed between releases. - - 3 commits were understood as [conventional](https://www.conventionalcommits.org). - - 4 unique issues were worked on: [#298](https://github.com/Byron/gitoxide/issues/298), [#317](https://github.com/Byron/gitoxide/issues/317), [#318](https://github.com/Byron/gitoxide/issues/318), [#364](https://github.com/Byron/gitoxide/issues/364) - -### Thanks Clippy - - - -[Clippy](https://github.com/rust-lang/rust-clippy) helped 1 time to make code idiomatic. - -### Commit Details - - - -
view details - - * **[#298](https://github.com/Byron/gitoxide/issues/298)** - - Fix docs; consistent naming of 'repo' ([`1f79bc3`](https://github.com/Byron/gitoxide/commit/1f79bc32ee3d7a70985b7bef830ccdd1dc762f05)) - - Adapt to changes in `git-repository' ([`16a1c36`](https://github.com/Byron/gitoxide/commit/16a1c360113b9bc910d5b0812384c3ab32cfc780)) - - Clarify different repository types much better ([`bbc6efe`](https://github.com/Byron/gitoxide/commit/bbc6efeceb26050973e1425e68a52e51b9df4572)) - - Upgrade parking_lot and cargo_toml ([`f95c1a0`](https://github.com/Byron/gitoxide/commit/f95c1a0d9c19bcc6feb9b8739a09d86f9970a0e0)) - * **[#317](https://github.com/Byron/gitoxide/issues/317)** - - Fix broken link in README; clarify 'pre-release' ([`1e2fa21`](https://github.com/Byron/gitoxide/commit/1e2fa21c3878a8c1c750d13a4ab44f6450280304)) - - Fix broken link in README; clarify 'pre-release' ([`375cd12`](https://github.com/Byron/gitoxide/commit/375cd12281297ce476df5ff9b26402356ee0ffb0)) - - Disambiguate usage of pre-release in stability guide ([`498072e`](https://github.com/Byron/gitoxide/commit/498072ea42dca7b9d00bedba42829bdac92195b9)) - * **[#318](https://github.com/Byron/gitoxide/issues/318)** - - Don't pass judgement on usefulness of certain kinds of git-conventional messages ([`1feb118`](https://github.com/Byron/gitoxide/commit/1feb118e87f302d030ceca03ce8f8c22d40d7f03)) - * **[#364](https://github.com/Byron/gitoxide/issues/364)** - - Prepare smart-release changelog ([`bba56ea`](https://github.com/Byron/gitoxide/commit/bba56ea71bb3ff86914e7fa940990d9fc0e73388)) - - Dial down log level for unparseable items again ([`2990f6b`](https://github.com/Byron/gitoxide/commit/2990f6bee433a9fdbe9caa88cc18ccf41a8df689)) - - Smart-release tries harder to wait for previously published packages ([`e175621`](https://github.com/Byron/gitoxide/commit/e1756218786fc1eb82bb4e74455bdf782a0e698c)) - - Consolidate naming of directories, use same convention as git2 ([`a7dbed1`](https://github.com/Byron/gitoxide/commit/a7dbed193cc25d05e03c4f2148d0fa9562a4a586)) - * **Uncategorized** - - Release git-diff v0.14.0, git-bitmap v0.1.0, git-index v0.2.0, git-tempfile v2.0.1, git-lock v2.0.0, git-mailmap v0.1.0, git-traverse v0.13.0, git-pack v0.17.0, git-quote v0.2.0, git-odb v0.27.0, git-packetline v0.12.4, git-url v0.4.0, git-transport v0.16.0, git-protocol v0.15.0, git-ref v0.12.0, git-worktree v0.1.0, git-repository v0.15.0, cargo-smart-release v0.9.0, safety bump 5 crates ([`e58dc30`](https://github.com/Byron/gitoxide/commit/e58dc3084cf17a9f618ae3a6554a7323e44428bf)) - - Thanks clippy ([`3079e11`](https://github.com/Byron/gitoxide/commit/3079e114dc1d2552e023aa793dc10c28258b34da)) - - Merge branch 'main' into mailmap ([`b2df941`](https://github.com/Byron/gitoxide/commit/b2df941feaf5ae9fa170fa49270189f3527f2eab)) - - Merge branch 'describe-rev' ([`77b7cd9`](https://github.com/Byron/gitoxide/commit/77b7cd9a7813aaa1a15d035ea42c1e3fe4eef8dd)) - - Adapt to breaking changes in git-actor ([`40c48c3`](https://github.com/Byron/gitoxide/commit/40c48c390eb796b427ebd516dde92e9538ce5fb7)) - - Merge branch 'short-id' ([`5849d5b`](https://github.com/Byron/gitoxide/commit/5849d5b326b83f98a16cf1d956c720c7f0fd4445)) - - Fix clap warnings ([`aa51e05`](https://github.com/Byron/gitoxide/commit/aa51e05923695e20aecc16317331c7e26d49a2e7)) - - Release git-tempfile v2.0.0, safety bump 6 crates ([`90b1c42`](https://github.com/Byron/gitoxide/commit/90b1c42d5487904a9f329362d185b035d0ddb975)) - - Adapt cargo-smart-release to changes in git-tempfile ([`46282ff`](https://github.com/Byron/gitoxide/commit/46282ff8eddae66a786334dd98e41c3fb36d1e36)) - - Improve headline parsing for git-conventional messages. ([`f9daba4`](https://github.com/Byron/gitoxide/commit/f9daba439e2d669c8b0a6bcac9ff50cbf9d80371)) -
- -## 0.8.0 (2022-01-23) - - - -### Chore - - - upgrade all dependencies - -### New Features - - - highlight (non-fatal) errors when losslessly parsing changelogs - - Commit statistics reveal the days passes between releases - -### Bug Fixes - - - more prominent message if 'bat' wasn't found in PATH - -### Changed (BREAKING) - - - Remove easy::borrow::Error entirely; support for multiple objects per handle - This massive simplification finally allows any amounts of objects to be - created while adding support for reusing their data buffers thanks - to a simple free-list stored with the handle. - - rename `easy::Object` to `OwnedObject`; remove `Ref` suffix from `ObjectRef` and `TreeRef` - -### New Features (BREAKING) - - - upgrade to crates-index 0.18 - It now assumes that the crates-index must exist, which might not always - be the case and rightfully so. Now we wrap it to get back to the - original behavior. - -### Commit Statistics - - - - - 34 commits contributed to the release over the course of 51 calendar days. - - 55 days passed between releases. - - 7 commits were understood as [conventional](https://www.conventionalcommits.org). - - 6 unique issues were worked on: [#266](https://github.com/Byron/gitoxide/issues/266), [#270](https://github.com/Byron/gitoxide/issues/270), [#274](https://github.com/Byron/gitoxide/issues/274), [#279](https://github.com/Byron/gitoxide/issues/279), [#287](https://github.com/Byron/gitoxide/issues/287), [#308](https://github.com/Byron/gitoxide/issues/308) - -### Thanks Clippy - - - -[Clippy](https://github.com/rust-lang/rust-clippy) helped 1 time to make code idiomatic. - -### Commit Details - - - -
view details - - * **[#266](https://github.com/Byron/gitoxide/issues/266)** - - Upgrade to crates-index 0.18 ([`15e60b2`](https://github.com/Byron/gitoxide/commit/15e60b2d80e4452a316d14f938583b23fb9e17e6)) - - Upgrade dependencies except for crates-index ([`c77c0d6`](https://github.com/Byron/gitoxide/commit/c77c0d6db78cdc2d175312c4e8704bb2ec28ddc5)) - - Revert "chore: upgrade all dependencies" ([`0dfe4a7`](https://github.com/Byron/gitoxide/commit/0dfe4a74144428e1195870a67f8aa56d1f43e1e5)) - - Upgrade all dependencies ([`a3caf39`](https://github.com/Byron/gitoxide/commit/a3caf3938bf0f1cea1bee0f55c082062dd250bed)) - - Adjustments due to change in `git-repository` ([`e44dc4d`](https://github.com/Byron/gitoxide/commit/e44dc4d64827fe71f5a556d88f5d742840de41ee)) - - Adjustments to match changes in `git-repository` ([`117d5f8`](https://github.com/Byron/gitoxide/commit/117d5f8625fd3af8f501e48eb0fad6d09fa814ba)) - - Adapt to changes in git-repository ([`3ab9b03`](https://github.com/Byron/gitoxide/commit/3ab9b03eee7d449b7bb87cb7dcbf164fdbe4ca48)) - * **[#270](https://github.com/Byron/gitoxide/issues/270)** - - Use new built-in sorting to avoid more expensive sorting later on ([`e5442df`](https://github.com/Byron/gitoxide/commit/e5442dfddc9422ee9bf5f7fca098c64458431045)) - * **[#274](https://github.com/Byron/gitoxide/issues/274)** - - Remove easy::borrow::Error entirely; support for multiple objects per handle ([`c4184f3`](https://github.com/Byron/gitoxide/commit/c4184f3c31ffc4597bd089e8140653906a6594d8)) - - Rename `easy::Object` to `OwnedObject`; remove `Ref` suffix from `ObjectRef` and `TreeRef` ([`880b564`](https://github.com/Byron/gitoxide/commit/880b56426859306aa30038ff35e2ad14607e9e90)) - * **[#279](https://github.com/Byron/gitoxide/issues/279)** - - Add missing docs ([`4137327`](https://github.com/Byron/gitoxide/commit/41373274fc7f23e3fed17dc52e3e3e94c2e9e41a)) - - Adjust to git-hash changes ([`54f3ab5`](https://github.com/Byron/gitoxide/commit/54f3ab5c25d72cd27b5554c777078df8b9249a45)) - * **[#287](https://github.com/Byron/gitoxide/issues/287)** - - Smart-release now actually shows the time between releases ([`cd8d343`](https://github.com/Byron/gitoxide/commit/cd8d34379b62c2964fd9599f17b42fdc826bee1f)) - * **[#308](https://github.com/Byron/gitoxide/issues/308)** - - More prominent message if 'bat' wasn't found in PATH ([`9c1e38b`](https://github.com/Byron/gitoxide/commit/9c1e38bfcffea372f06c78a44b2abc2284b7a87e)) - * **Uncategorized** - - Release cargo-smart-release v0.8.0 ([`fbe2c93`](https://github.com/Byron/gitoxide/commit/fbe2c93b13fc05414dc5c7d80f4197d279b6b81b)) - - Release git-protocol v0.14.0, git-ref v0.11.0, git-repository v0.14.0, cargo-smart-release v0.8.0 ([`b286b24`](https://github.com/Byron/gitoxide/commit/b286b24a51878be7d2e0fd77ff0c5c99b439a6a0)) - - Release git-odb v0.26.0, git-packetline v0.12.3, git-url v0.3.5, git-transport v0.15.0, git-protocol v0.14.0, git-ref v0.11.0, git-repository v0.14.0, cargo-smart-release v0.8.0 ([`42ebb53`](https://github.com/Byron/gitoxide/commit/42ebb536cd6086f096b8422291776c9720fa0948)) - - Release git-diff v0.13.0, git-tempfile v1.0.4, git-chunk v0.3.0, git-traverse v0.12.0, git-pack v0.16.0, git-odb v0.26.0, git-packetline v0.12.3, git-url v0.3.5, git-transport v0.15.0, git-protocol v0.14.0, git-ref v0.11.0, git-repository v0.14.0, cargo-smart-release v0.8.0 ([`1b76119`](https://github.com/Byron/gitoxide/commit/1b76119259b8168aeb99cbbec233f7ddaa2d7d2c)) - - Release git-actor v0.8.0, git-config v0.1.10, git-object v0.17.0, git-diff v0.13.0, git-tempfile v1.0.4, git-chunk v0.3.0, git-traverse v0.12.0, git-pack v0.16.0, git-odb v0.26.0, git-packetline v0.12.3, git-url v0.3.5, git-transport v0.15.0, git-protocol v0.14.0, git-ref v0.11.0, git-repository v0.14.0, cargo-smart-release v0.8.0 ([`8f57c29`](https://github.com/Byron/gitoxide/commit/8f57c297d7d6ed68cf51415ea7ede4bf9263326e)) - - Release git-features v0.19.1, git-actor v0.8.0, git-config v0.1.10, git-object v0.17.0, git-diff v0.13.0, git-tempfile v1.0.4, git-chunk v0.3.0, git-traverse v0.12.0, git-pack v0.16.0, git-odb v0.26.0, git-packetline v0.12.3, git-url v0.3.5, git-transport v0.15.0, git-protocol v0.14.0, git-ref v0.11.0, git-repository v0.14.0, cargo-smart-release v0.8.0 ([`d78aab7`](https://github.com/Byron/gitoxide/commit/d78aab7b9c4b431d437ac70a0ef96263acb64e46)) - - Release git-hash v0.9.1, git-features v0.19.1, git-actor v0.8.0, git-config v0.1.10, git-object v0.17.0, git-diff v0.13.0, git-tempfile v1.0.4, git-chunk v0.3.0, git-traverse v0.12.0, git-pack v0.16.0, git-odb v0.26.0, git-packetline v0.12.3, git-url v0.3.5, git-transport v0.15.0, git-protocol v0.14.0, git-ref v0.11.0, git-repository v0.14.0, cargo-smart-release v0.8.0, safety bump 4 crates ([`373cbc8`](https://github.com/Byron/gitoxide/commit/373cbc877f7ad60dac682e57c52a7b90f108ebe3)) - - Prepar changelogs for cargo-smart-release release ([`8900d69`](https://github.com/Byron/gitoxide/commit/8900d699226eb0995be70d66249827ce348261df)) - - Highlight (non-fatal) errors when losslessly parsing changelogs ([`51d1c68`](https://github.com/Byron/gitoxide/commit/51d1c686763b4c036ec2c3c15d7c3ebb48e208de)) - - Better not have items within items in changelogs ([`6946125`](https://github.com/Byron/gitoxide/commit/69461254b1bfda5e60911164096e4a061e241296)) - - Upgrade dependencies ([`968df47`](https://github.com/Byron/gitoxide/commit/968df4746729556dcf4f5039b1d1ed1a1da2705a)) - - Minor refactor ([`dae710f`](https://github.com/Byron/gitoxide/commit/dae710f902b8dbdc663cdcd2fb3918d76219ec5f)) - - Upgrade to pulldown-cmark 0.9 ([`11f5fd8`](https://github.com/Byron/gitoxide/commit/11f5fd84a9a080cab4bed81cc073fc632c4d5646)) - - Commit statistics reveal the days passes between releases ([`4843b7b`](https://github.com/Byron/gitoxide/commit/4843b7bdcb1b05e2b99e199e168665be07123846)) - - Upgrade to clap 3.0.0 ([`3325d50`](https://github.com/Byron/gitoxide/commit/3325d5022a43085e93d4c7b65b01b65b36e2f77d)) - - Adapt to changes in git-repository ([`9f63852`](https://github.com/Byron/gitoxide/commit/9f63852a268b3a069fff147cb9011084fc842dca)) - - Release git-chunk v0.2.0, safety bump 4 crates ([`b792fab`](https://github.com/Byron/gitoxide/commit/b792fabf9f5f93ab906ac5a5bb3e4f01c179290a)) - - Upgrade to latest clap rc ([`1b76db0`](https://github.com/Byron/gitoxide/commit/1b76db05e097c4106de3d326079cbff83629589b)) - - Make fmt ([`066f3ff`](https://github.com/Byron/gitoxide/commit/066f3ffb8740f242c1b03e680c3c5c1a0e4c36c3)) - - Thanks clippy ([`7dd2313`](https://github.com/Byron/gitoxide/commit/7dd2313d980fe7c058319ae66d313b3097e3ae5f)) -
- -## 0.7.0 (2021-11-29) - -### Bug Fixes - - - don't mistake prefixed tags for versions - Previously we would be too generous when accepting version tags, now - we accept the prefixes 'v' and 'vers' and no prefix at all. - - don't panic if there is a version requirement without version - - don't claim missing user edits if there are some - -### Commit Statistics - - - - - 7 commits contributed to the release over the course of 3 calendar days. - - 12 days passed between releases. - - 3 commits were understood as [conventional](https://www.conventionalcommits.org). - - 2 unique issues were worked on: [#259](https://github.com/Byron/gitoxide/issues/259), [#262](https://github.com/Byron/gitoxide/issues/262) - -### Commit Details - - - -
view details - - * **[#259](https://github.com/Byron/gitoxide/issues/259)** - - Btree/hashmap free lookup of packs in store, keeping things more bundled ([`a88981b`](https://github.com/Byron/gitoxide/commit/a88981b6f38b86624588f0c8ff200d17f38d0263)) - * **[#262](https://github.com/Byron/gitoxide/issues/262)** - - Don't claim missing user edits if there are some ([`b12b76c`](https://github.com/Byron/gitoxide/commit/b12b76c93db43044d6976ae218c11a8f3f3cd81d)) - - Don't mistake prefixed tags for versions ([`f4421d8`](https://github.com/Byron/gitoxide/commit/f4421d83d022a56e47f534a8c676bcb9cb3d230d)) - - Don't panic if there is a version requirement without version ([`6eae7f1`](https://github.com/Byron/gitoxide/commit/6eae7f1119e2a7928286f233fc397b92274bb0ab)) - * **Uncategorized** - - Release git-actor v0.7.0, git-config v0.1.9, git-object v0.16.0, git-diff v0.12.0, git-traverse v0.11.0, git-pack v0.15.0, git-odb v0.25.0, git-packetline v0.12.2, git-transport v0.14.0, git-protocol v0.13.0, git-ref v0.10.0, git-repository v0.13.0, cargo-smart-release v0.7.0 ([`d3f9227`](https://github.com/Byron/gitoxide/commit/d3f922781a81e8fbb81aa47afdbe9afeb06d666b)) - - Release git-features v0.18.0, git-actor v0.7.0, git-config v0.1.9, git-object v0.16.0, git-diff v0.12.0, git-traverse v0.11.0, git-pack v0.15.0, git-odb v0.25.0, git-packetline v0.12.2, git-transport v0.14.0, git-protocol v0.13.0, git-ref v0.10.0, git-repository v0.13.0, cargo-smart-release v0.7.0, safety bump 12 crates ([`acd3737`](https://github.com/Byron/gitoxide/commit/acd37371dcd92ebac3d1f039224d02f2b4e9fa0b)) - - Merge branch 'pack-consistency' ([`5982406`](https://github.com/Byron/gitoxide/commit/5982406b4e1b26fd383d9ec21a3cf652ec8ab25f)) -
- -## 0.6.0 (2021-11-16) - - - -### Other - - - try to auto-update crates index with lifetime craziness - Even though it could work, it's too complicated. - -### New Features - - - auto-update crates-index if there is an indication - There is the possibility of false-positives triggering such an update - if manifests are edited by hand, which is not the common case. - - If it is, please let us know. - - 'changelog' understands '-e/--execute' as well. - This makes writing changelogs before release easier as the command-line - has to change less. - -### Bug Fixes - - - Don't let dev-dependencies participate in traversal unless they have a version specified. - This prevents safety bumps due to breaking changes in dev dependencies, - which are generally ignored if there is no version specified. - -### Commit Statistics - - - - - 12 commits contributed to the release over the course of 26 calendar days. - - 26 days passed between releases. - - 4 commits were understood as [conventional](https://www.conventionalcommits.org). - - 3 unique issues were worked on: [#228](https://github.com/Byron/gitoxide/issues/228), [#234](https://github.com/Byron/gitoxide/issues/234), [#241](https://github.com/Byron/gitoxide/issues/241) - -### Commit Details - - - -
view details - - * **[#228](https://github.com/Byron/gitoxide/issues/228)** - - 'changelog' understands '-e/--execute' as well. ([`a4a5376`](https://github.com/Byron/gitoxide/commit/a4a53765952729d4ad59d8adcd3ce66c4c71589f)) - * **[#234](https://github.com/Byron/gitoxide/issues/234)** - - Auto-update crates-index if there is an indication ([`aafb055`](https://github.com/Byron/gitoxide/commit/aafb0550222aab97b52c8d716c506709b6720d3f)) - - Revert "FAIL: try to auto-udpate crates index with lifetime crazyness" ([`0df3b8f`](https://github.com/Byron/gitoxide/commit/0df3b8f1da1946c7ad57ba2f4d67fc5a1b9cc0d1)) - - Try to auto-udpate crates index with lifetime crazyness ([`82075e8`](https://github.com/Byron/gitoxide/commit/82075e8a101adb2fda0c11e6567e2148d2e66b8f)) - * **[#241](https://github.com/Byron/gitoxide/issues/241)** - - Improve usability of the pack-cache environment variable ([`47d8162`](https://github.com/Byron/gitoxide/commit/47d81629a0bfa2eccf75cbe081de55d80d0abd59)) - * **Uncategorized** - - Release git-repository v0.12.0, cargo-smart-release v0.6.0 ([`831a777`](https://github.com/Byron/gitoxide/commit/831a777487452a6f51a7bc0a9f9ca34b0fd778ed)) - - Release git-config v0.1.8, git-object v0.15.1, git-diff v0.11.1, git-traverse v0.10.1, git-pack v0.14.0, git-odb v0.24.0, git-packetline v0.12.1, git-transport v0.13.1, git-protocol v0.12.1, git-ref v0.9.1, git-repository v0.12.0, cargo-smart-release v0.6.0 ([`f606fa9`](https://github.com/Byron/gitoxide/commit/f606fa9a0ca338534252df8921cd5e9d3875bf94)) - - Adjusting changelogs prior to release of git-config v0.1.8, git-object v0.15.1, git-diff v0.11.1, git-traverse v0.10.1, git-pack v0.14.0, git-odb v0.24.0, git-packetline v0.12.1, git-transport v0.13.1, git-protocol v0.12.1, git-ref v0.9.1, git-repository v0.12.0, cargo-smart-release v0.6.0, safety bump 5 crates ([`39b40c8`](https://github.com/Byron/gitoxide/commit/39b40c8c3691029cc146b893fa0d8d25d56d0819)) - - Don't let dev-dependencies participate in traversal unless they have a version specified. ([`57a50a6`](https://github.com/Byron/gitoxide/commit/57a50a68313cee4c63b1c32f3dedb2837bb751fc)) - - Note about smart-release being (too) eager to release ([`7954527`](https://github.com/Byron/gitoxide/commit/7954527ecc190b6e91229871c67f3b80d22ada6d)) - - Refactor ([`6a1e74c`](https://github.com/Byron/gitoxide/commit/6a1e74c04a9769a7651bf065917e533f87652620)) - - Write down a few more 'cargo changelog' shortcomings ([`a5f2597`](https://github.com/Byron/gitoxide/commit/a5f2597002ba50255083e7a01a97e63a09766bb3)) -
- -## 0.5.6 (2021-10-20) - -### Bug Fixes - - - nicer previews thanks to added newline - -### Commit Statistics - - - - - 2 commits contributed to the release. - - 1 commit was understood as [conventional](https://www.conventionalcommits.org). - - 1 unique issue was worked on: [#228](https://github.com/Byron/gitoxide/issues/228) - -### Commit Details - - - -
view details - - * **[#228](https://github.com/Byron/gitoxide/issues/228)** - - Nicer previews thanks to added newline ([`ff2c07a`](https://github.com/Byron/gitoxide/commit/ff2c07acea56eeed679dfbe59b5ab1d4baa45d42)) - * **Uncategorized** - - Release cargo-smart-release v0.5.6 ([`0375ba7`](https://github.com/Byron/gitoxide/commit/0375ba7bf324d3a1470dfd5abb46907a7fb795ce)) -
- -## 0.5.5 (2021-10-20) - -The `v` prefix is not enforced anymore and is handled depending on what's already present. - -This helps to handle changelogs with slightly different styles as well. - -### New Features - - - Support for lack of prefixes in version headers. - - These are also inherited so once set by a single versioned release - section, fully generated sections will inherit their prefix from - that one. - -### Bug Fixes - - - Assume manifests cannot necessarily be read by `cargo_toml::Manifest` and fallback. - - This prevents errors to occur in some configurations when no crate is specified on the command-line. - -### Commit Statistics - - - - - 5 commits contributed to the release. - - 2 commits were understood as [conventional](https://www.conventionalcommits.org). - - 1 unique issue was worked on: [#228](https://github.com/Byron/gitoxide/issues/228) - -### Commit Details - - - -
view details - - * **[#228](https://github.com/Byron/gitoxide/issues/228)** - - Update changelog ([`435be34`](https://github.com/Byron/gitoxide/commit/435be349b5164ba52a91b70e90336a3cb2df7f33)) - - Flexible tag parsing allows to find any version tags ([`a1b12e6`](https://github.com/Byron/gitoxide/commit/a1b12e695c08e344becbfcddb6192e34c3cf8ae5)) - - Support for no prefixes in version headers ([`3613a95`](https://github.com/Byron/gitoxide/commit/3613a95d730d0aeef87d9c256f93bd528d4945bb)) - - Assume manifests cannot necessarily be read by `cargo_toml::Manifest` and fallback ([`9d0d1fd`](https://github.com/Byron/gitoxide/commit/9d0d1fd71196b129b229a7d9475fdd6b99e8675b)) - * **Uncategorized** - - Release cargo-smart-release v0.5.5 ([`7df536e`](https://github.com/Byron/gitoxide/commit/7df536ee902a4e9a49daaad4c0f71f4ef05c8acc)) -
- -## v0.5.4 (2021-10-20) - -### Bug Fixes - - - create github release only after tags were created and pushed - -### Commit Statistics - - - - - 2 commits contributed to the release. - - 1 commit was understood as [conventional](https://www.conventionalcommits.org). - - 1 unique issue was worked on: [#227](https://github.com/Byron/gitoxide/issues/227) - -### Commit Details - - - -
view details - - * **[#227](https://github.com/Byron/gitoxide/issues/227)** - - Create github release only after tags were created and pushed ([`77f433e`](https://github.com/Byron/gitoxide/commit/77f433e806e43c8d355b3e176ed740ba4de9777c)) - * **Uncategorized** - - Release cargo-smart-release v0.5.4 ([`447d689`](https://github.com/Byron/gitoxide/commit/447d689776a6eaebf00bbccb5f84e0906876d547)) -
- -## v0.5.3 (2021-10-20) - -### Bug Fixes - - - strip `.git` suffix from repository paths when using it in urls - - remove extra '/' after https://github.com/ based URLs - -### Commit Statistics - - - - - 4 commits contributed to the release. - - 2 commits were understood as [conventional](https://www.conventionalcommits.org). - - 1 unique issue was worked on: [#222](https://github.com/Byron/gitoxide/issues/222) - -### Commit Details - - - -
view details - - * **[#222](https://github.com/Byron/gitoxide/issues/222)** - - Fix smart-release journey test expecations ([`4b638ae`](https://github.com/Byron/gitoxide/commit/4b638ae72d070bb0d362f358f5eaad035db0e2ae)) - * **Uncategorized** - - Release cargo-smart-release v0.5.3 ([`0953239`](https://github.com/Byron/gitoxide/commit/0953239faebccfce05dc7fef3bf07c43340b3e7f)) - - Strip `.git` suffix from repository paths when using it in urls ([`a3aaa3e`](https://github.com/Byron/gitoxide/commit/a3aaa3e0fa38085530bc20443de176306fc8d5d2)) - - Remove extra '/' after https://github.com/ based URLs ([`53ee1a7`](https://github.com/Byron/gitoxide/commit/53ee1a751e5d79aa3e325a5fd3c3a211fc3d06a1)) -
- -## v0.5.2 (2021-10-19) - -Releases will be more atomic and it will try hard to complete all pending operations even in the light -of failure. Now GitHub releases will be created right after a publish succeeded, and tags will be pushed -for all successful publishes. - -### New Features - - - Add `-d` short flag for `--allow-dirty` in `changelog` - -### Bug Fixes - - - Push all available tags even if an error occurred. - - That way, tags don't remain unpushed despite having been created - successfully, just because one crate later in the publishing - process fails. - - Create GitHub release right after publishing succeeds. - - This is more atomic and prevents loosing all github releases if one - publish fails later on. - - `src/` dir of root packages is only used if there is multiple workspace members. - - Otherwise one part of the dependency resolver might have concluded that there are changes, while another part would not have. - The outcome would have been the same, but the messaging around it would have been different unnecessarily. - -### Commit Statistics - - - - - 7 commits contributed to the release. - - 4 commits were understood as [conventional](https://www.conventionalcommits.org). - - 1 unique issue was worked on: [#222](https://github.com/Byron/gitoxide/issues/222) - -### Commit Details - - - -
view details - - * **[#222](https://github.com/Byron/gitoxide/issues/222)** - - Adjust changelog ([`6ce09b7`](https://github.com/Byron/gitoxide/commit/6ce09b7b73c42f8c58f27a2460829d2de387d25a)) - - Add `-d` short flag for `--allow-dirty` in `changelog` ([`db3cb11`](https://github.com/Byron/gitoxide/commit/db3cb11c466fff57f3f272d7269dc95a636e1c1f)) - - Adjust changelog ([`2db6d88`](https://github.com/Byron/gitoxide/commit/2db6d88f390d6577c8660b9da00f94a4a3943ebd)) - - Push all available tags even if an error occurred ([`8c3ca9c`](https://github.com/Byron/gitoxide/commit/8c3ca9cf58c44af627fc9b3c4138891635b1c554)) - - Create GitHub release right after publishing succeeds ([`b769c47`](https://github.com/Byron/gitoxide/commit/b769c47079a16042ef592a0199cb2d0f6afeeb5e)) - - Src/ dir of root packages is only used if there is multiple workspace members ([`ae85700`](https://github.com/Byron/gitoxide/commit/ae8570050a313457bb2fd6659e31f34fd29bc325)) - * **Uncategorized** - - Release cargo-smart-release v0.5.2 ([`69b7142`](https://github.com/Byron/gitoxide/commit/69b714256346f7e459aa70100ac8a261d5403c86)) -
- -## v0.5.1 (2021-10-19) - -This release contains an important bugfix which may have caused panics when the root-package didn't have changes. - -### New Features - - - `changelog` subcommand fails if there is nothing to do - -### Bug Fixes - - - Fix panic due to unexpected internal state. - - When there was no change in the src/ directory of the top-level crate, - the dependency resolution would not be able to auto-bump the version - as no change occurred, but another part would usually detect a change - as it wasn't confined to the top-level src/ directory. - - This could lead to a panic as an invariant wasn't upheld. - - This was fixed by letting both parts agree to use the src/ directory - to determine changes of the top-level directory, and by making panics - impossible while improving the messaging around this state should it - still occur. The latter is rough, probably rare, but usable. - - Correct the reporting of manifest changes. - - Previously even unchanged crates would trigger workspace crates - to be recorded for manifest changes. - - Now only crates that are to receive manifest changes will be triggering - this. - -### Commit Statistics - - - - - 7 commits contributed to the release. - - 3 commits were understood as [conventional](https://www.conventionalcommits.org). - - 1 unique issue was worked on: [#222](https://github.com/Byron/gitoxide/issues/222) - -### Commit Details - - - -
view details - - * **[#222](https://github.com/Byron/gitoxide/issues/222)** - - Adjust changelog for release, now definitely ([`7133f5d`](https://github.com/Byron/gitoxide/commit/7133f5d7738e70b7bdf9ce033f3f9a0485dc844f)) - - Correct reporting of manifest changes ([`6ee4f5d`](https://github.com/Byron/gitoxide/commit/6ee4f5d20c832a54ca5d841773d93f0927a16f25)) - - Adjust changelog for smart-release release ([`210b09a`](https://github.com/Byron/gitoxide/commit/210b09ae63be853fb233547e8173e7176ca9a4d0)) - - `changelog` subcommand fails if there is nothing to do ([`ed8abfd`](https://github.com/Byron/gitoxide/commit/ed8abfdac40f5c8b17981b8a990572f6f07c8862)) - - Panic due to unexpected internal state ([`ce68733`](https://github.com/Byron/gitoxide/commit/ce68733379a8ab4644c849ba1571bc7063962c64)) - - Crude fix to avoid version related invariants to kick in during dependency resolution ([`3cdebf5`](https://github.com/Byron/gitoxide/commit/3cdebf5c34845ecef195ce762e344dbff7c1b035)) - * **Uncategorized** - - Release cargo-smart-release v0.5.1 ([`31a1481`](https://github.com/Byron/gitoxide/commit/31a148153c4c9faa320de60af2a55cfb2131c797)) -
- -## v0.5.0 (2021-10-19) - - - - -A release with breaking changes as the dependency engine was reworked to handle even more cases -and make future improvements easier. - -### Other - - - try to assure that breaking changes are always published in correct order - The problem here is that even though we can turn non-publishable breaks - into publishable ones without loosing information, they will not be in - the correct order. - - The solution is to merge dependency trees instead of clearing them with - weird logic. - -### New Features - - - Respect `publish=false` in cargo manifest - - Perform safety bumps without forcing a publish. - - This is what's required to assure that future publishes of such - transitively dependent crates won't cause downstream breakage the next time the tool is run. - - Inform about safety bumps more explicitly, - and generally greatly improve the way the course of action is described. - -### Bug Fixes - - - Dependency resolution. - - Previously the ordering of crates for release might not have been - correct due to this issue that is now fixed. - - We need depth-first traversals and previously it would extend skipped - dependencies, effectively putting them into their own ordering. - - Previously it would restore that ordering, but not anymore, causing - this bug that was entirely unnecessary. - - `--no-changelog` during smart-release is now actually working - - Previously the flag had no effect and changelogs would always be - generated, possibly stopping the release as at least one of them - needed manual work. - - Pin version of clap to beta 5. - - This assures we don't get broken automatically in future. - Previously that wasn't possible as the dependency of `clap`, - `clap-derive` was also using a beta version and wasn't constrained, - hence it would be updated and cause breaking changes with pinned - versions of consumers of `clap`. - - ! breaking changes cause intermediate (otherwise skipped) crates to be published. - This assures that about-to-be-released crates that have breaking changes - anywhere in their dependency graph will cause all crates leading up to, - and including, a breaking change to be published as well. - -### Changed (BREAKING) - - - - - `changelog` subcommand inverts `--dependencies` to `--no-dependencies` - - Remove `--no-multi-crate-release` support entirely - - As the default is to do multi-crate releases and now having to deal - with single-create releases reduces maintenance burden. - - The solution to this problem is to not specify version constraints in - dev-dependencies to workspace crates. - - We also don't check for this anymore, which might be re-added - at some point if there is demand.This makes dependency resolution similar to cargo smart-release by default and is less surprising. - -### Commit Statistics - - - - - 82 commits contributed to the release over the course of 3 calendar days. - - 3 days passed between releases. - - 11 commits were understood as [conventional](https://www.conventionalcommits.org). - - 4 unique issues were worked on: [#198](https://github.com/Byron/gitoxide/issues/198), [#221](https://github.com/Byron/gitoxide/issues/221), [#222](https://github.com/Byron/gitoxide/issues/222), [#224](https://github.com/Byron/gitoxide/issues/224) - -### Thanks Clippy - - - -[Clippy](https://github.com/rust-lang/rust-clippy) helped 3 times to make code idiomatic. - -### Commit Details - - - -
view details - - * **[#198](https://github.com/Byron/gitoxide/issues/198)** - - Add yet another video ([`dc8f7ca`](https://github.com/Byron/gitoxide/commit/dc8f7ca20424e31ef5621cab2cc802f2d2b1686a)) - - Update Asciinema link in readme ([`b56a31e`](https://github.com/Byron/gitoxide/commit/b56a31e69c625ca41c923c14e411da9ee71428e7)) - * **[#221](https://github.com/Byron/gitoxide/issues/221)** - - Add tests which indicate the problem: safety-bump not applied to auto-publishes… ([`32e1f1a`](https://github.com/Byron/gitoxide/commit/32e1f1aa1d97b061e07878ae94f23ec99f56d64d)) - - --no-changelog-preview isn't needed anymore in dry-run mode ([`1b6a4ad`](https://github.com/Byron/gitoxide/commit/1b6a4adecbb884ad973d5b1e2cbc420b163ad390)) - - Refactor ([`aff053f`](https://github.com/Byron/gitoxide/commit/aff053f0e2b1e3f5920d3db5a44292a0dc3ac708)) - - Inform about safety bumps more explicitly ([`b806a9c`](https://github.com/Byron/gitoxide/commit/b806a9c982da1e5ff42c268e430c67363f3a7918)) - - Refactor ([`23073e8`](https://github.com/Byron/gitoxide/commit/23073e88c8d083d064cd5b79800c063a9fdc949f)) - * **[#222](https://github.com/Byron/gitoxide/issues/222)** - - Refactor ([`72bda30`](https://github.com/Byron/gitoxide/commit/72bda306c00642571cd22d909775b4b7cc2c85b6)) - - Refactor ([`c8c0dcd`](https://github.com/Byron/gitoxide/commit/c8c0dcd167556e7c45baf8eff34e4aeff8e28379)) - - Refactor ([`f7a8847`](https://github.com/Byron/gitoxide/commit/f7a8847c8afb5504cf9bfd779a6a99f7c996e05d)) - - Fix merging of dependency graphs for multiple crates ([`d332cdf`](https://github.com/Byron/gitoxide/commit/d332cdf9532add5e34c1ade16d4b775ba56171e5)) - - Revert "FAIL: try to assure that breaking changes are always published in correct order" ([`f25e7c7`](https://github.com/Byron/gitoxide/commit/f25e7c706d340c02d851ce2b5fe06ef43a0ce95c)) - - Try to assure that breaking changes are always published in correct order ([`3519f9a`](https://github.com/Byron/gitoxide/commit/3519f9a1f4002232aec752dadf7d3737bd97ce3d)) - - Update changelogs prior to release ([`9a493d0`](https://github.com/Byron/gitoxide/commit/9a493d0651b0b6d71cf230dc510a658be7f8cb19)) - - Respect user selection when re-adding crates for manifest change ([`72d16bf`](https://github.com/Byron/gitoxide/commit/72d16bf935bccf0faff9274156ce399a72540e73)) - - Dependency resolution ([`501c1d1`](https://github.com/Byron/gitoxide/commit/501c1d102c0e5e4635120bb1aa857e97a2b537b4)) - - --no-changelog during smart-release is now actually working ([`5e98e55`](https://github.com/Byron/gitoxide/commit/5e98e5559707cf308e2cd64494fe73a99f9e9c8e)) - - Replace TODO with runtime logging ([`f457e65`](https://github.com/Byron/gitoxide/commit/f457e659623ea2e14ca6ab0678b22329ef7a7763)) - - Unify presentation even more ([`7c32409`](https://github.com/Byron/gitoxide/commit/7c32409e49b21a6b0e3017357e0fe1755faaa467)) - - Adjust expectations in smart-release journey tests ([`1f96a72`](https://github.com/Byron/gitoxide/commit/1f96a7215b78bfeb56074b1894bb6bbc8b598011)) - - Group skipped items by skipped reason ([`ba28746`](https://github.com/Byron/gitoxide/commit/ba287464731bb15785930183290cecdd9694e458)) - - Unify reporting style ([`99be2e1`](https://github.com/Byron/gitoxide/commit/99be2e16cba34a613d41fd2e46cf3576a511ee1c)) - - Fix reporting of skipped crates, consider adjustment ([`ac91016`](https://github.com/Byron/gitoxide/commit/ac91016841348476f1c1f32c2d1121359986e9f6)) - - Abort if not a single provided crate would need publishing ([`478c4ea`](https://github.com/Byron/gitoxide/commit/478c4eaa3ff60f0c83933581a3d0170429a95381)) - - Improved reporting of skipped/refused crates; abort operation if there is nothing to publish ([`f9358f1`](https://github.com/Byron/gitoxide/commit/f9358f124726d69dc11e6103d649c5cab30c738b)) - - Better reporting of crates that where refused to be published ([`1d7142a`](https://github.com/Byron/gitoxide/commit/1d7142a861636f088694500855a1f7acbcdbeded)) - - 'changelog' subcommand change --dependencies to --no-dependencies ([`59302ae`](https://github.com/Byron/gitoxide/commit/59302ae24db791988c22322c2c1ad72e2918f89a)) - - Properly resolve breaking propagation through the graph ([`4f25236`](https://github.com/Byron/gitoxide/commit/4f252365147aae2f8a9f12a0ae6087adc0ed4644)) - - Multi-round discovery of breaking changes from published packages ([`dc93e1a`](https://github.com/Byron/gitoxide/commit/dc93e1a828c6cd97fcb64aa92293cb8f3899316a)) - - Verify and partially fix journey tests ([`e53a7f6`](https://github.com/Byron/gitoxide/commit/e53a7f6b4d67da52ac7fee7706dfd067b67e0275)) - - Remove all now unused items ([`40f2da2`](https://github.com/Byron/gitoxide/commit/40f2da20395213b48d4a8517cf2b63513f901e93)) - - Use Dependency in manifest editor ([`d5c905a`](https://github.com/Byron/gitoxide/commit/d5c905ab4132626eb1af2a8e5410440f8fdc7a8f)) - - Upgrade to clap 3 beta 5 ([`2ddc4ed`](https://github.com/Byron/gitoxide/commit/2ddc4eddda23c77b5891a11a3e7215702c63882b)) - - Show only changelogs that would be published ([`e20f498`](https://github.com/Byron/gitoxide/commit/e20f498b0d07d39a47b36a454c384068404119ad)) - - Refactor ([`244431f`](https://github.com/Byron/gitoxide/commit/244431fbb12de811feb8f53e0faaeb9d683aa834)) - - Fix reporting of skipped crates ([`a305232`](https://github.com/Byron/gitoxide/commit/a305232bc1f027d65ef3d7dc7898931745cf652c)) - - Respect publish=false in cargo manifest ([`6d4edfa`](https://github.com/Byron/gitoxide/commit/6d4edfa3b2d2c6700e0956716a575831b940cb50)) - - More consistent reporting of what would be done ([`47ce4b0`](https://github.com/Byron/gitoxide/commit/47ce4b0a6a6545be6cd8b3928289478694a2f764)) - - Refactor ([`369fa93`](https://github.com/Byron/gitoxide/commit/369fa93a16ed9af3ea0b70c08c8426759bdc7d11)) - - Don't try to change crates that are already at the correct version ([`561aac3`](https://github.com/Byron/gitoxide/commit/561aac30a709974fb48fc02cb5d21828d7df1e54)) - - Keep ordering of causes for breaking changes when printing ([`f4a0970`](https://github.com/Byron/gitoxide/commit/f4a0970ba0d0a4175972c6f231eceba1ff1c33fb)) - - Better safety bumps to be more concise ([`7c8335a`](https://github.com/Byron/gitoxide/commit/7c8335a5f0b0168997f8a08d4da942e9d60e71d4)) - - Perform safety bumps without forcing a publish ([`7648bf3`](https://github.com/Byron/gitoxide/commit/7648bf3c7554352bec8e1355f9b593d891b2b17f)) - - Refactor ([`ebec001`](https://github.com/Byron/gitoxide/commit/ebec001a2ca6f1faa17f27847ea274146506e9ce)) - - Inform about the crates seeing a mnifest update too; only show fully-skipped crates ([`7f2a927`](https://github.com/Byron/gitoxide/commit/7f2a927eb0d880c58f5b9eed59e3a9640adf5c95)) - - ! breaking changes cause intermediate (otherwise skipped) crates to be published. ([`fb6b909`](https://github.com/Byron/gitoxide/commit/fb6b909e49d8428e53da6e2ce3c2f878025e00f7)) - - Reverse-bumping for safety works, including publishing :) ([`5e1713c`](https://github.com/Byron/gitoxide/commit/5e1713c4bf0772d23678a28ff281cc36a77b5991)) - - Track root-cause as well ([`7f8e720`](https://github.com/Byron/gitoxide/commit/7f8e720283416d101c0bbea545bbd504cc3f7204)) - - Sketch backwards search for lifting crates to be published ([`0b018c0`](https://github.com/Byron/gitoxide/commit/0b018c0decf2d45eb58a5eaf3704d62c46b0a72c)) - - Realize that the search can't be 'flat' ([`13db698`](https://github.com/Byron/gitoxide/commit/13db6985159d24c3e6806a70120f17c81999803b)) - - Start sketching backward traversal… ([`de1d7f7`](https://github.com/Byron/gitoxide/commit/de1d7f7242ddc6d357dc165532f1336a239b472b)) - - Sumarize manifest updates rather than spelling out each one ([`8cf00e0`](https://github.com/Byron/gitoxide/commit/8cf00e06f1017fff1c328afe4a97428d56c1cca6)) - - Update test expectations and formulate 'the algorithm' ([`c0693ae`](https://github.com/Byron/gitoxide/commit/c0693aebb3bc4306124be7287a54c1c1f1a31a65)) - - Refactor ([`0bfb1b1`](https://github.com/Byron/gitoxide/commit/0bfb1b17ff7fc25aed1ad108fa407b56f35c7274)) - - Assure changelog picks up safety bumps as well ([`f2a497b`](https://github.com/Byron/gitoxide/commit/f2a497b3eebecd0ca94801ac656d4fc2852505f2)) - - Collect crates for manifest updates ([`56ccdd2`](https://github.com/Byron/gitoxide/commit/56ccdd2195802a920fa084f85eae797e2cf17da7)) - - Remove --no-multi-crate-release support entirely ([`07372dd`](https://github.com/Byron/gitoxide/commit/07372dd045de88f283d35d8f3dcc4c079dce88e9)) - - Remove performance measurements ([`37bacee`](https://github.com/Byron/gitoxide/commit/37bacee619fadf9dc1ff645a85c4e340cb84a569)) - - Refactor ([`ac85cdf`](https://github.com/Byron/gitoxide/commit/ac85cdfccd0545b7da6276f0df086b32a7a9dfc0)) - - No newlines in gh traces ([`afd9b9e`](https://github.com/Byron/gitoxide/commit/afd9b9ebffa5db09b0ed69b29c878ccfd156a528)) - - Refactor ([`03c7dba`](https://github.com/Byron/gitoxide/commit/03c7dbabff14bd5dd150bd5174f53148d4ee0fec)) - - Simplify use of 'verbose' flag by using log::trace! as well ([`4dc5f4b`](https://github.com/Byron/gitoxide/commit/4dc5f4b5e54a35f2794bb61ebc4c00758447bf75)) - - Refactor ([`e256949`](https://github.com/Byron/gitoxide/commit/e256949f4a679ff74bece435b302490998f1cc6e)) - - Refactor ([`e4ffa71`](https://github.com/Byron/gitoxide/commit/e4ffa71161d949cd134bc5289963ed7533607def)) - - Try to represent safety-bump versions ([`9f3001f`](https://github.com/Byron/gitoxide/commit/9f3001f3300b5ceb350b157f541a30bf54a51549)) - - Refactor ([`6f84e0b`](https://github.com/Byron/gitoxide/commit/6f84e0b6e7da2fce4ef7c4f43a6c5a67f4930e0d)) - - Simple version bumping logic based on what currently exists, with printout ([`81e5785`](https://github.com/Byron/gitoxide/commit/81e5785fca30c6cb71c962132ddcd573ba950d72)) - - Fully data-driven presentation of dependency tracking results… ([`fd53e22`](https://github.com/Byron/gitoxide/commit/fd53e22a2f975010fd4ca6a95513339bc1102740)) - - Refactor ([`51a5d36`](https://github.com/Byron/gitoxide/commit/51a5d365f71bf44ab60ece4511d8dce1a77f5442)) - - Refactor ([`b8a5fc8`](https://github.com/Byron/gitoxide/commit/b8a5fc8bbe1dc58813c8c86cf0ad0dcdd5bff8ad)) - - Refactor ([`10aa1eb`](https://github.com/Byron/gitoxide/commit/10aa1eb344fdc42528717f240b2446be60da360b)) - - Refactor ([`cfec54d`](https://github.com/Byron/gitoxide/commit/cfec54d02d7df8fbc1c7cec5459ea267e7f3f236)) - - Remove `--only` alias and invert `--no-dependencies` to `--dependencies` ([`2f87196`](https://github.com/Byron/gitoxide/commit/2f87196217a6e685dc447b4af091842926aed6d0)) - - Keep track of skipped crate names for future use ([`f0a04c7`](https://github.com/Byron/gitoxide/commit/f0a04c7148729bf9c322692610c501b78c9557a9)) - * **[#224](https://github.com/Byron/gitoxide/issues/224)** - - Pin version of clap to beta 5 ([`dfc588b`](https://github.com/Byron/gitoxide/commit/dfc588b25ede3faa578eb8e131e73c857117a6df)) - * **Uncategorized** - - Release cargo-smart-release v0.5.0 ([`c03e8cb`](https://github.com/Byron/gitoxide/commit/c03e8cb31d61401450564bef9cd18d6638c681b7)) - - Changelog update ([`7fcd02e`](https://github.com/Byron/gitoxide/commit/7fcd02e3baf49bc498a702ed87511d42f2e71f05)) - - Adjusting changelogs prior to release of cargo-smart-release v0.5.0 ([`11f55d3`](https://github.com/Byron/gitoxide/commit/11f55d36b2db19dc9e43c7fbed5d3fb4a8cdc9e1)) - - Release git-hash v0.8.0, git-features v0.17.0, git-actor v0.6.0, git-object v0.15.0, git-diff v0.11.0, git-traverse v0.10.0, git-pack v0.13.0, git-odb v0.23.0, git-packetline v0.12.0, git-transport v0.13.0, git-protocol v0.12.0, git-ref v0.9.0, git-repository v0.11.0, git-commitgraph v0.6.0, gitoxide-core v0.12.0, gitoxide v0.10.0, cargo-smart-release v0.5.0, safety bump 16 crates ([`0e02953`](https://github.com/Byron/gitoxide/commit/0e029537a7f6242d02ccf7e63d8d92f5246e6c5e)) - - Thanks clippy ([`7496ba3`](https://github.com/Byron/gitoxide/commit/7496ba38ef815d4f4cb6b78bdead5226fb48f2b6)) - - Thanks clippy ([`b717323`](https://github.com/Byron/gitoxide/commit/b7173235ef4b118d96a0989f671424e06910ef46)) - - Thanks clippy ([`c4efd9d`](https://github.com/Byron/gitoxide/commit/c4efd9dc1be51049b38c0dd2a3263437ca51fee0)) -
- -## v0.4.0 (2021-10-15) - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -This major release adds **changelog** support to automatically generate scaffolding to be filled in by hand. The feature is driven by -[conventional commit](https://www.conventionalcommits.org) messages which are used sparingly to mark important changes only. -Furthermore, it will deduce the require version bump, i.e. patch, minor or major, automatically by looking at the commit history -and interpreting _'conventional commit'_ messages. This means that from time to time one would sprinkle in a specifically formatted -commit message to leave enough information to determine the correct release version and create changelog scaffolding. - -If you have 10 minutes, the following video gives the whirlwind tour through the new features (_and note that all issues discovered there -have been fixed :)_). - -[![12 minute introduction video](https://img.youtube.com/vi/EOft_uMDVYE/0.jpg)](https://www.youtube.com/watch?v=EOft_uMDVYE) - -If you have 30 minutes, there is also [a long version of the video](https://youtu.be/a4CzzxJ7ecE). - -And there is another one showing `cargo smart-release` releasing `gitoxide 0.9.0`, along with some explanation on how it works. - -[![8 minute video releasing gitoxide](https://img.youtube.com/vi/ZS9fwPDYLpI/0.jpg)](https://www.youtube.com/watch?v=ZS9fwPDYLpI) - -### Refactor - - - split data::output::count::objects into files - -### Other - - - :remote_url() is now optional - Otherwise it wouldn't work on repos that don't have a remote set yet. - Instead of failing, we don't create links. - - assure the current package version is actually breaking - - better verbosity handling when comparing to crates-index - - turn off safety bump with its own flag - - improved safety bump log message - - commit message reveals safety bumps - - released crates only receive minor bumps… - …which signals a change while allowing dependents to pin themselves to - patch updates only. - - This would be users of "unstable" git-repository features for example. - which then also don't want to see new minor versions automatically - as it may cause breakage. - - update changelog - - way more tests to nail current log output - This is the basis for adjusting the output verbosity or information - where it matters. - - dependency upgrade works - - calculate new version of dependent - - don't claim "conservative" updates for major version change - - assure we can find non-sequential connections - - all logic to calculate dependent version bumps - - an algorithm to collect dependencies by 'growing' - - foundation for bumping versions - The idea is that the dependency traversal may also produce a new version - number, which is when it will naturally be set for all dependents later. - - - - add git-conventional - - consider nom for custom parsing, but… - …realize that the easiest way is definitely the excellent - git-conventional crate. - - This also means we have to stop specifying crates in commit messages - or find another way to do that. - - refactor - - refactor - - refactor - - a seemingly slow version of path lookup, but… - …in debug mode it's faster than the fast path, despite doing more - and being the same when it comes to searching path components. - - fast filter by single-component path - - prepare for fast lookup of paths - - configure caches with env vars using `apply_environment()` - - refactor - - set package cache via RepositoryAccessExt - - object-cache to allow for a speed boost… - …by avoiding duplicate accesses to hit the object database. - However, the cost for the cache are relatively high and involve some - memory copying, so hit rates of about 50% is certainly what is needed - to get any speed boost at all. - - actually build the segment vec, without pruning for now - - build commit history for later use in changelog generation - - sketch history acquisition - - add 'Head::peeled()' method - - some performance logging - - build ref lookup table - - loose reference iteration with non-dir prefixes… - Previously it was expected for the prefix `Path` to always exist for - the prefix to be valid. This, however, is not similar to packed - prefixes, which allow non-dir prefixes as well. - - Now we will check if the prefix is actually a directory, and if not - split it into its parent directory and the filename portion. The latter - is then used for prefix matching file names within that directory. - - Add 'references().all().peeled().'… - …to not only make typical usage of iterated references more convenient - but also work around a double-borrow error one would see otherwise. - - filter refs correctly, but… - …it needs a way to peel references right away without trying - to double-borrow. This means the Iterator needs to implement this. - - find tag references by name… - …even though it's clear that loose refs won't be found with prefixes - that aren't directories, but contain a partial file. - - This is more like a bug to be fixed, as that works naturally for - packed-refs for instance. - - improve changelog format - - sketch first step of info generation - - changelog gets crates to work on - - handle unborn heads - - fmt - - refactor - - refactor - - refactor - - initial test for changelog - Which doesn't test that much. - - very basic support for changelog command… - …which shows that it probably just wants to be separate for now before - being integrated? - - add 'cargo changelog' sub-command binary - - add changelog to most tests - -### Changelog Support in `cargo smart-release` - -When using `cargo smart-release` in dry-run mode (_default_), additional information regarding changelog will be printed. -This informs you a release would be attempted, or if manual adjustments to the changelogs would be required, for example as -they are fully generated with statistical information only. - -If there is no issue with the initial changelogs, passing the `--execute` flag will write the changelogs after -providing them to you for preview (using `bat`) for a last chance to abort the operation. Otherwise the publishing -will proceed, which includes the creation of tag objects containing the relevant section of the changelog, along with -a GitHub release which is annotated with the same section (_only if the repository is hosted on GitHub_). - -If there are issues to be corrected, there will be suggestions to run `cargo changelog --write --only ` -one by one, or the release operation will have left a single commit with all changelogs written out. -In any case, it's recommended to re-write the changelog after editing to assure it is indeed stable and won't change each time -the generator is run. - -For more information, run `cargo smart-release -h`. - -### The `cargo changelog` Sub-Command - -This new sub-command sports the same dependency resolution as `smart-release` itself, operates in dry-run mode by default -to preview changelogs that would be written. Use the `--write` flag to actually write changes to disk. - -It's primary use is to conveniently generate changelogs from time to time to add the final polish by hand before -actually releasing them along with the crate with `smart-release`. - -For more information, run `cargo changelog -h`. - -### Other BREAKING Changes - -- renamed `--skip-*` flags to `--no-*` for consistency -- rename `--skip-dependencies` to `--no-dependencies` to be more inline with existing terminology of other flags. -- rename short name for `--execute` to `-e` from `-n` for consistency - -### Other Changes - - - `--no-dependencies` now has `--only` as alias - -### Bug Fixes - - - Previously it might have been possible to see that it won't use a 'new' crate version as it's already in the manifest, _even_ if these are the same. This is now fixed. - -### Commit Statistics - - - - - 282 commits contributed to the release over the course of 36 calendar days. - - 38 days passed between releases. - - 63 commits were understood as [conventional](https://www.conventionalcommits.org). - - 6 unique issues were worked on: [#192](https://github.com/Byron/gitoxide/issues/192), [#197](https://github.com/Byron/gitoxide/issues/197), [#198](https://github.com/Byron/gitoxide/issues/198), [#200](https://github.com/Byron/gitoxide/issues/200), [#213](https://github.com/Byron/gitoxide/issues/213), [#67](https://github.com/Byron/gitoxide/issues/67) - -### Thanks Clippy - - - -[Clippy](https://github.com/rust-lang/rust-clippy) helped 27 times to make code idiomatic. - -### Commit Details - - - -
view details - - * **[#192](https://github.com/Byron/gitoxide/issues/192)** - - Assure the current package version is actually breaking ([`fb750b6`](https://github.com/Byron/gitoxide/commit/fb750b65ca64c894ffb79cd0049f10a8db255ab6)) - - Better verbosity handling when comparing to crates-index ([`f6f2d1b`](https://github.com/Byron/gitoxide/commit/f6f2d1b2c1c50d36ee046ed58ffffed0444cd25a)) - - Turn off safety bump with its own flag ([`a040f7d`](https://github.com/Byron/gitoxide/commit/a040f7d882eb5f6db0d54ba7e32437da3579a075)) - - ([`443f000`](https://github.com/Byron/gitoxide/commit/443f000015de2117eae08fedf7d23f0d1ac6abff)) - * **[#197](https://github.com/Byron/gitoxide/issues/197)** - - Improved safety bump log message ([`9b78c34`](https://github.com/Byron/gitoxide/commit/9b78c344ee287c4c2908ccbe64bd64c2c9648459)) - - Commit message reveals safety bumps ([`b1a3904`](https://github.com/Byron/gitoxide/commit/b1a39046056bf4a862cebe69f44f3ea1e53a2069)) - - Released crates only receive minor bumps… ([`ecf38b8`](https://github.com/Byron/gitoxide/commit/ecf38b8c013e46a33aa0b2c1b4e9cf547c8393c4)) - - Update changelog ([`342b443`](https://github.com/Byron/gitoxide/commit/342b443a4f49736a10c2b311d69841dbf581ceec)) - - Way more tests to nail current log output ([`0d30094`](https://github.com/Byron/gitoxide/commit/0d30094f4d397f932288f8c04ffd01f956113dc8)) - - Dependency upgrade works ([`a56bd7b`](https://github.com/Byron/gitoxide/commit/a56bd7b134d315e22e5c8d01ca2d927de75955a9)) - - Calculate new version of dependent ([`c50704a`](https://github.com/Byron/gitoxide/commit/c50704a0595884c3fb20629aba0f22bf99893cbf)) - - Don't claim "conservative" updates for major version change ([`681d743`](https://github.com/Byron/gitoxide/commit/681d743e5579197d7262c40237dda0116fc4af1c)) - - Assure we can find non-sequential connections ([`798b650`](https://github.com/Byron/gitoxide/commit/798b650ad848001b10018087ed6c5d8a4055ece8)) - - All logic to calculate dependent version bumps ([`7ca029c`](https://github.com/Byron/gitoxide/commit/7ca029c73eee51302d6828c6f9e8862d3fd4fbd4)) - - An algorithm to collect dependencies by 'growing' ([`73794a4`](https://github.com/Byron/gitoxide/commit/73794a4e382404cb7b684c9054278fb4ff8a84ce)) - - Foundation for bumping versions ([`d1145d1`](https://github.com/Byron/gitoxide/commit/d1145d1a6219ddafa7a41c82d6149b289f033640)) - * **[#198](https://github.com/Byron/gitoxide/issues/198)** - - Polish README a little more ([`455c45d`](https://github.com/Byron/gitoxide/commit/455c45d9a534805cf9659b9c33c3995673e8709f)) - - First version of updated README ([`45dcc68`](https://github.com/Byron/gitoxide/commit/45dcc684e16017cb0289cff209fd1d436fa50c2c)) - - Finish changelog ([`e341b22`](https://github.com/Byron/gitoxide/commit/e341b221086cb75a24053da61ed90aed166538cd)) - - Enforce an empty line after user sections ([`79f0093`](https://github.com/Byron/gitoxide/commit/79f00933f4bbf24551fc093e33e8d94ff8365eb6)) - - Respect release-level removed-id list even when inserting sections ([`2970fff`](https://github.com/Byron/gitoxide/commit/2970fffc681657d0ab393b4c20d9be20675d808d)) - - Rename short name for `--execute` to `-e` from `-n` for consistency ([`19fc134`](https://github.com/Byron/gitoxide/commit/19fc134d2a34f2ea84b2cc8fbd15ca55c55df35e)) - - `--no-dependencies` now has `--only` as alias ([`e668bf2`](https://github.com/Byron/gitoxide/commit/e668bf23ddba9a676a885f1f401d2d2885784eef)) - - Write more of the smart-release changelog to learn --no-dependencies needs an alias ([`65468c8`](https://github.com/Byron/gitoxide/commit/65468c88c241914847a91a563663c60b8931ef9f)) - - Show how many more changelogs are going to be previewed… ([`94a6788`](https://github.com/Byron/gitoxide/commit/94a678843edb7b0da98f2227745900f5c89b9b56)) - - Start writing the 0.4 changelog ([`5f18bc9`](https://github.com/Byron/gitoxide/commit/5f18bc96147a48226be957de2c996f14ba55f1bc)) - - Only use src/ directory for top-level crate change tracking… ([`f26b581`](https://github.com/Byron/gitoxide/commit/f26b58143491300c3375a815f3ffaa1a7ea2bcea)) - - Refactor ([`78c4ad5`](https://github.com/Byron/gitoxide/commit/78c4ad5d05a9bd02131238be4d503080cade8924)) - - Don't show previews in dry-run mode; provide help on how to fix this before release ([`cdb8db4`](https://github.com/Byron/gitoxide/commit/cdb8db412fad2063f78f0e4c677a3bb429c0fd76)) - - Fix naughty issue that isn't even reproducible… ([`95cb79c`](https://github.com/Byron/gitoxide/commit/95cb79cc7927c886080c0e7fef540e173eb51c3e)) - - Correctly parse back single-word conventional messages ([`bfa0777`](https://github.com/Byron/gitoxide/commit/bfa0777719303e732c8a3314f1652bc3a33f6bc0)) - - Fix logic to determine if breaking changes are already handled by package version ([`cb06e9d`](https://github.com/Byron/gitoxide/commit/cb06e9d74b2afd648ec81b1b279a2a416253579d)) - - Greatly simplify dry-run preview for clear visuals ([`2990028`](https://github.com/Byron/gitoxide/commit/2990028a7812790654293d0958713391018e15d3)) - - Update expectations for log messages ([`494e8e5`](https://github.com/Byron/gitoxide/commit/494e8e51210bb5b392b507c6826953bae34d9f31)) - - Use correct title for github release to match name of tag ([`90f39ad`](https://github.com/Byron/gitoxide/commit/90f39ad693e0998bc3307bf553fccdc37c8dc0c8)) - - Fix logic to determine if links should be used… ([`dcc5c1c`](https://github.com/Byron/gitoxide/commit/dcc5c1c7d8a635869da73b58dd579636f69e06ff)) - - Fix logic to determine if there are conventional headlines to fix - ignore non-breaking ([`f80b7fc`](https://github.com/Byron/gitoxide/commit/f80b7fc9ac7d85c52376d539f21ba9ecbe06d560)) - - Fix commit subject line when release would stop due changelog ([`2cdc852`](https://github.com/Byron/gitoxide/commit/2cdc85223b30c93e73fb73f2f14c9961140d4d02)) - - Fix github release invocation ([`6f0fdbf`](https://github.com/Byron/gitoxide/commit/6f0fdbfaf8bae53bd75adeac81d17bc124468bb0)) - - Less surprising location of the 'prepare release' message ([`0dd739b`](https://github.com/Byron/gitoxide/commit/0dd739b58b04e74090bbc2917c610498e788e5fb)) - - Much better preview titles ([`b70f815`](https://github.com/Byron/gitoxide/commit/b70f81540ed69386f50e8876bd0913764b85c7ac)) - - Use --file-name flag to shorten displayed path ([`6e6dcda`](https://github.com/Byron/gitoxide/commit/6e6dcda283dc56bd2c0d4342da1c2cb222cc05ce)) - - Fix crate name and version for --version flag ([`4cc0213`](https://github.com/Byron/gitoxide/commit/4cc0213ac728e1c27a1d7c9a4167645e8bd8ebe7)) - - Clap second pass with arg headlines and better help messages ([`624076f`](https://github.com/Byron/gitoxide/commit/624076f4de0e0ad3483a5c0dec8a49c6d4210f43)) - - First pass of using clap instead of argh ([`836837c`](https://github.com/Byron/gitoxide/commit/836837c53337c1c5f52804e33bfae93dab5f0bd3)) - - Use fmt::Display instead of io::Write when creating markdown docs… ([`fb946b6`](https://github.com/Byron/gitoxide/commit/fb946b6d879e54244886079b3158456d611bec65)) - - Even cleaner release text, just with detail tags… ([`52a6cc8`](https://github.com/Byron/gitoxide/commit/52a6cc81e3152b1805ecc3422fc479c300d8dc05)) - - Less verbose gh tool logging in dry-run mode ([`75ebf0b`](https://github.com/Byron/gitoxide/commit/75ebf0bb35ee5757497964a0736dd3769bb34026)) - - Try to do github releases for multi-crate releases, too ([`552ae4f`](https://github.com/Byron/gitoxide/commit/552ae4f4e1aff192c767fe8ba4ad83b159c8ae63)) - - Improve commit message titles and simplify tag-name logic ([`4aa68bd`](https://github.com/Byron/gitoxide/commit/4aa68bdeac7f863a5e7ee9c833a1aa691bf13f4c)) - - Refactor ([`a6d3bb1`](https://github.com/Byron/gitoxide/commit/a6d3bb168096f1174e45a4bc544429c045859aa2)) - - First sketch of running gh tool to create releases ([`bf7f020`](https://github.com/Byron/gitoxide/commit/bf7f02075b664ab6477fbe7e791b23c90a9ef7e8)) - - Support for ssh->https github urls; more robustness in general ([`ab7ea71`](https://github.com/Byron/gitoxide/commit/ab7ea7170f987991952da0c1c062513062f0891f)) - - Add flag to allow disabling github releases ([`5f6c4de`](https://github.com/Byron/gitoxide/commit/5f6c4de7b09250d24f447571c47c80e1b8afabe7)) - - Sketch incorporation of github CLI support ([`5aa6ef9`](https://github.com/Byron/gitoxide/commit/5aa6ef9483498a18ee5aa548b7c29df7f228d3fb)) - - :remote_url() is now optional ([`e16603b`](https://github.com/Byron/gitoxide/commit/e16603b15b5488b81563c583cd8f5292ab9d24a2)) - - Inform about the difference between tag objects and references in verbose logs ([`98a9f10`](https://github.com/Byron/gitoxide/commit/98a9f10fa0a544ea27f9dd98eeb008470f1616df)) - - Rename `ObjectAccessExt::tag(…)` to `*::tag_reference(…)`, add `easy::Object::try_to_tag()` ([`e59f901`](https://github.com/Byron/gitoxide/commit/e59f901f47fb0180211494a1591aed62b856406a)) - - Add easy::ext::ObjectAccessExt::tag(…) to create tag objects ([`80b8331`](https://github.com/Byron/gitoxide/commit/80b8331092f4856f52afa1d85fa375ae688bdd28)) - - Allow to skip writing section titles and html tags ([`7b29406`](https://github.com/Byron/gitoxide/commit/7b29406d1b5814956a8474aa187d1e60e5eddf38)) - - Allow to turn off changelog links ([`b33e737`](https://github.com/Byron/gitoxide/commit/b33e7375509a74762c43f03ffc74e33b69c8f800)) - - Pass release section text to function soon creating a tag object ([`a4ac96c`](https://github.com/Byron/gitoxide/commit/a4ac96c6ca834b91e5311f89f6cd35acb3f85f54)) - - Precise change tracking for changelogs ([`d038c06`](https://github.com/Byron/gitoxide/commit/d038c0673f3ee48446aa5fade071766ce23c5c6a)) - - Fix stop-release-for-changelog logic and fix all affected changelogs ([`52b38bc`](https://github.com/Byron/gitoxide/commit/52b38bc4856be5ba8b5372a3dd20f5d06504e7ed)) - - Less verbose changelog and smart-release sub-commands related to changelogs ([`c096805`](https://github.com/Byron/gitoxide/commit/c09680524a8c07b09f8bf421381ce93b1ae4610b)) - - Adjust all changelogs to fulfil requirements for publishing ([`04b9ca0`](https://github.com/Byron/gitoxide/commit/04b9ca025a1667529b2221ab4280bd3c8dae01cf)) - - Handle changelogs with upcoming version section if they were left for editing ([`0f5f47d`](https://github.com/Byron/gitoxide/commit/0f5f47da4662b596cbbbd9c0d83e135e2cc52c11)) - - Refactor ([`6d30e2c`](https://github.com/Byron/gitoxide/commit/6d30e2c7e20ce1572afbebeee232d0c138a38462)) - - Automatically stop releases if changelogs are fully generated, and a flag to disable that ([`7161340`](https://github.com/Byron/gitoxide/commit/7161340ba7c4f2802e1a87cb02268d0adea8c0f8)) - - Check for changelog sections which are purely generated and warn about those ([`a9b8321`](https://github.com/Byron/gitoxide/commit/a9b83214cf425ec8853dacfbc96cba65e2005373)) - - See how it deals with major versions and auto-bumping in journey tests ([`b450bf3`](https://github.com/Byron/gitoxide/commit/b450bf3fb26fc399b405fc45972820d50281cef3)) - - More consistent log messages pertaining crate names ([`b32d8d6`](https://github.com/Byron/gitoxide/commit/b32d8d63841fed8c95436b9ae611aef9c11291cf)) - - First working version of version auto-bumping based on changelog ([`5ca7b1d`](https://github.com/Byron/gitoxide/commit/5ca7b1d1d703387d2e690a5a32a4033d87742217)) - - Issue links for category headlines ([`425d3df`](https://github.com/Byron/gitoxide/commit/425d3dfc114e62db16c8c16c0b3e7c6b4a2a3ae4)) - - Prepare for arrival of 'auto' bump mode ([`306035c`](https://github.com/Byron/gitoxide/commit/306035cf68dcc29466e736081ca8cdd3a5f57134)) - - Fix git-url re-export to respect feature flags ([`ec4e3ca`](https://github.com/Byron/gitoxide/commit/ec4e3ca4c7211655549a76cae252742633da1083)) - - Deduplicate conventional message ids ([`e695eda`](https://github.com/Byron/gitoxide/commit/e695eda8cd183f703d9a3e59b7c3c7fa496ea1d2)) - - Regenerate all changelogs to get links ([`0c81769`](https://github.com/Byron/gitoxide/commit/0c817690bd444f52bed2936b2b451cafd87dde92)) - - Link up github issue ids in statistics ([`661cd39`](https://github.com/Byron/gitoxide/commit/661cd3928002ef2f288d7410b37a046a6f0ea21b)) - - Format links for commit ids ([`9426db5`](https://github.com/Byron/gitoxide/commit/9426db53537162d58a65648f3f3a3a3b65f621dc)) - - Pass actual repository url down from commands ([`4e03515`](https://github.com/Byron/gitoxide/commit/4e03515622afd79b145db081ef9e3cb301ce6e97)) - - Make `git_url::Url` available under `git_repository::Url` ([`0ebfeb6`](https://github.com/Byron/gitoxide/commit/0ebfeb614264ca06ab763189e55e6c016c9997af)) - - Foundation for rendering links if needed ([`ba4ce96`](https://github.com/Byron/gitoxide/commit/ba4ce96e32676b2aed529330ee526da2fc2f6d49)) - - Rename title for "Fixed" to "Bug Fixes" ([`e766b01`](https://github.com/Byron/gitoxide/commit/e766b01c73813dd80c72e13e43c5acdda741521a)) - - Mention actual issues that where worked on ([`a517e39`](https://github.com/Byron/gitoxide/commit/a517e39a81145b331f6c7a6cc2fc22e25daf42e2)) - - Also parse 'style' if there are breaking changes ([`bc9d85a`](https://github.com/Byron/gitoxide/commit/bc9d85a15d94a54dd2dbc67f20f1ffdbdf2b4789)) - - Allow 'refactor' and 'other' in conventional messages if they have breaking changes ([`4eebaac`](https://github.com/Byron/gitoxide/commit/4eebaac669e590beed112b622752997c64772ef1)) - - Support writing whole bodies in conventional messages… ([`c1f3c9d`](https://github.com/Byron/gitoxide/commit/c1f3c9d2bd5a8e123ac9b376c257e3d5630876a0)) - - Support for paragraphs in conventional items ([`7f52823`](https://github.com/Byron/gitoxide/commit/7f528239089788f4dd1f75a85bee1d0492285d60)) - - Respect release-wide ignore list to allow removing entire conventional headlines ([`145103d`](https://github.com/Byron/gitoxide/commit/145103d4aa715386da9d4953f7f85fadc49fff9a)) - - Only write headlines that we can parse back… ([`d44369a`](https://github.com/Byron/gitoxide/commit/d44369ab5d849720dda9a9c0edc1ba1a3c1a78b5)) - - Handle all possible changelog headlines and add roundtrip tests ([`fda5ccf`](https://github.com/Byron/gitoxide/commit/fda5ccfcb224f9dcbb79be501a2ef639a906a493)) - - First basic parsing of conventional user and generated messages ([`56cd4ac`](https://github.com/Byron/gitoxide/commit/56cd4ac11a25710db889a8038d9ba8eb902b544b)) - - Parsing of removed conventional messages from changelogs ([`c593252`](https://github.com/Byron/gitoxide/commit/c5932522178af3e2b1c22eb6e5f0b3a282f12f07)) - - First basic merging of conventional messages… ([`9af3248`](https://github.com/Byron/gitoxide/commit/9af3248b9402a4e1cf63cbb03ac53ab3d7fbf015)) - - Trivially emulate gits way of handling commit dates… ([`f58b30a`](https://github.com/Byron/gitoxide/commit/f58b30a78078f222f0db8b70d2c98c83af59c1a0)) - - Also consider changes of changelogs themselves… ([`8a2042c`](https://github.com/Byron/gitoxide/commit/8a2042cd2aa8aa212e456587187ab33ed0f70e3e)) - - Adjust date of upcoming version as well ([`fab4649`](https://github.com/Byron/gitoxide/commit/fab4649f3319fac2cc61cf2deba1e150f85206b0)) - - Assure git-conventional is treated like user generated content for statistics ([`1fd5acb`](https://github.com/Byron/gitoxide/commit/1fd5acbcbcc038fc28cdfa529c3a108cbe22f706)) - - Merge doesn't consider user generated sections, only the ones it would want to add ([`ebbebdd`](https://github.com/Byron/gitoxide/commit/ebbebdd70aeec9aa3ad453d61375429a7f555bbc)) - - Quick and dirty writing of conventional messages… ([`adfbd0d`](https://github.com/Byron/gitoxide/commit/adfbd0d812718868063a5d3142e02b026e3cf2fc)) - - Basic generation of git-conventional information ([`77b0feb`](https://github.com/Byron/gitoxide/commit/77b0feb954232d34e4618e502f22a59dda7e6a2d)) - - Sketch out data structure for git-conventional segments ([`2713c02`](https://github.com/Byron/gitoxide/commit/2713c022317a72cd3af60698e380d370093ea499)) - - Refactor ([`bcdec5e`](https://github.com/Byron/gitoxide/commit/bcdec5e62f8e5b6e97b8ead9e2d9abc0a61779b3)) - - Smart-release with --changelog-without option… ([`ae8780e`](https://github.com/Byron/gitoxide/commit/ae8780e08303946412cedc19ea4d2679be49ec97)) - - Changelog command learns the --without
option ([`509550f`](https://github.com/Byron/gitoxide/commit/509550f8aa8210f3688c78167a56a21fc1817515)) - - Easy removal of statistical sections, by just removing them… ([`91efd68`](https://github.com/Byron/gitoxide/commit/91efd68aea84dcd22569c429f22e06c5fc7f8f6e)) - - Rebuild all changelogs to assure properly ordered headlines ([`4a9a05f`](https://github.com/Byron/gitoxide/commit/4a9a05f95930bad5938d4ce9c517ebf0e0b990f1)) - - Reorder headlines according to version ordering… ([`2ff0c20`](https://github.com/Byron/gitoxide/commit/2ff0c2078d12f6d17862a6f64bbec19fcc227be8)) - - Sort all commits by time, descending… ([`f536bad`](https://github.com/Byron/gitoxide/commit/f536bad20ffbac4dc353dfeb1a917bb88becbb78)) - - Greatly reduce changelog size now that the traversal fix is applied ([`a0bc98c`](https://github.com/Byron/gitoxide/commit/a0bc98c06c349de2fd6e0d4593606e68b98def72)) - - Use most relevant parent tree for change comparison… ([`5b9dd14`](https://github.com/Byron/gitoxide/commit/5b9dd148289d6c82dff5f74d8ebf7fabafc0c463)) - - Use hashmap based lookup for trees… ([`48a0c76`](https://github.com/Byron/gitoxide/commit/48a0c76ab163b6e35b19dd2a9efc2e101a721633)) - - Refactor and improve path filtering to find relevant commits… ([`01b2466`](https://github.com/Byron/gitoxide/commit/01b246644c76d842892a8dfcf8392026baf288d8)) - - The first headline level controls all the other ones ([`715ea54`](https://github.com/Byron/gitoxide/commit/715ea54624a2651a4828ccd8cd035889495212b8)) - - Adapt to git-hash refactor ([`925d668`](https://github.com/Byron/gitoxide/commit/925d6685df58a4a1135e426a70c370280f2ac142)) - - Fixup remaining changelogs… ([`2f75db2`](https://github.com/Byron/gitoxide/commit/2f75db294fcf20c325555822f65629611be52971)) - - Generate changelogs with details ([`e1861ca`](https://github.com/Byron/gitoxide/commit/e1861caa435d312953a9fea7ceff6d2e07b03443)) - - Only use short hashes for logs, without detecting ambiguity for now ([`772525c`](https://github.com/Byron/gitoxide/commit/772525c8b46136654e907b5b6362792806e6a897)) - - Boost allowed package sizes… ([`1b21d71`](https://github.com/Byron/gitoxide/commit/1b21d71b9cb28ded42b6c2fb2c6b7e3c134b281e)) - - Stable smart-release journey tests… ([`fc79188`](https://github.com/Byron/gitoxide/commit/fc791887f4286411d33db676ebb0ee35591557a4)) - - Update all changelogs with details ([`58ab2ae`](https://github.com/Byron/gitoxide/commit/58ab2aee23ba70a536e9487b44fb04c610374d1a)) - - Put commit details to the end of generated segments ([`054d207`](https://github.com/Byron/gitoxide/commit/054d207ae40452ae024693162a4586c63b489df0)) - - Use message commit id instead of body… ([`9b46f32`](https://github.com/Byron/gitoxide/commit/9b46f3212a62e96bbbdaa4d0af443c73f5d657ee)) - - Fix md formatting on github ([`262c000`](https://github.com/Byron/gitoxide/commit/262c00095a7eb16c2c6e9990e9247d1e9ef9bb1d)) - - Create details headline based on log message ([`04bbcbb`](https://github.com/Byron/gitoxide/commit/04bbcbb9109abe2e0715cdb5446d9fd2231fc9a5)) - - Add details behind a fold, but… ([`3360b2e`](https://github.com/Byron/gitoxide/commit/3360b2e2740e265ee46fd1b9a28596de5ebb8a2e)) - - Use the notion of 'changes after merge' only to drive previews… ([`634267c`](https://github.com/Byron/gitoxide/commit/634267cad2f3243b58603df224dc2831c45cd5fc)) - - Update changelogs ([`c857d61`](https://github.com/Byron/gitoxide/commit/c857d61ce3ce342012a2c4ba10a8327822aa530e)) - - Refactor ([`7a83103`](https://github.com/Byron/gitoxide/commit/7a83103e632be4fff50391caa8aff5237bc4baca)) - - Also provide a duration in days for preparing a release as part of statistics ([`bd12cac`](https://github.com/Byron/gitoxide/commit/bd12cac57898951eea0846e193839ccdbd41da89)) - - Fix tests ([`6c98afc`](https://github.com/Byron/gitoxide/commit/6c98afc351fca32d4f056a2f398328676c4c8163)) - - Refactor ([`65fa0a4`](https://github.com/Byron/gitoxide/commit/65fa0a49f20b0895083e06c738dc68baa932dd7d)) - - More commit statistics ([`0840e7e`](https://github.com/Byron/gitoxide/commit/0840e7e67e107aea0b5c8a6e8efcdb584990875e)) - - Basic commit statistics with round-trip, more actual information to come ([`6d097ae`](https://github.com/Byron/gitoxide/commit/6d097ae29d2c3afd8a23a81d58712ebecf89b563)) - - Refactor… ([`ce0dda2`](https://github.com/Byron/gitoxide/commit/ce0dda259d61725898190de6769e1577d32068d4)) - - More robust parsing of read-only sections ([`a3954f4`](https://github.com/Byron/gitoxide/commit/a3954f4949695e3fdb910ea6bc94ae4eca7e25de)) - - Treat clippy as generated statistical section… ([`1cff425`](https://github.com/Byron/gitoxide/commit/1cff425d5797c181a8c3709d241381091b14e487)) - - Add new section type and write it out: clippy ([`6fca2ac`](https://github.com/Byron/gitoxide/commit/6fca2ac8421f300e64429de6cf4581168d8db409)) - - Introduce notion of essential sections in a changelog… ([`be891e2`](https://github.com/Byron/gitoxide/commit/be891e20cb0152af52ceec47400cf3401e2112fb)) - - Preview changelog support for smart-release as well ([`b9e6de1`](https://github.com/Byron/gitoxide/commit/b9e6de124eab5e961c1effe797a5e54e23228284)) - - Detect changes after merge; add flag for controlling changelog preview ([`6beb734`](https://github.com/Byron/gitoxide/commit/6beb7345f0329592081c2955cf7ad2c9adf0e68a)) - - A lot of logic to handle messaging around changelog generation and halting… ([`28f6e18`](https://github.com/Byron/gitoxide/commit/28f6e181ff0e14e52704544bc6ed5f41bd7fb234)) - - Unconditional changelog creation in smart-release ([`48b5228`](https://github.com/Byron/gitoxide/commit/48b52281f789a93415fefe38d661228ab582a107)) - - Rename --skip-* flags to --no-* for consistency ([`3c0a638`](https://github.com/Byron/gitoxide/commit/3c0a6389fe5ff981dadca20e8a4a4a0d2ef66e13)) - - Fix windows tests by transforming line endings ([`e276d77`](https://github.com/Byron/gitoxide/commit/e276d777eb7a88dc424badbf88a929b5f567e5de)) - - Avoid adding newlines which make writing unstable ([`6b5c394`](https://github.com/Byron/gitoxide/commit/6b5c394f49282a8d09c2a9ffece840e4683572db)) - - Fix section headline level ([`9d6f263`](https://github.com/Byron/gitoxide/commit/9d6f263beef289d227dec1acc2d4240087cb9be6)) - - Write first version of changlogs thus far… ([`719b6bd`](https://github.com/Byron/gitoxide/commit/719b6bdf543b8269ccafad9ad6b46e0c55efaa38)) - - Implement --write actually ([`69d36ff`](https://github.com/Byron/gitoxide/commit/69d36ffbeea68259add2d8e15a9eb74137b14156)) - - Parse more user generated section content, adapt existing changelogs to work correctly ([`2f43a54`](https://github.com/Byron/gitoxide/commit/2f43a54298e7ecfff2334627df149fe0882b5d1d)) - - A test case showing that headlines are currently ignored, and links too ([`2a57b75`](https://github.com/Byron/gitoxide/commit/2a57b755c5513544987be74b3b4b65d35e7718c9)) - - Don't try to run tests in binaries that have none… ([`d453fe5`](https://github.com/Byron/gitoxide/commit/d453fe5086f819e590af78bba1083659fcc44c01)) - - It's already getting there, even though a few parts are completely missing ([`ee4aa08`](https://github.com/Byron/gitoxide/commit/ee4aa08fc0ed4bd06c7a987b2a9c86425400d68a)) - - Only parse into 'unknown' catch all in special cases… ([`c0296c4`](https://github.com/Byron/gitoxide/commit/c0296c4d28016044f7d82afeba10971a526eca36)) - - First basic parsing of unknown parts as segments in sections ([`f265982`](https://github.com/Byron/gitoxide/commit/f265982a58600b68674f8552252e1ea156fe163d)) - - Quick and dirty switch to getting access to a range of parsed input… ([`f5902f2`](https://github.com/Byron/gitoxide/commit/f5902f2fa9a6b876497278c9c62a91e58de1c31f)) - - Setup test for old method of parsing unknown text… ([`996c39d`](https://github.com/Byron/gitoxide/commit/996c39d002d1781fd7193dabe958af6045936411)) - - Refactor tests: unit to integration level ([`4326322`](https://github.com/Byron/gitoxide/commit/43263226420c0bd9db5d4920f5ce2f76c5367aa8)) - - Don't add a date to unreleased versions ([`ba4d024`](https://github.com/Byron/gitoxide/commit/ba4d02404e0a00c1b0d1553032c8062806d09b84)) - - Actually integrated generated changelog with existing ones… ([`aa095e2`](https://github.com/Byron/gitoxide/commit/aa095e2447fff350492c38600c7303d38ae38824)) - - Inform about 'bat's absence ([`c82c5bc`](https://github.com/Byron/gitoxide/commit/c82c5bc682f6b4cc53b5965e3a124a826933718f)) - - Rename --no-bat to --no-preview… ([`1087dd8`](https://github.com/Byron/gitoxide/commit/1087dd81ce869de9c886379766a962ec30c93e36)) - - Basic merging now works ([`6c6c200`](https://github.com/Byron/gitoxide/commit/6c6c20002cf7632e8fed11b83a1e2f69b669d907)) - - Sketch for finding insertion points and merging sections ([`2a49033`](https://github.com/Byron/gitoxide/commit/2a4903348f6179f6939e6b87d3477e5643acb7b7)) - - Sketch merging logic… ([`1932e2c`](https://github.com/Byron/gitoxide/commit/1932e2ca848db57f3907b93e804553524dfa27ac)) - - Prepare test for basic merging… ([`0a14ced`](https://github.com/Byron/gitoxide/commit/0a14cedbd68058ac296e34a84ab1fe1083a0bf5e)) - - Nicer 'thanks clippy' message ([`4344216`](https://github.com/Byron/gitoxide/commit/43442162aa22f561a33cab78936514d05d8214a0)) - - Show with simple example how the round-tripping works, neat ([`9510d9b`](https://github.com/Byron/gitoxide/commit/9510d9bd2c3b2d5cffe32485d7bc3fff374343ee)) - - Collect unknown text so things don't get lost entirely… ([`60040c9`](https://github.com/Byron/gitoxide/commit/60040c9301e6468c72a0c52095c0b86f8b3041f5)) - - Parse back what we write out, perfectly… ([`5cab315`](https://github.com/Byron/gitoxide/commit/5cab315b0f28d9b9f6f6b4e037d053fb501fdfaa)) - - Fix journey test ([`3006e59`](https://github.com/Byron/gitoxide/commit/3006e5975e023c9ad56e62ce3163dd65964c0c57)) - - Write new changelogs with bat if available ([`cca8e52`](https://github.com/Byron/gitoxide/commit/cca8e52fdd2ebd16b08247d428ed5387a1058cd5)) - - Use `cargo diet` to reduce package size ([`cc5709e`](https://github.com/Byron/gitoxide/commit/cc5709e812aea79e9d9a6f16637d09f22cb73f81)) - - Write markdown changelog to lock file ([`400046e`](https://github.com/Byron/gitoxide/commit/400046ec65100a15cd1757143c1abba05091f129)) - - Refactor ([`b05ce15`](https://github.com/Byron/gitoxide/commit/b05ce15a31aba9b0084792b7f0e7155b73b46e2d)) - - Basic serialization of ChangeLog ([`205b569`](https://github.com/Byron/gitoxide/commit/205b5698072c6919036190cacac120a7dd5dbd73)) - - Support for generated headers ([`bcc4323`](https://github.com/Byron/gitoxide/commit/bcc4323785c5aca698e5af2ee5cf32e171727ed3)) - - Refactor ([`1ebb736`](https://github.com/Byron/gitoxide/commit/1ebb7365ce564d55bd4f16f7316375b9458b4659)) - - Use 'to_*' when converting `easy::Object` to specific object kind ([`1cb41f8`](https://github.com/Byron/gitoxide/commit/1cb41f81cffe19c75aadf49a5cc7ec390ec6cae7)) - - Transform history segments into changelog parts ([`348b05c`](https://github.com/Byron/gitoxide/commit/348b05cbe6e93e871393a6db9d1ebfea59ec7fdb)) - - Layout structure for ChangeLog generation from history items ([`40e9075`](https://github.com/Byron/gitoxide/commit/40e9075238f7272c08497851f55d0b525f47f2db)) - - More general commit history ([`39522ec`](https://github.com/Byron/gitoxide/commit/39522ec59d2eb7f439c75a5cc5dc0315db9497d5)) - - Invert meaning of changelog's --dependencies flag… ([`51eb8cb`](https://github.com/Byron/gitoxide/commit/51eb8cba67edf431ebe3e32232022dbf8971e6ac)) - - Rename --skip-dependencies to --no-dependencies… ([`77ed17c`](https://github.com/Byron/gitoxide/commit/77ed17c703e502e132cda9a94eb8c63db0b627ad)) - - Remove strong-weak typing for conventional type ([`b71c579`](https://github.com/Byron/gitoxide/commit/b71c5790fd8c14f10df00a96f3a344c121278418)) - - Fix panic related to incorrect handling of character boundaries ([`9e92cff`](https://github.com/Byron/gitoxide/commit/9e92cff33f4f53d3b2d6b55a722d577c2dd6a4f2)) - - Parse message fully (and own it) to allow markdown generation ([`b8107e5`](https://github.com/Byron/gitoxide/commit/b8107e5d33da70f91225e9fd37443e3ba2b20f7c)) - - Tests for conventional and unconventional description parsing ([`faade3f`](https://github.com/Byron/gitoxide/commit/faade3f95f861736ec0ccf7f0a811c1cf12831cd)) - - Make use of fixed git-conventional ([`b7b92b6`](https://github.com/Byron/gitoxide/commit/b7b92b6c72051d462ab01c7645ea09d7d21cb918)) - - Update git-conventional dependency ([`2d369e8`](https://github.com/Byron/gitoxide/commit/2d369e863b15269ba8714b025fe596f69e5b1217)) - - First test and sketch for stripping of additional title values ([`55b7fe8`](https://github.com/Byron/gitoxide/commit/55b7fe8c9391e3a9562e084ae7524bb9f83ec36c)) - - Basic message parsing, either conventional or not, without additions ([`b3b6a2d`](https://github.com/Byron/gitoxide/commit/b3b6a2dc07c2eff38556ee66b9290b0c66b463ed)) - - Sketch Message fields from which change logs can be built ([`b167d39`](https://github.com/Byron/gitoxide/commit/b167d39ecf0cd306dcf4d2c00413251cbfd02ed6)) - - Fix build ([`d0a956f`](https://github.com/Byron/gitoxide/commit/d0a956fdb5a822dbd116792bfbe70d1532a95ec9)) - - More message parsing tests, now with legit failure… ([`625be8d`](https://github.com/Byron/gitoxide/commit/625be8dbd4204ea1a7131ade9b17f63dcc7e30d7)) - - Sketch data for parsed messages ([`32dd280`](https://github.com/Byron/gitoxide/commit/32dd280eaada635994e11b4f2722a4efc59faa8f)) - - Add git-conventional ([`0c355ed`](https://github.com/Byron/gitoxide/commit/0c355ed24eb230e9834e797d5c8dc72ae21f0c46)) - - Consider nom for custom parsing, but… ([`5fc3326`](https://github.com/Byron/gitoxide/commit/5fc33266b2626a07b19d2f5bd075e2c600204a3d)) - - Refactor ([`17322fa`](https://github.com/Byron/gitoxide/commit/17322fa378fdecad80ad1349292aaaee8bcd00f6)) - - Refactor ([`ac0696b`](https://github.com/Byron/gitoxide/commit/ac0696b8226a1478fa90b932306f35e5dbf464b1)) - - Refactor ([`87ebacc`](https://github.com/Byron/gitoxide/commit/87ebacc65f56f8765eb787fea1bd27f2c99dfd97)) - - A seemingly slow version of path lookup, but… ([`41afad3`](https://github.com/Byron/gitoxide/commit/41afad3386461b658ee859225785b6de86d13cfb)) - - Fast filter by single-component path ([`ae7def4`](https://github.com/Byron/gitoxide/commit/ae7def47388aeb56c7df4a73fd13ff508cee7017)) - - Prepare for fast lookup of paths ([`fbf267e`](https://github.com/Byron/gitoxide/commit/fbf267eeb424bf90649be278ee847fe3f2a3db80)) - - Configure caches with env vars using `apply_environment()` ([`d422b9a`](https://github.com/Byron/gitoxide/commit/d422b9a31a37a03551bec4382039aaf3a7e49902)) - - Refactor ([`e7c061b`](https://github.com/Byron/gitoxide/commit/e7c061b10c263001eb4abf03098d6694b770f828)) - - Set package cache via RepositoryAccessExt ([`66292fd`](https://github.com/Byron/gitoxide/commit/66292fd1076c2c9db4694c5ded09799a0be11a03)) - - Object-cache to allow for a speed boost… ([`06996e0`](https://github.com/Byron/gitoxide/commit/06996e032b1e451a674395ebaca94434fac46f05)) - - Actually build the segment vec, without pruning for now ([`422701b`](https://github.com/Byron/gitoxide/commit/422701be4ed6d2a61361af9b6eb0f4f470d1d782)) - - Build commit history for later use in changelog generation ([`daec716`](https://github.com/Byron/gitoxide/commit/daec7167df524b329daad7dabb1b9920b6ef8936)) - - Sketch history acquisition ([`debe009`](https://github.com/Byron/gitoxide/commit/debe0094826f83839f907523715def929133fd58)) - - Add 'Head::peeled()' method ([`56e39fa`](https://github.com/Byron/gitoxide/commit/56e39fac54bfa3871c42bbf76a9f7c49486b85be)) - - Some performance logging ([`1954b46`](https://github.com/Byron/gitoxide/commit/1954b467cf1e97e22629c55487b4a66cb1380a89)) - - Build ref lookup table ([`9062a47`](https://github.com/Byron/gitoxide/commit/9062a472ac63887900562ed341c7b68665b8587a)) - - Loose reference iteration with non-dir prefixes… ([`293bfc0`](https://github.com/Byron/gitoxide/commit/293bfc0278c5983c0beaec93253fb51f00d81156)) - - Add 'references().all().peeled().'… ([`6502412`](https://github.com/Byron/gitoxide/commit/650241251a420602f74037babfc24c9f64df78d8)) - - Filter refs correctly, but… ([`2b4a615`](https://github.com/Byron/gitoxide/commit/2b4a61589a7cba3f7600710e21304e731ae3b36a)) - - Find tag references by name… ([`72e1752`](https://github.com/Byron/gitoxide/commit/72e175209441b12f3d4630e5118e21a3156146df)) - - Improve changelog format ([`90e6128`](https://github.com/Byron/gitoxide/commit/90e6128727932f917c485f411e623fc6a9c2ad4d)) - - Sketch first step of info generation ([`ff894e5`](https://github.com/Byron/gitoxide/commit/ff894e5b0257722c31578772ed694324194c0741)) - - Changelog gets crates to work on ([`78d31d9`](https://github.com/Byron/gitoxide/commit/78d31d9de2710b4369862c1226f18d4a2d79a9c4)) - - Handle unborn heads ([`0e02831`](https://github.com/Byron/gitoxide/commit/0e02831fff83f6d6b0ea8889d54196e54e4e4aff)) - - Fmt ([`d66c5ae`](https://github.com/Byron/gitoxide/commit/d66c5aea01a7d1df2cc539c52b789ad39a058ad2)) - - Refactor ([`d4ffb4f`](https://github.com/Byron/gitoxide/commit/d4ffb4f2ac935f6345bdc7d03cc1878007609503)) - - Refactor ([`9fc15f9`](https://github.com/Byron/gitoxide/commit/9fc15f92ddec4ccfd0803d2b1231ed08d424cf33)) - - Refactor ([`9e430df`](https://github.com/Byron/gitoxide/commit/9e430df135e87ee9e9673e7d52f072f39abaf4d9)) - - Initial test for changelog ([`a33dd5d`](https://github.com/Byron/gitoxide/commit/a33dd5d21039441556ab89c997195f1bcc5bc543)) - - Very basic support for changelog command… ([`1a683a9`](https://github.com/Byron/gitoxide/commit/1a683a91a2850d663cf87fb326e5ab66ae86fc96)) - - Add 'cargo changelog' sub-command binary ([`3677b78`](https://github.com/Byron/gitoxide/commit/3677b782f8bc63a38d4d49b8555b5a6b9a618f84)) - - Add changelog to most tests ([`cdf4199`](https://github.com/Byron/gitoxide/commit/cdf41998360527161a1b04821bab377489f6c5f0)) - * **[#200](https://github.com/Byron/gitoxide/issues/200)** - - Parse issue numbers from description and clean it up ([`95c0a51`](https://github.com/Byron/gitoxide/commit/95c0a510f875e8fd889b87caee356a4c1e099ea8)) - * **[#213](https://github.com/Byron/gitoxide/issues/213)** - - Fix version logic to handle breaking version updates correctly ([`67ed644`](https://github.com/Byron/gitoxide/commit/67ed6449c410cca61ac5b40589408695eee4df69)) - * **[#67](https://github.com/Byron/gitoxide/issues/67)** - - Split data::output::count::objects into files ([`8fe4612`](https://github.com/Byron/gitoxide/commit/8fe461281842b58aa11437445637c6e587bedd63)) - * **Uncategorized** - - Release git-hash v0.7.0, git-features v0.16.5, git-actor v0.5.3, git-config v0.1.7, git-validate v0.5.3, git-object v0.14.1, git-diff v0.10.0, git-tempfile v1.0.3, git-lock v1.0.1, git-traverse v0.9.0, git-pack v0.12.0, git-odb v0.22.0, git-packetline v0.11.0, git-url v0.3.4, git-transport v0.12.0, git-protocol v0.11.0, git-ref v0.8.0, git-repository v0.10.0, cargo-smart-release v0.4.0 ([`59ffbd9`](https://github.com/Byron/gitoxide/commit/59ffbd9f15583c8248b7f48b3f55ec6faffe7cfe)) - - Thanks clippy ([`2113d79`](https://github.com/Byron/gitoxide/commit/2113d7989b5e5dde5fc7594e1c63abef0bfba650)) - - Thanks clippy ([`7c78dcf`](https://github.com/Byron/gitoxide/commit/7c78dcf468a2947e7b46103f275c27eb49b1547c)) - - Thanks clippy ([`fc9da4c`](https://github.com/Byron/gitoxide/commit/fc9da4c3eef70bcc780224f42e0b78e477f3b199)) - - Thanks clippy ([`41ed695`](https://github.com/Byron/gitoxide/commit/41ed695a6a739df00d39bf86dae2cc12b8e280b6)) - - Thanks clippy ([`2b62956`](https://github.com/Byron/gitoxide/commit/2b629561ba7d08c6861746c512bd21dc5324e1bb)) - - Adjusting changelogs prior to release of git-hash v0.7.0, git-features v0.16.5, git-actor v0.5.3, git-validate v0.5.3, git-object v0.14.1, git-diff v0.10.0, git-tempfile v1.0.3, git-lock v1.0.1, git-traverse v0.9.0, git-pack v0.12.0, git-odb v0.22.0, git-packetline v0.11.0, git-url v0.3.4, git-transport v0.12.0, git-protocol v0.11.0, git-ref v0.8.0, git-repository v0.10.0, cargo-smart-release v0.4.0, safety bump 3 crates ([`a474395`](https://github.com/Byron/gitoxide/commit/a47439590e36b1cb8b516b6053fd5cbfc42efed7)) - - Thanks clippy ([`87d2f49`](https://github.com/Byron/gitoxide/commit/87d2f491b4c177bd5b67eea57e6a4e516f25d1e8)) - - Thanks clippy ([`a1ebd80`](https://github.com/Byron/gitoxide/commit/a1ebd800e46094ada7dbd8298a63b33724de0431)) - - Thanks clippy ([`ca0d943`](https://github.com/Byron/gitoxide/commit/ca0d9432869c40135cc8db26af29bec44f3ae74a)) - - Thanks clippy ([`8b3d9ea`](https://github.com/Byron/gitoxide/commit/8b3d9ea5aa7f161d2baebeafc4c1ab966583f5ac)) - - Thanks clippy ([`ce48e18`](https://github.com/Byron/gitoxide/commit/ce48e184f37bf0a9c558f8e9a0eaa3b4526fdc2e)) - - Thanks clippy ([`af9d137`](https://github.com/Byron/gitoxide/commit/af9d13745ae4e14d9553d3a4aa5a82cc15957a7e)) - - Update changelogs just for fun ([`21541b3`](https://github.com/Byron/gitoxide/commit/21541b3301de1e053fc0e84373be60d2162fbaae)) - - Thanks clippy ([`bf514a2`](https://github.com/Byron/gitoxide/commit/bf514a27b6b79d4ad680092019039f292c94b0f1)) - - Thanks clippy ([`ead04f2`](https://github.com/Byron/gitoxide/commit/ead04f23d671039ee08ee3e6809edadfe9732ed9)) - - Thanks clippy ([`e4f1c09`](https://github.com/Byron/gitoxide/commit/e4f1c091ac6cce21ee313d93bd0b0ace38aa131b)) - - Merge branch 'changelog-generation' ([`bf0106e`](https://github.com/Byron/gitoxide/commit/bf0106ea21734d4e59d190b424c22743c22da966)) - - Thanks clippy ([`b856da4`](https://github.com/Byron/gitoxide/commit/b856da409e6a8fdc81ea32ebb4a534b0e70baebc)) - - Thanks clippy ([`31498bb`](https://github.com/Byron/gitoxide/commit/31498bbee4b2bc766b42171dfd6529d885d3bc84)) - - Thanks clippy ([`c55f909`](https://github.com/Byron/gitoxide/commit/c55f90977756c794939454072e4cc648f1e4348f)) - - Thanks clippy ([`b200ee8`](https://github.com/Byron/gitoxide/commit/b200ee8d7522f0c83e0e01f0d793784cba7028aa)) - - Thanks clippy ([`4b3407d`](https://github.com/Byron/gitoxide/commit/4b3407d0baf32b6eeb04cee07faa4bb9c1270e4e)) - - Thanks clippy ([`1dece2b`](https://github.com/Byron/gitoxide/commit/1dece2b8dd18d0266210152c749c39595d70db5a)) - - Thanks clippy ([`a89d08c`](https://github.com/Byron/gitoxide/commit/a89d08c4ce28f0c466f01758e9f4db09eeb02458)) - - Merge branch 'main' into changelog-generation ([`c956f33`](https://github.com/Byron/gitoxide/commit/c956f3351d766c748faf0460780e32ac8dfe8165)) - - Don't claim to change manifest version if it's the same one ([`11eebdc`](https://github.com/Byron/gitoxide/commit/11eebdcc572a72b2e66a9db3cae0a01f12a81619)) - - Thanks clippy ([`68ea77d`](https://github.com/Byron/gitoxide/commit/68ea77dcdd5eb8033618e7af2e3eb0989007b89b)) - - Thanks clippy ([`7899ef1`](https://github.com/Byron/gitoxide/commit/7899ef10f2f4a6df43beed598ddf396991dcd9e5)) - - Thanks clippy ([`2b55427`](https://github.com/Byron/gitoxide/commit/2b5542761ab160cd9460b133928efd6f0cb55e75)) - - Thanks clippy ([`a554b9d`](https://github.com/Byron/gitoxide/commit/a554b9d356d4e44c9504f7b35aa2c4f9c660df9b)) - - Bump git-repository v0.10.0 ([`5a10dde`](https://github.com/Byron/gitoxide/commit/5a10dde1bcbc03157f3ba45104638a8b5b296cb9)) - - Thanks clippy ([`d15fded`](https://github.com/Byron/gitoxide/commit/d15fded08224c45dcbd34cf742398e2594f39964)) - - [repository #164] fix build ([`1db5542`](https://github.com/Byron/gitoxide/commit/1db554216e99c5df62a2fc7fa3f8693fdc35b3eb)) - - Release git-repository v0.9.1 ([`262c122`](https://github.com/Byron/gitoxide/commit/262c1229d6d2d55c70fe0e199ab15d10954d967b)) - - [smart-release] auto-detect changes in production crates as well ([`24bc1bd`](https://github.com/Byron/gitoxide/commit/24bc1bd678602e6b1af771b0b47eb3a39f8aa3a7)) - - [smart-release #195] update test output to match CI… ([`f864386`](https://github.com/Byron/gitoxide/commit/f86438609a1f99173efbe6b1fe91229433c1fc76)) - - [smart-release #195] better error for untracked files. ([`f5266f9`](https://github.com/Byron/gitoxide/commit/f5266f9756b1dbb9dc9846ba6efb863bdc12ae35)) - - [smart-release #195] assure dependent packages are not packages to be published ([`6792ebc`](https://github.com/Byron/gitoxide/commit/6792ebc9d09aec81ebc81b3b0fa58ca7c6ce4fcc)) - - [smart-release #195] refactor ([`f354b61`](https://github.com/Byron/gitoxide/commit/f354b61b986369865de3471ab4eed2ae7bcc60e3)) - - [smart-release #195] refactor ([`968b6e1`](https://github.com/Byron/gitoxide/commit/968b6e19894a1b42546c15ed3cf5c8485dbc701c)) - - [smart-release #195] don't tout changes that aren't really there… ([`5931012`](https://github.com/Byron/gitoxide/commit/5931012d0183b97e29de58eb93d07055f855a34f)) - - [smart-release #195] another test to validate log output ([`6148ebf`](https://github.com/Byron/gitoxide/commit/6148ebf361363f362f281bc2bdf0d37a6618f4fc)) - - [smart-release #195] a test that in theory should trigger the desired behaviour ([`fd50208`](https://github.com/Byron/gitoxide/commit/fd5020868c7141e377a604c0d34cbc527d4959f9)) - - [smart-release #194] basic journey test setup ([`d5d90a6`](https://github.com/Byron/gitoxide/commit/d5d90a654170c32750ef26872b72a6080184ac5d)) - - Thanks clippy ([`8fedb68`](https://github.com/Byron/gitoxide/commit/8fedb686bcf195bf69eadd828cbacb77ff19f386)) - - [smart-release #194] conservative pre-release version updates ([`f23442d`](https://github.com/Byron/gitoxide/commit/f23442d90e710bde63dd597ae6c4509b1f909a34)) - - Bump git-repository v0.9.0 ([`b797fc1`](https://github.com/Byron/gitoxide/commit/b797fc10f3f3d1fbc23916a4ff6e5e860e2dd4ed)) -
- -## v0.3.1 (2021-09-07) - -### Commit Statistics - - - - - 5 commits contributed to the release over the course of 2 calendar days. - - 10 days passed between releases. - - 0 commits were understood as [conventional](https://www.conventionalcommits.org). - - 0 issues like '(#ID)' were seen in commit messages - -### Commit Details - - - -
view details - - * **Uncategorized** - - Release cargo-smart-release v0.3.1 ([`1bcea9a`](https://github.com/Byron/gitoxide/commit/1bcea9a9b3be1bbb19a279ae9a8143d008fcefe3)) - - Merge branch 'repository-integration' ([`49f5453`](https://github.com/Byron/gitoxide/commit/49f5453629646ac24d752f53c532e5f67eb09374)) - - [repository #190] refactor ([`e7188e0`](https://github.com/Byron/gitoxide/commit/e7188e047529cb0f4b20b3876f36b4592e9d2dc4)) - - [repository #190] fix build ([`f5e118c`](https://github.com/Byron/gitoxide/commit/f5e118c8871e45ed3db9da9cd6bc63a5ea99621e)) - - [repository #190] a major step forward with `head()` access ([`43ac4f5`](https://github.com/Byron/gitoxide/commit/43ac4f5acbe3ace5d43ed3ed1bc394d721f0e273)) -
- -## v0.3.0 (2021-08-27) - -- add `--skip-dependencies` flag -- add `--verbose` flag and be less verbose in dry-runs by default to provide only essential information -- improvements to notification clarity - -### Breaking - -- Use short flag for `--no-bump-on-demand` in `--bump-dependencies` - -### Commit Statistics - - - - - 47 commits contributed to the release over the course of 11 calendar days. - - 11 days passed between releases. - - 0 commits were understood as [conventional](https://www.conventionalcommits.org). - - 0 issues like '(#ID)' were seen in commit messages - -### Commit Details - - - -
view details - - * **Uncategorized** - - Release cargo-smart-release v0.3.0 ([`82f0cec`](https://github.com/Byron/gitoxide/commit/82f0cec9c8f0f5610ddbd6cd1ac0716a9633d7c6)) - - [smart-release #174] add asciinema recording of failed release ([`6668527`](https://github.com/Byron/gitoxide/commit/6668527ee961df214bda41619d6fb76540b0dda1)) - - [smart-release #174] prepare changelog ([`0d9a2b8`](https://github.com/Byron/gitoxide/commit/0d9a2b802d5a544a08ba1c88f9fd8fe62e8e3dc6)) - - Bump git-repository v0.8.0 ([`cdb45ff`](https://github.com/Byron/gitoxide/commit/cdb45ffa0810e9fcc9fd25bff7b696c2d27eeef5)) - - [smart-release] Adjust commit message depending on whether we are skipping the publish… ([`c190c6b`](https://github.com/Byron/gitoxide/commit/c190c6b963dbaaf80a70a51135e591ee2cb9c157)) - - [object #177] migrate immutable::tree to crate::tree ([`fa5cd06`](https://github.com/Byron/gitoxide/commit/fa5cd0648d5c855060ab2b75ee933851987c2dcf)) - - Merge branch 'git-ref-refactor' ([`5dbf753`](https://github.com/Byron/gitoxide/commit/5dbf753ce2035ffd07e4bce7ceb3bcd4e309c16e)) - - [ref #175] make 'mutable' module private ([`a80dbcf`](https://github.com/Byron/gitoxide/commit/a80dbcf083bfcf2e291013f7b13bba9e787c5cb4)) - - Release git-lock v1.0.0 ([`f38f72c`](https://github.com/Byron/gitoxide/commit/f38f72c73f69775358d8b047de2e354364fcafc2)) - - [stability #171] git-ref is now ST1 and available through git-repository ([`50154cd`](https://github.com/Byron/gitoxide/commit/50154cd02fdd90930a1d7c5a4406d53c8067cb4b)) - - [smart-release #171] Try to avoid unstable git-repository features… ([`c8f325b`](https://github.com/Byron/gitoxide/commit/c8f325bed5d644eded035109702098f9fed3fba3)) - - [stability #171] Don't provide access to less stable crates in `Respository` ([`e4c5b58`](https://github.com/Byron/gitoxide/commit/e4c5b58ad935c907dfbd0d61049453dcb64a7e19)) - - [stability #171] Don't leak unstable plumbing crates in git-repository… ([`71eb30f`](https://github.com/Byron/gitoxide/commit/71eb30f1caa41c1f9fe5d2785b71c9d77922c2af)) - - [stability #171] finish tier description… ([`4fe1259`](https://github.com/Byron/gitoxide/commit/4fe125973304b765f0171deb1c26bca64bbff5d7)) - - [ref #165] refactor ([`66624c3`](https://github.com/Byron/gitoxide/commit/66624c3ef1faf7048ee86ed73cf5f622802c061e)) - - [repository #165] refactor ([`1547d0b`](https://github.com/Byron/gitoxide/commit/1547d0b062e35bad2229dac532e6f30bf105db73)) - - [repository #165] refactor; fine grained allow(missing_docs)… ([`aa0511f`](https://github.com/Byron/gitoxide/commit/aa0511f80f11de8e83fc333e78db369ceb9b2794)) - - [repository #165] prepare for writing light docs for Easy ([`f8834c9`](https://github.com/Byron/gitoxide/commit/f8834c9c8d2ab2ce87857c6773c6204f60df240e)) - - [repository #165] refactor ([`3a0160e`](https://github.com/Byron/gitoxide/commit/3a0160ed1c5bc33d330ad4e9189c4937d194e98d)) - - [repository #165] a sample of a simpler way to create a tag ([`fb8f584`](https://github.com/Byron/gitoxide/commit/fb8f58412cdd32991a182a41cbc0d463127a4e0e)) - - [smart-release #165] Use generic edit-reference functionality ([`be3e57f`](https://github.com/Byron/gitoxide/commit/be3e57f6221dc87505ba1aad1166e28c328c3b54)) - - [repository #165] refactor ([`00ec15d`](https://github.com/Byron/gitoxide/commit/00ec15dcfdb839095e508139d238df384ea418eb)) - - [repository #165] offer panicking type conversions for objects ([`f802f8c`](https://github.com/Byron/gitoxide/commit/f802f8c8c382f8063fa615fda022857a740a974a)) - - [repository #165] try a more common naming convention for fallbile things… ([`fc70393`](https://github.com/Byron/gitoxide/commit/fc703937a078937840ea1c254f11e64aaf31de90)) - - [smart-release #162] use TreeRef capabilities to lookup path ([`51d1943`](https://github.com/Byron/gitoxide/commit/51d19433e6704fabb6547a0ba1b5c32afce43d8b)) - - [repository #162] finally let smart-release use the correct abstraction for peeling ([`ba243a3`](https://github.com/Byron/gitoxide/commit/ba243a35ff6f059e5581c6f7ff80e1253ceca6f8)) - - [repository #162] Add id field to ObjectRef… ([`f5ba98e`](https://github.com/Byron/gitoxide/commit/f5ba98ebd0e1d7d0491871be58476cb6882b8436)) - - [repository #162] experiment with finding objects… ([`312a692`](https://github.com/Byron/gitoxide/commit/312a69256a67a0f9d3f3f5c5f9eaf51b50971c5e)) - - [repository #162] Cannot ever store a RefCell Ref in an object… ([`5c17199`](https://github.com/Byron/gitoxide/commit/5c171995383fa9a3698b6aaf3fbd9537110c0299)) - - [repository #162] experiemnt with optionally keeping data in Object ([`b8a8e08`](https://github.com/Byron/gitoxide/commit/b8a8e08e1d972e5069b136c30407c079825b7e1d)) - - [smart-release #162] Fix short flags ([`08f3418`](https://github.com/Byron/gitoxide/commit/08f3418a0b763b7860d95536446fe615cf361adf)) - - [smart-release #162] don't throw away work… ([`b43b780`](https://github.com/Byron/gitoxide/commit/b43b780c0382683edc859e3fbd27739716a47141)) - - [smart-release #162] refactor ([`7f2421b`](https://github.com/Byron/gitoxide/commit/7f2421bddf7510d1cd6a12fa1457e3e842b38879)) - - [smart-release #162] peeling objects to a certain target kind… ([`5785136`](https://github.com/Byron/gitoxide/commit/57851361f3fc729b964fd0ca5dca9f084fe20f5e)) - - [smart-release #162] a single import path for ReferenceExt ([`7060797`](https://github.com/Byron/gitoxide/commit/7060797031e5bdbb8d635cc2da3269996bdfc4cc)) - - [smart-release #162] replace reference peeling with git_easy ([`7cfd5f9`](https://github.com/Byron/gitoxide/commit/7cfd5f9e0a7f828152594f0393a919617c60a9d6)) - - [smart-release #162] smart-release uses Easy repository in 'plumbing' mode ([`4fb672a`](https://github.com/Byron/gitoxide/commit/4fb672a6e7116722577cbbeeee67887871f583bf)) - - [smart-release #164] improve handling of empty commits ([`bd93fcb`](https://github.com/Byron/gitoxide/commit/bd93fcbbf372099abc1cd3a56cb57105581232ad)) - - [smart-release #164] Make it easier to change a single crate's version only ([`38d28ce`](https://github.com/Byron/gitoxide/commit/38d28ceb1b57da36d59ce0ec418a3dbd9f6fd8fb)) - - [smart-release #162] only warn if there is working tree modifications in dry-run mode… ([`f8ce62f`](https://github.com/Byron/gitoxide/commit/f8ce62fec67845ad89be4bb5482452e9ca7d0035)) - - [smart-release #162] clearer messages ([`aa7417f`](https://github.com/Byron/gitoxide/commit/aa7417fb8ab58761ae31ff926898855c76a8fd9f)) - - Thanks clippy ([`45c5c3c`](https://github.com/Byron/gitoxide/commit/45c5c3cb4679721f296ac72db382b8536f8774c7)) - - [smart-release #162] top-level crate uses version-only tag ([`85e5b1a`](https://github.com/Byron/gitoxide/commit/85e5b1a6e24107f4a26c2b3119c94bbb67fd6068)) - - [smart-release #162] FAIL: single-crate workspaces use version-only tags ([`c5947c4`](https://github.com/Byron/gitoxide/commit/c5947c42eb330bc2cc84889755c461858925cc2e)) - - [smart-release] better --verbosity handling ([`8cccb11`](https://github.com/Byron/gitoxide/commit/8cccb1181e8ad708205524886ac0188ab74da163)) - - [smart-release] properly obtain top-level crate name using manifest ([`d74b32e`](https://github.com/Byron/gitoxide/commit/d74b32eb57c45bef4f6257b4fbe7a9dfc5a41a78)) - - Apply nightly rustfmt rules. ([`5e0edba`](https://github.com/Byron/gitoxide/commit/5e0edbadb39673d4de640f112fa306349fb11814)) -
- -### Thanks Clippy - - - -[Clippy](https://github.com/rust-lang/rust-clippy) helped 1 time to make code idiomatic. - -## v0.2.4 (2021-08-15) - -- Fix auto-push functionality - -### Commit Statistics - - - - - 2 commits contributed to the release. - - 0 commits were understood as [conventional](https://www.conventionalcommits.org). - - 0 issues like '(#ID)' were seen in commit messages - -### Commit Details - - - -
view details - - * **Uncategorized** - - Release cargo-smart-release v0.2.4 ([`19f21a4`](https://github.com/Byron/gitoxide/commit/19f21a4d53c8fcb237ee79c098d39510830806ed)) - - [smart-release #160] fix auto-push issue ([`73051d3`](https://github.com/Byron/gitoxide/commit/73051d3c85a2b0356286deb5da6863e7f9e72b35)) -
- -## v0.2.3 (2021-08-15) - -- Less verbosity by default which is helpful on the first run to get an overview. Use `--verbose/-v` for all the details. -- Also push tags and HEAD by default, unless `--skip-push` is specified. - -### Commit Statistics - - - - - 7 commits contributed to the release. - - 0 commits were understood as [conventional](https://www.conventionalcommits.org). - - 0 issues like '(#ID)' were seen in commit messages - -### Commit Details - - - -
view details - - * **Uncategorized** - - Release cargo-smart-release v0.2.3 ([`f50bac8`](https://github.com/Byron/gitoxide/commit/f50bac894363d008f670d1d0f15a03bdad98b9c2)) - - [smart-release #160] update chnagelog ([`7c4ff64`](https://github.com/Byron/gitoxide/commit/7c4ff64492c584bf5cfa99432aed714c9baeaa9c)) - - [smart-release #160] Add the --skip-push flag… ([`6ebfc85`](https://github.com/Byron/gitoxide/commit/6ebfc854c723799466f2136e77986d1ffb2b6f63)) - - [smart-release #160] Push after creating a single tag ([`6add57f`](https://github.com/Byron/gitoxide/commit/6add57f321610de446f67d1c1395a683660b54a4)) - - [smart-release #160] a seemingly nice '--verbose' mode… ([`bf55679`](https://github.com/Byron/gitoxide/commit/bf55679d973bc4a36faf426d33cd5d91d6783656)) - - Thanks clippy ([`bc7c9a8`](https://github.com/Byron/gitoxide/commit/bc7c9a89c56bf0c6ddb2a9edb2bee6c6aea5b746)) - - [smart-release #160] avoid trying to use an empty path when detecting changes… ([`836324e`](https://github.com/Byron/gitoxide/commit/836324ea67b16dd2dd3dd2f09e6e04c5ae39fb35)) -
- -### Thanks Clippy - - - -[Clippy](https://github.com/rust-lang/rust-clippy) helped 1 time to make code idiomatic. - -## v0.2.2 (2021-08-15) - -- support for unsorted packed-refs files - -### Commit Statistics - - - - - 1 commit contributed to the release. - - 1 day passed between releases. - - 0 commits were understood as [conventional](https://www.conventionalcommits.org). - - 0 issues like '(#ID)' were seen in commit messages - -### Commit Details - - - -
view details - - * **Uncategorized** - - Release cargo-smart-release v0.2.2 ([`f73c729`](https://github.com/Byron/gitoxide/commit/f73c72972abca7ebf7c7ad52c078e3df3157ae7b)) -
- -## v0.2.1 (2021-08-13) - -### Commit Statistics - - - - - 2 commits contributed to the release. - - 0 commits were understood as [conventional](https://www.conventionalcommits.org). - - 0 issues like '(#ID)' were seen in commit messages - -### Commit Details - - - -
view details - - * **Uncategorized** - - Release cargo-smart-release v0.2.1 ([`a3c45de`](https://github.com/Byron/gitoxide/commit/a3c45de6b0e1cc75ab016bf9c3b0bfa7039ba6c7)) - - [smart-release #155] Another note ([`5feb437`](https://github.com/Byron/gitoxide/commit/5feb4379ac400086468b9838c22d95504d0c5ea5)) -
- -## v0.2.0 (2021-08-13) - -### Commit Statistics - - - - - 7 commits contributed to the release. - - 0 commits were understood as [conventional](https://www.conventionalcommits.org). - - 0 issues like '(#ID)' were seen in commit messages - -### Commit Details - - - -
view details - - * **Uncategorized** - - [smart-release #155] how to increase version numbers ([`0bad7b7`](https://github.com/Byron/gitoxide/commit/0bad7b7a20bc4d8d73d6ac0d308c47bcd9368a23)) - - Release cargo-smart-release v0.2.0 ([`b95d7ed`](https://github.com/Byron/gitoxide/commit/b95d7ed464c499694784de153b63461c70f0dbe0)) - - [smart-release #155] keep dependency versions by default ([`4f53287`](https://github.com/Byron/gitoxide/commit/4f5328743c2d5dd80f8f1c17f90c21a7142e45f9)) - - [smart-release #155] fix bug :D ([`3d2a044`](https://github.com/Byron/gitoxide/commit/3d2a044252830c7c6e3092aa36184f5d25a7c855)) - - [smart-release #155] workflow notes and inversion of flag for comfort ([`1ffb66c`](https://github.com/Byron/gitoxide/commit/1ffb66c6f3b8ec199809d0485bcd19d71d879385)) - - Thanks clippy ([`c50bd73`](https://github.com/Byron/gitoxide/commit/c50bd735a3764bcd25d9e312da81bed60c711133)) - - [smart-release #155] inform about latest features ([`133e43a`](https://github.com/Byron/gitoxide/commit/133e43a776403af1115b0f09eb046d02e779e12e)) -
- -### Thanks Clippy - - - -[Clippy](https://github.com/rust-lang/rust-clippy) helped 1 time to make code idiomatic. - -## v0.1.0 (2021-08-13) - -- initial release - -### Thanks Clippy - - - -[Clippy](https://github.com/rust-lang/rust-clippy) helped 2 times to make code idiomatic. - -### Commit Statistics - - - - - 45 commits contributed to the release. - - 0 commits were understood as [conventional](https://www.conventionalcommits.org). - - 0 issues like '(#ID)' were seen in commit messages - -### Commit Details - - - -
view details - - * **Uncategorized** - - [smart-release #155] refactor ([`21192b8`](https://github.com/Byron/gitoxide/commit/21192b899a246e5824b1d5156c4123cab2cc404e)) - - [smart-release #155] prepare release ([`4684557`](https://github.com/Byron/gitoxide/commit/4684557651237ba41e52e648f42efcddd18489d3)) - - [smart-release #155] even smarter bumping ([`1f38680`](https://github.com/Byron/gitoxide/commit/1f38680ada9a33966bef3e5e752b795c0c005224)) - - [smart-release #155] --bump-dependencies only ([`19d87a6`](https://github.com/Byron/gitoxide/commit/19d87a651f9f3a8db89bed533d4c31758f5bfc1f)) - - [smart-release #155] incorporate crates-index for additional version check ([`08bd13d`](https://github.com/Byron/gitoxide/commit/08bd13d7f94390e58ba2516c9328303e023805e5)) - - [smart-release #155] prepare for crates-index; refactor ([`498b6cc`](https://github.com/Byron/gitoxide/commit/498b6cc11f625c60ca7ccc40b014fc6a7d20183d)) - - [smart-release #155] make it an actual depth-first traversal :D ([`b05a21f`](https://github.com/Byron/gitoxide/commit/b05a21f668f8d0ef176b450a160b4def23d3d79b)) - - [smart-release #155] sanity check for dry-run/no-dry-run-cargo-publish ([`2fa7b0b`](https://github.com/Byron/gitoxide/commit/2fa7b0b3053644f1132f1e8689d2f685c4e5b95d)) - - [smart-release #155] update README, add changelog ([`b5dd553`](https://github.com/Byron/gitoxide/commit/b5dd55333b48869c89dd38f437dbba2d217c14d8)) - - Thanks clippy ([`7709ca0`](https://github.com/Byron/gitoxide/commit/7709ca0eeed793825a3b2f3c3fd84e9feff1e494)) - - [smart-release #155] graceful handling of unspecified crate to publish ([`e65b657`](https://github.com/Byron/gitoxide/commit/e65b657300208513f957ad52cedc3af64666cd6d)) - - [smart-release #155] rely only on cargo metadata for root paths ([`217dafb`](https://github.com/Byron/gitoxide/commit/217dafbd2453e079d8da82fb95753b965b359569)) - - [smart-release #155] also ignore provided crate names if they didn't change ([`2110a8c`](https://github.com/Byron/gitoxide/commit/2110a8c3da4266083f2d46e75e8956d212598c86)) - - [smart-release #155] gracefully fail when encountering unknown comparators ([`bee367b`](https://github.com/Byron/gitoxide/commit/bee367bfc816247316dede4b4f638fafa69d0fba)) - - [smart-release #155] don't set versions if the new ones match ([`dd0f428`](https://github.com/Byron/gitoxide/commit/dd0f42848ce9906cdaff3418498f3e42b2c41e2c)) - - [smart-release #155] refactor ([`07dc6d8`](https://github.com/Byron/gitoxide/commit/07dc6d81377b1830b8d1f76118dd9c220516d9fd)) - - [smart-release #155] remove dia-semver ([`07f84c7`](https://github.com/Byron/gitoxide/commit/07f84c76e10b17e36cfaae05b4becfe186e2bebe)) - - [smart-release #155] don't set versions where there are none when fixing manifests ([`a1cc79f`](https://github.com/Byron/gitoxide/commit/a1cc79f4b97182a54d54f6cb8b41b756cd75ff81)) - - [smart-release #155] also find renamed dependencies when updating versions ([`06bc6a9`](https://github.com/Byron/gitoxide/commit/06bc6a9dd0715b0deb158968e62aa216d1902014)) - - [smart-release #155] a note ([`a726225`](https://github.com/Byron/gitoxide/commit/a726225df5967a02776e7caf26d9499ab0cfb262)) - - [smart-release #155] invert meaning of cargo-publish dryrun flag ([`cc57eb8`](https://github.com/Byron/gitoxide/commit/cc57eb8100f4502b0cb9ac0223f37444141884a3)) - - [smart-release #155] allow dry-running cargo publish, too… ([`15e611e`](https://github.com/Byron/gitoxide/commit/15e611e8abb770f4b9c424faf678fbf7e6e541d5)) - - [smart-release #155] allow dry-running cargo-publish, too ([`a3add55`](https://github.com/Byron/gitoxide/commit/a3add5510395e47bddfea3ba9ad4a6e5aeba8ff7)) - - [smart-release #155] Flag to auto-publish dependent stable crates as well ([`bded12f`](https://github.com/Byron/gitoxide/commit/bded12ffd4c92fdb97c320a813a3eccde824c47f)) - - [smart-release #155] don't auto-add stable crates but suggest to do something about it ([`d1dca70`](https://github.com/Byron/gitoxide/commit/d1dca70f5893e4df5bc0fd7ecaffd739d007f1ee)) - - [smart-release #155] refactor ([`8e78e77`](https://github.com/Byron/gitoxide/commit/8e78e77248066f03ff26e8ab1556377f57f6b901)) - - Thanks clippy ([`507cb94`](https://github.com/Byron/gitoxide/commit/507cb94c1be97c6e3c0f15a8142c88291bfe1482)) - - [smart-release #155] refactor ([`fb1fb57`](https://github.com/Byron/gitoxide/commit/fb1fb57230fd8ae3b6b2654d33b4c130478f2781)) - - [smart-release #155] don't rely on cargo resolution order for cyclic case/publish groups ([`7c97fa4`](https://github.com/Byron/gitoxide/commit/7c97fa4eeeb261ec12a93fde5de90d11db1b6e60)) - - [smart-release #155] avoid using cargo resolution order ([`4b7d9d1`](https://github.com/Byron/gitoxide/commit/4b7d9d1704c7236ff343634eb5d120beff6ff18c)) - - [smart-release #155] properly handle multi-crate dependencies (if there is no cycle) ([`e8838a9`](https://github.com/Byron/gitoxide/commit/e8838a97e143f67efe92fd98dc70b868d3ab3487)) - - [smart-release #155] trust our own resolution order more… ([`a977925`](https://github.com/Byron/gitoxide/commit/a977925262f000d2f33a25f80e298d5efce33347)) - - [smart-release #155] refactor ([`0841088`](https://github.com/Byron/gitoxide/commit/0841088f9ca70d727ca221ffb05daf6f5bf7b888)) - - [smart-release #155] don't check cycles on dependencies without version ([`9eeaa2f`](https://github.com/Byron/gitoxide/commit/9eeaa2f11ee063dec88b783d0be2c64902cfe093)) - - [smart-release #155] refactor ([`3f887a7`](https://github.com/Byron/gitoxide/commit/3f887a7f59b8c56a9e4aaa042bbab5f00382d089)) - - [smart-release #155] refactor ([`680675b`](https://github.com/Byron/gitoxide/commit/680675b5a37c1a7ab77357460b8daf2df347a11f)) - - [smart-release #155] refactor ([`20a3aef`](https://github.com/Byron/gitoxide/commit/20a3aef84d480cecaa437a258d23e0904d004cb3)) - - Remove dev-dependency cycles by removing their version ([`c40faca`](https://github.com/Byron/gitoxide/commit/c40faca41632cd2a226daf4ddf5293b65d1fdc82)) - - [smart-release #155] prepare release ([`1330dff`](https://github.com/Byron/gitoxide/commit/1330dff97d6a94e9653c98b0aa4330ea9b441ad1)) - - [smart-release #155] cargo compatibility ([`d432a8e`](https://github.com/Byron/gitoxide/commit/d432a8e95dd88224b3c18cc173035458ef57faea)) - - [smart-release #155] add readme ([`86252eb`](https://github.com/Byron/gitoxide/commit/86252ebb2f1bd8b5430600c09e01516359f4274f)) - - [smart-release #155] --skip-tag flag ([`469de34`](https://github.com/Byron/gitoxide/commit/469de34e19ea25174b7461361e595815d1554343)) - - [smart-release #155] --bump option ([`552d244`](https://github.com/Byron/gitoxide/commit/552d24422e0b4a91bb0cb1f7e98dc101e0e19a5b)) - - [smart-release #155] remove subcommands ([`9f82828`](https://github.com/Byron/gitoxide/commit/9f828280307648be37926c803e19b51ade8dee8b)) - - [smart-release #155] rename from 'utils' ([`a9e6fcc`](https://github.com/Byron/gitoxide/commit/a9e6fccda617ea44eb8593f4da18519eff56bf8c)) -
- diff --git a/cargo-smart-release/Cargo.lock b/cargo-smart-release/Cargo.lock deleted file mode 100644 index 9a99692ac8d..00000000000 --- a/cargo-smart-release/Cargo.lock +++ /dev/null @@ -1,2693 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 3 - -[[package]] -name = "adler" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" - -[[package]] -name = "ahash" -version = "0.8.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c99f64d1e06488f620f932677e24bc6e2897582980441ae90a671415bd7ec2f" -dependencies = [ - "cfg-if", - "getrandom", - "once_cell", - "version_check", -] - -[[package]] -name = "anstream" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ca84f3628370c59db74ee214b3263d58f9aadd9b4fe7e711fd87dc452b7f163" -dependencies = [ - "anstyle", - "anstyle-parse", - "anstyle-query", - "anstyle-wincon", - "colorchoice", - "is-terminal", - "utf8parse", -] - -[[package]] -name = "anstyle" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a30da5c5f2d5e72842e00bcb57657162cdabef0931f40e2deb9b4140440cecd" - -[[package]] -name = "anstyle-parse" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "938874ff5980b03a87c5524b3ae5b59cf99b1d6bc836848df7bc5ada9643c333" -dependencies = [ - "utf8parse", -] - -[[package]] -name = "anstyle-query" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ca11d4be1bab0c8bc8734a9aa7bf4ee8316d462a08c6ac5052f888fef5b494b" -dependencies = [ - "windows-sys 0.48.0", -] - -[[package]] -name = "anstyle-wincon" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "180abfa45703aebe0093f79badacc01b8fd4ea2e35118747e5811127f926e188" -dependencies = [ - "anstyle", - "windows-sys 0.48.0", -] - -[[package]] -name = "anyhow" -version = "1.0.72" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b13c32d80ecc7ab747b80c3784bce54ee8a7a0cc4fbda9bf4cda2cf6fe90854" - -[[package]] -name = "arc-swap" -version = "1.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bddcadddf5e9015d310179a59bb28c4d4b9920ad0f11e8e14dbadf654890c9a6" - -[[package]] -name = "arrayvec" -version = "0.7.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711" - -[[package]] -name = "autocfg" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" - -[[package]] -name = "base64" -version = "0.21.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "604178f6c5c21f02dc555784810edfb88d34ac2c73b2eae109655649ee73ce3d" - -[[package]] -name = "bitflags" -version = "1.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" - -[[package]] -name = "bitflags" -version = "2.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "630be753d4e58660abd17930c71b647fe46c27ea6b63cc59e1e3851406972e42" - -[[package]] -name = "block-buffer" -version = "0.10.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" -dependencies = [ - "generic-array", -] - -[[package]] -name = "bstr" -version = "1.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6798148dccfbff0fae41c7574d2fa8f1ef3492fba0face179de5d8d447d67b05" -dependencies = [ - "memchr", - "regex-automata", - "serde", -] - -[[package]] -name = "btoi" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9dd6407f73a9b8b6162d8a2ef999fe6afd7cc15902ebf42c5cd296addf17e0ad" -dependencies = [ - "num-traits", -] - -[[package]] -name = "bytes" -version = "1.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89b2fd2a0dcf38d7971e2194b6b6eebab45ae01067456a7fd93d5547a61b70be" - -[[package]] -name = "camino" -version = "1.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c59e92b5a388f549b863a7bea62612c09f24c8393560709a54558a9abdfb3b9c" -dependencies = [ - "serde", -] - -[[package]] -name = "cargo-platform" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2cfa25e60aea747ec7e1124f238816749faa93759c6ff5b31f1ccdda137f4479" -dependencies = [ - "serde", -] - -[[package]] -name = "cargo-smart-release" -version = "0.20.0" -dependencies = [ - "anyhow", - "bitflags 2.3.3", - "cargo_metadata", - "cargo_toml", - "clap", - "crates-index", - "env_logger", - "git-conventional", - "gix", - "gix-testtools", - "insta", - "log", - "pulldown-cmark", - "semver", - "time", - "toml_edit", - "winnow", -] - -[[package]] -name = "cargo_metadata" -version = "0.17.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7daec1a2a2129eeba1644b220b4647ec537b0b5d4bfd6876fcc5a540056b592" -dependencies = [ - "camino", - "cargo-platform", - "semver", - "serde", - "serde_json", - "thiserror", -] - -[[package]] -name = "cargo_toml" -version = "0.15.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "599aa35200ffff8f04c1925aa1acc92fa2e08874379ef42e210a80e527e60838" -dependencies = [ - "serde", - "toml", -] - -[[package]] -name = "cc" -version = "1.0.79" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f" - -[[package]] -name = "cfg-if" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" - -[[package]] -name = "clap" -version = "4.3.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5fd304a20bff958a57f04c4e96a2e7594cc4490a0e809cbd48bb6437edaa452d" -dependencies = [ - "clap_builder", - "clap_derive", - "once_cell", -] - -[[package]] -name = "clap_builder" -version = "4.3.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01c6a3f08f1fe5662a35cfe393aec09c4df95f60ee93b7556505260f75eee9e1" -dependencies = [ - "anstream", - "anstyle", - "clap_lex", - "once_cell", - "strsim", -] - -[[package]] -name = "clap_derive" -version = "4.3.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "54a9bb5758fc5dfe728d1019941681eccaf0cf8a4189b692a0ee2f2ecf90a050" -dependencies = [ - "heck", - "proc-macro2", - "quote", - "syn 2.0.27", -] - -[[package]] -name = "clap_lex" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2da6da31387c7e4ef160ffab6d5e7f00c42626fe39aea70a7b0f1773f7dd6c1b" - -[[package]] -name = "clru" -version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8191fa7302e03607ff0e237d4246cc043ff5b3cb9409d995172ba3bea16b807" - -[[package]] -name = "cmake" -version = "0.1.50" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a31c789563b815f77f4250caee12365734369f942439b7defd71e18a48197130" -dependencies = [ - "cc", -] - -[[package]] -name = "colorchoice" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7" - -[[package]] -name = "console" -version = "0.15.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c926e00cc70edefdc64d3a5ff31cc65bb97a3460097762bd23afb4d8145fccf8" -dependencies = [ - "encode_unicode", - "lazy_static", - "libc", - "windows-sys 0.45.0", -] - -[[package]] -name = "cpufeatures" -version = "0.2.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a17b76ff3a4162b0b27f354a0c87015ddad39d35f9c0c36607a3bdd175dde1f1" -dependencies = [ - "libc", -] - -[[package]] -name = "crates-index" -version = "2.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2d899e96f67edf44af465951d34f354c7bc04d10a42b813537cd70d62dfbb50" -dependencies = [ - "gix", - "hex", - "home", - "memchr", - "rustc-hash", - "semver", - "serde", - "serde_derive", - "serde_json", - "smol_str", - "thiserror", - "toml", -] - -[[package]] -name = "crc" -version = "3.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86ec7a15cbe22e59248fc7eadb1907dab5ba09372595da4d73dd805ed4417dfe" -dependencies = [ - "crc-catalog", -] - -[[package]] -name = "crc-catalog" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9cace84e55f07e7301bae1c519df89cdad8cc3cd868413d3fdbdeca9ff3db484" - -[[package]] -name = "crc32fast" -version = "1.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d" -dependencies = [ - "cfg-if", -] - -[[package]] -name = "crossbeam" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2801af0d36612ae591caa9568261fddce32ce6e08a7275ea334a06a4ad021a2c" -dependencies = [ - "cfg-if", - "crossbeam-channel", - "crossbeam-deque", - "crossbeam-epoch", - "crossbeam-queue", - "crossbeam-utils", -] - -[[package]] -name = "crossbeam-channel" -version = "0.5.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a33c2bf77f2df06183c3aa30d1e96c0695a313d4f9c453cc3762a6db39f99200" -dependencies = [ - "cfg-if", - "crossbeam-utils", -] - -[[package]] -name = "crossbeam-deque" -version = "0.8.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce6fd6f855243022dcecf8702fef0c297d4338e226845fe067f6341ad9fa0cef" -dependencies = [ - "cfg-if", - "crossbeam-epoch", - "crossbeam-utils", -] - -[[package]] -name = "crossbeam-epoch" -version = "0.9.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae211234986c545741a7dc064309f67ee1e5ad243d0e48335adc0484d960bcc7" -dependencies = [ - "autocfg", - "cfg-if", - "crossbeam-utils", - "memoffset", - "scopeguard", -] - -[[package]] -name = "crossbeam-queue" -version = "0.3.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d1cfb3ea8a53f37c40dea2c7bedcbd88bdfae54f5e2175d6ecaff1c988353add" -dependencies = [ - "cfg-if", - "crossbeam-utils", -] - -[[package]] -name = "crossbeam-utils" -version = "0.8.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a22b2d63d4d1dc0b7f1b6b2747dd0088008a9be28b6ddf0b1e7d335e3037294" -dependencies = [ - "cfg-if", -] - -[[package]] -name = "crypto-common" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" -dependencies = [ - "generic-array", - "typenum", -] - -[[package]] -name = "curl" -version = "0.4.44" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "509bd11746c7ac09ebd19f0b17782eae80aadee26237658a6b4808afb5c11a22" -dependencies = [ - "curl-sys", - "libc", - "openssl-probe", - "openssl-sys", - "schannel", - "socket2", - "winapi", -] - -[[package]] -name = "curl-sys" -version = "0.4.65+curl-8.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "961ba061c9ef2fe34bbd12b807152d96f0badd2bebe7b90ce6c8c8b7572a0986" -dependencies = [ - "cc", - "libc", - "libz-sys", - "openssl-sys", - "pkg-config", - "vcpkg", - "winapi", -] - -[[package]] -name = "digest" -version = "0.10.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" -dependencies = [ - "block-buffer", - "crypto-common", -] - -[[package]] -name = "doc-comment" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fea41bba32d969b513997752735605054bc0dfa92b4c56bf1189f2e174be7a10" - -[[package]] -name = "dunce" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56ce8c6da7551ec6c462cbaf3bfbc75131ebbfa1c944aeaa9dab51ca1c5f0c3b" - -[[package]] -name = "either" -version = "1.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07" - -[[package]] -name = "encode_unicode" -version = "0.3.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f" - -[[package]] -name = "encoding_rs" -version = "0.8.32" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "071a31f4ee85403370b58aca746f01041ede6f0da2730960ad001edc2b71b394" -dependencies = [ - "cfg-if", -] - -[[package]] -name = "env_logger" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85cdab6a89accf66733ad5a1693a4dcced6aeff64602b634530dd73c1f3ee9f0" -dependencies = [ - "humantime", - "is-terminal", - "log", - "termcolor", -] - -[[package]] -name = "equivalent" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" - -[[package]] -name = "errno" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4bcfec3a70f97c962c307b2d2c56e358cf1d00b558d74262b5f929ee8cc7e73a" -dependencies = [ - "errno-dragonfly", - "libc", - "windows-sys 0.48.0", -] - -[[package]] -name = "errno-dragonfly" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf" -dependencies = [ - "cc", - "libc", -] - -[[package]] -name = "fastrand" -version = "1.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e51093e27b0797c359783294ca4f0a911c270184cb10f85783b118614a1501be" -dependencies = [ - "instant", -] - -[[package]] -name = "fastrand" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6999dc1837253364c2ebb0704ba97994bd874e8f195d665c50b7548f6ea92764" - -[[package]] -name = "filetime" -version = "0.2.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5cbc844cecaee9d4443931972e1289c8ff485cb4cc2767cb03ca139ed6885153" -dependencies = [ - "cfg-if", - "libc", - "redox_syscall 0.2.16", - "windows-sys 0.48.0", -] - -[[package]] -name = "flate2" -version = "1.0.26" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b9429470923de8e8cbd4d2dc513535400b4b3fef0319fb5c4e1f520a7bef743" -dependencies = [ - "crc32fast", - "libz-ng-sys", - "miniz_oxide", -] - -[[package]] -name = "form_urlencoded" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a62bc1cf6f830c2ec14a513a9fb124d0a213a629668a4186f329db21fe045652" -dependencies = [ - "percent-encoding", -] - -[[package]] -name = "fs_extra" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42703706b716c37f96a77aea830392ad231f44c9e9a67872fa5548707e11b11c" - -[[package]] -name = "generic-array" -version = "0.14.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" -dependencies = [ - "typenum", - "version_check", -] - -[[package]] -name = "getopts" -version = "0.2.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14dbbfd5c71d70241ecf9e6f13737f7b5ce823821063188d7e46c41d371eebd5" -dependencies = [ - "unicode-width", -] - -[[package]] -name = "getrandom" -version = "0.2.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427" -dependencies = [ - "cfg-if", - "libc", - "wasi", -] - -[[package]] -name = "git-conventional" -version = "0.12.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b3db1aca6f1a2607dd99beed5d99df831ac73eae5994ff301dae712928e2dac" -dependencies = [ - "doc-comment", - "unicase", - "winnow", -] - -[[package]] -name = "gix" -version = "0.50.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "275b1bfa0d6f6ed31a2e2e878a4539f4994eac8840546283ab3aebbd8fcaa42d" -dependencies = [ - "gix-actor 0.24.1", - "gix-attributes 0.16.0", - "gix-commitgraph", - "gix-config", - "gix-credentials", - "gix-date 0.7.1", - "gix-diff", - "gix-discover 0.22.1", - "gix-features 0.32.1", - "gix-filter", - "gix-fs 0.4.1", - "gix-glob 0.10.1", - "gix-hash", - "gix-hashtable", - "gix-ignore 0.5.1", - "gix-index 0.21.1", - "gix-lock 7.0.2", - "gix-mailmap", - "gix-negotiate", - "gix-object 0.33.1", - "gix-odb", - "gix-pack", - "gix-path", - "gix-prompt", - "gix-protocol", - "gix-ref 0.33.2", - "gix-refspec", - "gix-revision", - "gix-sec", - "gix-tempfile 7.0.2", - "gix-trace", - "gix-transport", - "gix-traverse 0.30.1", - "gix-url", - "gix-utils", - "gix-validate", - "gix-worktree 0.23.0", - "log", - "once_cell", - "signal-hook", - "smallvec", - "thiserror", - "unicode-normalization", -] - -[[package]] -name = "gix-actor" -version = "0.20.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "848efa0f1210cea8638f95691c82a46f98a74b9e3524f01d4955ebc25a8f84f3" -dependencies = [ - "bstr", - "btoi", - "gix-date 0.5.1", - "itoa", - "nom", - "thiserror", -] - -[[package]] -name = "gix-actor" -version = "0.24.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7606482631d56cc6bfba3394ae42fc64927635024298befbb7923b6144774e8" -dependencies = [ - "bstr", - "btoi", - "gix-date 0.7.1", - "itoa", - "nom", - "thiserror", -] - -[[package]] -name = "gix-attributes" -version = "0.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3015baa01ad2122fbcaab7863c857a603eb7b7ec12ac8141207c42c6439805e2" -dependencies = [ - "bstr", - "gix-glob 0.7.0", - "gix-path", - "gix-quote", - "kstring", - "log", - "smallvec", - "thiserror", - "unicode-bom", -] - -[[package]] -name = "gix-attributes" -version = "0.16.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "63a134a674e39e238bd273326a9815296cc71f867ad5466518da71392cff98ce" -dependencies = [ - "bstr", - "gix-glob 0.10.1", - "gix-path", - "gix-quote", - "kstring", - "log", - "smallvec", - "thiserror", - "unicode-bom", -] - -[[package]] -name = "gix-bitmap" -version = "0.2.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0aa8bbde7551a9e3e783a2871f53bbb0f50aac7a77db5680c8709f69e8ce724f" -dependencies = [ - "thiserror", -] - -[[package]] -name = "gix-chunk" -version = "0.4.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b42ea64420f7994000130328f3c7a2038f639120518870436d31b8bde704493" -dependencies = [ - "thiserror", -] - -[[package]] -name = "gix-command" -version = "0.2.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2783ad148fb16bf9cfd46423706ba552a62a4d4a18fda5dd07648eb0228862dd" -dependencies = [ - "bstr", -] - -[[package]] -name = "gix-commitgraph" -version = "0.18.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4c2d5ce99eba59fe9477a9e3037b0e1d0266d53925cc4b322bc06c566589b99" -dependencies = [ - "bstr", - "gix-chunk", - "gix-features 0.32.1", - "gix-hash", - "memmap2 0.7.1", - "thiserror", -] - -[[package]] -name = "gix-config" -version = "0.26.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b51e83bd9d08118e0ff06ea14be953c418b4c056e57d93c8103e777584e48b0a" -dependencies = [ - "bstr", - "gix-config-value", - "gix-features 0.32.1", - "gix-glob 0.10.1", - "gix-path", - "gix-ref 0.33.2", - "gix-sec", - "log", - "memchr", - "nom", - "once_cell", - "smallvec", - "thiserror", - "unicode-bom", -] - -[[package]] -name = "gix-config-value" -version = "0.12.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e874f41437441c02991dcea76990b9058fadfc54b02ab4dd06ab2218af43897" -dependencies = [ - "bitflags 2.3.3", - "bstr", - "gix-path", - "libc", - "thiserror", -] - -[[package]] -name = "gix-credentials" -version = "0.17.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "307d91ec5f7c8e9bfaa217fe30c2e0099101cbe83dbed27a222dbb6def38725f" -dependencies = [ - "bstr", - "gix-command", - "gix-config-value", - "gix-path", - "gix-prompt", - "gix-sec", - "gix-url", - "thiserror", -] - -[[package]] -name = "gix-date" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc164145670e9130a60a21670d9b6f0f4f8de04e5dd256c51fa5a0340c625902" -dependencies = [ - "bstr", - "itoa", - "thiserror", - "time", -] - -[[package]] -name = "gix-date" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56b0312dba1ad003d9b8c502bed52fbcf106f8de3a9a26bfa7b45642a6f94b72" -dependencies = [ - "bstr", - "itoa", - "thiserror", - "time", -] - -[[package]] -name = "gix-diff" -version = "0.33.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a49d7a9a9ed5ec3428c3061da45d0fc5f50b3c07b91ea4e7ec4959668f25f6c" -dependencies = [ - "gix-hash", - "gix-object 0.33.1", - "imara-diff", - "thiserror", -] - -[[package]] -name = "gix-discover" -version = "0.18.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a6b61363e63e7cdaa3e6f96acb0257ebdb3d8883e21eba5930c99f07f0a5fc0" -dependencies = [ - "bstr", - "dunce", - "gix-hash", - "gix-path", - "gix-ref 0.29.1", - "gix-sec", - "thiserror", -] - -[[package]] -name = "gix-discover" -version = "0.22.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "041480eb03d8aa0894d9b73d25d182d51bc4d0ea8925a6ee0c971262bbc7715e" -dependencies = [ - "bstr", - "dunce", - "gix-hash", - "gix-path", - "gix-ref 0.33.2", - "gix-sec", - "thiserror", -] - -[[package]] -name = "gix-features" -version = "0.29.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf69b0f5c701cc3ae22d3204b671907668f6437ca88862d355eaf9bc47a4f897" -dependencies = [ - "gix-hash", - "libc", - "prodash 23.1.2", - "sha1_smol", - "walkdir", -] - -[[package]] -name = "gix-features" -version = "0.32.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "882695cccf38da4c3cc7ee687bdb412cf25e37932d7f8f2c306112ea712449f1" -dependencies = [ - "bytes", - "crc32fast", - "crossbeam-channel", - "flate2", - "gix-hash", - "gix-trace", - "jwalk", - "libc", - "once_cell", - "parking_lot", - "prodash 25.0.1", - "sha1", - "sha1_smol", - "thiserror", - "walkdir", -] - -[[package]] -name = "gix-filter" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef4d4d61f2ab07de4612f8e078d7f1a443c7ab5c40f382784c8eacdf0fd172b9" -dependencies = [ - "bstr", - "encoding_rs", - "gix-attributes 0.16.0", - "gix-command", - "gix-hash", - "gix-object 0.33.1", - "gix-packetline-blocking", - "gix-path", - "gix-quote", - "gix-trace", - "smallvec", - "thiserror", -] - -[[package]] -name = "gix-fs" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b37a1832f691fdc09910bd267f9a2e413737c1f9ec68c6e31f9e802616278a9" -dependencies = [ - "gix-features 0.29.0", -] - -[[package]] -name = "gix-fs" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d5b6e9d34a2c61ea4a02bbca94c409ab6dbbca1348cbb67298cd7fed8758761" -dependencies = [ - "gix-features 0.32.1", -] - -[[package]] -name = "gix-glob" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c07c98204529ac3f24b34754540a852593d2a4c7349008df389240266627a72a" -dependencies = [ - "bitflags 2.3.3", - "bstr", - "gix-features 0.29.0", - "gix-path", -] - -[[package]] -name = "gix-glob" -version = "0.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7c79b881a18d89a75876ba277476d5a2bad5b19f03759c7a07e0808dfe08212" -dependencies = [ - "bitflags 2.3.3", - "bstr", - "gix-features 0.32.1", - "gix-path", -] - -[[package]] -name = "gix-hash" -version = "0.11.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b422ff2ad9a0628baaad6da468cf05385bf3f5ab495ad5a33cce99b9f41092f" -dependencies = [ - "hex", - "thiserror", -] - -[[package]] -name = "gix-hashtable" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "385f4ce6ecf3692d313ca3aa9bd3b3d8490de53368d6d94bedff3af8b6d9c58d" -dependencies = [ - "gix-hash", - "hashbrown 0.14.0", - "parking_lot", -] - -[[package]] -name = "gix-ignore" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba205b6df563e2906768bb22834c82eb46c5fdfcd86ba2c347270bc8309a05b2" -dependencies = [ - "bstr", - "gix-glob 0.7.0", - "gix-path", - "unicode-bom", -] - -[[package]] -name = "gix-ignore" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a88b95ceb3bc45abcab6eb55ef4e0053e58b4df0712d3f9aec7d0ca990952603" -dependencies = [ - "bstr", - "gix-glob 0.10.1", - "gix-path", - "unicode-bom", -] - -[[package]] -name = "gix-index" -version = "0.16.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f39c1ccc8f1912cbbd5191efc28dbc5f0d0598042aa56bc09427b7c34efab3ba" -dependencies = [ - "bitflags 2.3.3", - "bstr", - "btoi", - "filetime", - "gix-bitmap", - "gix-features 0.29.0", - "gix-hash", - "gix-lock 5.0.1", - "gix-object 0.29.2", - "gix-traverse 0.25.0", - "itoa", - "memmap2 0.5.10", - "smallvec", - "thiserror", -] - -[[package]] -name = "gix-index" -version = "0.21.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "732f61ec71576bd443a3c24f4716dc7eac180d8929e7bb8603c7310161507106" -dependencies = [ - "bitflags 2.3.3", - "bstr", - "btoi", - "filetime", - "gix-bitmap", - "gix-features 0.32.1", - "gix-fs 0.4.1", - "gix-hash", - "gix-lock 7.0.2", - "gix-object 0.33.1", - "gix-traverse 0.30.1", - "itoa", - "memmap2 0.7.1", - "smallvec", - "thiserror", -] - -[[package]] -name = "gix-lock" -version = "5.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c693d7f05730fa74a7c467150adc7cea393518410c65f0672f80226b8111555" -dependencies = [ - "gix-tempfile 5.0.3", - "gix-utils", - "thiserror", -] - -[[package]] -name = "gix-lock" -version = "7.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e82ec23c8a281f91044bf3ed126063b91b59f9c9340bf0ae746f385cc85a6fa" -dependencies = [ - "gix-tempfile 7.0.2", - "gix-utils", - "thiserror", -] - -[[package]] -name = "gix-mailmap" -version = "0.16.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fc0dbbf35d29639770af68d7ff55924d83786c8924b0e6a1766af1a98b7d58b" -dependencies = [ - "bstr", - "gix-actor 0.24.1", - "gix-date 0.7.1", - "thiserror", -] - -[[package]] -name = "gix-negotiate" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce0061b7ae867e830c77b1ecfc5875f0d042aebb3d7e6014d04fd86ca6c71d59" -dependencies = [ - "bitflags 2.3.3", - "gix-commitgraph", - "gix-date 0.7.1", - "gix-hash", - "gix-object 0.33.1", - "gix-revwalk", - "smallvec", - "thiserror", -] - -[[package]] -name = "gix-object" -version = "0.29.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d96bd620fd08accdd37f70b2183cfa0b001b4f1c6ade8b7f6e15cb3d9e261ce" -dependencies = [ - "bstr", - "btoi", - "gix-actor 0.20.0", - "gix-features 0.29.0", - "gix-hash", - "gix-validate", - "hex", - "itoa", - "nom", - "smallvec", - "thiserror", -] - -[[package]] -name = "gix-object" -version = "0.33.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70f18b688854af4440695b943e705877f94171325b8bcacaee2d898ecf2766d2" -dependencies = [ - "bstr", - "btoi", - "gix-actor 0.24.1", - "gix-date 0.7.1", - "gix-features 0.32.1", - "gix-hash", - "gix-validate", - "hex", - "itoa", - "nom", - "smallvec", - "thiserror", -] - -[[package]] -name = "gix-odb" -version = "0.50.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7dc2129d25313b594adfb5a71f2a617aaa2c3c4cfd3b2943823692db12fbc1db" -dependencies = [ - "arc-swap", - "gix-date 0.7.1", - "gix-features 0.32.1", - "gix-hash", - "gix-object 0.33.1", - "gix-pack", - "gix-path", - "gix-quote", - "parking_lot", - "tempfile", - "thiserror", -] - -[[package]] -name = "gix-pack" -version = "0.40.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46f029a4dce9ac91da35c968c3abdcae573b3e52c123be86cbab3011599de533" -dependencies = [ - "clru", - "gix-chunk", - "gix-diff", - "gix-features 0.32.1", - "gix-hash", - "gix-hashtable", - "gix-object 0.33.1", - "gix-path", - "gix-tempfile 7.0.2", - "gix-traverse 0.30.1", - "memmap2 0.7.1", - "parking_lot", - "smallvec", - "thiserror", - "uluru", -] - -[[package]] -name = "gix-packetline" -version = "0.16.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb532b34627186a9a2705a360f64f6a8feb34c42344b127f9f230687d85358bd" -dependencies = [ - "bstr", - "hex", - "thiserror", -] - -[[package]] -name = "gix-packetline-blocking" -version = "0.16.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "20276373def40fc3be7a86d09e1bb607d33dd6bf83e3504e83cd594e51438667" -dependencies = [ - "bstr", - "hex", - "thiserror", -] - -[[package]] -name = "gix-path" -version = "0.8.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18609c8cbec8508ea97c64938c33cd305b75dfc04a78d0c3b78b8b3fd618a77c" -dependencies = [ - "bstr", - "gix-trace", - "home", - "once_cell", - "thiserror", -] - -[[package]] -name = "gix-prompt" -version = "0.5.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f755e8eb83ee9a06642a8fbd3009b033db2b5bd774f3aaf3de0b07f9b6ebdc5" -dependencies = [ - "gix-command", - "gix-config-value", - "parking_lot", - "rustix", - "thiserror", -] - -[[package]] -name = "gix-protocol" -version = "0.36.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f8cf8b48ad5510a6ea3c8b529f51fd0f31009a2e46579f3a0ed917669035170" -dependencies = [ - "bstr", - "btoi", - "gix-credentials", - "gix-date 0.7.1", - "gix-features 0.32.1", - "gix-hash", - "gix-transport", - "maybe-async", - "nom", - "thiserror", -] - -[[package]] -name = "gix-quote" -version = "0.4.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfd80d3d0c733508df9449b1d3795da36083807e31d851d7d61d29af13bd4b0a" -dependencies = [ - "bstr", - "btoi", - "thiserror", -] - -[[package]] -name = "gix-ref" -version = "0.29.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e03989e9d49954368e1b526578230fc7189d1634acdfbe79e9ba1de717e15d5" -dependencies = [ - "gix-actor 0.20.0", - "gix-features 0.29.0", - "gix-fs 0.1.1", - "gix-hash", - "gix-lock 5.0.1", - "gix-object 0.29.2", - "gix-path", - "gix-tempfile 5.0.3", - "gix-validate", - "memmap2 0.5.10", - "nom", - "thiserror", -] - -[[package]] -name = "gix-ref" -version = "0.33.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c16776eab78f4a918464064fa9c0f640014e8f1c3f9d1d366e929251c7193b2c" -dependencies = [ - "gix-actor 0.24.1", - "gix-date 0.7.1", - "gix-features 0.32.1", - "gix-fs 0.4.1", - "gix-hash", - "gix-lock 7.0.2", - "gix-object 0.33.1", - "gix-path", - "gix-tempfile 7.0.2", - "gix-validate", - "memmap2 0.7.1", - "nom", - "thiserror", -] - -[[package]] -name = "gix-refspec" -version = "0.14.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d19a02bf740b326d6c082a7d6f754ebe56eef900986c5e91be7cf000df9ea18d" -dependencies = [ - "bstr", - "gix-hash", - "gix-revision", - "gix-validate", - "smallvec", - "thiserror", -] - -[[package]] -name = "gix-revision" -version = "0.18.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38a13500890435e3b9e7746bceda248646bfc69e259210884c98e29bb7a1aa6f" -dependencies = [ - "bstr", - "gix-date 0.7.1", - "gix-hash", - "gix-hashtable", - "gix-object 0.33.1", - "gix-revwalk", - "thiserror", -] - -[[package]] -name = "gix-revwalk" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "71d4cbaf3cfbfde2b81b5ee8b469aff42c34693ce0fe17fc3c244d5085307f2c" -dependencies = [ - "gix-commitgraph", - "gix-date 0.7.1", - "gix-hash", - "gix-hashtable", - "gix-object 0.33.1", - "smallvec", - "thiserror", -] - -[[package]] -name = "gix-sec" -version = "0.8.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9615cbd6b456898aeb942cd75e5810c382fbfc48dbbff2fa23ebd2d33dcbe9c7" -dependencies = [ - "bitflags 2.3.3", - "gix-path", - "libc", - "windows", -] - -[[package]] -name = "gix-tempfile" -version = "5.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d71a0d32f34e71e86586124225caefd78dabc605d0486de580d717653addf182" -dependencies = [ - "gix-fs 0.1.1", - "libc", - "once_cell", - "parking_lot", - "signal-hook", - "signal-hook-registry", - "tempfile", -] - -[[package]] -name = "gix-tempfile" -version = "7.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa28d567848cec8fdd77d36ad4f5f78ecfaba7d78f647d4f63c8ae1a2cec7243" -dependencies = [ - "gix-fs 0.4.1", - "libc", - "once_cell", - "parking_lot", - "signal-hook", - "signal-hook-registry", - "tempfile", -] - -[[package]] -name = "gix-testtools" -version = "0.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94b97758c4cf4671353e423696e8019c42a564f369edbf7d0d30d2c93a8e268a" -dependencies = [ - "bstr", - "crc", - "fastrand 1.9.0", - "fs_extra", - "gix-discover 0.18.1", - "gix-fs 0.1.1", - "gix-ignore 0.2.0", - "gix-lock 5.0.1", - "gix-tempfile 5.0.3", - "gix-worktree 0.17.1", - "io-close", - "is_ci", - "nom", - "once_cell", - "parking_lot", - "tar", - "tempfile", - "xz2", -] - -[[package]] -name = "gix-trace" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96b6d623a1152c3facb79067d6e2ecdae48130030cf27d6eb21109f13bd7b836" - -[[package]] -name = "gix-transport" -version = "0.34.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "99fffe5a95a522200ad47b97c19c9b0c204fc415dffa4a993d727394e6d59ef8" -dependencies = [ - "base64", - "bstr", - "curl", - "gix-command", - "gix-credentials", - "gix-features 0.32.1", - "gix-packetline", - "gix-quote", - "gix-sec", - "gix-url", - "thiserror", -] - -[[package]] -name = "gix-traverse" -version = "0.25.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a5be1e807f288c33bb005075111886cceb43ed8a167b3182a0f62c186e2a0dd1" -dependencies = [ - "gix-hash", - "gix-hashtable", - "gix-object 0.29.2", - "thiserror", -] - -[[package]] -name = "gix-traverse" -version = "0.30.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e12e0fe428394226c37dd686ad64b09a04b569fe157d638b125b4a4c1e7e2df0" -dependencies = [ - "gix-commitgraph", - "gix-date 0.7.1", - "gix-hash", - "gix-hashtable", - "gix-object 0.33.1", - "gix-revwalk", - "smallvec", - "thiserror", -] - -[[package]] -name = "gix-url" -version = "0.21.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4411bdbd1d46b35ae50e84c191660d437f89974e4236627785024be0b577170a" -dependencies = [ - "bstr", - "gix-features 0.32.1", - "gix-path", - "home", - "thiserror", - "url", -] - -[[package]] -name = "gix-utils" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b85d89dc728613e26e0ed952a19583744e7f5240fcd4aa30d6c824ffd8b52f0f" -dependencies = [ - "fastrand 2.0.0", -] - -[[package]] -name = "gix-validate" -version = "0.7.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba9b3737b2cef3dcd014633485f0034b0f1a931ee54aeb7d8f87f177f3c89040" -dependencies = [ - "bstr", - "thiserror", -] - -[[package]] -name = "gix-worktree" -version = "0.17.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a69eaff0ae973a9d37c40f02ae5ae50fa726c8fc2fd3ab79d0a19eb61975aafa" -dependencies = [ - "bstr", - "filetime", - "gix-attributes 0.12.0", - "gix-features 0.29.0", - "gix-fs 0.1.1", - "gix-glob 0.7.0", - "gix-hash", - "gix-ignore 0.2.0", - "gix-index 0.16.1", - "gix-object 0.29.2", - "gix-path", - "io-close", - "thiserror", -] - -[[package]] -name = "gix-worktree" -version = "0.23.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fd60b32d15287aef77e4fb1955627e0db1f13e40bf9a3481100223a51791f5f" -dependencies = [ - "bstr", - "filetime", - "gix-attributes 0.16.0", - "gix-features 0.32.1", - "gix-filter", - "gix-fs 0.4.1", - "gix-glob 0.10.1", - "gix-hash", - "gix-ignore 0.5.1", - "gix-index 0.21.1", - "gix-object 0.33.1", - "gix-path", - "io-close", - "thiserror", -] - -[[package]] -name = "hashbrown" -version = "0.12.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" - -[[package]] -name = "hashbrown" -version = "0.14.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c6201b9ff9fd90a5a3bac2e56a830d0caa509576f0e503818ee82c181b3437a" - -[[package]] -name = "heck" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" - -[[package]] -name = "hermit-abi" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "443144c8cdadd93ebf52ddb4056d257f5b52c04d3c804e657d19eb73fc33668b" - -[[package]] -name = "hex" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" -dependencies = [ - "serde", -] - -[[package]] -name = "home" -version = "0.5.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5444c27eef6923071f7ebcc33e3444508466a76f7a2b93da00ed6e19f30c1ddb" -dependencies = [ - "windows-sys 0.48.0", -] - -[[package]] -name = "humantime" -version = "2.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" - -[[package]] -name = "idna" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d20d6b07bfbc108882d88ed8e37d39636dcc260e15e30c45e6ba089610b917c" -dependencies = [ - "unicode-bidi", - "unicode-normalization", -] - -[[package]] -name = "imara-diff" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e98c1d0ad70fc91b8b9654b1f33db55e59579d3b3de2bffdced0fdb810570cb8" -dependencies = [ - "ahash", - "hashbrown 0.12.3", -] - -[[package]] -name = "indexmap" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d5477fe2230a79769d8dc68e0eabf5437907c0457a5614a9e8dddb67f65eb65d" -dependencies = [ - "equivalent", - "hashbrown 0.14.0", -] - -[[package]] -name = "insta" -version = "1.31.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a0770b0a3d4c70567f0d58331f3088b0e4c4f56c9b8d764efe654b4a5d46de3a" -dependencies = [ - "console", - "lazy_static", - "linked-hash-map", - "similar", - "yaml-rust", -] - -[[package]] -name = "instant" -version = "0.1.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" -dependencies = [ - "cfg-if", -] - -[[package]] -name = "io-close" -version = "0.3.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9cadcf447f06744f8ce713d2d6239bb5bde2c357a452397a9ed90c625da390bc" -dependencies = [ - "libc", - "winapi", -] - -[[package]] -name = "is-terminal" -version = "0.4.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb0889898416213fab133e1d33a0e5858a48177452750691bde3666d0fdbaf8b" -dependencies = [ - "hermit-abi", - "rustix", - "windows-sys 0.48.0", -] - -[[package]] -name = "is_ci" -version = "1.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "616cde7c720bb2bb5824a224687d8f77bfd38922027f01d825cd7453be5099fb" - -[[package]] -name = "itoa" -version = "1.0.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38" - -[[package]] -name = "jwalk" -version = "0.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2735847566356cd2179a2a38264839308f7079fa96e6bd5a42d740460e003c56" -dependencies = [ - "crossbeam", - "rayon", -] - -[[package]] -name = "kstring" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec3066350882a1cd6d950d055997f379ac37fd39f81cd4d8ed186032eb3c5747" -dependencies = [ - "static_assertions", -] - -[[package]] -name = "lazy_static" -version = "1.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" - -[[package]] -name = "libc" -version = "0.2.147" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3" - -[[package]] -name = "libz-ng-sys" -version = "1.1.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3dd9f43e75536a46ee0f92b758f6b63846e594e86638c61a9251338a65baea63" -dependencies = [ - "cmake", - "libc", -] - -[[package]] -name = "libz-sys" -version = "1.1.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d97137b25e321a73eef1418d1d5d2eda4d77e12813f8e6dead84bc52c5870a7b" -dependencies = [ - "cc", - "libc", - "pkg-config", - "vcpkg", -] - -[[package]] -name = "linked-hash-map" -version = "0.5.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f" - -[[package]] -name = "linux-raw-sys" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09fc20d2ca12cb9f044c93e3bd6d32d523e6e2ec3db4f7b2939cd99026ecd3f0" - -[[package]] -name = "lock_api" -version = "0.4.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1cc9717a20b1bb222f333e6a92fd32f7d8a18ddc5a3191a11af45dcbf4dcd16" -dependencies = [ - "autocfg", - "scopeguard", -] - -[[package]] -name = "log" -version = "0.4.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b06a4cde4c0f271a446782e3eff8de789548ce57dbc8eca9292c27f4a42004b4" - -[[package]] -name = "lzma-sys" -version = "0.1.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5fda04ab3764e6cde78b9974eec4f779acaba7c4e84b36eca3cf77c581b85d27" -dependencies = [ - "cc", - "libc", - "pkg-config", -] - -[[package]] -name = "maybe-async" -version = "0.2.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f1b8c13cb1f814b634a96b2c725449fe7ed464a7b8781de8688be5ffbd3f305" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "memchr" -version = "2.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" - -[[package]] -name = "memmap2" -version = "0.5.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83faa42c0a078c393f6b29d5db232d8be22776a891f8f56e5284faee4a20b327" -dependencies = [ - "libc", -] - -[[package]] -name = "memmap2" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f49388d20533534cd19360ad3d6a7dadc885944aa802ba3995040c5ec11288c6" -dependencies = [ - "libc", -] - -[[package]] -name = "memoffset" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a634b1c61a95585bd15607c6ab0c4e5b226e695ff2800ba0cdccddf208c406c" -dependencies = [ - "autocfg", -] - -[[package]] -name = "minimal-lexical" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" - -[[package]] -name = "miniz_oxide" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7810e0be55b428ada41041c41f32c9f1a42817901b4ccf45fa3d4b6561e74c7" -dependencies = [ - "adler", -] - -[[package]] -name = "nom" -version = "7.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" -dependencies = [ - "memchr", - "minimal-lexical", -] - -[[package]] -name = "num-traits" -version = "0.2.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f30b0abd723be7e2ffca1272140fac1a2f084c77ec3e123c192b66af1ee9e6c2" -dependencies = [ - "autocfg", -] - -[[package]] -name = "num_cpus" -version = "1.16.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" -dependencies = [ - "hermit-abi", - "libc", -] - -[[package]] -name = "num_threads" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2819ce041d2ee131036f4fc9d6ae7ae125a3a40e97ba64d04fe799ad9dabbb44" -dependencies = [ - "libc", -] - -[[package]] -name = "once_cell" -version = "1.18.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" - -[[package]] -name = "openssl-probe" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" - -[[package]] -name = "openssl-sys" -version = "0.9.90" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "374533b0e45f3a7ced10fcaeccca020e66656bc03dac384f852e4e5a7a8104a6" -dependencies = [ - "cc", - "libc", - "pkg-config", - "vcpkg", -] - -[[package]] -name = "parking_lot" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" -dependencies = [ - "lock_api", - "parking_lot_core", -] - -[[package]] -name = "parking_lot_core" -version = "0.9.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93f00c865fe7cabf650081affecd3871070f26767e7b2070a3ffae14c654b447" -dependencies = [ - "cfg-if", - "libc", - "redox_syscall 0.3.5", - "smallvec", - "windows-targets 0.48.1", -] - -[[package]] -name = "percent-encoding" -version = "2.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b2a4787296e9989611394c33f193f676704af1686e70b8f8033ab5ba9a35a94" - -[[package]] -name = "pkg-config" -version = "0.3.27" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26072860ba924cbfa98ea39c8c19b4dd6a4a25423dbdf219c1eca91aa0cf6964" - -[[package]] -name = "proc-macro2" -version = "1.0.66" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18fb31db3f9bddb2ea821cde30a9f70117e3f119938b5ee630b7403aa6e2ead9" -dependencies = [ - "unicode-ident", -] - -[[package]] -name = "prodash" -version = "23.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9516b775656bc3e8985e19cd4b8c0c0de045095074e453d2c0a513b5f978392d" - -[[package]] -name = "prodash" -version = "25.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c236e70b7f9b9ea00d33c69f63ec1ae6e9ae96118923cd37bd4e9c7396f0b107" - -[[package]] -name = "pulldown-cmark" -version = "0.9.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77a1a2f1f0a7ecff9c31abbe177637be0e97a0aef46cf8738ece09327985d998" -dependencies = [ - "bitflags 1.3.2", - "getopts", - "memchr", - "unicase", -] - -[[package]] -name = "quote" -version = "1.0.32" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50f3b39ccfb720540debaa0164757101c08ecb8d326b15358ce76a62c7e85965" -dependencies = [ - "proc-macro2", -] - -[[package]] -name = "rayon" -version = "1.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d2df5196e37bcc87abebc0053e20787d73847bb33134a69841207dd0a47f03b" -dependencies = [ - "either", - "rayon-core", -] - -[[package]] -name = "rayon-core" -version = "1.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b8f95bd6966f5c87776639160a66bd8ab9895d9d4ab01ddba9fc60661aebe8d" -dependencies = [ - "crossbeam-channel", - "crossbeam-deque", - "crossbeam-utils", - "num_cpus", -] - -[[package]] -name = "redox_syscall" -version = "0.2.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" -dependencies = [ - "bitflags 1.3.2", -] - -[[package]] -name = "redox_syscall" -version = "0.3.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29" -dependencies = [ - "bitflags 1.3.2", -] - -[[package]] -name = "regex-automata" -version = "0.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7b6d6190b7594385f61bd3911cd1be99dfddcfc365a4160cc2ab5bff4aed294" - -[[package]] -name = "rustc-hash" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" - -[[package]] -name = "rustix" -version = "0.38.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a962918ea88d644592894bc6dc55acc6c0956488adcebbfb6e273506b7fd6e5" -dependencies = [ - "bitflags 2.3.3", - "errno", - "libc", - "linux-raw-sys", - "windows-sys 0.48.0", -] - -[[package]] -name = "ryu" -version = "1.0.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741" - -[[package]] -name = "same-file" -version = "1.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" -dependencies = [ - "winapi-util", -] - -[[package]] -name = "schannel" -version = "0.1.22" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c3733bf4cf7ea0880754e19cb5a462007c4a8c1914bff372ccc95b464f1df88" -dependencies = [ - "windows-sys 0.48.0", -] - -[[package]] -name = "scopeguard" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" - -[[package]] -name = "semver" -version = "1.0.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0293b4b29daaf487284529cc2f5675b8e57c61f70167ba415a463651fd6a918" -dependencies = [ - "serde", -] - -[[package]] -name = "serde" -version = "1.0.178" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60363bdd39a7be0266a520dab25fdc9241d2f987b08a01e01f0ec6d06a981348" -dependencies = [ - "serde_derive", -] - -[[package]] -name = "serde_derive" -version = "1.0.178" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f28482318d6641454cb273da158647922d1be6b5a2fcc6165cd89ebdd7ed576b" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.27", -] - -[[package]] -name = "serde_json" -version = "1.0.104" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "076066c5f1078eac5b722a31827a8832fe108bed65dfa75e233c89f8206e976c" -dependencies = [ - "itoa", - "ryu", - "serde", -] - -[[package]] -name = "serde_spanned" -version = "0.6.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96426c9936fd7a0124915f9185ea1d20aa9445cc9821142f0a73bc9207a2e186" -dependencies = [ - "serde", -] - -[[package]] -name = "sha1" -version = "0.10.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f04293dc80c3993519f2d7f6f511707ee7094fe0c6d3406feb330cdb3540eba3" -dependencies = [ - "cfg-if", - "cpufeatures", - "digest", - "sha1-asm", -] - -[[package]] -name = "sha1-asm" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "563d4f7100bc3fce234e5f37bbf63dc2752558964505ba6ac3f7204bdc59eaac" -dependencies = [ - "cc", -] - -[[package]] -name = "sha1_smol" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae1a47186c03a32177042e55dbc5fd5aee900b8e0069a8d70fba96a9375cd012" - -[[package]] -name = "signal-hook" -version = "0.3.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8621587d4798caf8eb44879d42e56b9a93ea5dcd315a6487c357130095b62801" -dependencies = [ - "libc", - "signal-hook-registry", -] - -[[package]] -name = "signal-hook-registry" -version = "1.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8229b473baa5980ac72ef434c4415e70c4b5e71b423043adb4ba059f89c99a1" -dependencies = [ - "libc", -] - -[[package]] -name = "similar" -version = "2.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "420acb44afdae038210c99e69aae24109f32f15500aa708e81d46c9f29d55fcf" - -[[package]] -name = "smallvec" -version = "1.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62bb4feee49fdd9f707ef802e22365a35de4b7b299de4763d44bfea899442ff9" - -[[package]] -name = "smol_str" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74212e6bbe9a4352329b2f68ba3130c15a3f26fe88ff22dbdc6cdd58fa85e99c" -dependencies = [ - "serde", -] - -[[package]] -name = "socket2" -version = "0.4.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64a4a911eed85daf18834cfaa86a79b7d266ff93ff5ba14005426219480ed662" -dependencies = [ - "libc", - "winapi", -] - -[[package]] -name = "static_assertions" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" - -[[package]] -name = "strsim" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" - -[[package]] -name = "syn" -version = "1.0.109" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "syn" -version = "2.0.27" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b60f673f44a8255b9c8c657daf66a596d435f2da81a555b06dc644d080ba45e0" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "tar" -version = "0.4.39" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec96d2ffad078296368d46ff1cb309be1c23c513b4ab0e22a45de0185275ac96" -dependencies = [ - "filetime", - "libc", -] - -[[package]] -name = "tempfile" -version = "3.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5486094ee78b2e5038a6382ed7645bc084dc2ec433426ca4c3cb61e2007b8998" -dependencies = [ - "cfg-if", - "fastrand 2.0.0", - "redox_syscall 0.3.5", - "rustix", - "windows-sys 0.48.0", -] - -[[package]] -name = "termcolor" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be55cf8942feac5c765c2c993422806843c9a9a45d4d5c407ad6dd2ea95eb9b6" -dependencies = [ - "winapi-util", -] - -[[package]] -name = "thiserror" -version = "1.0.44" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "611040a08a0439f8248d1990b111c95baa9c704c805fa1f62104b39655fd7f90" -dependencies = [ - "thiserror-impl", -] - -[[package]] -name = "thiserror-impl" -version = "1.0.44" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "090198534930841fab3a5d1bb637cde49e339654e606195f8d9c76eeb081dc96" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.27", -] - -[[package]] -name = "time" -version = "0.3.23" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59e399c068f43a5d116fedaf73b203fa4f9c519f17e2b34f63221d3792f81446" -dependencies = [ - "itoa", - "libc", - "num_threads", - "serde", - "time-core", - "time-macros", -] - -[[package]] -name = "time-core" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7300fbefb4dadc1af235a9cef3737cea692a9d97e1b9cbcd4ebdae6f8868e6fb" - -[[package]] -name = "time-macros" -version = "0.2.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96ba15a897f3c86766b757e5ac7221554c6750054d74d5b28844fce5fb36a6c4" -dependencies = [ - "time-core", -] - -[[package]] -name = "tinyvec" -version = "1.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" -dependencies = [ - "tinyvec_macros", -] - -[[package]] -name = "tinyvec_macros" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" - -[[package]] -name = "toml" -version = "0.7.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c17e963a819c331dcacd7ab957d80bc2b9a9c1e71c804826d2f283dd65306542" -dependencies = [ - "serde", - "serde_spanned", - "toml_datetime", - "toml_edit", -] - -[[package]] -name = "toml_datetime" -version = "0.6.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7cda73e2f1397b1262d6dfdcef8aafae14d1de7748d66822d3bfeeb6d03e5e4b" -dependencies = [ - "serde", -] - -[[package]] -name = "toml_edit" -version = "0.19.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8123f27e969974a3dfba720fdb560be359f57b44302d280ba72e76a74480e8a" -dependencies = [ - "indexmap", - "serde", - "serde_spanned", - "toml_datetime", - "winnow", -] - -[[package]] -name = "typenum" -version = "1.16.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba" - -[[package]] -name = "uluru" -version = "3.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "794a32261a1f5eb6a4462c81b59cec87b5c27d5deea7dd1ac8fc781c41d226db" -dependencies = [ - "arrayvec", -] - -[[package]] -name = "unicase" -version = "2.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50f37be617794602aabbeee0be4f259dc1778fabe05e2d67ee8f79326d5cb4f6" -dependencies = [ - "version_check", -] - -[[package]] -name = "unicode-bidi" -version = "0.3.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92888ba5573ff080736b3648696b70cafad7d250551175acbaa4e0385b3e1460" - -[[package]] -name = "unicode-bom" -version = "2.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "98e90c70c9f0d4d1ee6d0a7d04aa06cb9bbd53d8cfbdd62a0269a7c2eb640552" - -[[package]] -name = "unicode-ident" -version = "1.0.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "301abaae475aa91687eb82514b328ab47a211a533026cb25fc3e519b86adfc3c" - -[[package]] -name = "unicode-normalization" -version = "0.1.22" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c5713f0fc4b5db668a2ac63cdb7bb4469d8c9fed047b1d0292cc7b0ce2ba921" -dependencies = [ - "tinyvec", -] - -[[package]] -name = "unicode-width" -version = "0.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b" - -[[package]] -name = "url" -version = "2.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50bff7831e19200a85b17131d085c25d7811bc4e186efdaf54bbd132994a88cb" -dependencies = [ - "form_urlencoded", - "idna", - "percent-encoding", -] - -[[package]] -name = "utf8parse" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" - -[[package]] -name = "vcpkg" -version = "0.2.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" - -[[package]] -name = "version_check" -version = "0.9.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" - -[[package]] -name = "walkdir" -version = "2.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "36df944cda56c7d8d8b7496af378e6b16de9284591917d307c9b4d313c44e698" -dependencies = [ - "same-file", - "winapi-util", -] - -[[package]] -name = "wasi" -version = "0.11.0+wasi-snapshot-preview1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" - -[[package]] -name = "winapi" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" -dependencies = [ - "winapi-i686-pc-windows-gnu", - "winapi-x86_64-pc-windows-gnu", -] - -[[package]] -name = "winapi-i686-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" - -[[package]] -name = "winapi-util" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" -dependencies = [ - "winapi", -] - -[[package]] -name = "winapi-x86_64-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" - -[[package]] -name = "windows" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e686886bc078bc1b0b600cac0147aadb815089b6e4da64016cbd754b6342700f" -dependencies = [ - "windows-targets 0.48.1", -] - -[[package]] -name = "windows-sys" -version = "0.45.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0" -dependencies = [ - "windows-targets 0.42.2", -] - -[[package]] -name = "windows-sys" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" -dependencies = [ - "windows-targets 0.48.1", -] - -[[package]] -name = "windows-targets" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071" -dependencies = [ - "windows_aarch64_gnullvm 0.42.2", - "windows_aarch64_msvc 0.42.2", - "windows_i686_gnu 0.42.2", - "windows_i686_msvc 0.42.2", - "windows_x86_64_gnu 0.42.2", - "windows_x86_64_gnullvm 0.42.2", - "windows_x86_64_msvc 0.42.2", -] - -[[package]] -name = "windows-targets" -version = "0.48.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05d4b17490f70499f20b9e791dcf6a299785ce8af4d709018206dc5b4953e95f" -dependencies = [ - "windows_aarch64_gnullvm 0.48.0", - "windows_aarch64_msvc 0.48.0", - "windows_i686_gnu 0.48.0", - "windows_i686_msvc 0.48.0", - "windows_x86_64_gnu 0.48.0", - "windows_x86_64_gnullvm 0.48.0", - "windows_x86_64_msvc 0.48.0", -] - -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8" - -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3" - -[[package]] -name = "windows_i686_gnu" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f" - -[[package]] -name = "windows_i686_gnu" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241" - -[[package]] -name = "windows_i686_msvc" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060" - -[[package]] -name = "windows_i686_msvc" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca2b8a661f7628cbd23440e50b05d705db3686f894fc9580820623656af974b1" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7896dbc1f41e08872e9d5e8f8baa8fdd2677f29468c4e156210174edc7f7b953" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a" - -[[package]] -name = "winnow" -version = "0.5.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83817bbecf72c73bad717ee86820ebf286203d2e04c3951f3cd538869c897364" -dependencies = [ - "memchr", -] - -[[package]] -name = "xz2" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "388c44dc09d76f1536602ead6d325eb532f5c122f17782bd57fb47baeeb767e2" -dependencies = [ - "lzma-sys", -] - -[[package]] -name = "yaml-rust" -version = "0.4.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56c1936c4cc7a1c9ab21a1ebb602eb942ba868cbd44a99cb7cdc5892335e1c85" -dependencies = [ - "linked-hash-map", -] diff --git a/cargo-smart-release/Cargo.toml b/cargo-smart-release/Cargo.toml deleted file mode 100644 index ee628557d13..00000000000 --- a/cargo-smart-release/Cargo.toml +++ /dev/null @@ -1,47 +0,0 @@ -[package] -name = "cargo-smart-release" -version = "0.20.0" -authors = ["Sebastian Thiel "] -repository = "https://github.com/Byron/gitoxide" -description = "Cargo subcommand for fearlessly releasing crates in workspaces." -license = "MIT OR Apache-2.0" -edition = "2021" -categories = ["development-tools::cargo-plugins"] -keywords = ["cargo"] -include = ["src/**/*", "README.md", "CHANGELOG.md"] - -[[bin]] -name = "cargo-smart-release" -path = "src/cli/main-smart-release.rs" -test = false - -[[bin]] -name = "cargo-changelog" -path = "src/cli/main-changelog.rs" -test = false - -[features] -cache-efficiency-debug = ["gix/cache-efficiency-debug"] - -[dependencies] -gix = { version = "^0.50.0", default-features = false, features = ["max-performance"] } -anyhow = "1.0.42" -clap = { version = "4.1.0", features = ["derive", "cargo"] } -env_logger = { version = "0.10.0", default-features = false, features = ["humantime", "auto-color"] } -cargo_metadata = "0.17.0" -log = "0.4.14" -toml_edit = "0.19.1" -semver = "1.0.4" -crates-index = { version = "2.1.0", default-features = false, features = ["git-performance", "git-https"] } -cargo_toml = "0.15.1" -winnow = "0.5.12" -git-conventional = "0.12.0" -time = "0.3.23" -pulldown-cmark = "0.9.0" -bitflags = "2" - -[dev-dependencies] -insta = "1.8.0" -gix-testtools = "0.12.0" - -[workspace] diff --git a/cargo-smart-release/README.md b/cargo-smart-release/README.md deleted file mode 100644 index aee742382c8..00000000000 --- a/cargo-smart-release/README.md +++ /dev/null @@ -1,106 +0,0 @@ -# `cargo smart-release` - -Fearlessly release workspace crates and with beautiful semi-handcrafted changelogs. - -[![asciicast](https://asciinema.org/a/65uPfzoWxGac43zEZ1gQ1yVVe.svg)](https://asciinema.org/a/65uPfzoWxGac43zEZ1gQ1yVVe) - -## Key Features - -* **zero-configuration** - * `cargo smart-release` needs no extra flags to _do the right thing™️_ smartly. If your intervention is needed it will let you know before it makes changes. - * It won't do anything if there are no changes. -* **made for multi-crate workspaces** - * "Nothing stands by itself, and everything is interconnected" - is how it sees the world, allowing it to efficiently handling complex workspace graphs. - * _works just as well for single-crate workspaces_ -* **changelogs-deluxe** - * It maintains beautiful changelogs for you while allowing you to edit them for the final polish. - * See your release notes via in-repository _tag objects_ and in _GitHub Releases_ - * **plays well with `cargo release`** - * `cargo changelog` writes changelogs non-destructively, and only that, leaving the release workflow to [cargo-release]. - -If seeing is believing, here is [a 12 minute demonstration](https://www.youtube.com/watch?v=EOft_uMDVYE), and the same in 30 minutes is [also available](https://youtu.be/a4CzzxJ7ecE). - -## Made for this Workflow - -When developing various crates in a workspace, when committing changes and if the edit is breaking, a feature, or another -change I want to see in changelogs, [conventional] git messages will be used. This helps building changelog scaffolding automatically later. - -When ready for releasing a particular crate or set of crates of interest, run `cargo smart-release [ ...]` to simulate a release. For particularly thorough -but error-prone simulations (as in false positives) one could run `cargo smart-release --dry-run-cargo-publish`. To polish changelogs, run `cargo changelog --write ` -to update the scaffolding and edit it by hand until it fits. - -After evaluating the release procedure and following instructions, -`cargo smart-release --execute` will cause the fully automatic release of one or more crates. - -There are various other options that shouldn't be needed in the common case, use `cargo smart-release --help` to see them. - -[conventional]: https://www.conventionalcommits.org - -## Installation - -### Cargo -Via `cargo`, which can be obtained using [rustup][rustup] - -``` -cargo install cargo-smart-release -``` - -## Features - -* [x] safe to use as actually performing an operation requires the `--execute` flag -* [x] avoid inconsistent states by making operations as atomic as possible, leveraging `gitoxide` technology to the fullest -* [x] handle workspace dependencies and cycles gracefully, allowing one invocation to publish multiple crates -* [x] avoid making any releases if there are no changes -* [x] avoid bumping versions if the current version isn't released, allowing you to control the version by editing the cargo manifest -* [x] [conventional] commit message drive changelog scaffolding and to automatically derive the crate version to publish -* [x] automatically release dependent workspace IDP crates along with the desired one if they changed since their last release -* [x] automatically adjust manifest versions and update manifests of crates which use those whose versions were incremented -* [x] conservatively bump downstream workspace crates in the light of breaking changes, even though these won't be published, making downstream breakage impossible -* [x] use git tags to know if a crate changed at all, skipping publishes if there is no code change at all -* [ ] it's _too eager_ to release and there should be a way to control patch releases. -* [ ] Handle pre-release versions, like 1.0.0-beta.1 -* [ ] Support other remote names than 'origin' - currently the latter name is assumed. Fix by getting the remote of the currently checked out branch. -* [ ] handle version specifications correctly [(tables vs values)](https://github.com/Byron/cargo-release/blob/master/src/cargo.rs#L179:L207) -* [ ] handle all version comparators correctly (see [here](https://github.com/Byron/cargo-release/blob/master/src/version.rs#L192:L226) for how it's done) -* [ ] Automatically detect if crate changes are breaking to suggest the correct version increment - -## Comparison to `cargo release` - -`cargo-release` is the reason this tool exists, as it got me addicted to an all automatic release workflow that knows git. This works perfectly -for simple workspaces or single-crate workspaces, as of 2021-08-12, so use it: `cargo install cargo-release`. - -Here is what `cargo smart-release` does differently: "It tries really hard to do what _I_ want most of the time when publishing workspace `gitoxide` crates". - -- ~~be safe to execute, so it's disarmed by default~~ -- specify one or more crates, and detect which crates need publishing automatically -- handle dependency cycles in such a way that increases the chances of overall success -- try really hard to not leave the workspace in an inconsistent state when something goes wrong -- be a playground for `gitoxide` to have a reason to make it much more convenient and more feasible for application authors (aka dog-fooding) -- create changelogs non-destructively, along with annotated tags and GitHub releases - -## Limitations - -* it requires tables to be used when specifying versions, i.e. `crate = { version = "1" }` instead of `crate = "1". -* it gracefully fails when encountering version requirement comparators which are not `^`, like `=` -* it's tested only by using it on `gitoxide`, there are only very few regression tests with little coverage. -* short object ids in changelogs may be ambiguous, as they are unconditionally truncated to 7 characters. -* changelog rewriting of user content will drop links if they are not of the 'inline' form -* it's very young and probably tries to eat underwear -* it needs a git repository to govern the workspace - -### Changelogs - -* When determining if something changed in top-level crates, only the `src/` directory is used, unless there is only a single crate in the workspace. This value is hard-coded. -* For change tracking, it will only obtain manifest values once to know where a crate lives, and - expects it to not be moved. -* If list items populated by commit messages contain items themselves, round-tripping will fail. Ideally there was a way to parse an item on the same level only. - -## Acknowledgements - -Thanks to [cargo-release] for showing the way and for incredible fast response times. I'd recommend everyone to participate there instead of writing your own. - -Special thanks go to [git-cliff] which gave me the nudge needed to want to write my own. - -[cargo-release]: https://github.com/sunng87/cargo-release/issues/224 -[git-cliff]: https://github.com/orhun/git-cliff -[rustup]: https://rustup.rs/ diff --git a/cargo-smart-release/build.rs b/cargo-smart-release/build.rs deleted file mode 100644 index 20ecf3f7c0e..00000000000 --- a/cargo-smart-release/build.rs +++ /dev/null @@ -1,17 +0,0 @@ -use std::process::Command; - -fn main() { - let version = Command::new(if cfg!(windows) { "git.exe" } else { "git" }) - .args(["describe", "--match=cargo-smart-release-*"]) - .output() - .ok() - .and_then(|out| parse_describe(&out.stdout)) - .unwrap_or_else(|| env!("CARGO_PKG_VERSION").into()); - - println!("cargo:rustc-env=CARGO_SMART_RELEASE_VERSION={version}"); -} - -fn parse_describe(input: &[u8]) -> Option { - let input = std::str::from_utf8(input).ok()?; - input.trim().to_owned().into() -} diff --git a/cargo-smart-release/src/bat.rs b/cargo-smart-release/src/bat.rs deleted file mode 100644 index 71c490d0859..00000000000 --- a/cargo-smart-release/src/bat.rs +++ /dev/null @@ -1,47 +0,0 @@ -use std::{io, path::Path, process::Command}; - -use crate::utils::Program; - -pub struct Support { - bat: Program, -} - -impl Default for Support { - fn default() -> Self { - Self::new() - } -} - -impl Support { - pub fn new() -> Self { - Support { - bat: Program::named("bat"), - } - } - - pub fn display_to_tty( - &self, - path: &Path, - path_for_title: &Path, - additional_title: impl AsRef, - ) -> io::Result<()> { - if !self.bat.found { - log::warn!( - "Would want to use 'bat' for colored preview of '{}', but it wasn't available in the PATH.", - path.display() - ); - return Ok(()); - } - if Command::new("bat") - .args(["--paging=always", "-l=md", "--file-name"]) - .arg(format!("{} ({})", path_for_title.display(), additional_title.as_ref())) - .arg(path) - .status()? - .success() - { - Ok(()) - } else { - Err(io::Error::new(io::ErrorKind::Other, "bat exited with an error")) - } - } -} diff --git a/cargo-smart-release/src/changelog/header.md b/cargo-smart-release/src/changelog/header.md deleted file mode 100644 index 52e80a16a21..00000000000 --- a/cargo-smart-release/src/changelog/header.md +++ /dev/null @@ -1,7 +0,0 @@ -# Changelog - -All notable changes to this project will be documented in this file. - -The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), -and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). - diff --git a/cargo-smart-release/src/changelog/init.rs b/cargo-smart-release/src/changelog/init.rs deleted file mode 100644 index 91985ce86a0..00000000000 --- a/cargo-smart-release/src/changelog/init.rs +++ /dev/null @@ -1,129 +0,0 @@ -use anyhow::Context; -use cargo_metadata::{ - camino::{Utf8Path, Utf8PathBuf}, - Package, -}; - -use crate::{ - changelog::{section::segment, Section}, - commit, ChangeLog, -}; - -#[derive(Clone, Copy)] -pub enum State { - Created, - Modified, - Unchanged, -} - -impl State { - pub fn is_modified(&self) -> bool { - !matches!(self, State::Unchanged) - } - pub fn as_str(&self) -> &'static str { - match self { - State::Created => "created", - State::Modified => "modified", - State::Unchanged => "unchanged", - } - } -} - -pub struct Outcome { - pub log: ChangeLog, - pub state: State, - pub lock: gix::lock::File, - pub previous_content: Option, -} - -impl ChangeLog { - pub fn for_package_with_write_lock<'a>( - package: &'a Package, - history: &commit::History, - ctx: &'a crate::Context, - selection: segment::Selection, - ) -> anyhow::Result { - let mut generated = ChangeLog::from_history_segments( - package, - &crate::git::history::crate_ref_segments( - package, - ctx, - history, - crate::git::history::SegmentScope::EntireHistory, - )?, - &ctx.repo, - selection, - ); - generated.sections.insert( - 0, - Section::Verbatim { - text: include_str!("header.md").to_owned(), - generated: true, - }, - ); - let changelog_path = path_from_manifest(&package.manifest_path); - let lock = - gix::lock::File::acquire_to_update_resource(&changelog_path, gix::lock::acquire::Fail::Immediately, None)?; - let (log, state, previous_content) = if let Ok(markdown) = std::fs::read_to_string(changelog_path) { - let existing_log = ChangeLog::from_markdown(&markdown); - let copy_of_existing = existing_log.clone(); - let merged = existing_log - .merge_generated(generated) - .with_context(|| format!("Changelog generation for crate {:?} failed", package.name))?; - let changed = merged != copy_of_existing; - ( - merged, - if changed { State::Modified } else { State::Unchanged }, - Some(markdown), - ) - } else { - (generated, State::Created, None) - }; - Ok(Outcome { - log, - state, - lock, - previous_content, - }) - } - - pub fn for_crate_by_name_with_write_lock<'a>( - package: &'a Package, - history: &commit::History, - ctx: &'a crate::Context, - selection: segment::Selection, - ) -> anyhow::Result<(Outcome, &'a Package)> { - let out = Self::for_package_with_write_lock(package, history, ctx, selection)?; - Ok((out, package)) - } - - pub fn from_history_segments( - package: &Package, - segments: &[commit::history::Segment<'_>], - repo: &gix::Repository, - selection: segment::Selection, - ) -> Self { - ChangeLog { - sections: { - let mut s = segments.windows(2).fold(Vec::new(), |mut acc, segments| { - acc.push(Section::from_history_segment( - package, - &segments[0], - repo, - selection, - (&segments[1]).into(), - )); - acc - }); - if let Some(segment) = segments.last() { - s.push(Section::from_history_segment(package, segment, repo, selection, None)) - } - s - }, - } - } -} - -fn path_from_manifest(path: &Utf8Path) -> Utf8PathBuf { - path.parent().expect("parent for Cargo.toml").join("CHANGELOG.md") -} diff --git a/cargo-smart-release/src/changelog/merge.rs b/cargo-smart-release/src/changelog/merge.rs deleted file mode 100644 index a50178910d9..00000000000 --- a/cargo-smart-release/src/changelog/merge.rs +++ /dev/null @@ -1,334 +0,0 @@ -use std::{collections::VecDeque, iter::FromIterator}; - -use anyhow::bail; -use gix::hash::ObjectId; - -use crate::{ - changelog::{ - section, - section::{segment::conventional, Segment}, - Section, Version, - }, - ChangeLog, -}; - -impl ChangeLog { - /// Bring `generated` into `self` in such a way that `self` preserves everything while enriching itself from `generated`. - /// Thus we clearly assume that `self` is parsed and `generated` is generated. - pub fn merge_generated(mut self, rhs: Self) -> anyhow::Result { - if self.sections.is_empty() { - return Ok(rhs); - } - - let mut sections_to_merge = VecDeque::from_iter(rhs.sections); - let sections = &mut self.sections; - - merge_generated_verbatim_section_if_there_is_only_releases_on_lhs(&mut sections_to_merge, sections); - - let (first_release_pos, first_release_indentation, first_version_prefix) = - match sections.iter().enumerate().find_map(|(idx, s)| match s { - Section::Release { - heading_level, - version_prefix, - .. - } => Some((idx, heading_level, version_prefix)), - _ => None, - }) { - Some((idx, level, prefix)) => (idx, *level, prefix.to_owned()), - None => { - sections.extend(sections_to_merge); - return Ok(self); - } - }; - - for mut section_to_merge in sections_to_merge { - match section_to_merge { - Section::Verbatim { .. } => { - bail!("BUG: generated logs may only have verbatim sections at the beginning") - } - Section::Release { ref name, .. } => match find_target_section(name, sections, first_release_pos) { - Insertion::MergeWith(pos) => sections[pos].merge(section_to_merge)?, - Insertion::At(pos) => { - if let Section::Release { - heading_level, - version_prefix, - .. - } = &mut section_to_merge - { - *heading_level = first_release_indentation; - *version_prefix = first_version_prefix.clone(); - } - sections.insert(pos, section_to_merge); - } - }, - } - } - - Ok(self) - } -} - -impl Section { - pub fn merge(&mut self, src: Section) -> anyhow::Result<()> { - let dest = self; - match (dest, src) { - (Section::Verbatim { .. }, _) | (_, Section::Verbatim { .. }) => { - bail!("BUG: we should never try to merge into or from a verbatim section") - } - ( - Section::Release { - date: dest_date, - segments: dest_segments, - removed_messages, - .. - }, - Section::Release { - date: src_date, - segments: src_segments, - unknown: src_unknown, - .. - }, - ) => { - assert!(src_unknown.is_empty(), "shouldn't ever generate 'unknown' portions"); - let has_no_read_only_segments = !dest_segments.iter().any(Segment::is_read_only); - let mode = if has_no_read_only_segments { - ReplaceMode::ReplaceAllOrAppend - } else { - ReplaceMode::ReplaceAllOrAppendIfPresentInLhs - }; - for rhs_segment in src_segments { - match rhs_segment { - Segment::User { markdown } => { - bail!("BUG: User segments are never auto-generated: {markdown}") - } - Segment::Details(section::Data::Parsed) - | Segment::Statistics(section::Data::Parsed) - | Segment::Clippy(section::Data::Parsed) => { - bail!("BUG: Clippy, statistics, and details are set if generated, or not present") - } - Segment::Conventional(conventional) => { - merge_conventional(removed_messages, dest_segments, conventional)? - } - clippy @ Segment::Clippy(_) => { - merge_read_only_segment(dest_segments, |s| matches!(s, Segment::Clippy(_)), clippy, mode) - } - stats @ Segment::Statistics(_) => { - merge_read_only_segment(dest_segments, |s| matches!(s, Segment::Statistics(_)), stats, mode) - } - details @ Segment::Details(_) => { - merge_read_only_segment(dest_segments, |s| matches!(s, Segment::Details(_)), details, mode) - } - } - } - *dest_date = src_date; - } - } - Ok(()) - } -} - -#[derive(Clone, Copy)] -enum ReplaceMode { - ReplaceAllOrAppend, - ReplaceAllOrAppendIfPresentInLhs, -} - -fn merge_read_only_segment( - dest: &mut Vec, - mut filter: impl FnMut(§ion::Segment) -> bool, - insert: Segment, - mode: ReplaceMode, -) { - let mut found_one = false; - for dest_segment in dest.iter_mut().filter(|s| filter(s)) { - *dest_segment = insert.clone(); - found_one = true; - } - if !found_one && matches!(mode, ReplaceMode::ReplaceAllOrAppend) { - dest.push(insert); - } -} - -fn merge_conventional( - removed_in_release: &[gix::hash::ObjectId], - dest_segments: &mut Vec, - mut src: section::segment::Conventional, -) -> anyhow::Result<()> { - assert!( - src.removed.is_empty(), - "generated sections never contains removed items" - ); - let mut found_one = false; - for dest_segment in dest_segments.iter_mut().filter( - |s| matches!(s, Segment::Conventional(rhs) if rhs.kind == src.kind && rhs.is_breaking == src.is_breaking), - ) { - match dest_segment { - Segment::Conventional(section::segment::Conventional { - removed, - messages, - kind: _, - is_breaking: _, - }) => { - for src_message in src.messages.clone() { - match src_message { - conventional::Message::Generated { id, title, body } => { - if removed.contains(&id) - || removed_in_release.contains(&id) - || messages.iter().any( - |m| matches!(m, conventional::Message::Generated {id: lhs_id, ..} if *lhs_id == id), - ) - { - continue; - } - let pos = messages - .iter() - .take_while(|m| matches!(m, conventional::Message::User { .. })) - .enumerate() - .map(|(pos, _)| pos + 1) - .last() - .unwrap_or(messages.len()); - messages.insert(pos, conventional::Message::Generated { id, title, body }); - } - conventional::Message::User { .. } => bail!("User messages are never generated"), - } - } - } - _ => bail!("assured correct type in filter"), - } - found_one = true; - } - - if !found_one - && (has_user_messages(&src.messages) - || at_least_one_generated_message_visible(removed_in_release, &src.messages)) - { - dest_segments.insert( - dest_segments - .iter() - .enumerate() - .find_map(|(pos, item)| { - if matches!(item, Segment::User { .. }) { - // we know that the segment that follows (if one) is generated, so this won't be between two user segments - Some(pos + 1) - } else { - None - } - }) - .unwrap_or(0), - { - src.messages.retain(|m| match m { - conventional::Message::User { .. } => true, - conventional::Message::Generated { id, .. } => !removed_in_release.contains(id), - }); - Segment::Conventional(src) - }, - ); - } - Ok(()) -} - -fn at_least_one_generated_message_visible(removed_in_release: &[ObjectId], messages: &[conventional::Message]) -> bool { - messages - .iter() - .any(|m| matches!(m, conventional::Message::Generated {id,..} if !removed_in_release.contains(id))) -} - -fn has_user_messages(messages: &[conventional::Message]) -> bool { - messages.iter().any(|m| matches!(m, conventional::Message::User { .. })) -} - -enum Insertion { - MergeWith(usize), - At(usize), -} - -fn find_target_section(wanted: &Version, sections: &[Section], first_release_index: usize) -> Insertion { - if sections.is_empty() { - return Insertion::At(0); - } - - match sections.iter().enumerate().find_map(|(idx, s)| match s { - Section::Release { name, .. } if name == wanted => Some(Insertion::MergeWith(idx)), - _ => None, - }) { - Some(res) => res, - None => match wanted { - Version::Unreleased => Insertion::At(first_release_index), - Version::Semantic(version) => { - let (mut pos, min_distance) = sections - .iter() - .enumerate() - .map(|(idx, section)| { - ( - idx, - match section { - Section::Verbatim { .. } => MAX_DISTANCE, - Section::Release { name, .. } => version_distance(name, version), - }, - ) - }) - .fold( - (usize::MAX, MAX_DISTANCE), - |(mut pos, mut dist), (cur_pos, cur_dist)| { - if abs_distance(cur_dist) < abs_distance(dist) { - dist = cur_dist; - pos = cur_pos; - } - (pos, dist) - }, - ); - if pos == usize::MAX { - // We had nothing to compare against, append to the end - pos = sections.len(); - } - if min_distance < (0, 0, 0) { - Insertion::At(pos + 1) - } else { - Insertion::At(pos) - } - } - }, - } -} - -type Distance = (i64, i64, i64); - -const MAX_DISTANCE: Distance = (i64::MAX, i64::MAX, i64::MAX); - -fn abs_distance((x, y, z): Distance) -> Distance { - (x.abs(), y.abs(), z.abs()) -} - -fn version_distance(from: &Version, to: &semver::Version) -> Distance { - match from { - Version::Unreleased => MAX_DISTANCE, - Version::Semantic(from) => ( - to.major as i64 - from.major as i64, - to.minor as i64 - from.minor as i64, - to.patch as i64 - from.patch as i64, - ), - } -} - -fn merge_generated_verbatim_section_if_there_is_only_releases_on_lhs( - sections_to_merge: &mut VecDeque
, - sections: &mut Vec
, -) { - while let Some(section_to_merge) = sections_to_merge.pop_front() { - match section_to_merge { - Section::Verbatim { generated, .. } => { - assert!(generated, "BUG: rhs must always be generated"); - let first_section = §ions[0]; - if matches!(first_section, Section::Release { .. }) - || matches!(first_section, Section::Verbatim {generated, ..} if *generated ) - { - sections.insert(0, section_to_merge) - } - } - Section::Release { .. } => { - sections_to_merge.push_front(section_to_merge); - break; - } - } - } -} diff --git a/cargo-smart-release/src/changelog/mod.rs b/cargo-smart-release/src/changelog/mod.rs deleted file mode 100644 index 44798d1ba4f..00000000000 --- a/cargo-smart-release/src/changelog/mod.rs +++ /dev/null @@ -1,116 +0,0 @@ -use std::cmp::Ordering; - -use crate::{changelog::section::segment::conventional::as_headline, ChangeLog}; - -pub mod init; -mod merge; -mod parse; -pub mod section; -#[cfg(test)] -mod tests; -pub mod write; - -pub const DEFAULT_HEADING_LEVEL: usize = 2; - -#[derive(PartialEq, Eq, Debug, Clone)] -pub enum Section { - /// A part of a changelog which couldn't be understood and is taken in verbatim. This is usually the pre-amble of the changelog - /// or a custom footer. - Verbatim { - /// The section text, unchanged, up until the next `Release`. - text: String, - /// True if this is not created by a human - generated: bool, - }, - - /// A segment describing a particular release - Release { - name: Version, - date: Option, - /// the amount of # in front of the heading denoting the release name - heading_level: usize, - /// What came right before the version - version_prefix: String, - /// text of events of everything we couldn't parse - unknown: String, - /// Removed git conventional messages parsed back from html tags. These may live without a headline, to delete the headline. - removed_messages: Vec, - /// portions of a release - segments: Vec, - }, -} - -#[derive(PartialEq, Eq, Debug, Clone)] -pub enum Version { - Unreleased, - Semantic(semver::Version), -} - -impl PartialOrd for Version { - fn partial_cmp(&self, other: &Self) -> Option { - match (self, other) { - (Version::Unreleased, _) => Ordering::Greater.into(), - (_, Version::Unreleased) => Ordering::Less.into(), - (Version::Semantic(lhs), Version::Semantic(rhs)) => lhs.partial_cmp(rhs), - } - } -} - -impl Ord for Version { - fn cmp(&self, other: &Self) -> Ordering { - match (self, other) { - (Version::Unreleased, _) => Ordering::Greater, - (_, Version::Unreleased) => Ordering::Less, - (Version::Semantic(lhs), Version::Semantic(rhs)) => lhs.cmp(rhs), - } - } -} - -impl ChangeLog { - pub fn take_recent_release_section(&mut self) -> Section { - let pos = self - .sections - .iter() - .enumerate() - .find_map(|(idx, s)| (matches!(s, Section::Release { .. })).then(|| idx)) - .expect("we never have an entirely empty changelog"); - self.sections.remove(pos) - } - pub fn most_recent_release_section_mut(&mut self) -> (usize, &mut Section) { - self.sections - .iter_mut() - .enumerate() - .find(|(_, s)| matches!(s, Section::Release { .. })) - .expect("we never have an entirely empty changelog") - } -} - -impl Section { - /// Returns true if there are segments that would always be present as they carry essential information about the release. - pub fn is_essential(&self) -> bool { - match self { - Section::Verbatim { .. } => true, - Section::Release { - segments, - unknown, - removed_messages, - .. - } => !unknown.is_empty() || !removed_messages.is_empty() || segments.iter().any(|s| !s.is_read_only()), - } - } - /// Returns true if there is no user-made section, or no edit by users in conventional segments at all. - /// Note that we can't tell if existing messages were edited (because we don't try hard enough). - pub fn is_probably_lacking_user_edits(&self) -> bool { - match self { - Section::Verbatim { .. } => false, - Section::Release { segments, .. } => { - if segments.iter().any(|s| matches!(s, section::Segment::User { .. })) { - return false; - }; - segments.iter().any( - |s| matches!(s, section::Segment::Conventional(section::segment::Conventional {kind, removed, is_breaking, ..}) if *is_breaking && removed.is_empty() && as_headline(kind).is_none()), - ) - } - } - } -} diff --git a/cargo-smart-release/src/changelog/parse.rs b/cargo-smart-release/src/changelog/parse.rs deleted file mode 100644 index 57958c5e337..00000000000 --- a/cargo-smart-release/src/changelog/parse.rs +++ /dev/null @@ -1,520 +0,0 @@ -use std::{ - convert::TryFrom, - iter::{FromIterator, Peekable}, - ops::Range, - str::FromStr, -}; - -use gix::bstr::ByteSlice; -use pulldown_cmark::{CowStr, Event, HeadingLevel, OffsetIter, Tag}; -use winnow::{ - combinator::alt, - combinator::opt, - combinator::{delimited, preceded, separated_pair, terminated}, - error::{FromExternalError, ParserError}, - prelude::*, - token::{tag_no_case, take_till0, take_while}, -}; - -use crate::{ - changelog, - changelog::{ - section, - section::{ - segment::{conventional::as_headline, Conventional}, - Segment, - }, - Section, - }, - ChangeLog, -}; - -impl ChangeLog { - /// Obtain as much information as possible from `input` and keep everything we didn't understand in respective sections. - pub fn from_markdown(input: &str) -> ChangeLog { - let mut sections = Vec::new(); - let mut section_body = String::new(); - let mut previous_headline = None::; - let mut first_heading_level = None; - for line in input.as_bytes().as_bstr().lines_with_terminator() { - let line = line.to_str().expect("valid UTF-8"); - match Headline::try_from(line) { - Ok(headline) => { - first_heading_level.get_or_insert(headline.level); - match previous_headline { - Some(mut headline) => { - headline.level = first_heading_level.expect("set first"); - sections.push(Section::from_headline_and_body( - headline, - std::mem::take(&mut section_body), - )); - } - None => { - if !section_body.is_empty() { - sections.push(Section::Verbatim { - text: std::mem::take(&mut section_body), - generated: false, - }) - } - } - }; - previous_headline = Some(headline); - } - Err(()) => { - section_body.push_str(line); - } - } - } - - match previous_headline { - Some(headline) => { - sections.push(Section::from_headline_and_body( - headline, - std::mem::take(&mut section_body), - )); - } - None => sections.push(Section::Verbatim { - text: section_body, - generated: false, - }), - } - - let insert_sorted_at_pos = sections.first().map_or(0, |s| match s { - Section::Verbatim { .. } => 1, - Section::Release { .. } => 0, - }); - let mut non_release_sections = Vec::new(); - let mut release_sections = Vec::new(); - for section in sections { - match section { - Section::Verbatim { .. } => non_release_sections.push(section), - Section::Release { .. } => release_sections.push(section), - } - } - release_sections.sort_by(|lhs, rhs| match (lhs, rhs) { - (Section::Release { name: lhs, .. }, Section::Release { name: rhs, .. }) => lhs.cmp(rhs).reverse(), - _ => unreachable!("BUG: there are only release sections here"), - }); - let mut sections = Vec::from_iter(non_release_sections.drain(..insert_sorted_at_pos)); - sections.append(&mut release_sections); - sections.append(&mut non_release_sections); - ChangeLog { sections } - } -} - -impl Section { - fn from_headline_and_body( - Headline { - level, - version_prefix, - version, - date, - }: Headline, - body: String, - ) -> Self { - let mut events = pulldown_cmark::Parser::new_ext(&body, pulldown_cmark::Options::all()) - .into_offset_iter() - .peekable(); - let mut unknown = String::new(); - let mut segments = Vec::new(); - - let mut unknown_range = None; - let mut removed_messages = Vec::new(); - while let Some((e, range)) = events.next() { - match e { - Event::Html(text) if text.starts_with(Section::UNKNOWN_TAG_START) => { - record_unknown_range(&mut segments, unknown_range.take(), &body); - for (event, _range) in events.by_ref().take_while( - |(e, _range)| !matches!(e, Event::Html(text) if text.starts_with(Section::UNKNOWN_TAG_END)), - ) { - track_unknown_event(event, &mut unknown); - } - } - Event::Html(text) if text.starts_with(section::segment::Conventional::REMOVED_HTML_PREFIX) => { - if let Some(id) = parse_message_id(text.as_ref()) { - if !removed_messages.contains(&id) { - removed_messages.push(id); - } - } - } - Event::Start(Tag::Heading(indent, _, _)) => { - record_unknown_range(&mut segments, unknown_range.take(), &body); - enum State { - ParseConventional { title: String }, - SkipGenerated, - ConsiderUserAuthored, - } - let state = match events.next() { - Some((Event::Text(title), _range)) - if title.starts_with(section::segment::ThanksClippy::TITLE) => - { - segments.push(Segment::Clippy(section::Data::Parsed)); - State::SkipGenerated - } - Some((Event::Text(title), _range)) - if title.starts_with(section::segment::CommitStatistics::TITLE) => - { - segments.push(Segment::Statistics(section::Data::Parsed)); - State::SkipGenerated - } - Some((Event::Text(title), _range)) if title.starts_with(section::segment::Details::TITLE) => { - segments.push(Segment::Details(section::Data::Parsed)); - State::SkipGenerated - } - Some((Event::Text(title), _range)) - if title.starts_with(as_headline("feat").expect("valid")) - || title.starts_with(as_headline("add").expect("valid")) - || title.starts_with(as_headline("revert").expect("valid")) - || title.starts_with(as_headline("remove").expect("valid")) - || title.starts_with(as_headline("change").expect("valid")) - || title.starts_with(as_headline("docs").expect("valid")) - || title.starts_with(as_headline("perf").expect("valid")) - || title.starts_with("refactor") - || title.starts_with("other") - || title.starts_with("style") - || title.starts_with(as_headline("fix").expect("valid")) => - { - State::ParseConventional { - title: title.into_string(), - } - } - Some((_event, next_range)) => { - update_unknown_range(&mut unknown_range, range); - update_unknown_range(&mut unknown_range, next_range); - State::ConsiderUserAuthored - } - None => State::ConsiderUserAuthored, - }; - - events - .by_ref() - .take_while(|(e, range)| { - if matches!(state, State::ConsiderUserAuthored) { - update_unknown_range(&mut unknown_range, range.clone()); - } - !matches!(e, Event::End(Tag::Heading(_, _, _))) - }) - .count(); - match state { - State::ParseConventional { title } => { - segments.push(parse_conventional_to_next_section_title( - &body, - title, - &mut events, - indent, - &mut unknown, - )); - } - State::SkipGenerated => { - skip_to_next_section_title(&mut events, indent); - } - State::ConsiderUserAuthored => {} - } - } - _unknown_event => update_unknown_range(&mut unknown_range, range), - }; - } - record_unknown_range(&mut segments, unknown_range.take(), &body); - Section::Release { - name: match version { - Some(version) => changelog::Version::Semantic(version), - None => changelog::Version::Unreleased, - }, - version_prefix, - date, - removed_messages, - heading_level: level, - segments, - unknown, - } - } -} - -fn parse_conventional_to_next_section_title( - markdown: &str, - title: String, - events: &mut Peekable>, - level: HeadingLevel, - unknown: &mut String, -) -> Segment { - let is_breaking = title.ends_with(section::segment::Conventional::BREAKING_TITLE_ENCLOSED); - let kind = [ - "fix", "add", "feat", "revert", "remove", "change", "docs", "perf", "refactor", "other", "style", - ] - .iter() - .find(|kind| { - let headline = section::segment::conventional::as_headline(kind).unwrap_or(*kind); - let common_len = headline.len().min(title.len()); - title - .get(..common_len) - .and_then(|t| headline.get(..common_len).map(|h| t.eq_ignore_ascii_case(h))) - .unwrap_or(false) - }) - .expect("BUG: this list needs an update too if new kinds of conventional messages are added"); - - let mut conventional = section::segment::Conventional { - kind, - is_breaking, - removed: vec![], - messages: vec![], - }; - while let Some((event, _range)) = events.peek() { - match event { - Event::Start(Tag::Heading(indent, _, _)) if *indent == level => break, - _ => { - let (event, _range) = events.next().expect("peeked before so event is present"); - match event { - Event::Html(ref tag) => match parse_message_id(tag.as_ref()) { - Some(id) => { - if !conventional.removed.contains(&id) { - conventional.removed.push(id) - } - } - None => track_unknown_event(event, unknown), - }, - Event::Start(Tag::List(_)) => { - while let Some((event, item_range)) = events.next() { - match event { - Event::Start(Tag::Item) => { - if let Some((possibly_html, _)) = events.next() { - match possibly_html { - Event::Start(Tag::Paragraph) => { - if let Some((possibly_html, _)) = events.next() { - match possibly_html { - Event::Html(tag) => { - parse_id_fallback_to_user_message( - markdown, - events, - &mut conventional, - item_range, - tag, - ); - } - _other_event => make_user_message_and_consume_item( - markdown, - events, - &mut conventional, - item_range, - ), - } - } - } - Event::Html(tag) => { - parse_id_fallback_to_user_message( - markdown, - events, - &mut conventional, - item_range, - tag, - ); - } - _other_event => make_user_message_and_consume_item( - markdown, - events, - &mut conventional, - item_range, - ), - } - } - } - Event::End(Tag::List(_)) => break, - event => track_unknown_event(event, unknown), - } - } - } - event => track_unknown_event(event, unknown), - } - continue; - } - } - } - section::Segment::Conventional(conventional) -} - -fn parse_id_fallback_to_user_message( - markdown: &str, - events: &mut Peekable>, - conventional: &mut Conventional, - item_range: Range, - tag: CowStr<'_>, -) { - match parse_message_id(tag.as_ref()) { - Some(id) => { - let mut events = events - .by_ref() - .take_while(|(e, _r)| !matches!(e, Event::End(Tag::Item))) - .map(|(_, r)| r); - let start = events.next(); - let end = events.last().or_else(|| start.clone()); - if let Some(title_and_body) = start - .map(|r| r.start) - .and_then(|start| end.map(|r| markdown[start..r.end].trim())) - { - let mut lines = title_and_body - .as_bytes() - .as_bstr() - .lines_with_terminator() - .map(|b| b.to_str().expect("always valid as source is UTF-8")); - conventional - .messages - .push(section::segment::conventional::Message::Generated { - id, - title: lines.next().map_or("", |l| l.trim()).to_owned(), - body: lines - .map(|l| { - match l - .chars() - .take_while(|c| *c == ' ' || *c == '\t') - .enumerate() - .map(|(idx, _)| idx) - .last() - { - Some(last_pos_to_truncate) => &l[last_pos_to_truncate + 1..], - None => l, - } - }) - .fold(None::, |mut acc, l| { - acc.get_or_insert_with(String::new).push_str(l); - acc - }), - }); - } - } - None => make_user_message_and_consume_item(markdown, events, conventional, item_range), - }; -} - -fn make_user_message_and_consume_item( - markdown: &str, - events: &mut Peekable>, - conventional: &mut Conventional, - range: Range, -) { - conventional - .messages - .push(section::segment::conventional::Message::User { - markdown: markdown[range].trim_end().to_owned(), - }); - events.take_while(|(e, _)| !matches!(e, Event::End(Tag::Item))).count(); -} - -fn parse_message_id(html: &str) -> Option { - let html = html.strip_prefix(section::segment::Conventional::REMOVED_HTML_PREFIX)?; - let end_of_hex = html.find(|c| { - !matches!(c, - 'a'..='f' | '0'..='9' - ) - })?; - gix::hash::ObjectId::from_hex(html[..end_of_hex].as_bytes()).ok() -} - -fn update_unknown_range(target: &mut Option>, source: Range) { - match target { - Some(range_thus_far) => { - if source.end > range_thus_far.end { - range_thus_far.end = source.end; - } - } - None => *target = source.into(), - } -} - -fn record_unknown_range(out: &mut Vec, range: Option>, markdown: &str) { - if let Some(range) = range { - out.push(Segment::User { - markdown: markdown[range].to_owned(), - }) - } -} - -fn track_unknown_event(unknown_event: Event<'_>, unknown: &mut String) { - log::trace!("Cannot handle {:?}", unknown_event); - match unknown_event { - Event::Html(text) - | Event::Code(text) - | Event::Text(text) - | Event::FootnoteReference(text) - | Event::Start( - Tag::FootnoteDefinition(text) - | Tag::CodeBlock(pulldown_cmark::CodeBlockKind::Fenced(text)) - | Tag::Link(_, text, _) - | Tag::Image(_, text, _), - ) => unknown.push_str(text.as_ref()), - _ => {} - } -} - -fn skip_to_next_section_title(events: &mut Peekable>, level: HeadingLevel) { - while let Some((event, _range)) = events.peek() { - match event { - Event::Start(Tag::Heading(indent, _, _)) if *indent == level => break, - _ => { - events.next(); - continue; - } - } - } -} - -struct Headline { - level: usize, - version_prefix: String, - version: Option, - date: Option, -} - -impl<'a> TryFrom<&'a str> for Headline { - type Error = (); - - fn try_from(value: &'a str) -> Result { - headline::<()>.parse(value).map_err(|err| err.into_inner()) - } -} - -fn headline<'a, E: ParserError<&'a str> + FromExternalError<&'a str, ()>>(i: &mut &'a str) -> PResult { - let hashes = take_while(0.., |c: char| c == '#'); - let greedy_whitespace = |i: &mut &'a str| take_while(0.., char::is_whitespace).parse_next(i); - let take_n_digits = - |n: usize| take_while(n, |c: char| c.is_ascii_digit()).try_map(|num| u32::from_str(num).map_err(|_| ())); - - terminated( - ( - separated_pair( - hashes, - greedy_whitespace, - alt(( - ( - opt("v"), - take_till0(char::is_whitespace) - .try_map(|v| semver::Version::parse(v).map_err(|_| ()).map(Some)), - ), - tag_no_case("unreleased").map(|_| (None, None)), - )), - ), - opt(preceded( - greedy_whitespace, - delimited( - "(", - (take_n_digits(4), "-", take_n_digits(2), "-", take_n_digits(2)).try_map( - |(year, _, month, _, day)| { - time::Month::try_from(month as u8).map_err(|_| ()).and_then(|month| { - time::Date::from_calendar_date(year as i32, month, day as u8) - .map_err(|_| ()) - .map(|d| d.midnight().assume_utc()) - }) - }, - ), - ")", - ), - )), - ), - greedy_whitespace, - ) - .map(|((hashes, (prefix, version)), date)| Headline { - level: hashes.len(), - version_prefix: prefix.map_or_else(String::new, ToOwned::to_owned), - version, - date, - }) - .parse_next(i) -} diff --git a/cargo-smart-release/src/changelog/section/from_history.rs b/cargo-smart-release/src/changelog/section/from_history.rs deleted file mode 100644 index 10218394204..00000000000 --- a/cargo-smart-release/src/changelog/section/from_history.rs +++ /dev/null @@ -1,174 +0,0 @@ -use std::{collections::BTreeMap, ops::Sub}; - -use cargo_metadata::Package; -use gix::prelude::ObjectIdExt; -use time::OffsetDateTime; - -use crate::{ - changelog, - changelog::{ - section, - section::{segment::Selection, Segment}, - Section, - }, - commit, utils, - utils::{is_top_level_package, time_to_offset_date_time}, -}; - -impl Section { - pub const DEFAULT_PREFIX: &'static str = "v"; - - pub fn from_history_segment( - package: &Package, - segment: &commit::history::Segment<'_>, - repo: &gix::Repository, - selection: section::segment::Selection, - prev_segment: Option<&commit::history::Segment<'_>>, - ) -> Self { - let date_time = segment_head_time(segment, repo); - let prev_date_time = prev_segment.map(|segment| segment_head_time(segment, repo)); - - let mut segments = Vec::new(); - let history = &segment.history; - if !history.is_empty() { - if selection.contains(Selection::GIT_CONVENTIONAL) { - let mut mapping = BTreeMap::default(); - for (id, kind, title, is_breaking, body) in history.iter().filter_map(|i| { - i.message.kind.as_ref().map(|kind| { - ( - i.id, - kind, - i.message.title.clone(), - i.message.breaking, - i.message.body.clone(), - ) - }) - }) { - mapping - .entry((is_breaking, kind)) - .or_insert_with(Vec::new) - .push(section::segment::conventional::Message::Generated { id, title, body }) - } - // TODO: proper sorting - segments.extend(mapping.into_iter().map(|((is_breaking, kind), messages)| { - Segment::Conventional(section::segment::Conventional { - kind, - is_breaking, - removed: Vec::new(), - messages, - }) - })); - } - let message_by_category = selection - .intersects(Selection::COMMIT_STATISTICS | Selection::COMMIT_DETAILS) - .then(|| { - let mut mapping = BTreeMap::default(); - for &item in history { - let mut issue_associations = 0; - for possibly_issue in &item.message.additions { - match possibly_issue { - commit::message::Addition::IssueId(issue) => { - mapping - .entry(section::segment::details::Category::Issue(issue.to_owned())) - .or_insert_with(Vec::new) - .push(item.into()); - issue_associations += 1; - } - } - } - if issue_associations == 0 { - mapping - .entry(section::segment::details::Category::Uncategorized) - .or_insert_with(Vec::new) - .push(item.into()); - } - } - mapping - }); - if let Some(commits_by_category) = message_by_category - .as_ref() - .filter(|_| selection.contains(Selection::COMMIT_STATISTICS)) - { - let duration = history - .last() - .map(|last| date_time.sub(time_to_offset_date_time(last.commit_time))); - segments.push(Segment::Statistics(section::Data::Generated( - section::segment::CommitStatistics { - count: history.len(), - duration, - time_passed_since_last_release: prev_date_time.map(|prev_time| date_time.sub(prev_time)), - conventional_count: history.iter().filter(|item| item.message.kind.is_some()).count(), - unique_issues: { - let mut v = commits_by_category - .keys() - .filter(|c| matches!(c, section::segment::details::Category::Issue(_))) - .cloned() - .collect::>(); - v.sort(); - v - }, - }, - ))); - } - if selection.contains(Selection::CLIPPY) { - let count = history - .iter() - .filter(|item| item.message.title.starts_with("thanks clippy")) - .count(); - if count > 0 { - segments.push(Segment::Clippy(section::Data::Generated( - section::segment::ThanksClippy { count }, - ))) - } - } - if let Some(commits_by_category) = - message_by_category.filter(|_| selection.contains(Selection::COMMIT_DETAILS)) - { - segments.push(Segment::Details(section::Data::Generated(section::segment::Details { - commits_by_category, - }))); - } - } - - let version = crate::git::try_strip_tag_path(segment.head.name.as_ref()).map_or_else( - || changelog::Version::Unreleased, - |tag_name| { - let package_name = - (!is_top_level_package(&package.manifest_path, repo)).then_some(package.name.as_str()); - changelog::Version::Semantic( - utils::parse_possibly_prefixed_tag_version(package_name, tag_name) - .expect("here we always have a valid version as it passed a filter when creating it"), - ) - }, - ); - let date = match version { - changelog::Version::Unreleased => None, - changelog::Version::Semantic(_) => Some(date_time), - }; - - Section::Release { - name: version, - date, - heading_level: changelog::DEFAULT_HEADING_LEVEL, - version_prefix: Self::DEFAULT_PREFIX.to_owned(), - segments, - removed_messages: Default::default(), - unknown: Default::default(), - } - } -} - -fn segment_head_time(segment: &commit::history::Segment<'_>, repo: &gix::Repository) -> OffsetDateTime { - let time = segment - .head - .peeled - .expect("all refs here are peeled") - .attach(repo) - .object() - .expect("object exists") - .to_commit_ref() - .committer - .time; - - time_to_offset_date_time(time) -} diff --git a/cargo-smart-release/src/changelog/section/mod.rs b/cargo-smart-release/src/changelog/section/mod.rs deleted file mode 100644 index 5c280d0d076..00000000000 --- a/cargo-smart-release/src/changelog/section/mod.rs +++ /dev/null @@ -1,38 +0,0 @@ -mod from_history; -pub mod segment; - -#[derive(Eq, PartialEq, Debug, Clone)] -pub enum Segment { - /// A portion of a Section that we couldn't make sense of, but which should be kept as is nonetheless. - User { - markdown: String, - }, - Conventional(segment::Conventional), - Details(Data), - Statistics(Data), - Clippy(Data), -} - -#[derive(Eq, Debug, Clone)] -pub enum Data { - Parsed, - Generated(T), -} - -impl> PartialEq> for Data { - fn eq(&self, other: &Data) -> bool { - match (self, other) { - (Data::Generated(lhs), Data::Generated(rhs)) => lhs == rhs, - (_, _) => true, - } - } -} - -impl Segment { - pub fn is_read_only(&self) -> bool { - match self { - Segment::User { .. } | Segment::Conventional { .. } => false, - Segment::Clippy(_) | Segment::Statistics(_) | Segment::Details(_) => true, - } - } -} diff --git a/cargo-smart-release/src/changelog/section/segment.rs b/cargo-smart-release/src/changelog/section/segment.rs deleted file mode 100644 index e67842b1892..00000000000 --- a/cargo-smart-release/src/changelog/section/segment.rs +++ /dev/null @@ -1,143 +0,0 @@ -use std::collections::BTreeMap; - -use bitflags::bitflags; - -pub mod conventional { - - /// A message that is associated with a Segment for a particular git-conventional segment - #[derive(PartialEq, Eq, Debug, Clone)] - pub enum Message { - User { - /// The user text for direct markdown-to-markdown copy - markdown: String, - }, - Generated { - /// The id of the message/commit the data is coming from, useful to identify the markdown associate with this message. - id: gix::ObjectId, - title: String, - body: Option, - }, - } - - /// Note that this depends on `crate::commit::message::to_static()`, - /// Not having a headline means it won't be written back unless it contains breaking changes. - pub fn as_headline(kind: &str) -> Option<&'static str> { - // NOTE: adding one here needs additions to parse.rs - Some(match kind { - "fix" => "Bug Fixes", - "add" | "added" => "Added", - "feat" => "New Features", - "revert" => "Reverted", - "remove" => "Removed", - "change" => "Changed", - "docs" => "Documentation", - "perf" => "Performance", - "chore" => "Chore", - "test" => "Test", - "refactor" => "Refactor", - "other" => "Other", - "style" => "Style", - _unknown => return None, - }) - } -} - -#[derive(Eq, PartialEq, Debug, Clone)] -pub struct Conventional { - /// The git-conventional kind - pub kind: &'static str, - /// Whether or not the segment contains only breaking changes - pub is_breaking: bool, - /// object IDs parsed from markdown with no surrounding text. These are considered removed, so we shouldn't repopulate them. - pub removed: Vec, - /// The messages to convey - pub messages: Vec, -} - -impl Conventional { - pub const REMOVED_HTML_PREFIX: &'static str = ") -> fmt::Result { - match self { - Category::Uncategorized => f.write_str("Uncategorized"), - Category::Issue(issue) => write!(f, "#{issue}"), - } - } - } - - #[derive(PartialEq, Eq, Debug, Clone)] - pub struct Message { - pub title: String, - pub id: gix::ObjectId, - } - - impl From<&crate::commit::history::Item> for Message { - fn from(v: &crate::commit::history::Item) -> Self { - Message { - title: v.message.title.to_owned(), - id: v.id, - } - } - } -} - -#[derive(PartialEq, Eq, Debug, Clone)] -pub struct Details { - pub commits_by_category: BTreeMap>, -} - -impl Details { - pub const TITLE: &'static str = "Commit Details"; - pub const HTML_PREFIX: &'static str = "
view details"; - pub const HTML_PREFIX_END: &'static str = "
"; -} - -#[derive(PartialEq, Eq, Debug, Clone)] -pub struct CommitStatistics { - /// Amount of commits that contributed to the release - pub count: usize, - /// The time span from first to last commit, if there is more than one. - pub duration: Option, - /// Amount of commits that could be parsed as git-conventional - pub conventional_count: usize, - /// The issue numbers that were referenced in commit messages - pub unique_issues: Vec, - /// The duration from the release before this one, if this isn't the first release. - pub time_passed_since_last_release: Option, -} - -impl CommitStatistics { - pub const TITLE: &'static str = "Commit Statistics"; -} - -#[derive(PartialEq, Eq, Debug, Clone)] -pub struct ThanksClippy { - pub count: usize, -} - -impl ThanksClippy { - pub const TITLE: &'static str = "Thanks Clippy"; -} - -bitflags! { - #[derive(Debug, Copy, Clone)] - pub struct Selection: u8 { - const CLIPPY = 1<<0; - const COMMIT_DETAILS = 1<<1; - const COMMIT_STATISTICS = 1<<2; - const GIT_CONVENTIONAL = 1<<3; - } -} diff --git a/cargo-smart-release/src/changelog/tests.rs b/cargo-smart-release/src/changelog/tests.rs deleted file mode 100644 index 1cf62f5e8bc..00000000000 --- a/cargo-smart-release/src/changelog/tests.rs +++ /dev/null @@ -1,22 +0,0 @@ -mod repository_url { - - use crate::changelog::write::RepositoryUrl; - - #[test] - fn github_https_url() { - for input in [ - "https://github.com/byron/gitoxide", - "https://github.com/byron/gitoxide.git", - "git://github.com/byron/gitoxide", - "git://github.com/byron/gitoxide.git", - "git@github.com:byron/gitoxide.git", - "git@github.com:byron/gitoxide", - ] { - let url = RepositoryUrl::from(gix::url::parse(input.into()).unwrap()); - assert_eq!( - url.github_https().expect("possible"), - "https://github.com/byron/gitoxide" - ) - } - } -} diff --git a/cargo-smart-release/src/changelog/write.rs b/cargo-smart-release/src/changelog/write.rs deleted file mode 100644 index 71482f6a7e5..00000000000 --- a/cargo-smart-release/src/changelog/write.rs +++ /dev/null @@ -1,422 +0,0 @@ -use std::borrow::Cow; - -use gix::{bstr::ByteSlice, url::Scheme, Url}; - -use crate::{ - changelog, - changelog::{ - section, - section::{segment, segment::details::Category, Segment}, - Section, - }, - ChangeLog, -}; - -struct PrefixedVersion<'a> { - version_prefix: &'a str, - name: &'a changelog::Version, -} - -impl<'a> std::fmt::Display for PrefixedVersion<'a> { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - match self.name { - changelog::Version::Unreleased => f.write_str("Unreleased"), - changelog::Version::Semantic(v) => write!(f, "{}{}", self.version_prefix, v), - } - } -} - -/// Define how linkable items should be written -#[derive(Clone)] -pub enum Linkables { - /// Use markdown links to link directly to the linkable items - AsLinks { - /// The location of the repository to link to - repository_url: RepositoryUrl, - }, - /// Leave them in a textual representation for the hosting platform to auto-link them - AsText, -} - -#[derive(Clone)] -pub struct RepositoryUrl { - pub inner: gix::Url, -} - -impl From for RepositoryUrl { - fn from(v: Url) -> Self { - RepositoryUrl { inner: v } - } -} - -impl RepositoryUrl { - pub fn is_github(&self) -> bool { - self.inner.host().map_or(false, |h| h == "github.com") - } - - fn cleaned_path(&self) -> String { - let path = self.inner.path.to_str_lossy().into_owned(); - #[allow(clippy::map_unwrap_or)] - let path = path.strip_suffix(".git").map(ToOwned::to_owned).unwrap_or(path); - if !path.starts_with('/') { - format!("/{path}") - } else { - path - } - } - - pub fn github_https(&self) -> Option { - match &self.inner.host() { - Some(host) if *host == "github.com" => match self.inner.scheme { - Scheme::Http | Scheme::Https | Scheme::Git => { - format!("https://github.com{}", self.cleaned_path()).into() - } - Scheme::Ssh => self - .inner - .user() - .filter(|user| *user == "git") - .map(|_git| format!("https://github.com{}", self.cleaned_path())), - _ => None, - }, - None | Some(_) => None, - } - } -} - -bitflags::bitflags! { - #[derive(Debug, Copy, Clone)] - pub struct Components: u8 { - const SECTION_TITLE = 1<<0; - const HTML_TAGS = 1<<1; - const DETAIL_TAGS = 1<<2; - } -} - -impl Section { - pub const UNKNOWN_TAG_START: &'static str = ""; - pub const UNKNOWN_TAG_END: &'static str = ""; - pub const READONLY_TAG: &'static str = "\n"; // needs a newline to not interfere with formatting - #[cfg(windows)] - pub const NL: &'static str = "\r\n"; - #[cfg(not(windows))] - pub const NL: &'static str = "\n"; - - /// Note that `headline` should be enabled by default as it will break parsing to some extend. It's a special case for tag - /// objects. - pub fn write_to( - &self, - mut out: impl std::fmt::Write, - link_mode: &Linkables, - components: Components, - capitalize_commit: bool, - ) -> std::fmt::Result { - match self { - Section::Verbatim { text, .. } => { - out.write_str(text)?; - assure_ends_with_empty_line(&mut out, text) - } - Section::Release { - name, - date, - heading_level, - version_prefix, - segments, - removed_messages, - unknown, - } => { - if components.contains(Components::SECTION_TITLE) { - write!( - out, - "{} {}", - heading(*heading_level), - PrefixedVersion { version_prefix, name } - )?; - match date { - None => out.write_str("\n\n"), - Some(date) => writeln!( - out, - " ({:04}-{:02}-{:02})\n", - date.year(), - date.month() as u32, - date.day() - ), - }?; - } - if !removed_messages.is_empty() && components.contains(Components::HTML_TAGS) { - for id in removed_messages { - writeln!(out, "{}{}/>", segment::Conventional::REMOVED_HTML_PREFIX, id)?; - } - writeln!(out)?; - } - - let section_level = *heading_level + 1; - for segment in segments { - segment.write_to(section_level, link_mode, components, capitalize_commit, &mut out)?; - } - if !unknown.is_empty() && components.contains(Components::HTML_TAGS) { - writeln!(out, "{}", Section::UNKNOWN_TAG_START)?; - out.write_str(unknown)?; - writeln!(out, "{}\n", Section::UNKNOWN_TAG_END)?; - } - Ok(()) - } - } - } -} - -fn assure_ends_with_empty_line(out: &mut impl std::fmt::Write, text: &str) -> std::fmt::Result { - if !(text.ends_with("\n\n") || text.ends_with("\r\n\r\n")) { - out.write_str(Section::NL)?; - if !(text.ends_with('\n') || text.ends_with("\r\n")) { - out.write_str(Section::NL)?; - } - }; - Ok(()) -} -fn heading(level: usize) -> String { - "#".repeat(level) -} - -impl ChangeLog { - pub fn write_to( - &self, - mut out: impl std::fmt::Write, - link_mode: &Linkables, - components: Components, - capitalize_commit: bool, - ) -> std::fmt::Result { - for section in &self.sections { - section.write_to(&mut out, link_mode, components, capitalize_commit)?; - } - Ok(()) - } -} - -impl section::Segment { - pub fn write_to( - &self, - section_level: usize, - link_mode: &Linkables, - components: Components, - capitalize_commit: bool, - mut out: impl std::fmt::Write, - ) -> std::fmt::Result { - let write_html = components.contains(Components::HTML_TAGS); - match self { - Segment::User { markdown } => { - out.write_str(markdown)?; - assure_ends_with_empty_line(&mut out, markdown)?; - } - Segment::Conventional(segment::Conventional { - kind, - is_breaking, - removed, - messages, - }) => match segment::conventional::as_headline(kind).or_else(|| is_breaking.then(|| *kind)) { - Some(headline) => { - writeln!( - out, - "{} {}{}\n", - heading(section_level), - headline, - if *is_breaking { - format!(" {}", segment::Conventional::BREAKING_TITLE_ENCLOSED) - } else { - "".into() - }, - )?; - - if !removed.is_empty() && write_html { - for id in removed { - writeln!(out, "{}{}/>", segment::Conventional::REMOVED_HTML_PREFIX, id)?; - } - writeln!(out)?; - } - - use segment::conventional::Message; - for message in messages { - match message { - Message::Generated { title, id, body } => { - let title = if capitalize_commit { - capitalize_message_title(title) - } else { - Cow::Borrowed(title.as_str()) - }; - if write_html { - writeln!( - out, - " - {}{}/> {}", - segment::Conventional::REMOVED_HTML_PREFIX, - id, - title - )?; - } else { - writeln!(out, " - {title}")?; - } - if let Some(body) = body { - for line in body.as_bytes().as_bstr().lines_with_terminator() { - write!(out, " {}", line.to_str().expect("cannot fail as original is UTF-8"))?; - } - if !body.ends_with('\n') { - writeln!(out)?; - } - } - } - Message::User { markdown } => { - out.write_str(markdown)?; - if !markdown.ends_with('\n') { - writeln!(out)?; - } - } - } - } - writeln!(out)?; - } - None => log::trace!( - "Skipping unknown git-conventional kind {:?} and all {} message(s) in it.", - kind, - messages.len() - ), - }, - Segment::Details(section::Data::Generated(segment::Details { commits_by_category })) - if !commits_by_category.is_empty() => - { - let write_details_tags = components.contains(Components::DETAIL_TAGS); - writeln!(out, "{} {}\n", heading(section_level), segment::Details::TITLE)?; - if write_details_tags { - writeln!(out, "{}", Section::READONLY_TAG)?; - writeln!(out, "{}\n", segment::Details::HTML_PREFIX)?; - } - for (category, messages) in commits_by_category.iter() { - writeln!(out, " * **{}**", format_category(category, link_mode))?; - for message in messages { - writeln!( - out, - " - {} ({})", - capitalize_message_title(&message.title), - format_oid(&message.id, link_mode) - )?; - } - } - if write_details_tags { - writeln!(out, "{}", segment::Details::HTML_PREFIX_END)?; - } - writeln!(out)?; - } - Segment::Statistics(section::Data::Generated(segment::CommitStatistics { - count, - duration, - conventional_count, - unique_issues, - time_passed_since_last_release, - })) => { - writeln!(out, "{} {}\n", heading(section_level), segment::CommitStatistics::TITLE)?; - if write_html { - writeln!(out, "{}", Section::READONLY_TAG)?; - } - writeln!( - out, - " - {} {} contributed to the release{}", - count, - if *count == 1 { "commit" } else { "commits" }, - match duration { - Some(duration) if duration.whole_days() > 0 => format!( - " over the course of {} calendar {}.", - duration.whole_days(), - if duration.whole_days() == 1 { "day" } else { "days" } - ), - _ => ".".into(), - } - )?; - if let Some(time_between_releases) = time_passed_since_last_release.filter(|d| d.whole_days() > 0) { - writeln!( - out, - " - {} {} passed between releases.", - time_between_releases.whole_days(), - if time_between_releases.whole_days() == 1 { - "day" - } else { - "days" - } - )?; - } - writeln!( - out, - " - {} {} {} understood as [conventional](https://www.conventionalcommits.org).", - conventional_count, - if *conventional_count == 1 { "commit" } else { "commits" }, - if *conventional_count == 1 { "was" } else { "were" } - )?; - if unique_issues.is_empty() { - writeln!(out, " - 0 issues like '(#ID)' were seen in commit messages")?; - } else { - writeln!( - out, - " - {} unique {} {} worked on: {}", - unique_issues.len(), - if unique_issues.len() == 1 { "issue" } else { "issues" }, - if unique_issues.len() == 1 { "was" } else { "were" }, - unique_issues - .iter() - .map(|c| format_category(c, link_mode)) - .collect::>() - .join(", ") - )?; - } - writeln!(out)?; - } - Segment::Clippy(section::Data::Generated(segment::ThanksClippy { count })) if *count > 0 => { - writeln!(out, "{} {}\n", heading(section_level), segment::ThanksClippy::TITLE)?; - if write_html { - writeln!(out, "{}", Section::READONLY_TAG)?; - } - writeln!( - out, - "[Clippy](https://github.com/rust-lang/rust-clippy) helped {} {} to make code idiomatic. \n", - count, - if *count > 1 { "times" } else { "time" } - )?; - } - Segment::Clippy(_) => {} - Segment::Statistics(_) => {} - Segment::Details(_) => {} - }; - Ok(()) - } -} - -fn format_category(cat: &Category, link_mode: &Linkables) -> String { - match (cat, link_mode) { - (Category::Issue(id), Linkables::AsLinks { repository_url }) => match repository_url.github_https() { - Some(base_url) => { - format!("[#{id}]({base_url}/issues/{id})") - } - None => format_category(cat, &Linkables::AsText), - }, - (_, _) => cat.to_string(), - } -} - -fn format_oid(id: &gix::oid, link_mode: &Linkables) -> String { - match link_mode { - Linkables::AsText => id.to_hex_with_len(7).to_string(), - Linkables::AsLinks { repository_url } => match repository_url.github_https() { - Some(base_url) => { - format!("[`{}`]({}/commit/{})", id.to_hex_with_len(7), base_url, id) - } - None => format_oid(id, &Linkables::AsText), - }, - } -} - -fn capitalize_message_title<'a>(title: impl Into>) -> Cow<'a, str> { - let mut title = title.into(); - let mut chars = title.chars(); - if let Some(first) = chars - .next() - .and_then(|c| (c.to_uppercase().next() != Some(c)).then_some(c)) - { - *title.to_mut() = first.to_uppercase().chain(chars).collect(); - } - title -} diff --git a/cargo-smart-release/src/cli/main-changelog.rs b/cargo-smart-release/src/cli/main-changelog.rs deleted file mode 100644 index d5be06a9871..00000000000 --- a/cargo-smart-release/src/cli/main-changelog.rs +++ /dev/null @@ -1 +0,0 @@ -include!("main.rs"); diff --git a/cargo-smart-release/src/cli/main-smart-release.rs b/cargo-smart-release/src/cli/main-smart-release.rs deleted file mode 100644 index d5be06a9871..00000000000 --- a/cargo-smart-release/src/cli/main-smart-release.rs +++ /dev/null @@ -1 +0,0 @@ -include!("main.rs"); diff --git a/cargo-smart-release/src/cli/main.rs b/cargo-smart-release/src/cli/main.rs deleted file mode 100644 index 6e8da0f01fe..00000000000 --- a/cargo-smart-release/src/cli/main.rs +++ /dev/null @@ -1,145 +0,0 @@ -mod options; -use clap::Parser; -use options::{Args, SubCommands}; - -use cargo_smart_release::command; - -fn main() -> anyhow::Result<()> { - gix::interrupt::init_handler(|| {})?; - unsafe { - // SAFETY: we don't manipulate the environment from any thread - time::util::local_offset::set_soundness(time::util::local_offset::Soundness::Unsound); - } - let args: Args = Args::parse(); - match args.subcommands { - SubCommands::Changelog { - write, - execute, - crates, - no_dependencies, - no_preview, - no_links, - without, - allow_dirty, - capitalize_commit, - } => { - init_logging(false); - command::changelog( - command::changelog::Options { - dry_run: !(write || execute), - allow_dirty, - no_links, - preview: !no_preview, - dependencies: !no_dependencies, - generator_segments: names_to_segment_selection(&without)?, - capitalize_commit, - }, - crates, - )? - } - SubCommands::SmartRelease { - execute, - verbose, - bump, - bump_dependencies, - crates, - allow_dirty, - ignore_instability, - no_publish, - no_tag, - no_push, - changelog_without, - dangerously_pass_no_verify, - auto_publish_of_stable_crates, - no_conservative_pre_release_version_handling, - dry_run_cargo_publish, - update_crates_index, - no_bump_on_demand, - no_changelog, - no_changelog_links, - no_changelog_preview, - no_changelog_github_release, - allow_fully_generated_changelogs, - no_dependencies, - no_isolate_dependencies_from_breaking_changes, - capitalize_commit, - } => { - let verbose = execute || verbose; - init_logging(verbose); - command::release( - command::release::Options { - dry_run: !execute, - verbose, - conservative_pre_release_version_handling: !no_conservative_pre_release_version_handling, - bump_when_needed: !no_bump_on_demand, - isolate_dependencies_from_breaking_changes: !no_isolate_dependencies_from_breaking_changes, - allow_dirty, - ignore_instability, - skip_publish: no_publish, - changelog: !no_changelog, - skip_tag: no_tag, - skip_push: no_push, - dependencies: !no_dependencies, - dry_run_cargo_publish, - no_verify: dangerously_pass_no_verify, - allow_auto_publish_of_stable_crates: auto_publish_of_stable_crates, - update_crates_index, - preview: !no_changelog_preview, - generator_segments: names_to_segment_selection(&changelog_without)?, - allow_fully_generated_changelogs, - changelog_links: !no_changelog_links, - allow_changelog_github_release: !no_changelog_github_release, - capitalize_commit, - }, - crates, - to_bump_spec(bump.as_deref().unwrap_or(DEFAULT_BUMP_SPEC))?, - to_bump_spec(bump_dependencies.as_deref().unwrap_or(DEFAULT_BUMP_SPEC))?, - )? - } - }; - - Ok(()) -} - -const DEFAULT_BUMP_SPEC: &str = "auto"; - -fn to_bump_spec(spec: &str) -> anyhow::Result { - use cargo_smart_release::version::BumpSpec::*; - Ok(match spec { - "patch" | "Patch" => Patch, - "minor" | "Minor" => Minor, - "major" | "Major" => Major, - "keep" | "Keep" => Keep, - "auto" | "Auto" => Auto, - unknown_spec => anyhow::bail!("Unknown bump specification: {:?}", unknown_spec), - }) -} - -fn names_to_segment_selection( - names: &[String], -) -> anyhow::Result { - use cargo_smart_release::changelog::section::segment::Selection; - Ok(if names.is_empty() { - Selection::all() - } else { - let mut deselected = Selection::empty(); - for name in names { - deselected |= match name.as_str() { - "clippy" => Selection::CLIPPY, - "commit-details" => Selection::COMMIT_DETAILS, - "commit-statistics" => Selection::COMMIT_STATISTICS, - "git-conventional" => Selection::GIT_CONVENTIONAL, - other => anyhow::bail!("Invalid changelog segment selector: {:?}", other), - }; - } - Selection::all().difference(deselected) - }) -} - -fn init_logging(verbose: bool) { - env_logger::Builder::from_env(env_logger::Env::default().default_filter_or(if verbose { "trace" } else { "info" })) - .format_module_path(false) - .format_target(false) - .format_timestamp(None) - .init(); -} diff --git a/cargo-smart-release/src/cli/options.rs b/cargo-smart-release/src/cli/options.rs deleted file mode 100644 index 74fa80c03fd..00000000000 --- a/cargo-smart-release/src/cli/options.rs +++ /dev/null @@ -1,213 +0,0 @@ -#[derive(clap::Parser)] -#[clap(subcommand_required = true)] -#[clap(disable_help_subcommand = true)] -#[clap(disable_version_flag = true)] -#[clap(bin_name = "cargo")] -/// Release workspace crates fearlessly. -/// -/// Use --execute to actually perform the operation. -pub struct Args { - #[clap(subcommand)] - pub subcommands: SubCommands, -} - -#[derive(clap::Parser)] -pub enum SubCommands { - #[clap(name = "smart-release", version = option_env!("CARGO_SMART_RELEASE_VERSION"))] - /// Release workspace crates fearlessly. - /// - /// Use --execute to actually perform the operation. - SmartRelease { - /// Actually perform a release. Dry-run mode is the default - #[clap(long, short = 'e', help_heading = Some("MAJOR"))] - execute: bool, - - /// Always update the crates-index beforehand. It is used to determine if the computed version to be published was - /// already published. - #[clap(long, short = 'u', help_heading = Some("MAJOR"))] - update_crates_index: bool, - - /// Don't generate a changelog automatically or update existing ones. This is useful if a manual changelog - /// is preferred or if its format strays to far from the suggestions on , making - /// generated content impossible to properly integrate with what's there. - #[clap(long, help_heading = Some("MAJOR"))] - no_changelog: bool, - - /// Specify the kind of version bump you seek for the crate and potentially it's dependencies. - /// - /// Can be 'major', 'minor' or 'patch', 'keep' and 'auto'. - /// With 'keep', the current version will be kept, useful if versions are specified by hand in the manifest. - /// - /// The default is 'auto', which derives the necessary information from the git commit history and occasional - /// conventional messages. - #[clap(long, short = 'b', help_heading = Some("MAJOR"))] - bump: Option, - - /// Specify the kind of version bump to apply to dependencies only. - /// - /// Can be 'major', 'minor' or 'patch', 'keep' and 'auto'. - /// With 'keep', the current version will be kept, useful if versions are specified by hand in the manifest. - /// - /// The default is 'auto', which derives the necessary information from the git commit history and occasional - /// conventional messages. - #[clap(long, short = 'd', help_heading = Some("MAJOR"))] - bump_dependencies: Option, - - /// The name of the crates to be released, along with all of their dependencies if needed. - /// - /// Defaults to the top-level workspace crate if unset. - crates: Vec, - - /// Provide more detailed messages on the INFO log level in dry-run mode. - /// - /// Note --verbose is implied with --execute. - #[clap(long, short = 'v', help_heading = Some("CUSTOMIZATION"))] - verbose: bool, - - /// Additionally run 'cargo publish --dry-run' when --execute is not set. This can be useful to see which local - /// crates do not build with the released versions of their workspace dependencies anymore. - #[clap(long, help_heading = Some("CUSTOMIZATION"))] - dry_run_cargo_publish: bool, - - /// Always bump versions as specified by --bump or --bump-dependencies even if this is not required - /// to publish a new version to crates.io. - /// - /// For instance, if the currently set version is 1.0 and the latest published version is 0.5, while - /// a minor version bump is specified like -b minor, 1.0 would be published instead of 1.1 unless this - /// flag is set. - #[clap(long, help_heading = Some("CUSTOMIZATION"))] - no_bump_on_demand: bool, - - /// Do not create a github release (if the repo is located on github) reflecting the content of the changelogs most recent - /// release section. - #[clap(long, help_heading = Some("CHANGELOG"))] - no_changelog_github_release: bool, - - /// If changelogs are generated from git-conventional comments extracted from the commit history exclusively, publishes - /// will fail as in order to give opportunity to author at least a portion of the upcoming release. - /// - /// With this flag set, the release will not stop. - /// Note that changelog entries purely composed of statistical information will always stop a release. - #[clap(long, help_heading = Some("CHANGELOG-EXPERT"))] - allow_fully_generated_changelogs: bool, - - /// Do not generate links to commits and issues when writing the changelogs. This currently only works for GitHub. - #[clap(long, help_heading = Some("CHANGELOG"))] - no_changelog_links: bool, - - /// Omits these kinds of generated changelog content, values are 'clippy', 'commit-statistics' and 'commit-details' - #[clap(long, help_heading = Some("CHANGELOG"))] - changelog_without: Vec, - - /// If unset, about-to-be changed changelogs will be previewed using 'bat', if available, and when executing. - /// - /// If set, no preview will ever be displayed, but note that empty changelogs will always stop the release process. - #[clap(long, help_heading = Some("CHANGELOG"))] - no_changelog_preview: bool, - - /// Allow publishes to take place on a dirty working tree. Really not recommended alongside --execute. - #[clap(long, help_heading = Some("EXPERT"))] - allow_dirty: bool, - - /// Allow to also publish stable crates when discovering changed crates, bumping their version according to `-d `. - #[clap(long, help_heading = Some("CUSTOMIZATION"))] - auto_publish_of_stable_crates: bool, - - /// Do not force 0.X version requirements to be updated in dependent crates on patch update, forcing - /// an update of the lower bound. - /// - /// It's best to look at this issue for a deeper understanding: - #[clap(long, help_heading = Some("EXPERT"))] - no_conservative_pre_release_version_handling: bool, - - /// Do not bump versions of dependent crates if the crates to be published indicate breaking changes with their semantic version. - /// - /// For details, it's best to look at - #[clap(long, help_heading = Some("EXPERT"))] - no_isolate_dependencies_from_breaking_changes: bool, - - /// Don't actually publish, but perform all other operations like manifest adjustments and tag creation. - #[clap(long, help_heading = Some("CUSTOMIZATION"))] - no_publish: bool, - - /// Don't create tags indicating the version numbers of all crates that are to be published after changing - /// their manifests. - #[clap(long, help_heading = Some("CUSTOMIZATION"))] - no_tag: bool, - - /// Don't push tags and the HEAD branch after any successful run of `cargo publish`. - #[clap(long, help_heading = Some("CUSTOMIZATION"))] - no_push: bool, - - /// Do not take into consideration any dependencies of the crates to publish. - /// - /// This flag is useful when various `--skip-X` are specified in order to bump versions only, without publishing. - #[clap(long, visible_alias = "only", help_heading = Some("CUSTOMIZATION"))] - no_dependencies: bool, - - /// Pass --no-verify to 'cargo publish' which should only be a last resort when fixing up packages that - /// otherwise wouldn't publish, but need to be publish to resolve the situation. - #[clap(long, help_heading = Some("EXPERT"))] - dangerously_pass_no_verify: bool, - - /// If set it will be allowed to publish crates with cycles to other workspace crates which are not published. - /// - /// Doing so causes repeated publishes to never stabilize, as one set of dependencies destabilizes another set. - /// A possible fix is to bump version numbers of all crates in the set at once and publishing those who would - /// depend on an unpublished version with "--no-validate". - #[clap(long, help_heading = Some("EXPERT"))] - ignore_instability: bool, - - /// Capitalize commit messages. - #[clap(long, help_heading = Some("CHANGELOG"))] - capitalize_commit: bool, - }, - #[clap(name = "changelog", version = option_env!("CARGO_SMART_RELEASE_VERSION"))] - /// Generate changelogs from commit histories, non-destructively. - /// - /// Use --write to actually write generated changelogs - Changelog { - /// Actually write the changelog to the respective files - #[clap(long, short = 'w', help_heading = Some("MAJOR"))] - write: bool, - - /// Actually write the changelog to the respective files, similar to --write, for consistency with 'smart-release' - #[clap(long, short = 'e', help_heading = Some("MAJOR"))] - execute: bool, - - /// omits these kinds of generated changelog content, values are 'clippy', 'commit-statistics' and 'commit-details' - #[clap(long, help_heading = Some("CUSTOMIZATION"))] - without: Vec, - - /// Take into consideration any dependencies of the crates to generate the changelog for. - /// - /// This flag is useful if you plan to review and finalize changelogs before a smart-release, where dependencies - /// are taken into consideration by default, instead of handling them one at a time. - #[clap(long, visible_alias = "only", help_heading = Some("CUSTOMIZATION"))] - no_dependencies: bool, - - /// The name of the crates to generate a changelog for. - /// - /// Defaults to the top-level workspace crate if unset. - crates: Vec, - - /// Allow changelog updates to take place on a dirty working tree when --write is set as well. - /// - /// For now this is not recommended as changelogs might be damaged beyond repair. - #[clap(long, short = 'd', help_heading = Some("EXPERT"))] - allow_dirty: bool, - - /// If --write is not set, 'bat' will be used (if available) to print the new changelog to stdout as preview. Use this flag - /// to disable such behaviour. - #[clap(long, help_heading = Some("CUSTOMIZATION"))] - no_preview: bool, - - /// Do not generate links to commits and issues when writing the changelogs. This currently only works for GitHub. - #[clap(long, help_heading = Some("CUSTOMIZATION"))] - no_links: bool, - - /// Capitalize commit messages. - #[clap(long, help_heading = Some("CUSTOMIZATION"))] - capitalize_commit: bool, - }, -} diff --git a/cargo-smart-release/src/command/changelog.rs b/cargo-smart-release/src/command/changelog.rs deleted file mode 100644 index 0f271319cb5..00000000000 --- a/cargo-smart-release/src/command/changelog.rs +++ /dev/null @@ -1,151 +0,0 @@ -use std::io::Write; - -use crate::{ - bat, - changelog::write::{Components, Linkables}, - command::changelog::Options, - git, - traverse::dependency, - utils::will, - version::BumpSpec, - ChangeLog, -}; - -pub fn changelog(opts: Options, crates: Vec) -> anyhow::Result<()> { - let Options { - generator_segments, - dependencies, - dry_run, - preview, - no_links, - capitalize_commit, - .. - } = opts; - let bump_spec = if dependencies { BumpSpec::Auto } else { BumpSpec::Keep }; - let force_history_segmentation = false; - let ctx = crate::Context::new(crates.clone(), force_history_segmentation, bump_spec, bump_spec)?; - let crates: Vec<_> = { - crate::traverse::dependencies( - &ctx, - crate::traverse::Options { - allow_auto_publish_of_stable_crates: true, - bump_when_needed: true, - isolate_dependencies_from_breaking_changes: true, - traverse_graph: dependencies, - }, - )? - .into_iter() - .filter_map(|d| match d.mode { - dependency::Mode::ToBePublished { .. } => Some(d.package), - dependency::Mode::NotForPublishing { .. } => { - if crates.contains(&d.package.name) { - log::info!( - "Skipping '{}' as it won't be published.{}", - d.package.name, - if !dependencies { - " Try not to specify --no-dependencies/--only." - } else { - "" - } - ); - } - None - } - }) - .collect() - }; - assure_working_tree_is_unchanged(opts)?; - let history = match git::history::collect(&ctx.repo)? { - None => return Ok(()), - Some(history) => history, - }; - - let bat = (dry_run && preview).then(bat::Support::new); - - let mut pending_changes = Vec::new(); - let linkables = if dry_run || no_links { - Linkables::AsText - } else { - git::remote_url(&ctx.repo)?.map_or(Linkables::AsText, |url| Linkables::AsLinks { - repository_url: url.into(), - }) - }; - let mut num_crates = 0; - for (idx, package) in crates.iter().enumerate() { - num_crates += 1; - let crate::changelog::init::Outcome { - log, mut lock, state, .. - } = ChangeLog::for_package_with_write_lock(package, &history, &ctx, generator_segments)?; - log::info!( - "{} write {} sections to {} ({})", - will(dry_run), - log.sections.len(), - lock.resource_path() - .strip_prefix(&ctx.root) - .expect("contained in workspace") - .display(), - state.as_str(), - ); - lock.with_mut(|file| { - let mut buf = String::new(); - log.write_to( - &mut buf, - &linkables, - if dry_run { - Components::SECTION_TITLE - } else { - Components::all() - }, - capitalize_commit, - ) - .map_err(|err| std::io::Error::new(std::io::ErrorKind::Other, err))?; - file.write_all(buf.as_bytes()) - })?; - if let Some(bat) = bat.as_ref() { - bat.display_to_tty( - lock.lock_path(), - lock.resource_path().strip_prefix(&ctx.root.to_path_buf())?, - format!("PREVIEW {} / {}, press Ctrl+C to cancel", idx + 1, crates.len()), - )?; - } - if !dry_run { - pending_changes.push(lock); - } - } - - if num_crates == 0 { - anyhow::bail!( - "The given crate{} {} didn't change and no changelog could be generated.", - if ctx.crate_names.len() != 1 { "s" } else { "" }, - ctx.crate_names - .iter() - .map(|c| format!("'{c}'")) - .collect::>() - .join(", ") - ) - } - - let num_changes = pending_changes.len(); - for change in pending_changes { - change.commit()?; - } - if num_changes != 0 { - log::info!("Wrote {} changelogs", num_changes); - } - - Ok(()) -} - -fn assure_working_tree_is_unchanged(options: Options) -> anyhow::Result<()> { - if options.allow_dirty { - Ok(()) - } else { - crate::git::assure_clean_working_tree().or_else(|err| - if options.dry_run { - log::warn!("The working tree has changes which will prevent changelog updates with --write unless --allow-dirty is also specified. The latter isn't recommended."); - Ok(()) - } else { - Err(err) - }) - } -} diff --git a/cargo-smart-release/src/command/mod.rs b/cargo-smart-release/src/command/mod.rs deleted file mode 100644 index 899d73b202d..00000000000 --- a/cargo-smart-release/src/command/mod.rs +++ /dev/null @@ -1,52 +0,0 @@ -pub mod release { - use crate::changelog::section::segment; - - #[derive(Debug, Clone, Copy)] - pub struct Options { - pub dry_run: bool, - pub allow_dirty: bool, - pub ignore_instability: bool, - pub skip_publish: bool, - pub dry_run_cargo_publish: bool, - pub conservative_pre_release_version_handling: bool, - /// Pass --no-verify unconditionally to cargo publish. Really just for fixing things - pub no_verify: bool, - pub skip_tag: bool, - pub allow_auto_publish_of_stable_crates: bool, - pub update_crates_index: bool, - pub bump_when_needed: bool, - pub verbose: bool, - pub skip_push: bool, - pub dependencies: bool, - pub isolate_dependencies_from_breaking_changes: bool, - pub changelog: bool, - pub preview: bool, - pub generator_segments: segment::Selection, - pub allow_fully_generated_changelogs: bool, - pub changelog_links: bool, - pub allow_changelog_github_release: bool, - pub capitalize_commit: bool, - } -} -#[path = "release/mod.rs"] -mod release_impl; -pub use release_impl::release; - -pub mod changelog { - use crate::changelog::section::segment; - - #[derive(Debug, Clone, Copy)] - pub struct Options { - pub dry_run: bool, - pub dependencies: bool, - pub allow_dirty: bool, - pub preview: bool, - // All the segments to generate - pub generator_segments: segment::Selection, - pub no_links: bool, - pub capitalize_commit: bool, - } -} -#[path = "changelog.rs"] -mod changelog_impl; -pub use changelog_impl::changelog; diff --git a/cargo-smart-release/src/command/release/cargo.rs b/cargo-smart-release/src/command/release/cargo.rs deleted file mode 100644 index 694fe5c41b9..00000000000 --- a/cargo-smart-release/src/command/release/cargo.rs +++ /dev/null @@ -1,66 +0,0 @@ -use std::process::Command; - -use anyhow::bail; -use cargo_metadata::Package; - -use super::Options; -use crate::utils::will; - -pub(in crate::command::release_impl) fn publish_crate( - publishee: &Package, - prevent_default_members: bool, - Options { - skip_publish, - dry_run, - dry_run_cargo_publish, - allow_dirty, - no_verify, - verbose, - .. - }: Options, -) -> anyhow::Result<()> { - if skip_publish { - return Ok(()); - } - let max_attempts = 3; - let uses_cargo_dry_run = dry_run && dry_run_cargo_publish; - let cargo_must_run = !dry_run || uses_cargo_dry_run; - for attempt in 1..=max_attempts { - let mut c = Command::new("cargo"); - c.arg("publish"); - - if allow_dirty { - c.arg("--allow-dirty"); - } - if no_verify { - c.arg("--no-verify"); - } - if uses_cargo_dry_run { - c.arg("--dry-run"); - } - c.arg("--manifest-path").arg(&publishee.manifest_path); - if prevent_default_members { - c.arg("--package").arg(&publishee.name); - } - if verbose { - log::trace!("{} run {:?}", will(!cargo_must_run), c); - } - if !cargo_must_run || c.status()?.success() { - break; - } else if attempt == max_attempts || dry_run { - bail!("Could not successfully execute 'cargo publish'.") - } else { - log::warn!( - "'cargo publish' run {} failed but we retry up to {} times to rule out flakiness", - attempt, - max_attempts - ); - } - } - Ok(()) -} - -pub fn refresh_lock_file() -> anyhow::Result<()> { - cargo_metadata::MetadataCommand::new().exec()?; - Ok(()) -} diff --git a/cargo-smart-release/src/command/release/git.rs b/cargo-smart-release/src/command/release/git.rs deleted file mode 100644 index b280d9ce991..00000000000 --- a/cargo-smart-release/src/command/release/git.rs +++ /dev/null @@ -1,117 +0,0 @@ -use std::{convert::TryInto, process::Command}; - -use anyhow::{anyhow, bail}; -use cargo_metadata::Package; -use gix::{bstr::ByteSlice, refs, refs::transaction::PreviousValue, Id}; - -use super::{tag_name, Options}; -use crate::utils::will; - -pub(in crate::command::release_impl) fn commit_changes( - message: impl AsRef, - dry_run: bool, - empty_commit_possible: bool, - ctx: &crate::Context, -) -> anyhow::Result>> { - // TODO: replace with gitoxide one day - let mut cmd = Command::new("git"); - cmd.arg("commit").arg("-am").arg(message.as_ref()); - if empty_commit_possible { - cmd.arg("--allow-empty"); - } - log::trace!("{} run {:?}", will(dry_run), cmd); - if dry_run { - return Ok(None); - } - - if !cmd.status()?.success() { - bail!("Failed to commit changed manifests"); - } - Ok(Some(ctx.repo.find_reference("HEAD")?.peel_to_id_in_place()?)) -} - -pub(in crate::command::release_impl) fn create_version_tag<'repo>( - publishee: &Package, - new_version: &semver::Version, - commit_id: Option>, - tag_message: Option, - ctx: &'repo crate::Context, - Options { dry_run, skip_tag, .. }: Options, -) -> anyhow::Result> { - if skip_tag { - return Ok(None); - } - let tag_name = tag_name(publishee, new_version, &ctx.repo); - if dry_run { - match tag_message { - Some(message) => { - log::trace!( - "WOULD create tag object {} with changelog message, first line is: '{}'", - tag_name, - message.lines().next().unwrap_or("") - ); - } - None => { - log::trace!("WOULD create tag {}", tag_name); - } - } - Ok(Some(format!("refs/tags/{tag_name}").try_into()?)) - } else { - let target = commit_id.expect("set in --execute mode"); - let constraint = PreviousValue::Any; - let tag = match tag_message { - Some(message) => { - let tag = ctx.repo.tag( - tag_name, - target, - gix::objs::Kind::Commit, - Some(crate::git::author()?.to_ref()), - message, - constraint, - )?; - log::info!("Created tag object {} with release notes.", tag.name().as_bstr()); - tag - } - None => { - let tag = ctx.repo.tag_reference(tag_name, target, constraint)?; - log::info!("Created tag {}", tag.name().as_bstr()); - tag - } - }; - Ok(Some(tag.inner.name)) - } -} - -// TODO: Use gitoxide here -pub fn push_tags_and_head( - repo: &gix::Repository, - tag_names: &[refs::FullName], - Options { dry_run, skip_push, .. }: Options, -) -> anyhow::Result<()> { - if skip_push || tag_names.is_empty() { - return Ok(()); - } - - let mut cmd = Command::new("git"); - cmd.arg("push") - .arg( - repo.head()? - .into_remote(gix::remote::Direction::Push) - .ok_or_else(|| anyhow!("Cannot push in uninitialized repo"))?? - .name() - .expect("configured remotes have a name") - .as_bstr() - .to_string(), - ) - .arg("HEAD"); - for tag_name in tag_names { - cmd.arg(tag_name.as_bstr().to_str()?); - } - - log::trace!("{} run {:?}", will(dry_run), cmd); - if dry_run || cmd.status()?.success() { - Ok(()) - } else { - bail!("'git push' invocation failed. Try to push manually and repeat the smart-release invocation to resume, possibly with --skip-push."); - } -} diff --git a/cargo-smart-release/src/command/release/github.rs b/cargo-smart-release/src/command/release/github.rs deleted file mode 100644 index 4cc1c38bb42..00000000000 --- a/cargo-smart-release/src/command/release/github.rs +++ /dev/null @@ -1,72 +0,0 @@ -#![allow(dead_code)] - -use std::{borrow::Cow, process::Command}; - -use cargo_metadata::Package; - -use crate::{ - command::release::Options, - utils::{will, Program}, - Context, -}; - -struct Support { - gh: Program, -} - -impl Default for Support { - fn default() -> Self { - Self::new() - } -} - -impl Support { - fn new() -> Self { - Support { - gh: Program::named("gh"), - } - } -} - -pub fn create_release( - publishee: &Package, - new_version: &semver::Version, - notes: &str, - Options { dry_run, .. }: Options, - ctx: &Context, -) -> anyhow::Result<()> { - let tag_name = crate::utils::tag_name(publishee, new_version, &ctx.repo); - let mut cmd = Command::new("gh"); - cmd.args(["release", "create"]) - .arg(&tag_name) - .arg("--title") - .arg(format!( - "{}v{}", - match crate::utils::tag_prefix(publishee, &ctx.repo) { - Some(prefix) => Cow::Owned(format!("{prefix} ")), - None => "".into(), - }, - new_version - )) - .arg("--notes"); - log::trace!( - "{} run {:?} \"{}…\" [note truncated]", - will(dry_run), - cmd, - notes - .chars() - .take(22) - .collect::() - .replace('\n', "\\n") - .replace("\r\n", "\\r\\n") - ); - - cmd.arg(notes); - if !dry_run && !cmd.status()?.success() { - log::warn!( - "'gh' tool execution failed - considering this non-critical, and you may try to create the release with: {:?}", - cmd - ); - } - Ok(()) -} diff --git a/cargo-smart-release/src/command/release/manifest.rs b/cargo-smart-release/src/command/release/manifest.rs deleted file mode 100644 index f9e54d14986..00000000000 --- a/cargo-smart-release/src/command/release/manifest.rs +++ /dev/null @@ -1,618 +0,0 @@ -use std::{ - borrow::Cow, - collections::{btree_map::Entry, BTreeMap}, - io::Write, - str::FromStr, -}; - -use anyhow::{bail, Context as ContextTrait}; -use cargo_metadata::{camino::Utf8PathBuf, Package}; -use gix::{lock::File, Id}; -use semver::{Version, VersionReq}; - -use super::{cargo, git, Context, Options}; -use crate::{ - changelog, - changelog::{write::Linkables, Section}, - traverse::Dependency, - utils::{names_and_versions, try_to_published_crate_and_new_version, version_req_unset_or_default, will}, - version, ChangeLog, -}; - -pub struct Outcome<'repo, 'meta> { - pub commit_id: Option>, - pub section_by_package: BTreeMap<&'meta str, changelog::Section>, -} - -pub(in crate::command::release_impl) fn edit_version_and_fixup_dependent_crates_and_handle_changelog<'repo, 'meta>( - crates: &[Dependency<'meta>], - opts: Options, - ctx: &'repo Context, -) -> anyhow::Result> { - let Options { dry_run, changelog, .. } = opts; - let crates_and_versions_to_be_published: Vec<_> = crates - .iter() - .filter_map(try_to_published_crate_and_new_version) - .collect(); - let GatherOutcome { - pending_changelogs, - mut locks_by_manifest_path, - changelog_ids_with_statistical_segments_only, - changelog_ids_probably_lacking_user_edits, - release_section_by_publishee, - mut made_change, - } = changelog - .then(|| gather_changelog_data(ctx, &crates_and_versions_to_be_published, opts)) - .transpose()? - .unwrap_or_default(); - - let crates_with_version_change: Vec<_> = crates - .iter() - .filter_map(|c| c.mode.version_adjustment_bump().map(|b| (c.package, &b.next_release))) - .collect(); - for (package, possibly_new_version) in crates - .iter() - .filter(|c| c.mode.manifest_will_change()) - .map(|c| (c.package, c.mode.version_adjustment_bump().map(|b| &b.next_release))) - { - let mut entry_store; - let lock = match locks_by_manifest_path.entry(&package.manifest_path) { - Entry::Occupied(entry) => { - entry_store = entry; - entry_store.get_mut() - } - Entry::Vacant(entry) => entry.insert(gix::lock::File::acquire_to_update_resource( - &package.manifest_path, - gix::lock::acquire::Fail::Immediately, - None, - )?), - }; - made_change |= set_version_and_update_package_dependency( - package, - possibly_new_version, - &crates_with_version_change, - lock, - opts, - )?; - } - - let would_stop_release = !(changelog_ids_with_statistical_segments_only.is_empty() - && changelog_ids_probably_lacking_user_edits.is_empty()); - let safety_bumped_packages = crates - .iter() - .filter_map(|c| c.mode.safety_bump().map(|b| (c.package, &b.next_release))) - .collect::>(); - let commit_message = generate_commit_message( - &crates_and_versions_to_be_published, - &safety_bumped_packages, - would_stop_release, - locks_by_manifest_path.len(), - &pending_changelogs, - opts, - ); - - preview_changelogs(ctx, &pending_changelogs, opts)?; - - let bail_message = commit_locks_and_generate_bail_message( - ctx, - pending_changelogs, - locks_by_manifest_path, - changelog_ids_with_statistical_segments_only, - changelog_ids_probably_lacking_user_edits, - opts, - )?; - - let res = git::commit_changes(commit_message, dry_run, !made_change, &ctx.base)?; - if let Some(bail_message) = bail_message { - bail!(bail_message); - } else { - Ok(Outcome { - commit_id: res, - section_by_package: release_section_by_publishee, - }) - } -} - -fn commit_locks_and_generate_bail_message( - ctx: &Context, - pending_changelogs: Vec<(&Package, bool, File)>, - locks_by_manifest_path: BTreeMap<&Utf8PathBuf, File>, - changelog_ids_with_statistical_segments_only: Vec, - changelog_ids_probably_lacking_user_edits: Vec, - Options { - dry_run, - skip_publish, - allow_fully_generated_changelogs, - .. - }: Options, -) -> anyhow::Result> { - let bail_message_after_commit = if !dry_run { - let mut packages_whose_changelogs_need_edits = None; - let mut packages_which_might_be_fully_generated = None; - for (idx, (package, _, lock)) in pending_changelogs.into_iter().enumerate() { - if changelog_ids_with_statistical_segments_only.is_empty() - || changelog_ids_with_statistical_segments_only.contains(&idx) - { - lock.commit()?; - if !changelog_ids_with_statistical_segments_only.is_empty() { - packages_whose_changelogs_need_edits - .get_or_insert_with(Vec::new) - .push(package); - } - } else { - drop(lock); - } - if changelog_ids_probably_lacking_user_edits.contains(&idx) { - packages_which_might_be_fully_generated - .get_or_insert_with(Vec::new) - .push(package); - } - } - for manifest_lock in locks_by_manifest_path.into_values() { - manifest_lock.commit()?; - } - // This is dangerous as incompatibilities can happen here, leaving the working tree dirty. - // For now we leave it that way without auto-restoring originals to facilitate debugging. - cargo::refresh_lock_file()?; - - packages_whose_changelogs_need_edits - .and_then(|logs| { - let names_of_crates_in_need_of_changelog_entry = - logs.iter().map(|p| p.name.as_str()).collect::>().join(", "); - if skip_publish { - log::warn!( - "Please consider creating changelog entries for crate{}: {}", - if logs.len() == 1 { "" } else { "s" }, - names_of_crates_in_need_of_changelog_entry - ); - None - } else { - Some(format!( - "Write changelog entries for crate(s) {names_of_crates_in_need_of_changelog_entry} and try again" - )) - } - }) - .or_else(|| { - packages_which_might_be_fully_generated.and_then(|packages| { - let crate_names = packages.iter().map(|p| p.name.as_str()).collect::>().join(", "); - (!allow_fully_generated_changelogs).then(|| { - format!( - "{} edits by hand to avoid being entirely generated: {}", - if crate_names.len() == 1 { - "This changelog needs" - } else { - "These changelogs need" - }, - crate_names - ) - }) - }) - }) - } else { - let crate_names = |ids: &[usize]| { - ids.iter() - .filter_map(|idx| { - pending_changelogs.iter().enumerate().find_map(|(pidx, (p, _, _))| { - if *idx == pidx { - Some(p.name.as_str()) - } else { - None - } - }) - }) - .collect::>() - }; - let fix_preamble = ""; - if !changelog_ids_with_statistical_segments_only.is_empty() { - let crate_names = crate_names(&changelog_ids_with_statistical_segments_only); - let names_of_crates_that_would_need_review = crate_names.join(", "); - log::warn!( - "WOULD {} as the changelog entry is empty for crate{}: {}", - if skip_publish { - "ask for review after commit" - } else { - "stop release after commit" - }, - if changelog_ids_with_statistical_segments_only.len() == 1 { - "" - } else { - "s" - }, - names_of_crates_that_would_need_review - ); - log::warn!( - "To fix the changelog manually, run: cargo changelog --write {}", - ctx.base.crate_names.join(" ") - ); - } - if !changelog_ids_probably_lacking_user_edits.is_empty() { - let crate_names = crate_names(&changelog_ids_probably_lacking_user_edits); - log::warn!( - "{} likely to be fully generated from commit history or contain lower-case git-conventional headlines: {}{}", - if changelog_ids_probably_lacking_user_edits.len() == 1 { - "This changelog is" - } else { - "These changelogs are" - }, - crate_names.join(", "), - if allow_fully_generated_changelogs { - "" - } else { - ". Would stop after commit to allow edits." - } - ); - if !allow_fully_generated_changelogs { - for crate_name in crate_names { - log::warn!("{} {}", fix_preamble, crate_name); - } - } - } - None - }; - Ok(bail_message_after_commit) -} - -fn preview_changelogs( - ctx: &Context, - pending_changelogs: &[(&Package, bool, File)], - Options { dry_run, preview, .. }: Options, -) -> anyhow::Result<()> { - if !pending_changelogs.is_empty() && preview && !dry_run { - let additional_info = - "use --no-changelog-preview to disable or Ctrl-C to abort, or the 'changelog' subcommand."; - let changelogs_with_changes = pending_changelogs - .iter() - .filter_map(|(_, has_changes, lock)| (*has_changes).then_some(lock)) - .collect::>(); - log::info!( - "About to preview {} pending changelog(s), {}", - changelogs_with_changes.len(), - additional_info - ); - - let bat = crate::bat::Support::new(); - for (idx, lock) in changelogs_with_changes.iter().enumerate() { - let additional_info = format!( - "PREVIEW {} / {}, {}{}", - idx + 1, - changelogs_with_changes.len(), - if dry_run { "simplified, " } else { "" }, - additional_info - ); - bat.display_to_tty( - lock.lock_path(), - lock.resource_path().strip_prefix(&ctx.base.root.to_path_buf())?, - additional_info, - )?; - } - } else if !pending_changelogs.is_empty() && preview { - log::info!( - "Up to {} changelog{} would be previewed if the --execute is set and --no-changelog-preview is unset.", - pending_changelogs.len(), - if pending_changelogs.len() == 1 { "" } else { "s" } - ); - } - Ok(()) -} - -fn generate_commit_message( - crates_and_versions_to_be_published: &[(&Package, &Version)], - safety_bumped_packages: &[(&Package, &Version)], - would_stop_release: bool, - num_locks: usize, - pending_changelogs: &[(&Package, bool, File)], - Options { - skip_publish, dry_run, .. - }: Options, -) -> String { - let message = format!( - "{} {}{}", - if would_stop_release { - "Adjusting changelogs prior to release of" - } else if skip_publish { - "Bump" - } else { - "Release" - }, - names_and_versions(crates_and_versions_to_be_published), - { - if safety_bumped_packages.is_empty() { - Cow::from("") - } else { - let names_and_versions = names_and_versions(safety_bumped_packages); - match safety_bumped_packages.len() { - 1 => format!(", safety bump {names_and_versions}").into(), - num_crates => { - format!(", safety bump {num_crates} crates\n\nSAFETY BUMP: {names_and_versions}").into() - } - } - } - } - ); - - log::trace!( - "{} persist changes to {} manifests {}with: {:?}", - will(dry_run), - num_locks, - match ( - pending_changelogs.len(), - pending_changelogs.iter().fold(0usize, |mut acc, (_, _, lock)| { - acc += usize::from(!lock.resource_path().is_file()); - acc - }) - ) { - (0, _) => Cow::Borrowed(""), - (num_logs, num_new) => format!( - "and {} changelogs {}", - num_logs, - match num_new { - 0 => Cow::Borrowed(""), - num_new => format!("({num_new} new) ").into(), - } - ) - .into(), - }, - message - ); - message -} - -#[derive(Default)] -pub struct GatherOutcome<'meta> { - pending_changelogs: Vec<(&'meta Package, bool, File)>, - locks_by_manifest_path: BTreeMap<&'meta Utf8PathBuf, File>, - /// Ids into `pending_changelogs` - changelog_ids_with_statistical_segments_only: Vec, - changelog_ids_probably_lacking_user_edits: Vec, - release_section_by_publishee: BTreeMap<&'meta str, Section>, - made_change: bool, -} - -fn gather_changelog_data<'meta>( - ctx: &Context, - crates_and_versions_to_be_published: &[(&'meta Package, &Version)], - Options { - dry_run, - generator_segments, - capitalize_commit, - .. - }: Options, -) -> anyhow::Result> { - let mut out = GatherOutcome::default(); - let GatherOutcome { - pending_changelogs, - locks_by_manifest_path, - changelog_ids_with_statistical_segments_only, - changelog_ids_probably_lacking_user_edits, - release_section_by_publishee, - made_change, - } = &mut out; - let next_commit_date = crate::utils::time_to_offset_date_time(crate::git::author()?.time); - for (publishee, new_version) in crates_and_versions_to_be_published { - let lock = gix::lock::File::acquire_to_update_resource( - &publishee.manifest_path, - gix::lock::acquire::Fail::Immediately, - None, - )?; - let previous = locks_by_manifest_path.insert(&publishee.manifest_path, lock); - assert!(previous.is_none(), "publishees are unique so insertion always happens"); - if let Some(history) = ctx.base.history.as_ref() { - let changelog::init::Outcome { - mut log, - state: log_init_state, - previous_content, - mut lock, - } = ChangeLog::for_package_with_write_lock(publishee, history, &ctx.base, generator_segments)?; - - log::info!( - "{} {} changelog for '{}'.", - will(dry_run), - match log_init_state { - changelog::init::State::Created => "create a new", - changelog::init::State::Modified => "modify existing", - changelog::init::State::Unchanged => "leave alone the", - }, - publishee.name - ); - - let (recent_idx, recent_release_section_in_log) = log.most_recent_release_section_mut(); - match recent_release_section_in_log { - changelog::Section::Release { - name: name @ changelog::Version::Unreleased, - date, - .. - } => { - if !log_init_state.is_modified() { - log::info!( - "{}: {} only change headline from 'Unreleased' to '{}'", - publishee.name, - will(dry_run), - new_version - ); - } - *name = changelog::Version::Semantic((*new_version).to_owned()); - *date = Some(next_commit_date); - let recent_section = log.sections.remove(recent_idx); - match log - .sections - .iter_mut() - .find(|s| matches!(s, changelog::Section::Release {name: changelog::Version::Semantic(v), ..} if v == *new_version)) - { - Some(version_section) => { - version_section.merge(recent_section).with_context(|| format!("Changelog generation of {:?} failed", publishee.name))?; - } - None => log.sections.insert(recent_idx, recent_section), - } - } - changelog::Section::Release { - name: changelog::Version::Semantic(recent_version), - date, - .. - } => { - if recent_version != *new_version { - anyhow::bail!( - "'{}' does not have an unreleased version, and most recent release is unexpected. Wanted {}, got {}.", - publishee.name, - new_version, - recent_version - ); - } - *date = Some(next_commit_date); - } - changelog::Section::Verbatim { .. } => unreachable!("BUG: checked in prior function"), - }; - { - let (_, recent_release_section_in_log) = log.most_recent_release_section_mut(); - if !recent_release_section_in_log.is_essential() { - changelog_ids_with_statistical_segments_only.push(pending_changelogs.len()); - } else if recent_release_section_in_log.is_probably_lacking_user_edits() { - changelog_ids_probably_lacking_user_edits.push(pending_changelogs.len()); - } - } - let mut write_buf = String::new(); - log.write_to( - &mut write_buf, - if dry_run { - &Linkables::AsText - } else { - &ctx.changelog_links - }, - if dry_run { - changelog::write::Components::SECTION_TITLE - } else { - changelog::write::Components::all() - }, - capitalize_commit, - )?; - lock.with_mut(|file| file.write_all(write_buf.as_bytes()))?; - *made_change |= previous_content.map_or(true, |previous| write_buf != previous); - pending_changelogs.push((publishee, log_init_state.is_modified(), lock)); - release_section_by_publishee.insert(publishee.name.as_str(), log.take_recent_release_section()); - } - } - Ok(out) -} - -fn set_version_and_update_package_dependency( - package_to_update: &Package, - new_package_version: Option<&semver::Version>, - crates: &[(&Package, &semver::Version)], - mut out: impl std::io::Write, - Options { - conservative_pre_release_version_handling, - .. - }: Options, -) -> anyhow::Result { - let manifest = std::fs::read_to_string(&package_to_update.manifest_path)?; - let mut doc = toml_edit::Document::from_str(&manifest)?; - - if let Some(new_version) = new_package_version { - let new_version = new_version.to_string(); - if doc["package"]["version"].as_str() != Some(new_version.as_str()) { - log::trace!( - "Pending '{}' manifest version update: \"{}\"", - package_to_update.name, - new_version - ); - doc["package"]["version"] = toml_edit::value(new_version); - } - } - for (dep_table, dep_type) in find_dependency_tables(&mut doc) { - for (name_to_find, new_version) in crates.iter().map(|(p, nv)| (&p.name, nv)) { - for name_to_find in package_to_update - .dependencies - .iter() - .filter(|dep| &dep.name == name_to_find) - .map(|dep| dep.rename.as_ref().unwrap_or(&dep.name)) - { - if let Some(current_version_req) = dep_table - .get_mut(name_to_find) - .and_then(toml_edit::Item::as_inline_table_mut) - .and_then(|name_table| name_table.get_mut("version")) - { - let version_req = VersionReq::parse(current_version_req.as_str().expect("versions are strings"))?; - let force_update = conservative_pre_release_version_handling - && version::is_pre_release(new_version) // setting the lower bound unnecessarily can be harmful - // don't claim to be conservative if this is necessary anyway - && req_as_version(&version_req).map_or(false, |req_version|!version::rhs_is_breaking_bump_for_lhs(&req_version, new_version)); - if !version_req.matches(new_version) || force_update { - if !version_req_unset_or_default(&version_req) { - bail!( - "{} has it's {} dependency set to a version requirement with comparator {} - cannot currently handle that.", - package_to_update.name, - name_to_find, - current_version_req - ); - } - let new_version = format!("^{new_version}"); - if version_req.to_string() != new_version { - log::trace!( - "Pending '{}' {}manifest {} update: '{} = \"{}\"' (from {})", - package_to_update.name, - if force_update { "conservative " } else { "" }, - dep_type, - name_to_find, - new_version, - current_version_req.to_string() - ); - } - *current_version_req = toml_edit::Value::from(new_version.as_str()); - } - } - } - } - } - let new_manifest = doc.to_string(); - out.write_all(new_manifest.as_bytes())?; - - Ok(manifest != new_manifest) -} - -// Originally copied from [cargo release](https://github.com/crate-ci/cargo-release/blob/9633353ad5a57dbdca9a9ed6a70c1cf78fc5a51f/src/cargo.rs#L235:L263). -// The licenses are compatible. -// With adjustments. -fn find_dependency_tables( - root: &mut toml_edit::Table, -) -> impl Iterator)> + '_ { - const DEP_TABLES: &[&str] = &["dependencies", "dev-dependencies", "build-dependencies"]; - - root.iter_mut() - .flat_map(|(k, v)| match DEP_TABLES.iter().find(|dtn| *dtn == &k.get()) { - Some(dtn) => v - .as_table_like_mut() - .into_iter() - .map(|t| (t, (*dtn).into())) - .collect::>(), - None if k == "target" => v - .as_table_like_mut() - .expect("pre-checked toml format") - .iter_mut() - .flat_map(|(target, v)| { - let target_name = target.get().to_string(); - v.as_table_like_mut().into_iter().flat_map(move |v| { - v.iter_mut().filter_map({ - let target_name = target_name.clone(); - move |(k, v)| match DEP_TABLES.iter().find(|dtn| *dtn == &k.get()) { - Some(dtn) => v.as_table_like_mut().map({ - let target_name = target_name.clone(); - move |t| (t, format!("{dtn} ({target_name})").into()) - }), - None => None, - } - }) - }) - }) - .collect::>(), - None => Vec::new(), - }) -} - -fn req_as_version(req: &VersionReq) -> Option { - req.comparators.first().map(|comp| Version { - major: comp.major, - minor: comp.minor.unwrap_or(0), - patch: comp.patch.unwrap_or(0), - pre: comp.pre.clone(), - build: Default::default(), - }) -} diff --git a/cargo-smart-release/src/command/release/mod.rs b/cargo-smart-release/src/command/release/mod.rs deleted file mode 100644 index be544af293d..00000000000 --- a/cargo-smart-release/src/command/release/mod.rs +++ /dev/null @@ -1,527 +0,0 @@ -use std::collections::BTreeMap; - -use anyhow::bail; - -use crate::{ - changelog, - changelog::{write::Linkables, Section}, - command::release::Options, - traverse::{ - self, dependency, - dependency::{ManifestAdjustment, VersionAdjustment}, - Dependency, - }, - utils::{tag_name, try_to_published_crate_and_new_version, will, Program}, - version, - version::BumpSpec, -}; - -mod cargo; -mod git; -mod github; -mod manifest; - -pub(crate) struct Context { - base: crate::Context, - changelog_links: Linkables, -} - -impl Context { - fn new( - crate_names: Vec, - bump: BumpSpec, - bump_dependencies: BumpSpec, - changelog: bool, - changelog_links: bool, - ) -> anyhow::Result { - let base = crate::Context::new(crate_names, changelog, bump, bump_dependencies)?; - let changelog_links = if changelog_links { - crate::git::remote_url(&base.repo)?.map_or(Linkables::AsText, |url| Linkables::AsLinks { - repository_url: url.into(), - }) - } else { - Linkables::AsText - }; - Ok(Context { base, changelog_links }) - } -} - -/// In order to try dealing with and also to make workspace -/// releases more selective. -pub fn release(opts: Options, crates: Vec, bump: BumpSpec, bump_dependencies: BumpSpec) -> anyhow::Result<()> { - if opts.dry_run_cargo_publish && !opts.dry_run { - bail!("The --no-dry-run-cargo-publish flag is only effective without --execute") - } - let allow_changelog = if opts.changelog && opts.skip_tag { - log::warn!("With --no-tag enabled, changelog generation will be disabled as it relies on tags to segment commit history."); - false - } else { - opts.changelog - }; - - if opts.update_crates_index { - // Do this before creating our context to pick up a possibly newly fetched/created index. - log::info!("Updating crates-io index",); - crates_index::GitIndex::new_cargo_default()?.update()?; - } else if opts.bump_when_needed { - log::warn!( - "Consider running with --update-crates-index to assure bumping on demand uses the latest information" - ); - } - - let ctx = Context::new(crates, bump, bump_dependencies, allow_changelog, opts.changelog_links)?; - if !ctx.base.crates_index.exists() { - log::warn!("Crates.io index doesn't exist. Consider using --update-crates-index to help determining if release versions are published already"); - } - - release_depth_first(ctx, opts)?; - Ok(()) -} - -impl From for traverse::Options { - fn from(v: Options) -> Self { - Self { - allow_auto_publish_of_stable_crates: v.allow_auto_publish_of_stable_crates, - bump_when_needed: v.bump_when_needed, - isolate_dependencies_from_breaking_changes: v.isolate_dependencies_from_breaking_changes, - traverse_graph: v.dependencies, - } - } -} - -fn release_depth_first(ctx: Context, opts: Options) -> anyhow::Result<()> { - let crates = { - traverse::dependencies(&ctx.base, opts.into()) - .and_then(|crates| assure_crates_index_is_uptodate(crates, &ctx.base, opts.into())) - .and_then(|crates| { - present_and_validate_dependencies(&crates, &ctx, opts.verbose, opts.dry_run).map(|_| crates) - })? - }; - - assure_working_tree_is_unchanged(opts)?; - perform_release(&ctx, opts, &crates)?; - - Ok(()) -} - -fn assure_crates_index_is_uptodate<'meta>( - crates: Vec>, - ctx: &'meta crate::Context, - opts: traverse::Options, -) -> anyhow::Result>> { - if let Some(dep) = crates - .iter() - .filter_map(|d| d.mode.version_adjustment_bump().map(|b| (d, b))) - .find_map(|(d, b)| { - b.latest_release - .as_ref() - .and_then(|lr| (lr >= &b.next_release).then_some(d)) - }) - { - let mut index = crate::crates_index::Index::new_cargo_default()?; - if index.exists() { - log::warn!("Crate '{}' computed version not greater than the current package version. Updating crates index to assure correct results.", dep.package.name); - index.update()?; - return traverse::dependencies(ctx, opts); - } - } - Ok(crates) -} - -fn present_and_validate_dependencies( - crates: &[Dependency<'_>], - ctx: &Context, - verbose: bool, - dry_run: bool, -) -> anyhow::Result<()> { - use dependency::Kind; - let all_skipped: Vec<_> = crates - .iter() - .filter_map(|dep| match &dep.mode { - dependency::Mode::NotForPublishing { reason, adjustment } => { - Some((dep.package.name.as_str(), adjustment.is_some(), *reason)) - } - _ => None, - }) - .collect(); - let mut num_refused = 0; - for (refused_crate, has_adjustment, _) in all_skipped - .iter() - .filter(|(name, _, _)| ctx.base.crate_names.iter().any(|n| n == *name)) - { - num_refused += 1; - log::warn!( - "Refused to publish '{}' as {}.", - refused_crate, - has_adjustment - .then(|| "only a manifest change is needed") - .unwrap_or("as it didn't change") - ); - } - - let no_requested_crate_will_publish = num_refused == ctx.base.crate_names.len(); - let no_crate_being_published_message = "No provided crate is actually eligible for publishing."; - if no_requested_crate_will_publish && !verbose { - bail!( - "{} Use --verbose to see the release plan nonetheless.", - no_crate_being_published_message - ) - } - - let skipped = all_skipped - .iter() - .filter_map(|(name, has_adjustment, reason)| (!has_adjustment).then_some((*name, reason))) - .collect::>(); - if !skipped.is_empty() { - let skipped_len = skipped.len(); - let mut crates_by_reason: Vec<_> = skipped - .into_iter() - .fold(BTreeMap::default(), |mut acc, (name, reason)| { - acc.entry(*reason).or_insert_with(Vec::new).push(name); - acc - }) - .into_iter() - .collect(); - crates_by_reason.sort_by_key(|(k, _)| *k); - - log::info!( - "Will not publish or alter {} dependent crate{}: {}", - skipped_len, - if skipped_len != 1 { "s" } else { "" }, - crates_by_reason - .into_iter() - .map(|(key, names)| format!( - "{} = {}", - key, - names.iter().map(|n| format!("'{n}'")).collect::>().join(", ") - )) - .collect::>() - .join(", ") - ); - } - - if all_skipped.len() == crates.len() { - bail!("There is no crate eligible for publishing."); - } - - let mut error = false; - for dep in crates { - let (bump_spec, kind) = match dep.kind { - Kind::UserSelection => (ctx.base.bump, "provided"), - Kind::DependencyOrDependentOfUserSelection => (ctx.base.bump_dependencies, "dependent"), - }; - match &dep.mode { - dependency::Mode::ToBePublished { adjustment } => { - let (bump, breaking_dependencies) = match adjustment { - VersionAdjustment::Breakage { - bump, - causing_dependency_names, - .. - } => (bump, Some(causing_dependency_names)), - VersionAdjustment::Changed { bump, .. } => (bump, None), - }; - if let Some(latest_release) = bump - .latest_release - .as_ref() - .and_then(|lr| (*lr >= bump.next_release).then_some(lr)) - { - let bump_flag = match dep.kind { - Kind::UserSelection => "--bump ", - Kind::DependencyOrDependentOfUserSelection => "--bump-dependencies ", - }; - if bump.next_release == bump.package_version { - log::error!( - "'{}' is unchanged. Consider using {} along with --no-bump-on-demand to force a version change.", - dep.package.name, - bump_flag - ); - } else { - log::error!( - "Latest published version of '{}' is {}, the new version is {}. Consider using {} or update the index with --update-crates-index.", - dep.package.name, - latest_release, - bump.next_release, - bump_flag - ); - } - error = true; - } - if bump.next_release > dep.package.version { - log::info!( - "{} {}-bump {} package '{}' from {} to {} for publishing{}{}{}", - will(dry_run), - bump_spec, - kind, - dep.package.name, - dep.package.version, - bump.next_release, - bump.latest_release - .as_ref() - .and_then(|latest_release| { - (dep.package.version != *latest_release) - .then(|| format!(", {latest_release} on crates.io")) - }) - .unwrap_or_default(), - breaking_dependencies - .map(|causes| format!( - ", for SAFETY due to breaking package{} {}", - if causes.len() == 1 { "" } else { "s" }, - causes.iter().map(|n| format!("'{n}'")).collect::>().join(", ") - )) - .unwrap_or_default(), - (bump.next_release != bump.desired_release) - .then(|| format!(", ignoring computed version {}", bump.desired_release)) - .unwrap_or_default(), - ); - } else if bump.desired_release != dep.package.version { - log::info!( - "Manifest version of {} package '{}' at {} is sufficient{}, ignoring computed version {}", - kind, - dep.package.name, - dep.package.version, - bump.latest_release.as_ref().map_or_else( - || ", creating a new release 🎉".into(), - |latest_release| format!(" to succeed latest released version {latest_release}") - ), - bump.desired_release - ); - }; - } - dependency::Mode::NotForPublishing { .. } => {} - } - } - - { - let affected_crates_by_cause = crates - .iter() - .filter_map(|dep| match &dep.mode { - dependency::Mode::NotForPublishing { - adjustment: - Some(ManifestAdjustment::Version(VersionAdjustment::Breakage { - bump, - causing_dependency_names, - .. - })), - .. - } - | dependency::Mode::ToBePublished { - adjustment: - VersionAdjustment::Breakage { - bump, - causing_dependency_names, - .. - }, - } => Some((dep, bump, causing_dependency_names)), - _ => None, - }) - .fold( - Vec::new(), - |mut acc: Vec<(&str, Vec<(&str, &version::Bump)>)>, (dep, bump, causing_names)| { - for name in causing_names { - match acc.iter_mut().find(|(k, _v)| k == name) { - Some((_k, deps)) => deps.push((dep.package.name.as_str(), bump)), - None => acc.push((name, vec![(dep.package.name.as_str(), bump)])), - } - } - acc - }, - ); - for (cause, deps_and_bumps) in affected_crates_by_cause { - let plural_s = if deps_and_bumps.len() != 1 { "s" } else { "" }; - log::info!( - "{} adjust {} manifest version{} due to breaking change in '{}': {}", - will(dry_run), - deps_and_bumps.len(), - plural_s, - cause, - deps_and_bumps - .into_iter() - .map(|(dep_name, bump)| format!("'{}' {} ➡ {}", dep_name, bump.package_version, bump.next_release)) - .collect::>() - .join(", ") - ); - } - } - - { - let crate_names_for_manifest_updates = crates - .iter() - .filter_map(|d| { - matches!( - d.mode, - dependency::Mode::NotForPublishing { - adjustment: Some(ManifestAdjustment::DueToDependencyChange), - .. - } - ) - .then(|| d.package.name.as_str()) - }) - .collect::>(); - if !crate_names_for_manifest_updates.is_empty() { - let plural_s = (crate_names_for_manifest_updates.len() > 1) - .then_some("s") - .unwrap_or_default(); - log::info!( - "{} adjust version constraints in manifest{} of {} package{} as direct dependencies are changing: {}", - will(dry_run), - plural_s, - crate_names_for_manifest_updates.len(), - plural_s, - crate_names_for_manifest_updates.join(", ") - ); - } - } - - if error { - bail!("Aborting due to previous error(s)"); - } else { - if no_requested_crate_will_publish { - bail!(no_crate_being_published_message) - } - Ok(()) - } -} - -fn assure_working_tree_is_unchanged(options: Options) -> anyhow::Result<()> { - if !options.allow_dirty { - if let Err(err) = crate::git::assure_clean_working_tree() { - if options.dry_run { - log::warn!("The working tree has changes which will prevent a release with --execute unless --allow-dirty is also specified. The latter isn't recommended.") - } else { - return Err(err); - } - } - } - Ok(()) -} - -fn perform_release(ctx: &Context, options: Options, crates: &[Dependency<'_>]) -> anyhow::Result<()> { - let manifest::Outcome { - commit_id, - section_by_package: release_section_by_publishee, - } = manifest::edit_version_and_fixup_dependent_crates_and_handle_changelog(crates, options, ctx)?; - - let should_publish_to_github = options.allow_changelog_github_release - && if Program::named("gh").found { - true - } else { - log::warn!("To create github releases, please install the 'gh' program and try again"); - false - }; - let mut tag_names = Vec::new(); - let mut successful_publishees_and_version = Vec::<(&cargo_metadata::Package, &semver::Version)>::new(); - let mut publish_err = None; - let prevent_default_members = ctx.base.meta.workspace_members.len() > 1; - for (publishee, new_version) in crates.iter().filter_map(try_to_published_crate_and_new_version) { - if let Some((crate_, version)) = successful_publishees_and_version.last() { - if let Err(err) = wait_for_release(crate_, version, options) { - log::warn!( - "Failed to wait for crates-index update - trying to publish '{} v{}' anyway: {}.", - publishee.name, - new_version, - err - ); - } - } - - if let Err(err) = cargo::publish_crate(publishee, prevent_default_members, options) { - publish_err = Some(err); - break; - } - successful_publishees_and_version.push((publishee, new_version)); - if let Some(tag_name) = git::create_version_tag( - publishee, - new_version, - commit_id, - release_section_by_publishee - .get(&publishee.name.as_str()) - .and_then(|s| section_to_string(s, WriteMode::Tag, options.capitalize_commit)), - &ctx.base, - options, - )? { - tag_names.push(tag_name); - } - } - git::push_tags_and_head(&ctx.base.repo, &tag_names, options)?; - if should_publish_to_github { - for (publishee, new_version) in successful_publishees_and_version { - release_section_by_publishee - .get(&publishee.name.as_str()) - .and_then(|s| section_to_string(s, WriteMode::GitHubRelease, options.capitalize_commit)) - .map(|release_notes| github::create_release(publishee, new_version, &release_notes, options, &ctx.base)) - .transpose()?; - } - } - - publish_err.map_or(Ok(()), Err) -} - -fn wait_for_release( - crate_: &cargo_metadata::Package, - crate_version: &semver::Version, - Options { - dry_run, - dry_run_cargo_publish, - skip_publish, - .. - }: Options, -) -> anyhow::Result<()> { - use anyhow::Context; - - if skip_publish || dry_run || dry_run_cargo_publish { - return Ok(()); - } - let timeout = std::time::Duration::from_secs(60); - let start = std::time::Instant::now(); - let sleep_time = std::time::Duration::from_secs(1); - let crate_version = crate_version.to_string(); - - log::info!("Waiting for '{} v{}' to arrive in index…", crate_.name, crate_version); - let mut crates_index = crates_index::GitIndex::new_cargo_default()?; - let mut attempt = 0; - while start.elapsed() < timeout { - attempt += 1; - log::trace!("Updating crates index…"); - crates_index.update()?; - let crate_ = crates_index.crate_(&crate_.name).with_context(|| { - format!( - "Couldn't find crate '{}' in index anymore - unexpected and fatal", - crate_.name - ) - })?; - - if crate_ - .versions() - .iter() - .rev() - .any(|version| version.version() == crate_version) - { - break; - } - - std::thread::sleep(sleep_time); - log::info!("attempt {}", attempt); - } - Ok(()) -} - -enum WriteMode { - Tag, - GitHubRelease, -} - -fn section_to_string(section: &Section, mode: WriteMode, capitalize_commit: bool) -> Option { - let mut b = String::new(); - section - .write_to( - &mut b, - &Linkables::AsText, - match mode { - WriteMode::Tag => changelog::write::Components::empty(), - WriteMode::GitHubRelease => changelog::write::Components::DETAIL_TAGS, - }, - capitalize_commit, - ) - .ok() - .map(|_| b) -} diff --git a/cargo-smart-release/src/commit/history.rs b/cargo-smart-release/src/commit/history.rs deleted file mode 100644 index 2e401007fa7..00000000000 --- a/cargo-smart-release/src/commit/history.rs +++ /dev/null @@ -1,30 +0,0 @@ -use crate::commit::Message; - -/// A head reference will all commits that are 'governed' by it, that is are in its exclusive ancestry. -pub struct Segment<'a> { - pub head: gix::refs::Reference, - /// only relevant history items, that is those that change code in the respective crate. - pub history: Vec<&'a Item>, -} - -pub struct Item { - pub id: gix::ObjectId, - pub message: Message, - pub commit_time: gix::date::Time, - pub tree_id: gix::ObjectId, - pub parent_tree_id: Option, -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn size_of_item() { - assert_eq!( - std::mem::size_of::(), - 200, - "there are plenty of these loaded at a time and we should not let it grow unnoticed." - ) - } -} diff --git a/cargo-smart-release/src/commit/message.rs b/cargo-smart-release/src/commit/message.rs deleted file mode 100644 index ba02768f582..00000000000 --- a/cargo-smart-release/src/commit/message.rs +++ /dev/null @@ -1,200 +0,0 @@ -use std::borrow::Cow; - -use gix::bstr::ByteSlice; - -use crate::commit::Message; - -#[derive(Debug)] -#[cfg_attr(test, derive(PartialEq, Eq))] -pub enum Addition { - /// The plain issue ID, like "123". - IssueId(String), -} - -mod additions { - use std::{borrow::Cow, ops::Range}; - - use crate::commit::message::Addition; - - fn cut(mut s: String, Range { start, end }: Range) -> String { - let part_to_left = &s[..start]; - let new_start = part_to_left - .rfind(|c: char| !c.is_whitespace()) - .and_then(|p| { - part_to_left - .is_char_boundary(p + 1) - .then_some(p + 1) - .or_else(|| part_to_left[p..].chars().next().map(|c| p + c.len_utf8())) - }) - .unwrap_or(start); - let new_end = s[end..].find(|c: char| !c.is_whitespace()).map_or(end, |p| p + end); - s.replace_range( - new_start..new_end, - if new_end != end && new_start != start { " " } else { "" }, - ); - s - } - - pub fn strip(mut title: Cow<'_, str>) -> (Cow<'_, str>, Vec) { - let mut additions = Vec::new(); - loop { - let previous_len = title.len(); - let issue_sep = "(#"; - if let Some((pos, end_pos)) = title.find(issue_sep).and_then(|mut pos| { - pos += issue_sep.len(); - title[pos..].find(')').map(|ep| (pos, ep)) - }) { - additions.push(Addition::IssueId(title[pos..][..end_pos].to_owned())); - title = cut(title.into_owned(), (pos - issue_sep.len())..(pos + end_pos + 1)).into(); - }; - if title.len() == previous_len { - break; - } - } - (title, additions) - } - - #[cfg(test)] - mod tests { - use super::*; - - #[test] - fn no_addition() { - let (nt, a) = strip("hello there [abc] (abc)".into()); - assert_eq!(nt, "hello there [abc] (abc)"); - assert_eq!(a, vec![]); - } - - #[test] - fn strip_multiple_issue_numbers() { - let (nt, a) = strip("(#other) foo (#123) hello (#42)".into()); - assert_eq!(nt, "foo hello"); - assert_eq!( - a, - vec![ - Addition::IssueId("other".into()), - Addition::IssueId("123".into()), - Addition::IssueId("42".into()) - ] - ); - } - } -} - -impl From<&'_ str> for Message { - fn from(m: &str) -> Self { - let (title, kind, body, breaking, breaking_description) = git_conventional::Commit::parse(m).map_or_else( - |_| { - let m = gix::objs::commit::MessageRef::from_bytes(m.as_bytes()); - ( - m.summary().as_ref().to_string().into(), - None, - m.body().map(|b| b.without_trailer().to_str_lossy()), - false, - None, - ) - }, - |c: git_conventional::Commit<'_>| { - ( - c.description().into(), - Some(c.type_()), - c.body().map(Into::into), - c.breaking(), - c.breaking_description() - .and_then(|d| if d == c.description() { None } else { Some(d) }), - ) - }, - ); - let (title, additions) = additions::strip(title); - Message { - title: title.into_owned(), - kind: as_static_str(kind), - body: body.map(Cow::into_owned), - breaking, - breaking_description: breaking_description.map(ToOwned::to_owned), - additions, - } - } -} - -/// Note that this depends on `crate::changelog::section::segment::Conventional::as_headline_name()`, -fn as_static_str(kind: Option>) -> Option<&'static str> { - kind.map(|kind| match kind.as_str() { - "feat" | "add" | "added" => "feat", - "fix" => "fix", - "revert" | "remove" => "revert", - "docs" => "docs", - "style" => "style", - "refactor" => "refactor", - "change" => "change", - "perf" => "perf", - "test" => "test", - "chore" => "chore", - _ => "other", - }) -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn no_conventional_no_additions_no_body() { - assert_eq!( - Message::from("hi"), - Message { - title: "hi".into(), - body: None, - kind: None, - breaking: false, - breaking_description: None, - additions: vec![] - } - ) - } - - #[test] - fn no_conventional_uses_summary() { - assert_eq!( - Message::from("hi\nho\nfoo\n\nbody"), - Message { - title: "hi ho foo".into(), - body: Some("body".into()), - kind: None, - breaking: false, - breaking_description: None, - additions: vec![] - } - ) - } - - #[test] - fn no_conventional_additions() { - assert_eq!( - Message::from("hi (#14123)\n\nbody\nother\n\nSigned: bar"), - Message { - title: "hi".into(), - body: Some("body\nother".into()), - kind: None, - breaking: false, - breaking_description: None, - additions: vec![Addition::IssueId("14123".into())] - } - ) - } - - #[test] - fn conventional_with_additions() { - assert_eq!( - Message::from("feat!: hi (#123)\n\nthe body\n\nBREAKING-CHANGE: breaks\n\nSigned: foobar"), - Message { - title: "hi".into(), - body: Some("the body".into()), - kind: Some("feat"), - breaking: true, - breaking_description: Some("breaks".into()), - additions: vec![Addition::IssueId("123".into())] - } - ) - } -} diff --git a/cargo-smart-release/src/commit/mod.rs b/cargo-smart-release/src/commit/mod.rs deleted file mode 100644 index 9022257eb50..00000000000 --- a/cargo-smart-release/src/commit/mod.rs +++ /dev/null @@ -1,29 +0,0 @@ -use std::collections::HashMap; - -pub mod history; - -#[derive(Debug)] -#[cfg_attr(test, derive(PartialEq, Eq))] -pub struct Message { - /// The cleared, plain title with any `additions` removed. - pub title: String, - /// More detailed information about the changes. - pub body: Option, - /// If set, the git-conventional scope to help organizing changes. - pub kind: Option<&'static str>, - /// If set, this is a breaking change as indicated git-conventional. - pub breaking: bool, - /// If set, this commit message body contains a specific description of the breaking change. - pub breaking_description: Option, - /// all additional information parsed from the title. - pub additions: Vec, -} - -pub struct History { - pub head: gix::refs::Reference, - pub items: Vec, - /// A mapping between trees and their data - pub data_by_tree_id: HashMap>, -} - -pub mod message; diff --git a/cargo-smart-release/src/context.rs b/cargo-smart-release/src/context.rs deleted file mode 100644 index 3e63cd3ef58..00000000000 --- a/cargo-smart-release/src/context.rs +++ /dev/null @@ -1,95 +0,0 @@ -use cargo_metadata::{ - camino::{Utf8Path, Utf8PathBuf}, - Metadata, Package, -}; - -use crate::version::BumpSpec; - -pub struct Context { - pub root: Utf8PathBuf, - pub meta: Metadata, - pub repo: gix::Repository, - pub crate_names: Vec, - pub crates_index: crate::crates_index::Index, - pub history: Option, - pub bump: BumpSpec, - pub bump_dependencies: BumpSpec, -} - -impl Context { - pub fn new( - crate_names: Vec, - force_history_segmentation: bool, - bump: BumpSpec, - bump_dependencies: BumpSpec, - ) -> anyhow::Result { - let meta = cargo_metadata::MetadataCommand::new().exec()?; - let root = meta.workspace_root.clone(); - let repo = gix::discover(&root)?; - let crates_index = crate::crates_index::Index::new_cargo_default()?; - let history = (force_history_segmentation - || matches!(bump, BumpSpec::Auto) - || matches!(bump_dependencies, BumpSpec::Auto)) - .then(|| crate::git::history::collect(&repo)) - .transpose()? - .flatten(); - Ok(Context { - root, - repo, - meta, - crate_names: fill_in_root_crate_if_needed(crate_names)?, - crates_index, - history, - bump, - bump_dependencies, - }) - } - - pub(crate) fn repo_relative_path<'a>(&self, p: &'a Package) -> Option<&'a Utf8Path> { - let dir = p - .manifest_path - .parent() - .expect("parent of a file is always present") - .strip_prefix(&self.root) - .unwrap_or_else(|_| { - panic!( - "workspace members are relative to the root directory: {:?} should contain {:?}", - self.root, - p.manifest_path.parent() - ) - }); - - if dir.as_os_str().is_empty() { - None - } else { - dir.into() - } - } -} - -fn fill_in_root_crate_if_needed(crate_names: Vec) -> anyhow::Result> { - Ok(if crate_names.is_empty() { - let current_dir = std::env::current_dir()?; - let manifest = current_dir.join("Cargo.toml"); - let dir_name = current_dir - .file_name() - .expect("a valid directory with a name") - .to_str() - .expect("directory is UTF8 representable"); - let crate_name = if manifest.is_file() { - cargo_toml::Manifest::from_path(manifest).map_or_else( - |_| dir_name.to_owned(), - |manifest| manifest.package.map_or(dir_name.to_owned(), |p| p.name), - ) - } else { - dir_name.to_owned() - }; - log::warn!( - "Using '{}' as crate name as no one was provided. Specify one if this isn't correct", - crate_name - ); - vec![crate_name] - } else { - crate_names - }) -} diff --git a/cargo-smart-release/src/crates_index.rs b/cargo-smart-release/src/crates_index.rs deleted file mode 100644 index 7695ae12a32..00000000000 --- a/cargo-smart-release/src/crates_index.rs +++ /dev/null @@ -1,24 +0,0 @@ -pub struct Index { - inner: Option, -} - -impl Index { - /// Like the original one, but doesn't create it if it doesn't exist - pub fn new_cargo_default() -> Result { - Ok(Index { - inner: crates_index::GitIndex::try_new_cargo_default()?, - }) - } - - pub fn exists(&self) -> bool { - self.inner.is_some() - } - - pub fn update(&mut self) -> Result<(), crates_index::Error> { - self.inner.as_mut().expect("BUG: call only after exists check").update() - } - - pub fn crate_(&self, name: &str) -> Option { - self.inner.as_ref().and_then(|idx| idx.crate_(name)) - } -} diff --git a/cargo-smart-release/src/git/history.rs b/cargo-smart-release/src/git/history.rs deleted file mode 100644 index 09fbbe7d825..00000000000 --- a/cargo-smart-release/src/git/history.rs +++ /dev/null @@ -1,280 +0,0 @@ -use std::{ - borrow::Cow, - collections::{BTreeMap, HashMap}, - iter::FromIterator, - path::PathBuf, -}; - -use anyhow::bail; -use cargo_metadata::Package; -use gix::{ - bstr::ByteSlice, - head, - prelude::{ObjectIdExt, ReferenceExt}, - Reference, -}; - -use crate::{ - commit, - commit::history::{Item, Segment}, - git::strip_tag_path, - utils::{component_to_bytes, is_tag_name, is_tag_version, tag_prefix}, - Context, -}; - -pub enum SegmentScope { - /// Stop finding segments after the unreleased/first section was processed. - Unreleased, - /// Obtain all segments, including unreleased and tags - EntireHistory, -} - -pub fn collect(repo: &gix::Repository) -> anyhow::Result> { - let mut handle = repo.clone(); - handle.object_cache_size(64 * 1024); - let reference = match handle.head()?.peeled()?.kind { - head::Kind::Detached { .. } => bail!("Refusing to operate on a detached head."), - head::Kind::Unborn { .. } => return Ok(None), - head::Kind::Symbolic(r) => r.attach(&handle), - }; - - let mut items = Vec::new(); - let mut data_by_tree_id = HashMap::default(); - for commit_id in reference - .id() - .ancestors() - .sorting(gix::traverse::commit::Sorting::ByCommitTimeNewestFirst) - .use_commit_graph(false) - .all()? - { - let commit = commit_id?; - let (message, tree_id, parent_tree_id, commit_time) = { - let (message, tree_id, commit_time, parent_commit_id) = { - let object = commit.object()?; - let commit = object.decode()?; - let parent = commit.parents().next(); - (commit.message.to_vec(), commit.tree(), commit.committer.time, parent) - }; - ( - message, - tree_id, - parent_commit_id.map(|id| id.attach(&handle).object().expect("present").to_commit_ref().tree()), - commit_time, - ) - }; - - let message = match message.to_str() { - Err(_) => { - log::warn!( - "Commit message of {} could not be decoded to UTF-8 - ignored", - commit.id - ); - continue; - } - Ok(m) => m, - }; - data_by_tree_id.insert(tree_id, handle.find_object(tree_id)?.data.to_owned()); - if let Some(tree_id) = parent_tree_id { - data_by_tree_id.insert(tree_id, handle.find_object(tree_id)?.data.to_owned()); - } - items.push(commit::history::Item { - id: commit.id, - commit_time, - message: commit::Message::from(message), - tree_id, - parent_tree_id, - }); - } - - Ok(Some(commit::History { - head: reference.detach(), - items, - data_by_tree_id, - })) -} - -/// Return the head reference followed by all tags affecting `crate_name` as per our tag name rules, ordered by ancestry. -pub fn crate_ref_segments<'h>( - package: &Package, - ctx: &crate::Context, - history: &'h commit::History, - scope: SegmentScope, -) -> anyhow::Result>> { - let tag_prefix = tag_prefix(package, &ctx.repo); - let mut tags_by_commit = { - let refs = ctx.repo.references()?; - match tag_prefix { - Some(prefix) => BTreeMap::from_iter( - refs.prefixed(PathBuf::from(format!("refs/tags/{prefix}-")))? - .peeled() - .filter_map(|r| r.ok().map(Reference::detach)) - .filter(|r| is_tag_name(prefix, strip_tag_path(r.name.as_ref()))) - .map(|r| { - let t = r.peeled.expect("already peeled"); - (t, r) - }), - ), - None => BTreeMap::from_iter( - refs.prefixed("refs/tags")? - .peeled() - .filter_map(|r| r.ok().map(Reference::detach)) - .filter(|r| is_tag_version(strip_tag_path(r.name.as_ref()))) - .map(|r| { - let t = r.peeled.expect("already peeled"); - (t, r) - }), - ), - } - }; - - let mut segments = Vec::new(); - let mut segment = commit::history::Segment { - head: history.head.to_owned(), - history: vec![], - }; - - let dir = ctx.repo_relative_path(package); - let mut filter = dir.map_or_else( - || { - if ctx.meta.workspace_members.len() == 1 { - Filter::None - } else { - log::info!( - "{}: Tracking top-level crate's changes in multi-crate workspace through 'src/' directory only.", - package.name - ); - // TODO: analyse .targets to find actual source directory. - Filter::Fast { - name: Cow::Borrowed(b"src"), - } - } - }, - |dir| { - let mut components = dir.components().collect::>(); - match components.len() { - 0 => unreachable!("BUG: it's None if empty"), - 1 => Filter::Fast { - name: components.pop().map(component_to_bytes).expect("exactly one").into(), - }, - _ => Filter::Slow { - components: components.into_iter().map(component_to_bytes).collect(), - }, - } - }, - ); - - for item in &history.items { - match tags_by_commit.remove(&item.id) { - None => add_item_if_package_changed(ctx, &mut segment, &mut filter, item, &history.data_by_tree_id)?, - Some(next_ref) => { - match scope { - SegmentScope::EntireHistory => { - segments.push(std::mem::replace( - &mut segment, - commit::history::Segment { - head: next_ref, - history: vec![], - }, - )); - } - SegmentScope::Unreleased => { - segments.push(segment); - return Ok(segments); - } - } - add_item_if_package_changed(ctx, &mut segment, &mut filter, item, &history.data_by_tree_id)? - } - } - } - segments.push(segment); - - if matches!(scope, SegmentScope::EntireHistory) && !tags_by_commit.is_empty() { - log::warn!( - "{}: The following tags were not encountered during commit graph traversal: {}", - package.name, - tags_by_commit - .into_values() - .map(|v| v.name.as_bstr().to_str_lossy().into_owned()) - .collect::>() - .join(", ") - ) - } - - Ok(segments) -} - -enum Filter<'a> { - /// Unconditionally use history items, we always consider them relevant for the package. - None, - /// The package sits directly at the root, allowing us to use our cached trees exclusively, which is the fastest possible change detection. - Fast { name: Cow<'a, [u8]> }, - /// The package sits at a deeper level which means we have to read other trees as well while determining its hash. - Slow { components: Vec<&'a [u8]> }, -} - -fn add_item_if_package_changed<'a>( - ctx: &Context, - segment: &mut Segment<'a>, - filter: &mut Filter<'_>, - item: &'a Item, - data_by_tree_id: &HashMap>, -) -> anyhow::Result<()> { - let history = &mut segment.history; - match filter { - Filter::None => history.push(item), - Filter::Fast { name } => { - let current = gix::objs::TreeRefIter::from_bytes(&data_by_tree_id[&item.tree_id]) - .filter_map(Result::ok) - .find(|e| e.filename == name.as_ref()); - let parent = item.parent_tree_id.and_then(|parent| { - gix::objs::TreeRefIter::from_bytes(&data_by_tree_id[&parent]) - .filter_map(Result::ok) - .find(|e| e.filename == name.as_ref()) - }); - match (current, parent) { - (Some(current), Some(parent)) => { - if current.oid != parent.oid { - history.push(item) - } - } - (Some(current), None) => { - if let Some(prev_item) = item.parent_tree_id.and_then(|parent| { - gix::objs::TreeRefIter::from_bytes(&data_by_tree_id[&parent]) - .filter_map(Result::ok) - .find(|e| e.oid == current.oid) - }) { - log::debug!( - "Tracking package named {:?} as {:?}", - name.as_bstr(), - prev_item.filename - ); - *name.to_mut() = prev_item.filename.to_owned().into(); - } - history.push(item) - } - (None, _) => {} - }; - } - Filter::Slow { ref components } => { - let mut repo = ctx.repo.clone(); - repo.object_cache_size(1024 * 1024); - let current = gix::Tree::from_data(item.id, data_by_tree_id[&item.tree_id].to_owned(), &ctx.repo) - .peel_to_entry(components.iter().copied())?; - let parent = match item.parent_tree_id { - Some(tree_id) => gix::Tree::from_data(tree_id, data_by_tree_id[&tree_id].to_owned(), &ctx.repo) - .peel_to_entry(components.iter().copied())?, - None => None, - }; - match (current, parent) { - (Some(current), Some(parent)) => { - if current.oid() != parent.oid() { - history.push(item) - } - } - (Some(_), None) => history.push(item), - (None, _) => {} - }; - } - }; - Ok(()) -} diff --git a/cargo-smart-release/src/git/mod.rs b/cargo-smart-release/src/git/mod.rs deleted file mode 100644 index 3f6719c81b5..00000000000 --- a/cargo-smart-release/src/git/mod.rs +++ /dev/null @@ -1,114 +0,0 @@ -use std::process::Command; - -use anyhow::{anyhow, bail}; -use cargo_metadata::{camino::Utf8Path, Package}; -use gix::{ - bstr::{BStr, ByteSlice}, - object, - refs::FullNameRef, -}; - -use crate::utils::{component_to_bytes, tag_name}; - -pub mod history; - -#[derive(Clone, Debug)] -pub enum PackageChangeKind { - Untagged { wanted_tag_name: String }, - ChangedOrNew, -} - -pub fn change_since_last_release(package: &Package, ctx: &crate::Context) -> anyhow::Result> { - let version_tag_name = tag_name(package, &package.version, &ctx.repo); - let mut tag_ref = match ctx.repo.try_find_reference(&version_tag_name)? { - None => { - return Ok(Some(PackageChangeKind::Untagged { - wanted_tag_name: version_tag_name, - })); - } - Some(r) => r, - }; - let repo_relative_crate_dir = ctx.repo_relative_path(package); - Ok(match ctx.repo.head()?.into_fully_peeled_id() { - Some(c) => { - let current_commit = c?; - let released_target = tag_ref.peel_to_id_in_place()?; - - match repo_relative_crate_dir - // If it's a top-level crate, use the src-directory for now - // KEEP THIS IN SYNC with gix::create_ref_history()! - .or_else(|| (ctx.meta.workspace_members.len() != 1).then(|| Utf8Path::new("src"))) - { - None => (current_commit != released_target).then_some(PackageChangeKind::ChangedOrNew), - Some(dir) => { - let components = dir.components().map(component_to_bytes); - let current_dir_id = current_commit - .object()? - .peel_to_kind(object::Kind::Tree)? - .into_tree() - .peel_to_entry(components.clone())? - .expect("path must exist in current commit") - .object_id(); - let released_dir_id = released_target - .object()? - .peel_to_kind(object::Kind::Tree)? - .into_tree() - .peel_to_entry(components)? - .expect("path must exist as it was supposedly released there") - .object_id(); - - (released_dir_id != current_dir_id).then_some(PackageChangeKind::ChangedOrNew) - } - } - } - None => Some(PackageChangeKind::ChangedOrNew), - }) -} - -pub fn assure_clean_working_tree() -> anyhow::Result<()> { - let tracked_changed = !Command::new("git") - .arg("diff") - .arg("HEAD") - .arg("--exit-code") - .arg("--name-only") - .status()? - .success(); - if tracked_changed { - bail!("Detected working tree changes. Please commit beforehand as otherwise these would be committed as part of manifest changes, or use --allow-dirty to force it.") - } - - let untracked = Command::new("git") - .arg("ls-files") - .arg("--exclude-standard") - .arg("--others") - .output()? - .stdout; - if !untracked.trim().is_empty() { - let err = anyhow!(gix::bstr::BString::from(untracked)); - return Err(err.context("Found untracked files which would possibly be packaged when publishing.")); - } - Ok(()) -} - -pub fn remote_url(repo: &gix::Repository) -> anyhow::Result> { - Ok(repo - .head()? - .into_remote(gix::remote::Direction::Push) - .transpose()? - .and_then(|r| r.url(gix::remote::Direction::Push).map(ToOwned::to_owned))) -} - -pub fn author() -> anyhow::Result { - Ok(gix::actor::SignatureRef::from_bytes::<()>( - &Command::new("git").arg("var").arg("GIT_AUTHOR_IDENT").output()?.stdout, - )? - .to_owned()) -} - -pub fn strip_tag_path(name: &FullNameRef) -> &BStr { - try_strip_tag_path(name).expect("prefix iteration works") -} - -pub fn try_strip_tag_path(name: &FullNameRef) -> Option<&BStr> { - name.as_bstr().strip_prefix(b"refs/tags/").map(ByteSlice::as_bstr) -} diff --git a/cargo-smart-release/src/lib.rs b/cargo-smart-release/src/lib.rs deleted file mode 100644 index 532d1c16784..00000000000 --- a/cargo-smart-release/src/lib.rs +++ /dev/null @@ -1,20 +0,0 @@ -#![deny(rust_2018_idioms)] - -pub use context::Context; - -#[derive(PartialEq, Eq, Debug, Clone)] -pub struct ChangeLog { - pub sections: Vec, -} - -pub mod changelog; -pub mod command; -pub(crate) mod commit; - -pub(crate) mod bat; -mod context; -mod crates_index; -pub(crate) mod git; -pub(crate) mod traverse; -mod utils; -pub mod version; diff --git a/cargo-smart-release/src/traverse.rs b/cargo-smart-release/src/traverse.rs deleted file mode 100644 index d3282037f60..00000000000 --- a/cargo-smart-release/src/traverse.rs +++ /dev/null @@ -1,608 +0,0 @@ -use std::collections::BTreeSet; - -use cargo_metadata::{DependencyKind, Package, PackageId}; - -use crate::{ - git, - traverse::dependency::{ManifestAdjustment, VersionAdjustment}, - utils::{ - is_pre_release_version, package_by_id, package_by_name, package_eq_dependency_ignore_dev_without_version, - workspace_package_by_dependency, - }, - version, - version::{Bump, BumpSpec}, - Context, -}; - -pub mod dependency { - use crate::{git, version}; - - /// Skipped crates are always dependent ones - #[derive(Copy, Clone, Debug, PartialOrd, Ord, Eq, PartialEq)] - pub enum NoPublishReason { - Unchanged, - DeniedAutopublishOfProductionCrate, - PublishDisabledInManifest, - BreakingChangeCausesManifestUpdate, - } - - impl std::fmt::Display for NoPublishReason { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - f.write_str(match self { - NoPublishReason::PublishDisabledInManifest => "disabled", - NoPublishReason::DeniedAutopublishOfProductionCrate => "denied", - NoPublishReason::Unchanged => "unchanged", - NoPublishReason::BreakingChangeCausesManifestUpdate => "dep-breaking", - }) - } - } - - #[derive(Clone, Copy, Debug, PartialEq, Eq)] - pub enum Kind { - /// Initially selected by user - UserSelection, - /// A changed dependency of the user selected crate that thus needs publishing - DependencyOrDependentOfUserSelection, - } - - #[derive(Clone, Debug)] - pub enum VersionAdjustment { - /// The crate changed and should see a version change - Changed { - change: git::PackageChangeKind, - bump: version::Bump, - }, - /// One of the crates dependencies signalled breaking changes, and is published because of that. - Breakage { - bump: version::Bump, - /// Set if there is a change at all, which might not be the case for previously skipped crates. - change: Option, - /// The direct dependency causing the breakage because it's breaking itself - causing_dependency_names: Vec, - }, - } - - impl VersionAdjustment { - pub fn bump(&self) -> &version::Bump { - match self { - VersionAdjustment::Breakage { bump, .. } | VersionAdjustment::Changed { bump, .. } => bump, - } - } - } - - #[allow(clippy::large_enum_variant)] - #[derive(Clone, Debug)] - pub enum ManifestAdjustment { - DueToDependencyChange, - Version(VersionAdjustment), - } - - #[derive(Clone, Debug)] - pub enum Mode { - ToBePublished { - adjustment: VersionAdjustment, - }, - /// Won't be published but manifest might have to be fixed if a version bump is present. - NotForPublishing { - reason: NoPublishReason, - adjustment: Option, - }, - } - - impl Mode { - pub fn manifest_will_change(&self) -> bool { - matches!( - self, - Mode::ToBePublished { .. } - | Mode::NotForPublishing { - adjustment: Some(_), - .. - } - ) - } - pub fn safety_bump(&self) -> Option<&version::Bump> { - match self { - Mode::ToBePublished { adjustment } - | Mode::NotForPublishing { - adjustment: Some(ManifestAdjustment::Version(adjustment)), - .. - } => match adjustment { - VersionAdjustment::Breakage { bump, .. } => Some(bump), - VersionAdjustment::Changed { .. } => None, - }, - _ => None, - } - } - pub fn version_adjustment_bump(&self) -> Option<&version::Bump> { - match self { - Mode::ToBePublished { adjustment } - | Mode::NotForPublishing { - adjustment: Some(ManifestAdjustment::Version(adjustment)), - .. - } => Some(adjustment.bump()), - _ => None, - } - } - } -} - -#[derive(Clone)] -pub struct Dependency<'meta> { - pub package: &'meta Package, - pub kind: dependency::Kind, - pub mode: dependency::Mode, -} - -impl<'a> std::fmt::Debug for Dependency<'a> { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - let mut dbg = f.debug_struct("Dependency"); - dbg.field("package", &self.package.id.repr); - dbg.field("kind", &self.kind); - dbg.field("mode", &self.mode); - dbg.finish() - } -} - -pub struct Options { - pub allow_auto_publish_of_stable_crates: bool, - pub bump_when_needed: bool, - pub isolate_dependencies_from_breaking_changes: bool, - pub traverse_graph: bool, -} - -pub fn dependencies( - ctx: &Context, - Options { - allow_auto_publish_of_stable_crates, - bump_when_needed, - isolate_dependencies_from_breaking_changes, - traverse_graph, - }: Options, -) -> anyhow::Result>> { - let mut seen = BTreeSet::new(); - let mut crates = Vec::new(); - for crate_name in &ctx.crate_names { - let mut crates_this_round = Vec::new(); - let package = package_by_name(&ctx.meta, crate_name)?; - if seen.contains(&&package.id) { - continue; - } - if traverse_graph { - depth_first_traversal( - ctx, - &mut seen, - &mut crates_this_round, - package, - allow_auto_publish_of_stable_crates, - bump_when_needed, - )?; - } - - match git::change_since_last_release(package, ctx)? { - Some(user_package_change) => { - crates_this_round.push(Dependency { - package, - kind: dependency::Kind::UserSelection, - mode: if package_may_be_published(package) { - dependency::Mode::ToBePublished { - adjustment: VersionAdjustment::Changed { - change: user_package_change, - bump: version::bump_package(package, ctx, bump_when_needed)?, - }, - } - } else { - dependency::Mode::NotForPublishing { - reason: dependency::NoPublishReason::PublishDisabledInManifest, - adjustment: None, - } - }, - }); - seen.insert(&package.id); - } - None => { - crates_this_round.push(Dependency { - package, - kind: dependency::Kind::UserSelection, - mode: dependency::Mode::NotForPublishing { - reason: dependency::NoPublishReason::Unchanged, - adjustment: None, - }, - }); - } - } - merge_crates(&mut crates, crates_this_round); - } - - if isolate_dependencies_from_breaking_changes { - forward_propagate_breaking_changes_for_publishing( - ctx, - &mut crates, - bump_when_needed, - allow_auto_publish_of_stable_crates, - )?; - forward_propagate_breaking_changes_for_manifest_updates( - ctx, - &mut crates, - bump_when_needed, - allow_auto_publish_of_stable_crates, - )?; - } - crates.extend(find_workspace_crates_depending_on_adjusted_crates(ctx, &crates)); - Ok(crates) -} - -fn merge_crates<'meta>(dest: &mut Vec>, src: Vec>) { - if dest.is_empty() { - *dest = src; - } else { - for dep in src { - if !dest.iter().any(|dest| dest.package.id == dep.package.id) { - dest.push(dep); - } - } - } -} - -fn forward_propagate_breaking_changes_for_manifest_updates<'meta>( - ctx: &'meta Context, - crates: &mut Vec>, - bump_when_needed: bool, - allow_auto_publish_of_stable_crates: bool, -) -> anyhow::Result<()> { - let mut non_publishing_crates_with_safety_bumps = Vec::new(); - let mut backing = crates - .iter() - .filter( - |c| matches!(&c.mode, dependency::Mode::ToBePublished { adjustment } if adjustment.bump().is_breaking()), - ) - .map(ToOwned::to_owned) - .collect::>(); - let workspace_packages: Vec<_> = ctx - .meta - .workspace_members - .iter() - .map(|wmid| package_by_id(&ctx.meta, wmid)) - .filter(|p| package_may_be_published(p)) // will publish, non-publishing ones need no safety bumps - .collect(); - let mut set_to_expand_from = &backing; - let mut seen = BTreeSet::default(); - loop { - let mut new_crates_this_round = Vec::>::new(); - for dependee in set_to_expand_from { - for dependant in workspace_packages.iter().filter(|p| { - p.dependencies - .iter() - .any(|dep| package_eq_dependency_ignore_dev_without_version(dependee.package, dep)) - }) { - if seen.contains(&&dependant.id) { - continue; - } - seen.insert(&dependant.id); - let crate_is_known_already = crates - .iter() - .find_map(|c| { - (c.package.id == dependant.id).then(|| c.mode.version_adjustment_bump().map(Bump::is_breaking)) - }) - .flatten(); - - let bump = breaking_version_bump(ctx, dependant, bump_when_needed)?; - if bump.next_release_changes_manifest() { - if crate_is_known_already.is_some() { - let is_breaking = crate_is_known_already.unwrap_or(false); - if !is_breaking { - log::debug!( - "Wanted to mark '{}' for breaking manifest change, but its already known without breaking change.", - dependant.name - ); - } - } else if is_pre_release_version(&dependant.version) || allow_auto_publish_of_stable_crates { - let kind = if ctx.crate_names.contains(&dependant.name) { - dependency::Kind::UserSelection - } else { - dependency::Kind::DependencyOrDependentOfUserSelection - }; - let adjustment = VersionAdjustment::Breakage { - bump, - change: None, - causing_dependency_names: vec![dependee.package.name.to_owned()], - }; - new_crates_this_round.push(Dependency { - package: dependant, - kind, - mode: match kind { - dependency::Kind::UserSelection => dependency::Mode::ToBePublished { adjustment }, - dependency::Kind::DependencyOrDependentOfUserSelection => { - dependency::Mode::NotForPublishing { - reason: dependency::NoPublishReason::BreakingChangeCausesManifestUpdate, - adjustment: Some(ManifestAdjustment::Version(adjustment)), - } - } - }, - }); - } else { - log::trace!( - "Ignored stable crate '{}' despite being eligible for safety bump and manifest change.", - dependant.name - ); - } - } - } - } - - if new_crates_this_round.is_empty() { - break; - } - non_publishing_crates_with_safety_bumps.extend(new_crates_this_round.iter().cloned()); - backing = new_crates_this_round; - set_to_expand_from = &backing; - } - crates.extend(non_publishing_crates_with_safety_bumps); - Ok(()) -} - -fn package_may_be_published(p: &Package) -> bool { - p.publish.is_none() -} - -fn forward_propagate_breaking_changes_for_publishing( - ctx: &Context, - crates: &mut [Dependency<'_>], - bump_when_needed: bool, - allow_auto_publish_of_stable_crates: bool, -) -> anyhow::Result<()> { - let mut previous_edits = Vec::new(); - loop { - let mut seen_this_round = BTreeSet::default(); - let mut edits = Vec::new(); - // skipped don't have version bumps, we don't have manifest updates yet - for (idx, starting_crate_for_backward_search) in crates - .iter() - .enumerate() - .rev() - .filter(|(_, c)| matches!(c.mode, dependency::Mode::ToBePublished { .. })) - { - find_safety_bump_edits_backwards_from_crates_for_publish( - crates, - (idx, starting_crate_for_backward_search), - &mut seen_this_round, - &mut edits, - ); - seen_this_round.insert(idx); - } - - if edits == previous_edits { - break; - } - - previous_edits = edits.clone(); - for edit_for_publish in edits { - edit_for_publish.apply(crates, ctx, bump_when_needed, allow_auto_publish_of_stable_crates)?; - } - } - Ok(()) -} - -#[derive(PartialEq, Eq, Clone)] -struct EditForPublish { - crates_idx: usize, - causing_dependency_indices: Vec, -} - -impl EditForPublish { - fn from(idx: usize, causing_dependency_indices: Vec) -> Self { - EditForPublish { - crates_idx: idx, - causing_dependency_indices, - } - } - - fn apply( - self, - crates: &mut [Dependency<'_>], - ctx: &Context, - bump_when_needed: bool, - allow_auto_publish_of_stable_crates: bool, - ) -> anyhow::Result<()> { - let causing_dependency_names = self - .causing_dependency_indices - .into_iter() - .map(|idx| crates[idx].package.name.clone()) - .collect(); - let dep_mut = &mut crates[self.crates_idx]; - if is_pre_release_version(&dep_mut.package.version) || allow_auto_publish_of_stable_crates { - let breaking_bump = breaking_version_bump(ctx, dep_mut.package, bump_when_needed)?; - match &mut dep_mut.mode { - dependency::Mode::NotForPublishing { - adjustment: maybe_adjustment, - .. - } => { - let adjustment = match maybe_adjustment.take() { - Some(ManifestAdjustment::DueToDependencyChange) => { - unreachable!("BUG: code generating these runs later") - } - Some(ManifestAdjustment::Version(mut adjustment)) => { - make_breaking(&mut adjustment, breaking_bump, causing_dependency_names); - adjustment - } - None => VersionAdjustment::Breakage { - bump: breaking_bump, - causing_dependency_names, - change: None, - }, - }; - dep_mut.mode = dependency::Mode::ToBePublished { adjustment }; - } - dependency::Mode::ToBePublished { adjustment, .. } => { - make_breaking(adjustment, breaking_bump, causing_dependency_names); - } - } - } else { - log::trace!( - "Ignored stable crate '{}' despite being eligible for safety bump and publishing.", - dep_mut.package.name - ); - } - Ok(()) - } -} - -fn breaking_version_bump(ctx: &Context, package: &Package, bump_when_needed: bool) -> anyhow::Result { - let breaking_spec = if is_pre_release_version(&package.version) { - BumpSpec::Minor - } else { - BumpSpec::Major - }; - version::bump_package_with_spec(package, breaking_spec, ctx, bump_when_needed) -} - -fn make_breaking(adjustment: &mut VersionAdjustment, breaking_bump: Bump, breaking_crate_names: Vec) { - match adjustment { - VersionAdjustment::Breakage { .. } => {} - VersionAdjustment::Changed { change, bump } => { - bump.next_release = breaking_bump.next_release; - *adjustment = VersionAdjustment::Breakage { - bump: bump.clone(), - change: Some(change.clone()), - causing_dependency_names: breaking_crate_names, - }; - } - } -} - -fn find_safety_bump_edits_backwards_from_crates_for_publish( - crates: &[Dependency<'_>], - start: (usize, &Dependency<'_>), - seen: &mut BTreeSet, - edits: &mut Vec, -) -> Vec { - let (current_idx, current) = start; - let mut breaking_indices = Vec::new(); - for (dep_idx, dep) in current.package.dependencies.iter().filter_map(|dep| { - crates - .iter() - .enumerate() - .find(|(_, c)| package_eq_dependency_ignore_dev_without_version(c.package, dep)) - }) { - if seen.contains(&dep_idx) { - continue; - } - match dep.mode.version_adjustment_bump() { - Some(dep_bump) if dep_bump.is_breaking() => { - if !edits.iter().any(|e| e.crates_idx == current_idx) { - edits.push(EditForPublish::from(current_idx, vec![dep_idx])); - } - if !breaking_indices.contains(&dep_idx) { - breaking_indices.push(dep_idx); - } - } - _ => { - seen.insert(dep_idx); - let breaking_package_indices = - find_safety_bump_edits_backwards_from_crates_for_publish(crates, (dep_idx, dep), seen, edits); - if !breaking_package_indices.is_empty() { - if !edits.iter().any(|e| e.crates_idx == current_idx) { - edits.push(EditForPublish::from(current_idx, breaking_package_indices.clone())); - } - for idx in breaking_package_indices { - if !breaking_indices.contains(&idx) { - breaking_indices.push(idx); - } - } - } - } - } - } - breaking_indices -} - -fn depth_first_traversal<'meta>( - ctx: &'meta Context, - seen: &mut BTreeSet<&'meta PackageId>, - crates: &mut Vec>, - root: &Package, - allow_auto_publish_of_stable_crates: bool, - bump_when_needed: bool, -) -> anyhow::Result<()> { - for workspace_dependency in root - .dependencies - .iter() - .filter(|d| d.kind == DependencyKind::Normal) - .filter_map(|d| workspace_package_by_dependency(&ctx.meta, d)) - { - if seen.contains(&&workspace_dependency.id) { - continue; - } - seen.insert(&workspace_dependency.id); - depth_first_traversal( - ctx, - seen, - crates, - workspace_dependency, - allow_auto_publish_of_stable_crates, - bump_when_needed, - )?; - - crates.push(match git::change_since_last_release(workspace_dependency, ctx)? { - Some(change) => { - if is_pre_release_version(&workspace_dependency.version) || allow_auto_publish_of_stable_crates { - Dependency { - package: workspace_dependency, - kind: dependency::Kind::DependencyOrDependentOfUserSelection, - mode: dependency::Mode::ToBePublished { - adjustment: VersionAdjustment::Changed { - change, - bump: version::bump_package(workspace_dependency, ctx, bump_when_needed)?, - }, - }, - } - } else { - Dependency { - package: workspace_dependency, - kind: dependency::Kind::DependencyOrDependentOfUserSelection, - mode: dependency::Mode::NotForPublishing { - reason: dependency::NoPublishReason::DeniedAutopublishOfProductionCrate, - adjustment: None, - }, - } - } - } - None => Dependency { - package: workspace_dependency, - kind: dependency::Kind::DependencyOrDependentOfUserSelection, - mode: dependency::Mode::NotForPublishing { - reason: dependency::NoPublishReason::Unchanged, - adjustment: None, - }, - }, - }); - } - Ok(()) -} - -fn find_workspace_crates_depending_on_adjusted_crates<'meta>( - ctx: &'meta Context, - crates: &[Dependency<'_>], -) -> Vec> { - ctx.meta - .workspace_members - .iter() - .map(|id| package_by_id(&ctx.meta, id)) - .filter(|wsp| crates.iter().all(|c| c.package.id != wsp.id)) - .filter(|wsp| { - wsp.dependencies.iter().any(|d| { - crates - .iter() - .filter(|c| c.mode.manifest_will_change()) - .any(|c| package_eq_dependency_ignore_dev_without_version(c.package, d)) - }) - }) - .map(|wsp| Dependency { - kind: dependency::Kind::DependencyOrDependentOfUserSelection, - package: wsp, - mode: dependency::Mode::NotForPublishing { - adjustment: ManifestAdjustment::DueToDependencyChange.into(), - reason: dependency::NoPublishReason::Unchanged, - }, - }) - .collect() -} diff --git a/cargo-smart-release/src/utils.rs b/cargo-smart-release/src/utils.rs deleted file mode 100644 index 1894c34880b..00000000000 --- a/cargo-smart-release/src/utils.rs +++ /dev/null @@ -1,306 +0,0 @@ -use std::process::Stdio; - -use anyhow::anyhow; -use cargo_metadata::{ - camino::{Utf8Component, Utf8Path}, - Dependency, DependencyKind, Metadata, Package, PackageId, -}; -use gix::bstr::{BStr, ByteSlice}; -use semver::{Version, VersionReq}; -use time::OffsetDateTime; - -pub struct Program { - pub found: bool, -} - -impl Program { - pub fn named(name: &'static str) -> Self { - Program { - found: std::process::Command::new(name) - .stdin(Stdio::null()) - .stdout(Stdio::null()) - .stderr(Stdio::null()) - .status() - .is_ok(), - } - } -} - -pub fn will(not_really: bool) -> &'static str { - if not_really { - "WOULD" - } else { - "Will" - } -} - -pub fn try_to_published_crate_and_new_version<'meta, 'a>( - c: &'a crate::traverse::Dependency<'meta>, -) -> Option<(&'meta Package, &'a semver::Version)> { - match &c.mode { - crate::traverse::dependency::Mode::ToBePublished { adjustment } => { - Some((c.package, &adjustment.bump().next_release)) - } - _ => None, - } -} - -pub fn is_pre_release_version(semver: &Version) -> bool { - semver.major == 0 -} - -pub fn is_top_level_package(manifest_path: &Utf8Path, repo: &gix::Repository) -> bool { - manifest_path - .strip_prefix( - std::env::current_dir() - .expect("cwd") - .join(repo.work_dir().as_ref().expect("repo with working tree")), - ) - .map_or(false, |p| p.components().count() == 1) -} - -pub fn version_req_unset_or_default(req: &VersionReq) -> bool { - req.comparators.last().map_or(true, |comp| comp.op == semver::Op::Caret) -} - -pub fn package_eq_dependency_ignore_dev_without_version(package: &Package, dependency: &Dependency) -> bool { - (dependency.kind != DependencyKind::Development || !version_req_unset_or_default(&dependency.req)) - && package.name == dependency.name -} - -pub fn workspace_package_by_dependency<'a>(meta: &'a Metadata, dep: &Dependency) -> Option<&'a Package> { - meta.packages - .iter() - .find(|p| p.name == dep.name && p.source.as_ref().map_or(true, |s| !s.is_crates_io())) - .filter(|p| meta.workspace_members.iter().any(|m| m == &p.id)) -} - -pub fn package_by_name<'a>(meta: &'a Metadata, name: &str) -> anyhow::Result<&'a Package> { - meta.packages - .iter() - .find(|p| p.name == name && p.source.as_ref().map_or(true, |s| !s.is_crates_io())) - .ok_or_else(|| anyhow!("workspace member '{}' must be a listed package", name)) -} - -pub fn names_and_versions<'a>(publishees: impl IntoIterator) -> String { - publishees - .into_iter() - .map(|(p, nv)| format!("{} v{}", p.name, nv)) - .collect::>() - .join(", ") -} - -pub fn package_by_id<'a>(meta: &'a Metadata, id: &PackageId) -> &'a Package { - meta.packages - .iter() - .find(|p| &p.id == id) - .expect("workspace members are in packages") -} - -pub fn tag_prefix<'p>(package: &'p Package, repo: &gix::Repository) -> Option<&'p str> { - if is_top_level_package(&package.manifest_path, repo) { - None - } else { - Some(&package.name) - } -} - -pub fn tag_name(package: &Package, version: &semver::Version, repo: &gix::Repository) -> String { - tag_name_inner(tag_prefix(package, repo), version) -} - -fn tag_name_inner(package_name: Option<&str>, version: &semver::Version) -> String { - match package_name { - Some(name) => format!("{name}-v{version}"), - None => format!("v{version}"), - } -} - -pub fn parse_possibly_prefixed_tag_version(package_name: Option<&str>, tag_name: &BStr) -> Option { - match package_name { - Some(name) => tag_name - .strip_prefix(name.as_bytes()) - .and_then(|r| r.strip_prefix(b"-")) - .and_then(|possibly_version| parse_tag_version(possibly_version.as_bstr())), - None => parse_tag_version(tag_name), - } -} - -pub fn parse_tag_version(name: &BStr) -> Option { - let version = name - .strip_prefix(b"vers") - .or_else(|| name.strip_prefix(b"v")) - .unwrap_or_else(|| name.as_bytes()) - .to_str() - .ok()?; - Version::parse(version).ok() -} - -pub fn is_tag_name(package_name: &str, tag_name: &gix::bstr::BStr) -> bool { - match tag_name - .strip_prefix(package_name.as_bytes()) - .and_then(|r| r.strip_prefix(b"-")) - { - None => false, - Some(possibly_version) => parse_tag_version(possibly_version.as_bstr()).is_some(), - } -} - -pub fn is_tag_version(name: &gix::bstr::BStr) -> bool { - parse_tag_version(name).is_some() -} - -pub fn component_to_bytes(c: Utf8Component<'_>) -> &[u8] { - match c { - Utf8Component::Normal(c) => c.as_bytes(), - _ => unreachable!("only normal components are possible in paths here"), - } -} - -#[cfg(test)] -mod tests { - mod parse_possibly_prefixed_tag_version { - mod matches { - use std::str::FromStr; - - use gix::bstr::ByteSlice; - use semver::Version; - - use crate::utils::{parse_possibly_prefixed_tag_version, tag_name_inner}; - - #[test] - fn whatever_tag_name_would_return() { - assert_eq!( - parse_possibly_prefixed_tag_version( - "git-test".into(), - tag_name_inner("git-test".into(), &Version::from_str("1.0.1").unwrap()) - .as_bytes() - .as_bstr() - ), - Version::parse("1.0.1").expect("valid").into() - ); - - assert_eq!( - parse_possibly_prefixed_tag_version( - "single".into(), - tag_name_inner("single".into(), &Version::from_str("0.0.1-beta.1").unwrap()) - .as_bytes() - .as_bstr() - ), - Version::parse("0.0.1-beta.1").expect("valid").into() - ); - - assert_eq!( - parse_possibly_prefixed_tag_version( - None, - tag_name_inner(None, &Version::from_str("0.0.1+123.x").unwrap()) - .as_bytes() - .as_bstr() - ), - Version::parse("0.0.1+123.x").expect("valid").into() - ); - } - } - } - - mod is_tag_name { - mod no_match { - use std::str::FromStr; - - use gix::bstr::ByteSlice; - use semver::Version; - - use crate::utils::{is_tag_name, tag_name_inner}; - - #[test] - fn due_to_crate_name() { - assert!(!is_tag_name( - "foo", - tag_name_inner("bar".into(), &Version::from_str("0.0.1-beta.1").unwrap()) - .as_bytes() - .as_bstr() - )); - } - } - mod matches { - use std::str::FromStr; - - use gix::bstr::ByteSlice; - use semver::Version; - - use crate::utils::{is_tag_name, tag_name_inner}; - - #[test] - fn whatever_tag_name_would_return() { - assert!(is_tag_name( - "git-test", - tag_name_inner("git-test".into(), &Version::from_str("1.0.1").unwrap()) - .as_bytes() - .as_bstr() - )); - - assert!(is_tag_name( - "single", - tag_name_inner("single".into(), &Version::from_str("0.0.1-beta.1").unwrap()) - .as_bytes() - .as_bstr() - )); - } - } - } - mod is_tag_version { - mod no_match { - use gix::bstr::ByteSlice; - - use crate::utils::is_tag_version; - - #[test] - fn not_enough_numbers() { - assert!(!is_tag_version(b"v0.0".as_bstr())); - } - - #[test] - fn funky() { - assert!(!is_tag_version(b"vHi.Ho.yada-anythingreally".as_bstr())); - } - - #[test] - fn prefixed() { - assert!(!is_tag_version(b"cargo-v1.0.0".as_bstr())); - } - } - mod matches { - use gix::bstr::ByteSlice; - - #[test] - fn no_prefix() { - assert!(is_tag_version(b"0.0.1".as_bstr())); - } - - #[test] - fn custom_prefix() { - assert!(is_tag_version(b"vers0.0.1".as_bstr())); - } - - use crate::utils::is_tag_version; - - #[test] - fn pre_release() { - assert!(is_tag_version(b"v0.0.1".as_bstr())); - assert!(is_tag_version(b"v0.10.0-beta.1".as_bstr())); - } - - #[test] - fn production() { - assert!(is_tag_version(b"v1.0.1-alpha.1".as_bstr())); - assert!(is_tag_version(b"v18.10.0+meta".as_bstr())); - } - } - } -} - -pub fn time_to_offset_date_time(time: gix::date::Time) -> OffsetDateTime { - time::OffsetDateTime::from_unix_timestamp(time.seconds) - .expect("always valid unix time") - .replace_offset(time::UtcOffset::from_whole_seconds(time.offset).expect("valid offset")) -} diff --git a/cargo-smart-release/src/version.rs b/cargo-smart-release/src/version.rs deleted file mode 100644 index 22daa1503e6..00000000000 --- a/cargo-smart-release/src/version.rs +++ /dev/null @@ -1,185 +0,0 @@ -use cargo_metadata::Package; -use semver::{Prerelease, Version}; - -use crate::Context; - -#[derive(Copy, Clone)] -pub enum BumpSpec { - Auto, - Keep, - Patch, - Minor, - Major, -} - -impl std::fmt::Display for BumpSpec { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - f.write_str(match self { - BumpSpec::Auto => "auto", - BumpSpec::Keep => "no", - BumpSpec::Patch => "patch", - BumpSpec::Minor => "minor", - BumpSpec::Major => "major", - }) - } -} - -#[allow(clippy::ptr_arg)] -pub(crate) fn select_publishee_bump_spec(name: &String, ctx: &Context) -> BumpSpec { - if ctx.crate_names.contains(name) { - ctx.bump - } else { - ctx.bump_dependencies - } -} - -/// Returns true if this would be a breaking change for `v`. -fn bump_major_minor_patch(v: &mut semver::Version, bump_spec: BumpSpec) -> bool { - use BumpSpec::*; - match bump_spec { - Major => { - v.major += 1; - v.minor = 0; - v.patch = 0; - v.pre = Prerelease::EMPTY; - true - } - Minor => { - v.minor += 1; - v.patch = 0; - v.pre = Prerelease::EMPTY; - is_pre_release(v) - } - Patch => { - v.patch += 1; - v.pre = Prerelease::EMPTY; - false - } - Keep | Auto => unreachable!("BUG: auto mode or keep are unsupported"), - } -} - -#[derive(Clone, Debug)] -pub struct Bump { - pub next_release: semver::Version, - /// The current version of the crate as read from Cargo.toml. - pub package_version: semver::Version, - /// The latest released version of the package, as read from the crates-index. - pub latest_release: Option, - /// The computed version, for example based on a user version bump or a computed version bump. - pub desired_release: semver::Version, -} - -impl Bump { - pub(crate) fn next_release_changes_manifest(&self) -> bool { - self.next_release > self.package_version - } - pub(crate) fn is_breaking(&self) -> bool { - rhs_is_breaking_bump_for_lhs(&self.package_version, &self.next_release) - } -} - -pub(crate) fn bump_package_with_spec( - package: &Package, - bump_spec: BumpSpec, - ctx: &Context, - bump_when_needed: bool, -) -> anyhow::Result { - let mut v = package.version.clone(); - use BumpSpec::*; - let package_version_must_be_breaking = match bump_spec { - Major | Minor | Patch => bump_major_minor_patch(&mut v, bump_spec), - Keep => false, - Auto => { - let segments = crate::git::history::crate_ref_segments( - package, - ctx, - ctx.history.as_ref().expect("BUG: assure history is set here"), - crate::git::history::SegmentScope::Unreleased, - )?; - assert_eq!( - segments.len(), - 1, - "there should be exactly one section, the 'unreleased' one" - ); - let unreleased = &segments[0]; - if unreleased.history.is_empty() { - false - } else if unreleased.history.iter().any(|item| item.message.breaking) { - let is_breaking = if is_pre_release(&v) { - bump_major_minor_patch(&mut v, Minor) - } else { - bump_major_minor_patch(&mut v, Major) - }; - assert!(is_breaking, "BUG: breaking changes are…breaking :D"); - is_breaking - } else if unreleased - .history - .iter() - .any(|item| item.message.kind.map_or(false, |kind| kind == "feat")) - { - let is_breaking = if is_pre_release(&v) { - bump_major_minor_patch(&mut v, Patch) - } else { - bump_major_minor_patch(&mut v, Minor) - }; - assert!(!is_breaking, "BUG: new features are never breaking"); - is_breaking - } else { - let is_breaking = bump_major_minor_patch(&mut v, Patch); - assert!(!is_breaking, "BUG: patch releases are never breaking"); - false - } - } - }; - let desired_release = v; - let (latest_release, next_release) = match ctx.crates_index.crate_(&package.name) { - Some(published_crate) => { - let latest_release = semver::Version::parse(published_crate.most_recent_version().version()) - .expect("valid version in crate index"); - let next_release = if latest_release >= desired_release { - desired_release.clone() - } else { - let mut next_release = desired_release.clone(); - if bump_when_needed && package.version > latest_release && desired_release != package.version { - if package_version_must_be_breaking { - if rhs_is_breaking_bump_for_lhs(&latest_release, &package.version) { - next_release = package.version.clone(); - } - } else { - next_release = package.version.clone(); - }; - } - next_release - }; - (Some(latest_release), next_release) - } - None => ( - None, - if bump_when_needed { - package.version.clone() - } else { - desired_release.clone() - }, - ), - }; - Ok(Bump { - next_release, - package_version: package.version.clone(), - desired_release, - latest_release, - }) -} - -pub(crate) fn bump_package(package: &Package, ctx: &Context, bump_when_needed: bool) -> anyhow::Result { - let bump_spec = select_publishee_bump_spec(&package.name, ctx); - bump_package_with_spec(package, bump_spec, ctx, bump_when_needed) -} - -pub(crate) fn is_pre_release(semver: &Version) -> bool { - crate::utils::is_pre_release_version(semver) -} - -pub(crate) fn rhs_is_breaking_bump_for_lhs(lhs: &Version, rhs: &Version) -> bool { - rhs.major > lhs.major || rhs.minor > lhs.minor -} diff --git a/cargo-smart-release/tests/changelog/merge.rs b/cargo-smart-release/tests/changelog/merge.rs deleted file mode 100644 index 453db1265f9..00000000000 --- a/cargo-smart-release/tests/changelog/merge.rs +++ /dev/null @@ -1,418 +0,0 @@ -use cargo_smart_release::{ - changelog, - changelog::{section, Section}, - ChangeLog, -}; -use time::OffsetDateTime; - -use crate::changelog::hex_to_id; - -#[test] -fn sections() { - let parsed = ChangeLog { - sections: vec![ - Section::Verbatim { - text: "preamble".into(), - generated: false, - }, - Section::Release { - heading_level: 3, - version_prefix: "".into(), - removed_messages: vec![], - date: Some( - time::Date::from_calendar_date(2021, time::Month::September, 14) - .unwrap() - .midnight() - .assume_utc(), - ), - name: changelog::Version::Semantic("1.0.0".parse().unwrap()), - segments: Vec::new(), - unknown: "never changed".into(), - }, - Section::Verbatim { - text: "something we couldn't parse".into(), - generated: false, - }, - Section::Release { - heading_level: 3, - version_prefix: Section::DEFAULT_PREFIX.into(), - removed_messages: vec![], - date: None, - name: changelog::Version::Semantic("0.9.0".parse().unwrap()), - segments: Vec::new(), - unknown: String::new(), - }, - ], - }; - let generated = ChangeLog { - sections: vec![ - Section::Verbatim { - text: "header".into(), - generated: true, - }, - Section::Release { - date: None, - removed_messages: vec![], - name: changelog::Version::Unreleased, - version_prefix: Section::DEFAULT_PREFIX.into(), - heading_level: 2, - segments: vec![section::Segment::Clippy(section::Data::Generated( - section::segment::ThanksClippy { count: 4 }, - ))], - unknown: Default::default(), - }, - Section::Release { - date: date_m_d(time::Month::September, 15).into(), // generated has a date is 'correct' - name: changelog::Version::Semantic("1.0.0".parse().unwrap()), - removed_messages: vec![], - heading_level: 2, - version_prefix: Section::DEFAULT_PREFIX.into(), - segments: vec![section::Segment::Clippy(section::Data::Generated( - section::segment::ThanksClippy { count: 3 }, - ))], - unknown: Default::default(), - }, - Section::Release { - date: date_m_d(time::Month::July, 1).into(), // generated has a date - name: changelog::Version::Semantic("0.9.0".parse().unwrap()), - unknown: String::new(), - removed_messages: vec![], - heading_level: 2, - version_prefix: Section::DEFAULT_PREFIX.into(), - segments: vec![section::Segment::Clippy(section::Data::Generated( - section::segment::ThanksClippy { count: 2 }, - ))], - }, - Section::Release { - date: date_m_d(time::Month::June, 1).into(), - name: changelog::Version::Semantic("0.8.0".parse().unwrap()), - unknown: "undocumented".into(), - removed_messages: vec![], - heading_level: 2, - version_prefix: Section::DEFAULT_PREFIX.into(), - segments: Vec::new(), - }, - ], - }; - - let merged = parsed.merge_generated(generated).expect("works"); - assert_eq!( - merged, - ChangeLog { - sections: vec![ - Section::Verbatim { - text: "preamble".into(), - generated: false, - }, - Section::Release { - date: None, - name: changelog::Version::Unreleased, - heading_level: 3, - version_prefix: "".into(), - removed_messages: vec![], - segments: vec![section::Segment::Clippy(section::Data::Generated( - section::segment::ThanksClippy { count: 4 } - ))], - unknown: Default::default(), - }, - Section::Release { - heading_level: 3, - removed_messages: vec![], - version_prefix: "".into(), - date: Some( - time::Date::from_calendar_date(2021, time::Month::September, 15) - .unwrap() - .midnight() - .assume_utc(), - ), - name: changelog::Version::Semantic("1.0.0".parse().unwrap()), - segments: vec![section::Segment::Clippy(section::Data::Generated( - section::segment::ThanksClippy { count: 3 } - ))], - unknown: "never changed".into(), - }, - Section::Verbatim { - text: "something we couldn't parse".into(), - generated: false, - }, - Section::Release { - date: date_m_d(time::Month::July, 1).into(), - name: changelog::Version::Semantic("0.9.0".parse().unwrap()), - unknown: String::new(), - heading_level: 3, - version_prefix: Section::DEFAULT_PREFIX.into(), - removed_messages: vec![], - segments: vec![section::Segment::Clippy(section::Data::Generated( - section::segment::ThanksClippy { count: 2 } - ))], - }, - Section::Release { - date: date_m_d(time::Month::June, 1).into(), - name: changelog::Version::Semantic("0.8.0".parse().unwrap()), - unknown: "undocumented".into(), - heading_level: 3, - version_prefix: "".into(), - removed_messages: vec![], - segments: Vec::new(), - }, - ] - }, - "retain user content, integrate generated one, as losslessly as possible" - ); -} - -#[test] -fn segments() { - let removed_message_id = hex_to_id("0000000000000000000000000000000000000001"); - let changed_message_id = hex_to_id("0000000000000000000000000000000000000002"); - let parsed = ChangeLog { - sections: vec![ - Section::Verbatim { - text: "preamble".into(), - generated: false, - }, - Section::Release { - date: date_m_d(time::Month::January, 1).into(), - name: changelog::Version::Semantic("0.7.0".parse().unwrap()), - unknown: "".into(), - heading_level: 3, - version_prefix: Section::DEFAULT_PREFIX.into(), - removed_messages: vec![], - segments: vec![ - section::Segment::Conventional(section::segment::Conventional { - kind: "feat", - is_breaking: false, - removed: vec![removed_message_id], - messages: vec![ - section::segment::conventional::Message::User { - markdown: "user text".into(), - }, - section::segment::conventional::Message::Generated { - id: changed_message_id, - title: "content changed by user".to_string(), - body: None, - }, - ], - }), // conventional is present and prevents new conventionals from showing up - section::Segment::Clippy(section::Data::Parsed), // statistical items prevent others from showing up - ], - }, - Section::Release { - date: None, - name: changelog::Version::Unreleased, - heading_level: 3, - version_prefix: Section::DEFAULT_PREFIX.into(), - removed_messages: vec![], - segments: vec![section::Segment::Clippy(section::Data::Parsed)], // only clippy still available - unknown: Default::default(), - }, - Section::Release { - heading_level: 3, - version_prefix: Section::DEFAULT_PREFIX.into(), - removed_messages: vec![], - date: Some( - time::Date::from_calendar_date(2021, time::Month::September, 15) - .unwrap() - .midnight() - .assume_utc(), - ), - name: changelog::Version::Semantic("1.0.0".parse().unwrap()), - segments: vec![section::Segment::User { - markdown: "user generated".into(), - }], // all segments removed, but user segment present - unknown: "".into(), - }, - Section::Release { - date: date_m_d(time::Month::June, 1).into(), - name: changelog::Version::Semantic("0.8.0".parse().unwrap()), - unknown: "".into(), - heading_level: 3, - version_prefix: Section::DEFAULT_PREFIX.into(), - removed_messages: vec![], - segments: vec![ - section::Segment::Details(section::Data::Parsed), - section::Segment::Statistics(section::Data::Parsed), - ], - }, - ], - }; - let clippy = section::Segment::Clippy(section::Data::Generated(section::segment::ThanksClippy { count: 42 })); - let statistics = section::Segment::Statistics(section::Data::Generated(section::segment::CommitStatistics { - count: 1, - duration: None, - time_passed_since_last_release: None, - conventional_count: 2, - unique_issues: vec![], - })); - let details = section::Segment::Details(section::Data::Generated(section::segment::Details { - commits_by_category: Default::default(), - })); - let added_message_id = hex_to_id("0000000000000000000000000000000000000003"); - let feat_conventional = section::Segment::Conventional(section::segment::Conventional { - kind: "feat", - is_breaking: false, - removed: vec![], - messages: vec![ - section::segment::conventional::Message::Generated { - id: removed_message_id, - title: "something removed".to_string(), - body: None, - }, - section::segment::conventional::Message::Generated { - id: changed_message_id, - title: "something added/changed".to_string(), - body: None, - }, - section::segment::conventional::Message::Generated { - id: added_message_id, - title: "to be inserted after user message".to_string(), - body: None, - }, - ], - }); - let segments = vec![statistics.clone(), clippy.clone(), details.clone()]; - let generated = ChangeLog { - sections: vec![ - Section::Verbatim { - text: "custom header".into(), - generated: true, - }, - Section::Release { - date: None, - name: changelog::Version::Unreleased, - heading_level: 3, - version_prefix: Section::DEFAULT_PREFIX.into(), - removed_messages: vec![], - segments: segments.clone(), - unknown: Default::default(), - }, - Section::Release { - heading_level: 3, - version_prefix: Section::DEFAULT_PREFIX.into(), - removed_messages: vec![], - date: Some( - time::Date::from_calendar_date(2021, time::Month::September, 15) - .unwrap() - .midnight() - .assume_utc(), - ), - name: changelog::Version::Semantic("1.0.0".parse().unwrap()), - segments: segments.clone(), - unknown: "".into(), - }, - Section::Release { - date: date_m_d(time::Month::June, 1).into(), - name: changelog::Version::Semantic("0.8.0".parse().unwrap()), - unknown: "".into(), - heading_level: 3, - version_prefix: Section::DEFAULT_PREFIX.into(), - removed_messages: vec![], - segments: segments.clone(), - }, - Section::Release { - date: date_m_d(time::Month::January, 1).into(), - name: changelog::Version::Semantic("0.7.0".parse().unwrap()), - unknown: "".into(), - heading_level: 3, - version_prefix: Section::DEFAULT_PREFIX.into(), - removed_messages: vec![], - segments: { - let mut v = segments.clone(); - v.push(feat_conventional); - v - }, - }, - ], - }; - let merged = parsed.merge_generated(generated).expect("works"); - assert_eq!( - merged, - ChangeLog { - sections: vec![ - Section::Verbatim { - text: "preamble".into(), - generated: false, - }, - Section::Release { - date: date_m_d(time::Month::January, 1).into(), - name: changelog::Version::Semantic("0.7.0".parse().unwrap()), - unknown: "".into(), - heading_level: 3, - version_prefix: Section::DEFAULT_PREFIX.into(), - removed_messages: vec![], - segments: vec![ - section::Segment::Conventional(section::segment::Conventional { - kind: "feat", - is_breaking: false, - removed: vec![removed_message_id], - messages: vec![ - section::segment::conventional::Message::User { - markdown: "user text".into(), - }, - section::segment::conventional::Message::Generated { - id: added_message_id, - title: "to be inserted after user message".to_string(), - body: None - }, // new messages are inserted after user content - section::segment::conventional::Message::Generated { - id: changed_message_id, - title: "content changed by user".to_string(), - body: None - }, // changed user content is preserved, don't overwrite, ever - ], - }), // conventional is present and prevents new conventionals from showing up, they have messages merged though - clippy.clone(), // statistical items prevent others from showing up - ], - }, // merge does not change the order of sections - Section::Release { - date: None, - name: changelog::Version::Unreleased, - heading_level: 3, - version_prefix: Section::DEFAULT_PREFIX.into(), - removed_messages: vec![], - segments: vec![clippy], - unknown: Default::default(), - }, - Section::Release { - heading_level: 3, - version_prefix: Section::DEFAULT_PREFIX.into(), - removed_messages: vec![], - date: Some( - time::Date::from_calendar_date(2021, time::Month::September, 15) - .unwrap() - .midnight() - .assume_utc(), - ), - name: changelog::Version::Semantic("1.0.0".parse().unwrap()), - segments: { - let mut s = segments; - s.insert( - 0, - section::Segment::User { - markdown: "user generated".into(), - }, - ); - s - }, - unknown: "".into(), - }, - Section::Release { - date: date_m_d(time::Month::June, 1).into(), - name: changelog::Version::Semantic("0.8.0".parse().unwrap()), - unknown: "".into(), - heading_level: 3, - version_prefix: Section::DEFAULT_PREFIX.into(), - removed_messages: vec![], - segments: vec![details, statistics], - }, - ], - } - ) -} - -fn date_m_d(month: time::Month, day: u8) -> OffsetDateTime { - time::Date::from_calendar_date(2021, month, day) // generated, correct date - .unwrap() - .midnight() - .assume_utc() -} diff --git a/cargo-smart-release/tests/changelog/mod.rs b/cargo-smart-release/tests/changelog/mod.rs deleted file mode 100644 index 702d61cf277..00000000000 --- a/cargo-smart-release/tests/changelog/mod.rs +++ /dev/null @@ -1,11 +0,0 @@ -use gix::ObjectId; - -mod parse; - -mod write_and_parse; - -mod merge; - -fn hex_to_id(hex: &str) -> ObjectId { - ObjectId::from_hex(hex.as_bytes()).expect("40 bytes hex") -} diff --git a/cargo-smart-release/tests/changelog/parse.rs b/cargo-smart-release/tests/changelog/parse.rs deleted file mode 100644 index 3156b92e8e0..00000000000 --- a/cargo-smart-release/tests/changelog/parse.rs +++ /dev/null @@ -1,120 +0,0 @@ -use std::path::Path; - -use cargo_smart_release::{ - changelog::{section::Segment, Section, Version}, - ChangeLog, -}; - -#[cfg(not(windows))] -fn fixup(v: String) -> String { - v -} - -#[cfg(windows)] -fn fixup(v: String) -> String { - // Git checks out text files with line ending conversions, git itself will of course not put '\r\n' anywhere, - // so that wouldn't be expected in an object and doesn't have to be parsed. - v.replace("\r\n", "\n") -} - -fn fixture(name: &str) -> std::io::Result { - let data = std::fs::read_to_string(gix_testtools::fixture_path( - Path::new("changelog").join("parse").join(name), - ))?; - Ok(fixup(data)) -} - -#[test] -fn all_unknown_in_section() { - let fixture = fixture("known-section-unknown-content.md").unwrap(); - let log = ChangeLog::from_markdown(&fixture); - assert_eq!( - log.sections, - vec![ - Section::Release { - name: Version::Unreleased, - removed_messages: vec![], - date: None, - heading_level: 3, - version_prefix: "".into(), - segments: vec![Segment::User { - markdown: "- hello ~~this is not understood~~\n* this isn't either\n\n".into() - }], - unknown: String::new(), - }, - Section::Release { - name: Version::Semantic("1.0.0".parse().unwrap()), - removed_messages: vec![], - date: None, - heading_level: 4, - version_prefix: Section::DEFAULT_PREFIX.into(), - segments: vec![Segment::User { - markdown: "Some free text in a paragraph\nthat won't parse.\n".into() - }], - unknown: String::new(), - } - ] - ) -} - -#[test] -fn unknown_link_and_headline() { - let fixture = fixture("known-section-unknown-headline-with-link.md").unwrap(); - let log = ChangeLog::from_markdown(&fixture); - assert_eq!( - log.sections, - vec![Section::Release { - name: Version::Unreleased, - removed_messages: vec![], - date: None, - heading_level: 4, - version_prefix: "".into(), - segments: vec![Segment::User { - markdown: "##### Special\n\nHello [there][194] period.\n".into() - }], - unknown: String::new(), - },] - ) -} - -#[test] -fn known_and_unknown_sections_are_sorted() { - let fixture = fixture("unknown-known-unknown-known-unsorted.md").unwrap(); - let log = ChangeLog::from_markdown(&fixture); - assert_eq!( - log.sections, - vec![ - Section::Verbatim { - text: "Hello, this is a changelog.\n\n".into(), - generated: false - }, - Section::Release { - name: Version::Unreleased, - removed_messages: vec![], - date: None, - heading_level: 3, - version_prefix: "".into(), - unknown: "".into(), - segments: vec![Segment::User { - markdown: "TBD\n".into() - }] - }, - Section::Release { - name: Version::Semantic(semver::Version::parse("1.0.0").unwrap()), - removed_messages: vec![], - date: None, - heading_level: 3, - version_prefix: Section::DEFAULT_PREFIX.into(), - unknown: "".into(), - segments: vec![ - Segment::User { - markdown: "- initial release\n\n".into() - }, - Segment::User { - markdown: "### Something in between\n\nintermezzo\n".into() - }, - ] - }, - ], - ) -} diff --git a/cargo-smart-release/tests/changelog/write_and_parse/mod.rs b/cargo-smart-release/tests/changelog/write_and_parse/mod.rs deleted file mode 100644 index 41adb03c688..00000000000 --- a/cargo-smart-release/tests/changelog/write_and_parse/mod.rs +++ /dev/null @@ -1,186 +0,0 @@ -use std::{collections::BTreeMap, convert::TryFrom}; - -use cargo_smart_release::{ - changelog, - changelog::{section, section::segment::conventional, Section}, - ChangeLog, -}; -use gix_testtools::bstr::ByteSlice; - -use crate::{changelog::hex_to_id, Result}; - -#[test] -fn conventional_write_empty_messages() -> Result { - let first_message = hex_to_id("0000000000000000000000000000000000000001"); - let second_message = hex_to_id("0000000000000000000000000000000000000002"); - - let log = ChangeLog { - sections: vec![Section::Release { - heading_level: 4, - version_prefix: Section::DEFAULT_PREFIX.into(), - date: Some(time::OffsetDateTime::from_unix_timestamp(0)?), - name: changelog::Version::Semantic("1.0.2-beta.2".parse()?), - removed_messages: vec![second_message], - segments: vec![section::Segment::Conventional(section::segment::Conventional { - kind: "feat", - is_breaking: true, - removed: vec![first_message], - messages: vec![ - conventional::Message::User { - markdown: " - verbatim `whatever` the _user_ writes [hello](world)".into(), - }, - conventional::Message::Generated { - id: hex_to_id("0000000000000000000000000000000000000003"), - title: "this messages comes straight from git conventional and _may_ contain markdown".into(), - body: Some("first line\nsecond line\n\nanother paragraph".into()), - }, - conventional::Message::Generated { - id: hex_to_id("0000000000000000000000000000000000000004"), - title: "spelling. Hello".into(), - body: None, - }, - conventional::Message::User { - markdown: - " - just another user message, this time\n with multiple lines\n\n and a new paragraph" - .into(), - }, - ], - })], - unknown: String::new(), - }], - }; - - for link_mode in &[ - changelog::write::Linkables::AsText, - changelog::write::Linkables::AsLinks { - repository_url: gix::Url::try_from(b"https://github.com/user/repo.git".as_bstr())?.into(), - }, - ] { - let log = log.clone(); - for _round in 1..=2 { - let mut md = String::new(); - log.write_to(&mut md, link_mode, changelog::write::Components::all(), false)?; - insta::assert_snapshot!(md); - - let parsed_log = ChangeLog::from_markdown(&md); - assert_eq!(parsed_log, log, "we can parse this back losslessly"); - } - } - for components in &[ - changelog::write::Components::empty(), - changelog::write::Components::all(), - ] { - for section in &log.sections { - let mut buf = String::new(); - section.write_to(&mut buf, &changelog::write::Linkables::AsText, *components, false)?; - insta::assert_snapshot!(buf); - } - } - Ok(()) -} - -#[test] -fn all_section_types_round_trips_lossy() -> Result { - let log = ChangeLog { - sections: vec![ - Section::Verbatim { - text: "# Changelog\n\nmy very own header\n\n".into(), - generated: false, - }, - Section::Release { - heading_level: 2, - removed_messages: vec![], - date: None, - name: changelog::Version::Unreleased, - version_prefix: "".into(), - segments: Vec::new(), - unknown: "hello\nworld\n".into(), - }, - Section::Release { - heading_level: 4, - version_prefix: "".into(), - removed_messages: vec![], - date: Some(time::OffsetDateTime::from_unix_timestamp(0)?), - name: changelog::Version::Semantic("1.0.2-beta.2".parse()?), - segments: vec![ - section::Segment::User { - markdown: "* hello world\n\tthis\n\n".into(), - }, - section::Segment::Clippy(section::Data::Generated(section::segment::ThanksClippy { count: 42 })), - section::Segment::Statistics(section::Data::Generated(section::segment::CommitStatistics { - count: 100, - duration: time::Duration::days(32).into(), - conventional_count: 20, - time_passed_since_last_release: Some(time::Duration::days(60)), - unique_issues: vec![ - section::segment::details::Category::Issue("1".into()), - section::segment::details::Category::Uncategorized, - section::segment::details::Category::Issue("42".into()), - ], - })), - section::Segment::Details(section::Data::Generated(section::segment::Details { - commits_by_category: { - let mut h = BTreeMap::default(); - h.insert( - section::segment::details::Category::Uncategorized, - vec![ - section::segment::details::Message { - title: "Just the title".into(), - id: hex_to_id("e69de29bb2d1d6434b8b29ae775ad8c2e48c5391"), - }, - section::segment::details::Message { - title: "Title and body".into(), - id: hex_to_id("e69de29bb2d1d6434b8b29ae775ad8c2e48c5392"), - }, - ], - ); - h.insert( - section::segment::details::Category::Issue("42".into()), - vec![ - section::segment::details::Message { - title: "Just the title".into(), - id: hex_to_id("e69de29bb2d1d6434b8b29ae775ad8c2e48c5392"), - }, - section::segment::details::Message { - title: "Another title".into(), - id: hex_to_id("e69de29bb2d1d6434b8b29ae775ad8c2e48c5391"), - }, - ], - ); - h - }, - })), - ], - unknown: String::new(), - }, - ], - }; - - for link_mode in &[ - changelog::write::Linkables::AsText, - changelog::write::Linkables::AsLinks { - repository_url: gix::Url::try_from(b"https://github.com/user/repo".as_bstr())?.into(), - }, - ] { - // NOTE: we can't run this a second time as the statistical information will be gone (it was never parsed back) - let mut md = String::new(); - log.write_to(&mut md, link_mode, changelog::write::Components::all(), false)?; - insta::assert_snapshot!(md); - - let parsed_log = ChangeLog::from_markdown(&md); - assert_eq!(parsed_log, log, "we must be able to parse the exact input back"); - } - - for components in &[ - changelog::write::Components::empty(), - changelog::write::Components::all(), - changelog::write::Components::DETAIL_TAGS, - ] { - for section in &log.sections { - let mut buf = String::new(); - section.write_to(&mut buf, &changelog::write::Linkables::AsText, *components, false)?; - insta::assert_snapshot!(buf); - } - } - Ok(()) -} diff --git a/cargo-smart-release/tests/changelog/write_and_parse/snapshots/integration__changelog__write_and_parse__all_section_types_round_trips_lossy-10.snap b/cargo-smart-release/tests/changelog/write_and_parse/snapshots/integration__changelog__write_and_parse__all_section_types_round_trips_lossy-10.snap deleted file mode 100644 index bd95ace0ebe..00000000000 --- a/cargo-smart-release/tests/changelog/write_and_parse/snapshots/integration__changelog__write_and_parse__all_section_types_round_trips_lossy-10.snap +++ /dev/null @@ -1,6 +0,0 @@ ---- -source: cargo-smart-release/tests/changelog/write_and_parse/mod.rs -expression: buf.to_str()? - ---- - diff --git a/cargo-smart-release/tests/changelog/write_and_parse/snapshots/integration__changelog__write_and_parse__all_section_types_round_trips_lossy-11.snap b/cargo-smart-release/tests/changelog/write_and_parse/snapshots/integration__changelog__write_and_parse__all_section_types_round_trips_lossy-11.snap deleted file mode 100644 index 887715cc553..00000000000 --- a/cargo-smart-release/tests/changelog/write_and_parse/snapshots/integration__changelog__write_and_parse__all_section_types_round_trips_lossy-11.snap +++ /dev/null @@ -1,33 +0,0 @@ ---- -source: cargo-smart-release/tests/changelog/write_and_parse/mod.rs -expression: buf ---- -* hello world - this - -##### Thanks Clippy - -[Clippy](https://github.com/rust-lang/rust-clippy) helped 42 times to make code idiomatic. - -##### Commit Statistics - - - 100 commits contributed to the release over the course of 32 calendar days. - - 60 days passed between releases. - - 20 commits were understood as [conventional](https://www.conventionalcommits.org). - - 3 unique issues were worked on: #1, Uncategorized, #42 - -##### Commit Details - - - -
view details - - * **#42** - - Just the title (e69de29) - - Another title (e69de29) - * **Uncategorized** - - Just the title (e69de29) - - Title and body (e69de29) -
- - diff --git a/cargo-smart-release/tests/changelog/write_and_parse/snapshots/integration__changelog__write_and_parse__all_section_types_round_trips_lossy-2.snap b/cargo-smart-release/tests/changelog/write_and_parse/snapshots/integration__changelog__write_and_parse__all_section_types_round_trips_lossy-2.snap deleted file mode 100644 index 00b4f356c1a..00000000000 --- a/cargo-smart-release/tests/changelog/write_and_parse/snapshots/integration__changelog__write_and_parse__all_section_types_round_trips_lossy-2.snap +++ /dev/null @@ -1,50 +0,0 @@ ---- -source: cargo-smart-release/tests/changelog/write_and_parse/mod.rs -expression: md ---- -# Changelog - -my very own header - -## Unreleased - - -hello -world - - -#### 1.0.2-beta.2 (1970-01-01) - -* hello world - this - -##### Thanks Clippy - - - -[Clippy](https://github.com/rust-lang/rust-clippy) helped 42 times to make code idiomatic. - -##### Commit Statistics - - - - - 100 commits contributed to the release over the course of 32 calendar days. - - 60 days passed between releases. - - 20 commits were understood as [conventional](https://www.conventionalcommits.org). - - 3 unique issues were worked on: [#1](https://github.com/user/repo/issues/1), Uncategorized, [#42](https://github.com/user/repo/issues/42) - -##### Commit Details - - - -
view details - - * **[#42](https://github.com/user/repo/issues/42)** - - Just the title ([`e69de29`](https://github.com/user/repo/commit/e69de29bb2d1d6434b8b29ae775ad8c2e48c5392)) - - Another title ([`e69de29`](https://github.com/user/repo/commit/e69de29bb2d1d6434b8b29ae775ad8c2e48c5391)) - * **Uncategorized** - - Just the title ([`e69de29`](https://github.com/user/repo/commit/e69de29bb2d1d6434b8b29ae775ad8c2e48c5391)) - - Title and body ([`e69de29`](https://github.com/user/repo/commit/e69de29bb2d1d6434b8b29ae775ad8c2e48c5392)) -
- - diff --git a/cargo-smart-release/tests/changelog/write_and_parse/snapshots/integration__changelog__write_and_parse__all_section_types_round_trips_lossy-3.snap b/cargo-smart-release/tests/changelog/write_and_parse/snapshots/integration__changelog__write_and_parse__all_section_types_round_trips_lossy-3.snap deleted file mode 100644 index 4f6e00869b5..00000000000 --- a/cargo-smart-release/tests/changelog/write_and_parse/snapshots/integration__changelog__write_and_parse__all_section_types_round_trips_lossy-3.snap +++ /dev/null @@ -1,10 +0,0 @@ ---- -source: cargo-smart-release/tests/changelog/write_and_parse/mod.rs -expression: buf.to_str()? - ---- -# Changelog - -my very own header - - diff --git a/cargo-smart-release/tests/changelog/write_and_parse/snapshots/integration__changelog__write_and_parse__all_section_types_round_trips_lossy-4.snap b/cargo-smart-release/tests/changelog/write_and_parse/snapshots/integration__changelog__write_and_parse__all_section_types_round_trips_lossy-4.snap deleted file mode 100644 index bd95ace0ebe..00000000000 --- a/cargo-smart-release/tests/changelog/write_and_parse/snapshots/integration__changelog__write_and_parse__all_section_types_round_trips_lossy-4.snap +++ /dev/null @@ -1,6 +0,0 @@ ---- -source: cargo-smart-release/tests/changelog/write_and_parse/mod.rs -expression: buf.to_str()? - ---- - diff --git a/cargo-smart-release/tests/changelog/write_and_parse/snapshots/integration__changelog__write_and_parse__all_section_types_round_trips_lossy-5.snap b/cargo-smart-release/tests/changelog/write_and_parse/snapshots/integration__changelog__write_and_parse__all_section_types_round_trips_lossy-5.snap deleted file mode 100644 index 7c15d2c32fa..00000000000 --- a/cargo-smart-release/tests/changelog/write_and_parse/snapshots/integration__changelog__write_and_parse__all_section_types_round_trips_lossy-5.snap +++ /dev/null @@ -1,28 +0,0 @@ ---- -source: cargo-smart-release/tests/changelog/write_and_parse/mod.rs -expression: buf ---- -* hello world - this - -##### Thanks Clippy - -[Clippy](https://github.com/rust-lang/rust-clippy) helped 42 times to make code idiomatic. - -##### Commit Statistics - - - 100 commits contributed to the release over the course of 32 calendar days. - - 60 days passed between releases. - - 20 commits were understood as [conventional](https://www.conventionalcommits.org). - - 3 unique issues were worked on: #1, Uncategorized, #42 - -##### Commit Details - - * **#42** - - Just the title (e69de29) - - Another title (e69de29) - * **Uncategorized** - - Just the title (e69de29) - - Title and body (e69de29) - - diff --git a/cargo-smart-release/tests/changelog/write_and_parse/snapshots/integration__changelog__write_and_parse__all_section_types_round_trips_lossy-6.snap b/cargo-smart-release/tests/changelog/write_and_parse/snapshots/integration__changelog__write_and_parse__all_section_types_round_trips_lossy-6.snap deleted file mode 100644 index 4f6e00869b5..00000000000 --- a/cargo-smart-release/tests/changelog/write_and_parse/snapshots/integration__changelog__write_and_parse__all_section_types_round_trips_lossy-6.snap +++ /dev/null @@ -1,10 +0,0 @@ ---- -source: cargo-smart-release/tests/changelog/write_and_parse/mod.rs -expression: buf.to_str()? - ---- -# Changelog - -my very own header - - diff --git a/cargo-smart-release/tests/changelog/write_and_parse/snapshots/integration__changelog__write_and_parse__all_section_types_round_trips_lossy-7.snap b/cargo-smart-release/tests/changelog/write_and_parse/snapshots/integration__changelog__write_and_parse__all_section_types_round_trips_lossy-7.snap deleted file mode 100644 index 19063943ef1..00000000000 --- a/cargo-smart-release/tests/changelog/write_and_parse/snapshots/integration__changelog__write_and_parse__all_section_types_round_trips_lossy-7.snap +++ /dev/null @@ -1,12 +0,0 @@ ---- -source: cargo-smart-release/tests/changelog/write_and_parse/mod.rs -expression: buf.to_str()? - ---- -## Unreleased - - -hello -world - - diff --git a/cargo-smart-release/tests/changelog/write_and_parse/snapshots/integration__changelog__write_and_parse__all_section_types_round_trips_lossy-8.snap b/cargo-smart-release/tests/changelog/write_and_parse/snapshots/integration__changelog__write_and_parse__all_section_types_round_trips_lossy-8.snap deleted file mode 100644 index 207eb81619e..00000000000 --- a/cargo-smart-release/tests/changelog/write_and_parse/snapshots/integration__changelog__write_and_parse__all_section_types_round_trips_lossy-8.snap +++ /dev/null @@ -1,39 +0,0 @@ ---- -source: cargo-smart-release/tests/changelog/write_and_parse/mod.rs -expression: buf ---- -#### 1.0.2-beta.2 (1970-01-01) - -* hello world - this - -##### Thanks Clippy - - - -[Clippy](https://github.com/rust-lang/rust-clippy) helped 42 times to make code idiomatic. - -##### Commit Statistics - - - - - 100 commits contributed to the release over the course of 32 calendar days. - - 60 days passed between releases. - - 20 commits were understood as [conventional](https://www.conventionalcommits.org). - - 3 unique issues were worked on: #1, Uncategorized, #42 - -##### Commit Details - - - -
view details - - * **#42** - - Just the title (e69de29) - - Another title (e69de29) - * **Uncategorized** - - Just the title (e69de29) - - Title and body (e69de29) -
- - diff --git a/cargo-smart-release/tests/changelog/write_and_parse/snapshots/integration__changelog__write_and_parse__all_section_types_round_trips_lossy-9.snap b/cargo-smart-release/tests/changelog/write_and_parse/snapshots/integration__changelog__write_and_parse__all_section_types_round_trips_lossy-9.snap deleted file mode 100644 index 4f6e00869b5..00000000000 --- a/cargo-smart-release/tests/changelog/write_and_parse/snapshots/integration__changelog__write_and_parse__all_section_types_round_trips_lossy-9.snap +++ /dev/null @@ -1,10 +0,0 @@ ---- -source: cargo-smart-release/tests/changelog/write_and_parse/mod.rs -expression: buf.to_str()? - ---- -# Changelog - -my very own header - - diff --git a/cargo-smart-release/tests/changelog/write_and_parse/snapshots/integration__changelog__write_and_parse__all_section_types_round_trips_lossy.snap b/cargo-smart-release/tests/changelog/write_and_parse/snapshots/integration__changelog__write_and_parse__all_section_types_round_trips_lossy.snap deleted file mode 100644 index 8b9ec9eaeaa..00000000000 --- a/cargo-smart-release/tests/changelog/write_and_parse/snapshots/integration__changelog__write_and_parse__all_section_types_round_trips_lossy.snap +++ /dev/null @@ -1,50 +0,0 @@ ---- -source: cargo-smart-release/tests/changelog/write_and_parse/mod.rs -expression: md ---- -# Changelog - -my very own header - -## Unreleased - - -hello -world - - -#### 1.0.2-beta.2 (1970-01-01) - -* hello world - this - -##### Thanks Clippy - - - -[Clippy](https://github.com/rust-lang/rust-clippy) helped 42 times to make code idiomatic. - -##### Commit Statistics - - - - - 100 commits contributed to the release over the course of 32 calendar days. - - 60 days passed between releases. - - 20 commits were understood as [conventional](https://www.conventionalcommits.org). - - 3 unique issues were worked on: #1, Uncategorized, #42 - -##### Commit Details - - - -
view details - - * **#42** - - Just the title (e69de29) - - Another title (e69de29) - * **Uncategorized** - - Just the title (e69de29) - - Title and body (e69de29) -
- - diff --git a/cargo-smart-release/tests/changelog/write_and_parse/snapshots/integration__changelog__write_and_parse__conventional_write_empty_messages-2.snap b/cargo-smart-release/tests/changelog/write_and_parse/snapshots/integration__changelog__write_and_parse__conventional_write_empty_messages-2.snap deleted file mode 100644 index ba27144850a..00000000000 --- a/cargo-smart-release/tests/changelog/write_and_parse/snapshots/integration__changelog__write_and_parse__conventional_write_empty_messages-2.snap +++ /dev/null @@ -1,26 +0,0 @@ ---- -source: cargo-smart-release/tests/changelog/write_and_parse/mod.rs -expression: md - ---- -#### v1.0.2-beta.2 (1970-01-01) - - - -##### New Features (BREAKING) - - - - - verbatim `whatever` the _user_ writes [hello](world) - - this messages comes straight from git conventional and _may_ contain markdown - first line - second line - - another paragraph - - spelling. Hello - - just another user message, this time - with multiple lines - - and a new paragraph - - diff --git a/cargo-smart-release/tests/changelog/write_and_parse/snapshots/integration__changelog__write_and_parse__conventional_write_empty_messages-3.snap b/cargo-smart-release/tests/changelog/write_and_parse/snapshots/integration__changelog__write_and_parse__conventional_write_empty_messages-3.snap deleted file mode 100644 index ba27144850a..00000000000 --- a/cargo-smart-release/tests/changelog/write_and_parse/snapshots/integration__changelog__write_and_parse__conventional_write_empty_messages-3.snap +++ /dev/null @@ -1,26 +0,0 @@ ---- -source: cargo-smart-release/tests/changelog/write_and_parse/mod.rs -expression: md - ---- -#### v1.0.2-beta.2 (1970-01-01) - - - -##### New Features (BREAKING) - - - - - verbatim `whatever` the _user_ writes [hello](world) - - this messages comes straight from git conventional and _may_ contain markdown - first line - second line - - another paragraph - - spelling. Hello - - just another user message, this time - with multiple lines - - and a new paragraph - - diff --git a/cargo-smart-release/tests/changelog/write_and_parse/snapshots/integration__changelog__write_and_parse__conventional_write_empty_messages-4.snap b/cargo-smart-release/tests/changelog/write_and_parse/snapshots/integration__changelog__write_and_parse__conventional_write_empty_messages-4.snap deleted file mode 100644 index ba27144850a..00000000000 --- a/cargo-smart-release/tests/changelog/write_and_parse/snapshots/integration__changelog__write_and_parse__conventional_write_empty_messages-4.snap +++ /dev/null @@ -1,26 +0,0 @@ ---- -source: cargo-smart-release/tests/changelog/write_and_parse/mod.rs -expression: md - ---- -#### v1.0.2-beta.2 (1970-01-01) - - - -##### New Features (BREAKING) - - - - - verbatim `whatever` the _user_ writes [hello](world) - - this messages comes straight from git conventional and _may_ contain markdown - first line - second line - - another paragraph - - spelling. Hello - - just another user message, this time - with multiple lines - - and a new paragraph - - diff --git a/cargo-smart-release/tests/changelog/write_and_parse/snapshots/integration__changelog__write_and_parse__conventional_write_empty_messages-5.snap b/cargo-smart-release/tests/changelog/write_and_parse/snapshots/integration__changelog__write_and_parse__conventional_write_empty_messages-5.snap deleted file mode 100644 index 010c421c624..00000000000 --- a/cargo-smart-release/tests/changelog/write_and_parse/snapshots/integration__changelog__write_and_parse__conventional_write_empty_messages-5.snap +++ /dev/null @@ -1,20 +0,0 @@ ---- -source: cargo-smart-release/tests/changelog/write_and_parse/mod.rs -expression: buf - ---- -##### New Features (BREAKING) - - - verbatim `whatever` the _user_ writes [hello](world) - - this messages comes straight from git conventional and _may_ contain markdown - first line - second line - - another paragraph - - spelling. Hello - - just another user message, this time - with multiple lines - - and a new paragraph - - diff --git a/cargo-smart-release/tests/changelog/write_and_parse/snapshots/integration__changelog__write_and_parse__conventional_write_empty_messages-6.snap b/cargo-smart-release/tests/changelog/write_and_parse/snapshots/integration__changelog__write_and_parse__conventional_write_empty_messages-6.snap deleted file mode 100644 index 4f79bc6485a..00000000000 --- a/cargo-smart-release/tests/changelog/write_and_parse/snapshots/integration__changelog__write_and_parse__conventional_write_empty_messages-6.snap +++ /dev/null @@ -1,26 +0,0 @@ ---- -source: cargo-smart-release/tests/changelog/write_and_parse/mod.rs -expression: buf - ---- -#### v1.0.2-beta.2 (1970-01-01) - - - -##### New Features (BREAKING) - - - - - verbatim `whatever` the _user_ writes [hello](world) - - this messages comes straight from git conventional and _may_ contain markdown - first line - second line - - another paragraph - - spelling. Hello - - just another user message, this time - with multiple lines - - and a new paragraph - - diff --git a/cargo-smart-release/tests/changelog/write_and_parse/snapshots/integration__changelog__write_and_parse__conventional_write_empty_messages.snap b/cargo-smart-release/tests/changelog/write_and_parse/snapshots/integration__changelog__write_and_parse__conventional_write_empty_messages.snap deleted file mode 100644 index 55eabed3ff0..00000000000 --- a/cargo-smart-release/tests/changelog/write_and_parse/snapshots/integration__changelog__write_and_parse__conventional_write_empty_messages.snap +++ /dev/null @@ -1,25 +0,0 @@ ---- -source: cargo-smart-release/tests/changelog/write_and_parse/mod.rs -expression: md ---- -#### v1.0.2-beta.2 (1970-01-01) - - - -##### New Features (BREAKING) - - - - - verbatim `whatever` the _user_ writes [hello](world) - - this messages comes straight from git conventional and _may_ contain markdown - first line - second line - - another paragraph - - spelling. Hello - - just another user message, this time - with multiple lines - - and a new paragraph - - diff --git a/cargo-smart-release/tests/fixtures/changelog/parse/known-section-unknown-content.md b/cargo-smart-release/tests/fixtures/changelog/parse/known-section-unknown-content.md deleted file mode 100644 index 98f25d9fd7f..00000000000 --- a/cargo-smart-release/tests/fixtures/changelog/parse/known-section-unknown-content.md +++ /dev/null @@ -1,9 +0,0 @@ -### Unreleased - -- hello ~~this is not understood~~ -* this isn't either - -#### v1.0.0 - -Some free text in a paragraph -that won't parse. diff --git a/cargo-smart-release/tests/fixtures/changelog/parse/known-section-unknown-headline-with-link.md b/cargo-smart-release/tests/fixtures/changelog/parse/known-section-unknown-headline-with-link.md deleted file mode 100644 index b1b80743c4a..00000000000 --- a/cargo-smart-release/tests/fixtures/changelog/parse/known-section-unknown-headline-with-link.md +++ /dev/null @@ -1,7 +0,0 @@ -#### Unreleased - -##### Special - -Hello [there][194] period. - -[194]: https://example.com diff --git a/cargo-smart-release/tests/fixtures/changelog/parse/unknown-known-unknown-known-unsorted.md b/cargo-smart-release/tests/fixtures/changelog/parse/unknown-known-unknown-known-unsorted.md deleted file mode 100644 index f491aa53cc9..00000000000 --- a/cargo-smart-release/tests/fixtures/changelog/parse/unknown-known-unknown-known-unsorted.md +++ /dev/null @@ -1,13 +0,0 @@ -Hello, this is a changelog. - -### v1.0.0 - -- initial release - -### Something in between - -intermezzo - -### Unreleased - -TBD diff --git a/cargo-smart-release/tests/fixtures/tri-depth-workspace/Cargo.lock b/cargo-smart-release/tests/fixtures/tri-depth-workspace/Cargo.lock deleted file mode 100644 index 9c6afe3e40d..00000000000 --- a/cargo-smart-release/tests/fixtures/tri-depth-workspace/Cargo.lock +++ /dev/null @@ -1,21 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 3 - -[[package]] -name = "a" -version = "0.8.0" - -[[package]] -name = "b" -version = "0.8.0" -dependencies = [ - "a", -] - -[[package]] -name = "c" -version = "8.0.0" -dependencies = [ - "b", -] diff --git a/cargo-smart-release/tests/fixtures/tri-depth-workspace/Cargo.toml b/cargo-smart-release/tests/fixtures/tri-depth-workspace/Cargo.toml deleted file mode 100644 index e7d118ceaa3..00000000000 --- a/cargo-smart-release/tests/fixtures/tri-depth-workspace/Cargo.toml +++ /dev/null @@ -1,2 +0,0 @@ -[workspace] -members = ["a", "b", "c"] diff --git a/cargo-smart-release/tests/fixtures/tri-depth-workspace/a/CHANGELOG.md b/cargo-smart-release/tests/fixtures/tri-depth-workspace/a/CHANGELOG.md deleted file mode 100644 index 1d013ff92fa..00000000000 --- a/cargo-smart-release/tests/fixtures/tri-depth-workspace/a/CHANGELOG.md +++ /dev/null @@ -1,6 +0,0 @@ -# Changelog - -All notable changes to this project will be documented in this file. - -The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), -and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). diff --git a/cargo-smart-release/tests/fixtures/tri-depth-workspace/a/Cargo.toml b/cargo-smart-release/tests/fixtures/tri-depth-workspace/a/Cargo.toml deleted file mode 100644 index e435f869e89..00000000000 --- a/cargo-smart-release/tests/fixtures/tri-depth-workspace/a/Cargo.toml +++ /dev/null @@ -1,8 +0,0 @@ -[package] -name = "a" -version = "0.8.0" -edition = "2018" - -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - -[dependencies] diff --git a/cargo-smart-release/tests/fixtures/tri-depth-workspace/a/src/lib.rs b/cargo-smart-release/tests/fixtures/tri-depth-workspace/a/src/lib.rs deleted file mode 100644 index 31e1bb209f9..00000000000 --- a/cargo-smart-release/tests/fixtures/tri-depth-workspace/a/src/lib.rs +++ /dev/null @@ -1,7 +0,0 @@ -#[cfg(test)] -mod tests { - #[test] - fn it_works() { - assert_eq!(2 + 2, 4); - } -} diff --git a/cargo-smart-release/tests/fixtures/tri-depth-workspace/b/CHANGELOG.md b/cargo-smart-release/tests/fixtures/tri-depth-workspace/b/CHANGELOG.md deleted file mode 100644 index a4f7c30e063..00000000000 --- a/cargo-smart-release/tests/fixtures/tri-depth-workspace/b/CHANGELOG.md +++ /dev/null @@ -1,9 +0,0 @@ -# Changelog - -All notable changes to this project will be documented in this file. - -The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), -and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). - -## Unreleased - diff --git a/cargo-smart-release/tests/fixtures/tri-depth-workspace/b/Cargo.toml b/cargo-smart-release/tests/fixtures/tri-depth-workspace/b/Cargo.toml deleted file mode 100644 index ad7533a6036..00000000000 --- a/cargo-smart-release/tests/fixtures/tri-depth-workspace/b/Cargo.toml +++ /dev/null @@ -1,9 +0,0 @@ -[package] -name = "b" -version = "0.8.0" -edition = "2018" - -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - -[dependencies] -a = { path = "../a", version = "0.8.0" } diff --git a/cargo-smart-release/tests/fixtures/tri-depth-workspace/b/src/lib.rs b/cargo-smart-release/tests/fixtures/tri-depth-workspace/b/src/lib.rs deleted file mode 100644 index 31e1bb209f9..00000000000 --- a/cargo-smart-release/tests/fixtures/tri-depth-workspace/b/src/lib.rs +++ /dev/null @@ -1,7 +0,0 @@ -#[cfg(test)] -mod tests { - #[test] - fn it_works() { - assert_eq!(2 + 2, 4); - } -} diff --git a/cargo-smart-release/tests/fixtures/tri-depth-workspace/c/Cargo.toml b/cargo-smart-release/tests/fixtures/tri-depth-workspace/c/Cargo.toml deleted file mode 100644 index 8f5c510ee03..00000000000 --- a/cargo-smart-release/tests/fixtures/tri-depth-workspace/c/Cargo.toml +++ /dev/null @@ -1,9 +0,0 @@ -[package] -name = "c" -version = "8.0.0" -edition = "2018" - -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - -[dependencies] -b = { path = "../b", version = "0.8.0" } diff --git a/cargo-smart-release/tests/fixtures/tri-depth-workspace/c/src/main.rs b/cargo-smart-release/tests/fixtures/tri-depth-workspace/c/src/main.rs deleted file mode 100644 index e7a11a969c0..00000000000 --- a/cargo-smart-release/tests/fixtures/tri-depth-workspace/c/src/main.rs +++ /dev/null @@ -1,3 +0,0 @@ -fn main() { - println!("Hello, world!"); -} diff --git a/cargo-smart-release/tests/integration.rs b/cargo-smart-release/tests/integration.rs deleted file mode 100644 index 6aefa4e7f7e..00000000000 --- a/cargo-smart-release/tests/integration.rs +++ /dev/null @@ -1,3 +0,0 @@ -type Result = std::result::Result<(), Box>; - -mod changelog; diff --git a/cargo-smart-release/tests/journey.sh b/cargo-smart-release/tests/journey.sh deleted file mode 100755 index 1421e47ae7c..00000000000 --- a/cargo-smart-release/tests/journey.sh +++ /dev/null @@ -1,196 +0,0 @@ -#!/usr/bin/env bash -set -eu - -exe=${1:?First argument must be the executable to test} - -root="$(cd "${0%/*}" && pwd)" - -# if exe path is relative eval it from the parent of this script's location -if [[ $exe != /* ]]; then - exe="${root}/../$exe" -fi - -# shellcheck disable=1090 -source "$root/utilities.sh" -snapshot="$root/snapshots" -fixtures="$root/fixtures" - -SUCCESSFULLY=0 -# WITH_FAILURE=1 - -function set-static-git-environment() { - set -a - export GIT_AUTHOR_DATE="2021-09-09 09:06:03 +0200" - export GIT_COMMITTER_DATE="${GIT_AUTHOR_DATE}" - export GIT_AUTHOR_NAME="Sebastian Thiel" - export GIT_COMMITTER_NAME="${GIT_AUTHOR_NAME}" - export GIT_AUTHOR_EMAIL="git@example.com" - export GIT_COMMITTER_EMAIL="${GIT_AUTHOR_EMAIL}" - set +a -} - -function init-git-repo() { - git init . && - git config commit.gpgsign false && - git config tag.gpgsign false && - git add . && git commit -q -m "initial" -} - -title "changelog" -(sandbox - set-static-git-environment - export CARGO_HOME=$PWD - - snapshot="$snapshot/triple-depth-workspace-changelog" - cp -R $fixtures/tri-depth-workspace/* . - { echo $'target/\n.package-cache' > .gitignore && init-git-repo; } &>/dev/null - - (when "interacting with 'a'" - (with 'dry-run only' - it "succeeds" && { - WITH_SNAPSHOT="$snapshot/a-dry-run-success-multi-crate" \ - expect_run $SUCCESSFULLY "$exe" changelog a --no-preview - } - ) - (with '--write' - it "succeeds" && { - expect_run $SUCCESSFULLY "$exe" changelog a --write - } - (with ".git and target/ directories removed" - rm -Rf .git/ target/ - it "managed to write a changelog" && { - expect_snapshot "$snapshot/crate-a-released" . - } - ) - ) - ) -) - -title "smart-release" -(sandbox - set-static-git-environment - export CARGO_HOME=$PWD - - snapshot="$snapshot/triple-depth-workspace" - cp -R $fixtures/tri-depth-workspace/* . - { echo 'target/' > .gitignore && init-git-repo; } &>/dev/null - - (with "'c'" - (with '-d minor to bump minor dependencies' - it "succeeds" && { - expect_run $SUCCESSFULLY "$exe" smart-release c -d minor -b keep --no-push - } - ) - ) - - (with_program gh - (when "releasing 'a'" - (with 'dry-run only' - (with 'conditional version bumping' - (with 'explicit bump specification' - it "succeeds" && { - WITH_SNAPSHOT="$snapshot/a-dry-run-success-multi-crate" \ - expect_run $SUCCESSFULLY "$exe" smart-release a --no-push --no-publish -v --allow-dirty -b minor - } - ) - (with 'implicit bump specification derived from commit history' - it "succeeds" && { - WITH_SNAPSHOT="$snapshot/a-dry-run-success-multi-crate-auto-bump-no-change" \ - expect_run $SUCCESSFULLY "$exe" smart-release a --no-push --no-publish -v --allow-dirty - } - (with "a breaking change" - (cd a && touch break && git add break && git commit -m "refactor!: break") &>/dev/null - it "succeeds" && { - WITH_SNAPSHOT="$snapshot/a-dry-run-success-multi-crate-auto-bump-breaking-change" \ - expect_run $SUCCESSFULLY "$exe" smart-release a --no-push --no-publish -v --allow-dirty --allow-fully-generated-changelogs - } - (with "unconditional version bumping" - it "succeeds" && { - WITH_SNAPSHOT="$snapshot/a-dry-run-success-multi-crate-auto-bump-breaking-change-no-bump-on-demand" \ - expect_run $SUCCESSFULLY "$exe" smart-release a --no-push --no-publish -v --allow-dirty --allow-fully-generated-changelogs --no-bump-on-demand --auto-publish-of-stable-crates - } - (with "--no-auto-publish-of-stable-crates" - it "succeeds" && { - WITH_SNAPSHOT="$snapshot/a-dry-run-success-multi-crate-auto-bump-breaking-change-no-bump-on-demand-no-publish-stable" \ - expect_run $SUCCESSFULLY "$exe" smart-release a --no-push --no-publish -v --allow-dirty --allow-fully-generated-changelogs --no-bump-on-demand - } - ) - ) - (when 'releasing "c" as well with unconditional version bumping' - it "succeeds" && { - WITH_SNAPSHOT="$snapshot/a-dry-run-success-multi-crate-auto-bump-breaking-change-dependant-publish" \ - expect_run $SUCCESSFULLY "$exe" smart-release c a --no-push --no-publish -v --allow-dirty --allow-fully-generated-changelogs --no-bump-on-demand --auto-publish-of-stable-crates - } - ) - git reset --hard HEAD~1 &>/dev/null - ) - (with "a new feature" - (cd a && touch feat && git add feat && git commit -m "feat: new") &>/dev/null - it "succeeds" && { - WITH_SNAPSHOT="$snapshot/a-dry-run-success-multi-crate-auto-bump-minor-change" \ - expect_run $SUCCESSFULLY "$exe" smart-release a --no-push --no-publish -v --allow-dirty - } - git reset --hard HEAD~1 &>/dev/null - ) - (when 'releasing "c" as well' - it "succeeds" && { - WITH_SNAPSHOT="$snapshot/c-dry-run-success-multi-crate-auto-bump-no-change" \ - expect_run $SUCCESSFULLY "$exe" smart-release c a --no-push --no-publish -v --allow-dirty - } - (with "a breaking change" - (cd c && touch break && git add break && git commit -m "refactor!: break") &>/dev/null - it "succeeds" && { - WITH_SNAPSHOT="$snapshot/c-dry-run-success-multi-crate-auto-bump-breaking-change" \ - expect_run $SUCCESSFULLY "$exe" smart-release c a --no-push --no-publish -v --allow-dirty - } - git reset --hard HEAD~1 &>/dev/null - ) - (with "a new feature" - (cd c && touch feat && git add feat && git commit -m "feat: new") &>/dev/null - it "succeeds" && { - WITH_SNAPSHOT="$snapshot/c-dry-run-success-multi-crate-auto-bump-minor-change" \ - expect_run $SUCCESSFULLY "$exe" smart-release c a --no-push --no-publish -v --allow-dirty - } - git reset --hard HEAD~1 &>/dev/null - ) - ) - ) - ) - (with 'unconditional version bumping' - it "succeeds" && { - WITH_SNAPSHOT="$snapshot/a-dry-run-success-multi-crate-unconditional" \ - expect_run $SUCCESSFULLY "$exe" smart-release a --no-push --no-publish -v --no-bump-on-demand -b minor --auto-publish-of-stable-crates - } - (when 'releasing b as well' - it "succeeds" && { - WITH_SNAPSHOT="$snapshot/a-b-dry-run-success-multi-crate-unconditional" \ - expect_run $SUCCESSFULLY "$exe" smart-release b a --no-push --no-publish -v --no-bump-on-demand -b minor --auto-publish-of-stable-crates - } - ) - ) - ) - (with '--execute but without side-effects' - it "succeeds" && { - expect_run $SUCCESSFULLY "$exe" smart-release a -b keep -d keep --no-push --no-publish --execute --allow-dirty --no-changelog-preview --auto-publish-of-stable-crates - } - (with ".git and target/ directories removed" - rm -Rf .git/ target/ - it "managed to bump B's minor but left C alone as it's not pre-release anymore" && { - expect_snapshot "$snapshot/crate-a-released" . - } - (with 'unconditional version minor bumping' - init-git-repo &>/dev/null - it "succeeds" && { - expect_run $SUCCESSFULLY "$exe" smart-release -b minor a --no-push --no-publish --no-bump-on-demand --execute --allow-dirty --no-changelog-preview --auto-publish-of-stable-crates - } - rm -Rf .git/ - it "managed additionally bumped b but not c as it's not pre-release" && { - expect_snapshot "$snapshot/crate-a-released-force-bump" . - } - ) - ) - ) - ) - ) -) - diff --git a/cargo-smart-release/tests/snapshots/triple-depth-workspace-changelog/a-dry-run-success-multi-crate b/cargo-smart-release/tests/snapshots/triple-depth-workspace-changelog/a-dry-run-success-multi-crate deleted file mode 100644 index 9775950fef2..00000000000 --- a/cargo-smart-release/tests/snapshots/triple-depth-workspace-changelog/a-dry-run-success-multi-crate +++ /dev/null @@ -1 +0,0 @@ -[INFO ] WOULD write 2 sections to a/CHANGELOG.md (modified) \ No newline at end of file diff --git a/cargo-smart-release/tests/snapshots/triple-depth-workspace-changelog/crate-a-released/.gitignore b/cargo-smart-release/tests/snapshots/triple-depth-workspace-changelog/crate-a-released/.gitignore deleted file mode 100644 index 87ae82fd3bb..00000000000 --- a/cargo-smart-release/tests/snapshots/triple-depth-workspace-changelog/crate-a-released/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -target/ -.package-cache diff --git a/cargo-smart-release/tests/snapshots/triple-depth-workspace-changelog/crate-a-released/Cargo.lock b/cargo-smart-release/tests/snapshots/triple-depth-workspace-changelog/crate-a-released/Cargo.lock deleted file mode 100644 index 9c6afe3e40d..00000000000 --- a/cargo-smart-release/tests/snapshots/triple-depth-workspace-changelog/crate-a-released/Cargo.lock +++ /dev/null @@ -1,21 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 3 - -[[package]] -name = "a" -version = "0.8.0" - -[[package]] -name = "b" -version = "0.8.0" -dependencies = [ - "a", -] - -[[package]] -name = "c" -version = "8.0.0" -dependencies = [ - "b", -] diff --git a/cargo-smart-release/tests/snapshots/triple-depth-workspace-changelog/crate-a-released/Cargo.toml b/cargo-smart-release/tests/snapshots/triple-depth-workspace-changelog/crate-a-released/Cargo.toml deleted file mode 100644 index e7d118ceaa3..00000000000 --- a/cargo-smart-release/tests/snapshots/triple-depth-workspace-changelog/crate-a-released/Cargo.toml +++ /dev/null @@ -1,2 +0,0 @@ -[workspace] -members = ["a", "b", "c"] diff --git a/cargo-smart-release/tests/snapshots/triple-depth-workspace-changelog/crate-a-released/a/CHANGELOG.md b/cargo-smart-release/tests/snapshots/triple-depth-workspace-changelog/crate-a-released/a/CHANGELOG.md deleted file mode 100644 index 08438e9d2ec..00000000000 --- a/cargo-smart-release/tests/snapshots/triple-depth-workspace-changelog/crate-a-released/a/CHANGELOG.md +++ /dev/null @@ -1,27 +0,0 @@ -# Changelog - -All notable changes to this project will be documented in this file. - -The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), -and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). - -## Unreleased - -### Commit Statistics - - - - - 1 commit contributed to the release. - - 0 commits were understood as [conventional](https://www.conventionalcommits.org). - - 0 issues like '(#ID)' were seen in commit messages - -### Commit Details - - - -
view details - - * **Uncategorized** - - Initial (8611afa) -
- diff --git a/cargo-smart-release/tests/snapshots/triple-depth-workspace-changelog/crate-a-released/a/Cargo.toml b/cargo-smart-release/tests/snapshots/triple-depth-workspace-changelog/crate-a-released/a/Cargo.toml deleted file mode 100644 index e435f869e89..00000000000 --- a/cargo-smart-release/tests/snapshots/triple-depth-workspace-changelog/crate-a-released/a/Cargo.toml +++ /dev/null @@ -1,8 +0,0 @@ -[package] -name = "a" -version = "0.8.0" -edition = "2018" - -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - -[dependencies] diff --git a/cargo-smart-release/tests/snapshots/triple-depth-workspace-changelog/crate-a-released/a/src/lib.rs b/cargo-smart-release/tests/snapshots/triple-depth-workspace-changelog/crate-a-released/a/src/lib.rs deleted file mode 100644 index 31e1bb209f9..00000000000 --- a/cargo-smart-release/tests/snapshots/triple-depth-workspace-changelog/crate-a-released/a/src/lib.rs +++ /dev/null @@ -1,7 +0,0 @@ -#[cfg(test)] -mod tests { - #[test] - fn it_works() { - assert_eq!(2 + 2, 4); - } -} diff --git a/cargo-smart-release/tests/snapshots/triple-depth-workspace-changelog/crate-a-released/b/CHANGELOG.md b/cargo-smart-release/tests/snapshots/triple-depth-workspace-changelog/crate-a-released/b/CHANGELOG.md deleted file mode 100644 index a4f7c30e063..00000000000 --- a/cargo-smart-release/tests/snapshots/triple-depth-workspace-changelog/crate-a-released/b/CHANGELOG.md +++ /dev/null @@ -1,9 +0,0 @@ -# Changelog - -All notable changes to this project will be documented in this file. - -The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), -and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). - -## Unreleased - diff --git a/cargo-smart-release/tests/snapshots/triple-depth-workspace-changelog/crate-a-released/b/Cargo.toml b/cargo-smart-release/tests/snapshots/triple-depth-workspace-changelog/crate-a-released/b/Cargo.toml deleted file mode 100644 index ad7533a6036..00000000000 --- a/cargo-smart-release/tests/snapshots/triple-depth-workspace-changelog/crate-a-released/b/Cargo.toml +++ /dev/null @@ -1,9 +0,0 @@ -[package] -name = "b" -version = "0.8.0" -edition = "2018" - -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - -[dependencies] -a = { path = "../a", version = "0.8.0" } diff --git a/cargo-smart-release/tests/snapshots/triple-depth-workspace-changelog/crate-a-released/b/src/lib.rs b/cargo-smart-release/tests/snapshots/triple-depth-workspace-changelog/crate-a-released/b/src/lib.rs deleted file mode 100644 index 31e1bb209f9..00000000000 --- a/cargo-smart-release/tests/snapshots/triple-depth-workspace-changelog/crate-a-released/b/src/lib.rs +++ /dev/null @@ -1,7 +0,0 @@ -#[cfg(test)] -mod tests { - #[test] - fn it_works() { - assert_eq!(2 + 2, 4); - } -} diff --git a/cargo-smart-release/tests/snapshots/triple-depth-workspace-changelog/crate-a-released/c/Cargo.toml b/cargo-smart-release/tests/snapshots/triple-depth-workspace-changelog/crate-a-released/c/Cargo.toml deleted file mode 100644 index 8f5c510ee03..00000000000 --- a/cargo-smart-release/tests/snapshots/triple-depth-workspace-changelog/crate-a-released/c/Cargo.toml +++ /dev/null @@ -1,9 +0,0 @@ -[package] -name = "c" -version = "8.0.0" -edition = "2018" - -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - -[dependencies] -b = { path = "../b", version = "0.8.0" } diff --git a/cargo-smart-release/tests/snapshots/triple-depth-workspace-changelog/crate-a-released/c/src/main.rs b/cargo-smart-release/tests/snapshots/triple-depth-workspace-changelog/crate-a-released/c/src/main.rs deleted file mode 100644 index e7a11a969c0..00000000000 --- a/cargo-smart-release/tests/snapshots/triple-depth-workspace-changelog/crate-a-released/c/src/main.rs +++ /dev/null @@ -1,3 +0,0 @@ -fn main() { - println!("Hello, world!"); -} diff --git a/cargo-smart-release/tests/snapshots/triple-depth-workspace/a-b-dry-run-success-multi-crate-unconditional b/cargo-smart-release/tests/snapshots/triple-depth-workspace/a-b-dry-run-success-multi-crate-unconditional deleted file mode 100644 index d3f07fbdbec..00000000000 --- a/cargo-smart-release/tests/snapshots/triple-depth-workspace/a-b-dry-run-success-multi-crate-unconditional +++ /dev/null @@ -1,22 +0,0 @@ -[WARN ] Crates.io index doesn't exist. Consider using --update-crates-index to help determining if release versions are published already -[INFO ] WOULD auto-bump dependent package 'a' from 0.8.0 to 0.9.0 for publishing -[INFO ] WOULD minor-bump provided package 'b' from 0.8.0 to 0.9.0 for publishing, for SAFETY due to breaking package 'a' -[INFO ] WOULD adjust 1 manifest version due to breaking change in 'a': 'b' 0.8.0 ➡ 0.9.0 -[INFO ] WOULD adjust 1 manifest version due to breaking change in 'b': 'c' 8.0.0 ➡ 9.0.0 -[WARN ] The working tree has changes which will prevent a release with --execute unless --allow-dirty is also specified. The latter isn't recommended. -[INFO ] WOULD modify existing changelog for 'a'. -[INFO ] WOULD modify existing changelog for 'b'. -[TRACE] Pending 'a' manifest version update: "0.9.0" -[TRACE] Pending 'b' manifest version update: "0.9.0" -[TRACE] Pending 'b' manifest dependencies update: 'a = "^0.9.0"' (from "0.8.0" ) -[TRACE] Pending 'c' manifest version update: "9.0.0" -[TRACE] Pending 'c' manifest dependencies update: 'b = "^0.9.0"' (from "0.8.0" ) -[TRACE] WOULD persist changes to 3 manifests and 2 changelogs with: "Adjusting changelogs prior to release of a v0.9.0, b v0.9.0, safety bump 2 crates\n\nSAFETY BUMP: b v0.9.0, c v9.0.0" -[INFO ] Up to 2 changelogs would be previewed if the --execute is set and --no-changelog-preview is unset. -[WARN ] WOULD ask for review after commit as the changelog entry is empty for crates: a, b -[WARN ] To fix the changelog manually, run: cargo changelog --write b a -[TRACE] WOULD run "git" "commit" "-am" "Adjusting changelogs prior to release of a v0.9.0, b v0.9.0, safety bump 2 crates\n\nSAFETY BUMP: b v0.9.0, c v9.0.0" -[TRACE] WOULD create tag object a-v0.9.0 with changelog message, first line is: '### Commit Statistics' -[TRACE] WOULD create tag object b-v0.9.0 with changelog message, first line is: '### Commit Statistics' -[TRACE] WOULD run "gh" "release" "create" "a-v0.9.0" "--title" "a v0.9.0" "--notes" "### Commit Statistics\n…" [note truncated] -[TRACE] WOULD run "gh" "release" "create" "b-v0.9.0" "--title" "b v0.9.0" "--notes" "### Commit Statistics\n…" [note truncated] \ No newline at end of file diff --git a/cargo-smart-release/tests/snapshots/triple-depth-workspace/a-dry-run-success-multi-crate b/cargo-smart-release/tests/snapshots/triple-depth-workspace/a-dry-run-success-multi-crate deleted file mode 100644 index 805afbf85c1..00000000000 --- a/cargo-smart-release/tests/snapshots/triple-depth-workspace/a-dry-run-success-multi-crate +++ /dev/null @@ -1,12 +0,0 @@ -[WARN ] Consider running with --update-crates-index to assure bumping on demand uses the latest information -[WARN ] Crates.io index doesn't exist. Consider using --update-crates-index to help determining if release versions are published already -[INFO ] Manifest version of provided package 'a' at 0.8.0 is sufficient, creating a new release 🎉, ignoring computed version 0.9.0 -[INFO ] WOULD adjust version constraints in manifest of 1 package as direct dependencies are changing: b -[INFO ] WOULD modify existing changelog for 'a'. -[TRACE] WOULD persist changes to 2 manifests and 1 changelogs with: "Adjusting changelogs prior to release of a v0.8.0" -[INFO ] Up to 1 changelog would be previewed if the --execute is set and --no-changelog-preview is unset. -[WARN ] WOULD ask for review after commit as the changelog entry is empty for crate: a -[WARN ] To fix the changelog manually, run: cargo changelog --write a -[TRACE] WOULD run "git" "commit" "-am" "Adjusting changelogs prior to release of a v0.8.0" -[TRACE] WOULD create tag object a-v0.8.0 with changelog message, first line is: '### Commit Statistics' -[TRACE] WOULD run "gh" "release" "create" "a-v0.8.0" "--title" "a v0.8.0" "--notes" "### Commit Statistics\n…" [note truncated] \ No newline at end of file diff --git a/cargo-smart-release/tests/snapshots/triple-depth-workspace/a-dry-run-success-multi-crate-auto-bump-breaking-change b/cargo-smart-release/tests/snapshots/triple-depth-workspace/a-dry-run-success-multi-crate-auto-bump-breaking-change deleted file mode 100644 index 3bdff542195..00000000000 --- a/cargo-smart-release/tests/snapshots/triple-depth-workspace/a-dry-run-success-multi-crate-auto-bump-breaking-change +++ /dev/null @@ -1,10 +0,0 @@ -[WARN ] Consider running with --update-crates-index to assure bumping on demand uses the latest information -[WARN ] Crates.io index doesn't exist. Consider using --update-crates-index to help determining if release versions are published already -[INFO ] Manifest version of provided package 'a' at 0.8.0 is sufficient, creating a new release 🎉, ignoring computed version 0.9.0 -[INFO ] WOULD adjust version constraints in manifest of 1 package as direct dependencies are changing: b -[INFO ] WOULD modify existing changelog for 'a'. -[TRACE] WOULD persist changes to 2 manifests and 1 changelogs with: "Bump a v0.8.0" -[INFO ] Up to 1 changelog would be previewed if the --execute is set and --no-changelog-preview is unset. -[TRACE] WOULD run "git" "commit" "-am" "Bump a v0.8.0" -[TRACE] WOULD create tag object a-v0.8.0 with changelog message, first line is: '### Refactor (BREAKING)' -[TRACE] WOULD run "gh" "release" "create" "a-v0.8.0" "--title" "a v0.8.0" "--notes" "### Refactor (BREAKING…" [note truncated] \ No newline at end of file diff --git a/cargo-smart-release/tests/snapshots/triple-depth-workspace/a-dry-run-success-multi-crate-auto-bump-breaking-change-dependant-publish b/cargo-smart-release/tests/snapshots/triple-depth-workspace/a-dry-run-success-multi-crate-auto-bump-breaking-change-dependant-publish deleted file mode 100644 index fb219a65a90..00000000000 --- a/cargo-smart-release/tests/snapshots/triple-depth-workspace/a-dry-run-success-multi-crate-auto-bump-breaking-change-dependant-publish +++ /dev/null @@ -1,24 +0,0 @@ -[WARN ] Crates.io index doesn't exist. Consider using --update-crates-index to help determining if release versions are published already -[INFO ] WOULD auto-bump dependent package 'a' from 0.8.0 to 0.9.0 for publishing -[INFO ] WOULD auto-bump dependent package 'b' from 0.8.0 to 0.9.0 for publishing, for SAFETY due to breaking package 'a', ignoring computed version 0.8.1 -[INFO ] WOULD auto-bump provided package 'c' from 8.0.0 to 9.0.0 for publishing, for SAFETY due to breaking package 'a', ignoring computed version 8.0.1 -[INFO ] WOULD adjust 2 manifest versions due to breaking change in 'a': 'b' 0.8.0 ➡ 0.9.0, 'c' 8.0.0 ➡ 9.0.0 -[INFO ] WOULD modify existing changelog for 'a'. -[INFO ] WOULD modify existing changelog for 'b'. -[INFO ] WOULD create a new changelog for 'c'. -[TRACE] Pending 'a' manifest version update: "0.9.0" -[TRACE] Pending 'b' manifest version update: "0.9.0" -[TRACE] Pending 'b' manifest dependencies update: 'a = "^0.9.0"' (from "0.8.0" ) -[TRACE] Pending 'c' manifest version update: "9.0.0" -[TRACE] Pending 'c' manifest dependencies update: 'b = "^0.9.0"' (from "0.8.0" ) -[TRACE] WOULD persist changes to 3 manifests and 3 changelogs (1 new) with: "Adjusting changelogs prior to release of a v0.9.0, b v0.9.0, c v9.0.0, safety bump 2 crates\n\nSAFETY BUMP: b v0.9.0, c v9.0.0" -[INFO ] Up to 3 changelogs would be previewed if the --execute is set and --no-changelog-preview is unset. -[WARN ] WOULD ask for review after commit as the changelog entry is empty for crates: b, c -[WARN ] To fix the changelog manually, run: cargo changelog --write c a -[TRACE] WOULD run "git" "commit" "-am" "Adjusting changelogs prior to release of a v0.9.0, b v0.9.0, c v9.0.0, safety bump 2 crates\n\nSAFETY BUMP: b v0.9.0, c v9.0.0" -[TRACE] WOULD create tag object a-v0.9.0 with changelog message, first line is: '### Refactor (BREAKING)' -[TRACE] WOULD create tag object b-v0.9.0 with changelog message, first line is: '### Commit Statistics' -[TRACE] WOULD create tag object c-v9.0.0 with changelog message, first line is: '### Commit Statistics' -[TRACE] WOULD run "gh" "release" "create" "a-v0.9.0" "--title" "a v0.9.0" "--notes" "### Refactor (BREAKING…" [note truncated] -[TRACE] WOULD run "gh" "release" "create" "b-v0.9.0" "--title" "b v0.9.0" "--notes" "### Commit Statistics\n…" [note truncated] -[TRACE] WOULD run "gh" "release" "create" "c-v9.0.0" "--title" "c v9.0.0" "--notes" "### Commit Statistics\n…" [note truncated] \ No newline at end of file diff --git a/cargo-smart-release/tests/snapshots/triple-depth-workspace/a-dry-run-success-multi-crate-auto-bump-breaking-change-no-bump-on-demand b/cargo-smart-release/tests/snapshots/triple-depth-workspace/a-dry-run-success-multi-crate-auto-bump-breaking-change-no-bump-on-demand deleted file mode 100644 index c0f42750f60..00000000000 --- a/cargo-smart-release/tests/snapshots/triple-depth-workspace/a-dry-run-success-multi-crate-auto-bump-breaking-change-no-bump-on-demand +++ /dev/null @@ -1,15 +0,0 @@ -[WARN ] Crates.io index doesn't exist. Consider using --update-crates-index to help determining if release versions are published already -[INFO ] WOULD auto-bump provided package 'a' from 0.8.0 to 0.9.0 for publishing -[INFO ] WOULD adjust 1 manifest version due to breaking change in 'a': 'b' 0.8.0 ➡ 0.9.0 -[INFO ] WOULD adjust 1 manifest version due to breaking change in 'b': 'c' 8.0.0 ➡ 9.0.0 -[INFO ] WOULD modify existing changelog for 'a'. -[TRACE] Pending 'a' manifest version update: "0.9.0" -[TRACE] Pending 'b' manifest version update: "0.9.0" -[TRACE] Pending 'b' manifest dependencies update: 'a = "^0.9.0"' (from "0.8.0" ) -[TRACE] Pending 'c' manifest version update: "9.0.0" -[TRACE] Pending 'c' manifest dependencies update: 'b = "^0.9.0"' (from "0.8.0" ) -[TRACE] WOULD persist changes to 3 manifests and 1 changelogs with: "Bump a v0.9.0, safety bump 2 crates\n\nSAFETY BUMP: b v0.9.0, c v9.0.0" -[INFO ] Up to 1 changelog would be previewed if the --execute is set and --no-changelog-preview is unset. -[TRACE] WOULD run "git" "commit" "-am" "Bump a v0.9.0, safety bump 2 crates\n\nSAFETY BUMP: b v0.9.0, c v9.0.0" -[TRACE] WOULD create tag object a-v0.9.0 with changelog message, first line is: '### Refactor (BREAKING)' -[TRACE] WOULD run "gh" "release" "create" "a-v0.9.0" "--title" "a v0.9.0" "--notes" "### Refactor (BREAKING…" [note truncated] \ No newline at end of file diff --git a/cargo-smart-release/tests/snapshots/triple-depth-workspace/a-dry-run-success-multi-crate-auto-bump-breaking-change-no-bump-on-demand-no-publish-stable b/cargo-smart-release/tests/snapshots/triple-depth-workspace/a-dry-run-success-multi-crate-auto-bump-breaking-change-no-bump-on-demand-no-publish-stable deleted file mode 100644 index 0b90e540064..00000000000 --- a/cargo-smart-release/tests/snapshots/triple-depth-workspace/a-dry-run-success-multi-crate-auto-bump-breaking-change-no-bump-on-demand-no-publish-stable +++ /dev/null @@ -1,15 +0,0 @@ -[WARN ] Crates.io index doesn't exist. Consider using --update-crates-index to help determining if release versions are published already -[TRACE] Ignored stable crate 'c' despite being eligible for safety bump and manifest change. -[INFO ] WOULD auto-bump provided package 'a' from 0.8.0 to 0.9.0 for publishing -[INFO ] WOULD adjust 1 manifest version due to breaking change in 'a': 'b' 0.8.0 ➡ 0.9.0 -[INFO ] WOULD adjust version constraints in manifest of 1 package as direct dependencies are changing: c -[INFO ] WOULD modify existing changelog for 'a'. -[TRACE] Pending 'a' manifest version update: "0.9.0" -[TRACE] Pending 'b' manifest version update: "0.9.0" -[TRACE] Pending 'b' manifest dependencies update: 'a = "^0.9.0"' (from "0.8.0" ) -[TRACE] Pending 'c' manifest dependencies update: 'b = "^0.9.0"' (from "0.8.0" ) -[TRACE] WOULD persist changes to 3 manifests and 1 changelogs with: "Bump a v0.9.0, safety bump b v0.9.0" -[INFO ] Up to 1 changelog would be previewed if the --execute is set and --no-changelog-preview is unset. -[TRACE] WOULD run "git" "commit" "-am" "Bump a v0.9.0, safety bump b v0.9.0" -[TRACE] WOULD create tag object a-v0.9.0 with changelog message, first line is: '### Refactor (BREAKING)' -[TRACE] WOULD run "gh" "release" "create" "a-v0.9.0" "--title" "a v0.9.0" "--notes" "### Refactor (BREAKING…" [note truncated] \ No newline at end of file diff --git a/cargo-smart-release/tests/snapshots/triple-depth-workspace/a-dry-run-success-multi-crate-auto-bump-minor-change b/cargo-smart-release/tests/snapshots/triple-depth-workspace/a-dry-run-success-multi-crate-auto-bump-minor-change deleted file mode 100644 index f326ccd5710..00000000000 --- a/cargo-smart-release/tests/snapshots/triple-depth-workspace/a-dry-run-success-multi-crate-auto-bump-minor-change +++ /dev/null @@ -1,10 +0,0 @@ -[WARN ] Consider running with --update-crates-index to assure bumping on demand uses the latest information -[WARN ] Crates.io index doesn't exist. Consider using --update-crates-index to help determining if release versions are published already -[INFO ] Manifest version of provided package 'a' at 0.8.0 is sufficient, creating a new release 🎉, ignoring computed version 0.8.1 -[INFO ] WOULD adjust version constraints in manifest of 1 package as direct dependencies are changing: b -[INFO ] WOULD modify existing changelog for 'a'. -[TRACE] WOULD persist changes to 2 manifests and 1 changelogs with: "Bump a v0.8.0" -[INFO ] Up to 1 changelog would be previewed if the --execute is set and --no-changelog-preview is unset. -[TRACE] WOULD run "git" "commit" "-am" "Bump a v0.8.0" -[TRACE] WOULD create tag object a-v0.8.0 with changelog message, first line is: '### New Features' -[TRACE] WOULD run "gh" "release" "create" "a-v0.8.0" "--title" "a v0.8.0" "--notes" "### New Features\n\n - n…" [note truncated] \ No newline at end of file diff --git a/cargo-smart-release/tests/snapshots/triple-depth-workspace/a-dry-run-success-multi-crate-auto-bump-no-change b/cargo-smart-release/tests/snapshots/triple-depth-workspace/a-dry-run-success-multi-crate-auto-bump-no-change deleted file mode 100644 index f0014c22382..00000000000 --- a/cargo-smart-release/tests/snapshots/triple-depth-workspace/a-dry-run-success-multi-crate-auto-bump-no-change +++ /dev/null @@ -1,12 +0,0 @@ -[WARN ] Consider running with --update-crates-index to assure bumping on demand uses the latest information -[WARN ] Crates.io index doesn't exist. Consider using --update-crates-index to help determining if release versions are published already -[INFO ] Manifest version of provided package 'a' at 0.8.0 is sufficient, creating a new release 🎉, ignoring computed version 0.8.1 -[INFO ] WOULD adjust version constraints in manifest of 1 package as direct dependencies are changing: b -[INFO ] WOULD modify existing changelog for 'a'. -[TRACE] WOULD persist changes to 2 manifests and 1 changelogs with: "Adjusting changelogs prior to release of a v0.8.0" -[INFO ] Up to 1 changelog would be previewed if the --execute is set and --no-changelog-preview is unset. -[WARN ] WOULD ask for review after commit as the changelog entry is empty for crate: a -[WARN ] To fix the changelog manually, run: cargo changelog --write a -[TRACE] WOULD run "git" "commit" "-am" "Adjusting changelogs prior to release of a v0.8.0" -[TRACE] WOULD create tag object a-v0.8.0 with changelog message, first line is: '### Commit Statistics' -[TRACE] WOULD run "gh" "release" "create" "a-v0.8.0" "--title" "a v0.8.0" "--notes" "### Commit Statistics\n…" [note truncated] \ No newline at end of file diff --git a/cargo-smart-release/tests/snapshots/triple-depth-workspace/a-dry-run-success-multi-crate-unconditional b/cargo-smart-release/tests/snapshots/triple-depth-workspace/a-dry-run-success-multi-crate-unconditional deleted file mode 100644 index 1b12b7967dc..00000000000 --- a/cargo-smart-release/tests/snapshots/triple-depth-workspace/a-dry-run-success-multi-crate-unconditional +++ /dev/null @@ -1,18 +0,0 @@ -[WARN ] Crates.io index doesn't exist. Consider using --update-crates-index to help determining if release versions are published already -[INFO ] WOULD minor-bump provided package 'a' from 0.8.0 to 0.9.0 for publishing -[INFO ] WOULD adjust 1 manifest version due to breaking change in 'a': 'b' 0.8.0 ➡ 0.9.0 -[INFO ] WOULD adjust 1 manifest version due to breaking change in 'b': 'c' 8.0.0 ➡ 9.0.0 -[WARN ] The working tree has changes which will prevent a release with --execute unless --allow-dirty is also specified. The latter isn't recommended. -[INFO ] WOULD modify existing changelog for 'a'. -[TRACE] Pending 'a' manifest version update: "0.9.0" -[TRACE] Pending 'b' manifest version update: "0.9.0" -[TRACE] Pending 'b' manifest dependencies update: 'a = "^0.9.0"' (from "0.8.0" ) -[TRACE] Pending 'c' manifest version update: "9.0.0" -[TRACE] Pending 'c' manifest dependencies update: 'b = "^0.9.0"' (from "0.8.0" ) -[TRACE] WOULD persist changes to 3 manifests and 1 changelogs with: "Adjusting changelogs prior to release of a v0.9.0, safety bump 2 crates\n\nSAFETY BUMP: b v0.9.0, c v9.0.0" -[INFO ] Up to 1 changelog would be previewed if the --execute is set and --no-changelog-preview is unset. -[WARN ] WOULD ask for review after commit as the changelog entry is empty for crate: a -[WARN ] To fix the changelog manually, run: cargo changelog --write a -[TRACE] WOULD run "git" "commit" "-am" "Adjusting changelogs prior to release of a v0.9.0, safety bump 2 crates\n\nSAFETY BUMP: b v0.9.0, c v9.0.0" -[TRACE] WOULD create tag object a-v0.9.0 with changelog message, first line is: '### Commit Statistics' -[TRACE] WOULD run "gh" "release" "create" "a-v0.9.0" "--title" "a v0.9.0" "--notes" "### Commit Statistics\n…" [note truncated] \ No newline at end of file diff --git a/cargo-smart-release/tests/snapshots/triple-depth-workspace/c-dry-run-success-multi-crate-auto-bump-breaking-change b/cargo-smart-release/tests/snapshots/triple-depth-workspace/c-dry-run-success-multi-crate-auto-bump-breaking-change deleted file mode 100644 index 84b76f8c543..00000000000 --- a/cargo-smart-release/tests/snapshots/triple-depth-workspace/c-dry-run-success-multi-crate-auto-bump-breaking-change +++ /dev/null @@ -1,19 +0,0 @@ -[WARN ] Consider running with --update-crates-index to assure bumping on demand uses the latest information -[WARN ] Crates.io index doesn't exist. Consider using --update-crates-index to help determining if release versions are published already -[INFO ] Manifest version of dependent package 'a' at 0.8.0 is sufficient, creating a new release 🎉, ignoring computed version 0.8.1 -[INFO ] Manifest version of dependent package 'b' at 0.8.0 is sufficient, creating a new release 🎉, ignoring computed version 0.8.1 -[INFO ] Manifest version of provided package 'c' at 8.0.0 is sufficient, creating a new release 🎉, ignoring computed version 9.0.0 -[INFO ] WOULD modify existing changelog for 'a'. -[INFO ] WOULD modify existing changelog for 'b'. -[INFO ] WOULD create a new changelog for 'c'. -[TRACE] WOULD persist changes to 3 manifests and 3 changelogs (1 new) with: "Adjusting changelogs prior to release of a v0.8.0, b v0.8.0, c v8.0.0" -[INFO ] Up to 3 changelogs would be previewed if the --execute is set and --no-changelog-preview is unset. -[WARN ] WOULD ask for review after commit as the changelog entry is empty for crates: a, b -[WARN ] To fix the changelog manually, run: cargo changelog --write c a -[TRACE] WOULD run "git" "commit" "-am" "Adjusting changelogs prior to release of a v0.8.0, b v0.8.0, c v8.0.0" -[TRACE] WOULD create tag object a-v0.8.0 with changelog message, first line is: '### Commit Statistics' -[TRACE] WOULD create tag object b-v0.8.0 with changelog message, first line is: '### Commit Statistics' -[TRACE] WOULD create tag object c-v8.0.0 with changelog message, first line is: '### Refactor (BREAKING)' -[TRACE] WOULD run "gh" "release" "create" "a-v0.8.0" "--title" "a v0.8.0" "--notes" "### Commit Statistics\n…" [note truncated] -[TRACE] WOULD run "gh" "release" "create" "b-v0.8.0" "--title" "b v0.8.0" "--notes" "### Commit Statistics\n…" [note truncated] -[TRACE] WOULD run "gh" "release" "create" "c-v8.0.0" "--title" "c v8.0.0" "--notes" "### Refactor (BREAKING…" [note truncated] \ No newline at end of file diff --git a/cargo-smart-release/tests/snapshots/triple-depth-workspace/c-dry-run-success-multi-crate-auto-bump-minor-change b/cargo-smart-release/tests/snapshots/triple-depth-workspace/c-dry-run-success-multi-crate-auto-bump-minor-change deleted file mode 100644 index 724f8a55780..00000000000 --- a/cargo-smart-release/tests/snapshots/triple-depth-workspace/c-dry-run-success-multi-crate-auto-bump-minor-change +++ /dev/null @@ -1,19 +0,0 @@ -[WARN ] Consider running with --update-crates-index to assure bumping on demand uses the latest information -[WARN ] Crates.io index doesn't exist. Consider using --update-crates-index to help determining if release versions are published already -[INFO ] Manifest version of dependent package 'a' at 0.8.0 is sufficient, creating a new release 🎉, ignoring computed version 0.8.1 -[INFO ] Manifest version of dependent package 'b' at 0.8.0 is sufficient, creating a new release 🎉, ignoring computed version 0.8.1 -[INFO ] Manifest version of provided package 'c' at 8.0.0 is sufficient, creating a new release 🎉, ignoring computed version 8.1.0 -[INFO ] WOULD modify existing changelog for 'a'. -[INFO ] WOULD modify existing changelog for 'b'. -[INFO ] WOULD create a new changelog for 'c'. -[TRACE] WOULD persist changes to 3 manifests and 3 changelogs (1 new) with: "Adjusting changelogs prior to release of a v0.8.0, b v0.8.0, c v8.0.0" -[INFO ] Up to 3 changelogs would be previewed if the --execute is set and --no-changelog-preview is unset. -[WARN ] WOULD ask for review after commit as the changelog entry is empty for crates: a, b -[WARN ] To fix the changelog manually, run: cargo changelog --write c a -[TRACE] WOULD run "git" "commit" "-am" "Adjusting changelogs prior to release of a v0.8.0, b v0.8.0, c v8.0.0" -[TRACE] WOULD create tag object a-v0.8.0 with changelog message, first line is: '### Commit Statistics' -[TRACE] WOULD create tag object b-v0.8.0 with changelog message, first line is: '### Commit Statistics' -[TRACE] WOULD create tag object c-v8.0.0 with changelog message, first line is: '### New Features' -[TRACE] WOULD run "gh" "release" "create" "a-v0.8.0" "--title" "a v0.8.0" "--notes" "### Commit Statistics\n…" [note truncated] -[TRACE] WOULD run "gh" "release" "create" "b-v0.8.0" "--title" "b v0.8.0" "--notes" "### Commit Statistics\n…" [note truncated] -[TRACE] WOULD run "gh" "release" "create" "c-v8.0.0" "--title" "c v8.0.0" "--notes" "### New Features\n\n - n…" [note truncated] \ No newline at end of file diff --git a/cargo-smart-release/tests/snapshots/triple-depth-workspace/c-dry-run-success-multi-crate-auto-bump-no-change b/cargo-smart-release/tests/snapshots/triple-depth-workspace/c-dry-run-success-multi-crate-auto-bump-no-change deleted file mode 100644 index 71147c620e9..00000000000 --- a/cargo-smart-release/tests/snapshots/triple-depth-workspace/c-dry-run-success-multi-crate-auto-bump-no-change +++ /dev/null @@ -1,19 +0,0 @@ -[WARN ] Consider running with --update-crates-index to assure bumping on demand uses the latest information -[WARN ] Crates.io index doesn't exist. Consider using --update-crates-index to help determining if release versions are published already -[INFO ] Manifest version of dependent package 'a' at 0.8.0 is sufficient, creating a new release 🎉, ignoring computed version 0.8.1 -[INFO ] Manifest version of dependent package 'b' at 0.8.0 is sufficient, creating a new release 🎉, ignoring computed version 0.8.1 -[INFO ] Manifest version of provided package 'c' at 8.0.0 is sufficient, creating a new release 🎉, ignoring computed version 8.0.1 -[INFO ] WOULD modify existing changelog for 'a'. -[INFO ] WOULD modify existing changelog for 'b'. -[INFO ] WOULD create a new changelog for 'c'. -[TRACE] WOULD persist changes to 3 manifests and 3 changelogs (1 new) with: "Adjusting changelogs prior to release of a v0.8.0, b v0.8.0, c v8.0.0" -[INFO ] Up to 3 changelogs would be previewed if the --execute is set and --no-changelog-preview is unset. -[WARN ] WOULD ask for review after commit as the changelog entry is empty for crates: a, b, c -[WARN ] To fix the changelog manually, run: cargo changelog --write c a -[TRACE] WOULD run "git" "commit" "-am" "Adjusting changelogs prior to release of a v0.8.0, b v0.8.0, c v8.0.0" -[TRACE] WOULD create tag object a-v0.8.0 with changelog message, first line is: '### Commit Statistics' -[TRACE] WOULD create tag object b-v0.8.0 with changelog message, first line is: '### Commit Statistics' -[TRACE] WOULD create tag object c-v8.0.0 with changelog message, first line is: '### Commit Statistics' -[TRACE] WOULD run "gh" "release" "create" "a-v0.8.0" "--title" "a v0.8.0" "--notes" "### Commit Statistics\n…" [note truncated] -[TRACE] WOULD run "gh" "release" "create" "b-v0.8.0" "--title" "b v0.8.0" "--notes" "### Commit Statistics\n…" [note truncated] -[TRACE] WOULD run "gh" "release" "create" "c-v8.0.0" "--title" "c v8.0.0" "--notes" "### Commit Statistics\n…" [note truncated] \ No newline at end of file diff --git a/cargo-smart-release/tests/snapshots/triple-depth-workspace/crate-a-released-force-bump/.gitignore b/cargo-smart-release/tests/snapshots/triple-depth-workspace/crate-a-released-force-bump/.gitignore deleted file mode 100644 index 2f7896d1d13..00000000000 --- a/cargo-smart-release/tests/snapshots/triple-depth-workspace/crate-a-released-force-bump/.gitignore +++ /dev/null @@ -1 +0,0 @@ -target/ diff --git a/cargo-smart-release/tests/snapshots/triple-depth-workspace/crate-a-released-force-bump/.package-cache b/cargo-smart-release/tests/snapshots/triple-depth-workspace/crate-a-released-force-bump/.package-cache deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/cargo-smart-release/tests/snapshots/triple-depth-workspace/crate-a-released-force-bump/Cargo.lock b/cargo-smart-release/tests/snapshots/triple-depth-workspace/crate-a-released-force-bump/Cargo.lock deleted file mode 100644 index 8b4e7ddcfe2..00000000000 --- a/cargo-smart-release/tests/snapshots/triple-depth-workspace/crate-a-released-force-bump/Cargo.lock +++ /dev/null @@ -1,21 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 3 - -[[package]] -name = "a" -version = "0.9.0" - -[[package]] -name = "b" -version = "0.9.0" -dependencies = [ - "a", -] - -[[package]] -name = "c" -version = "9.0.0" -dependencies = [ - "b", -] diff --git a/cargo-smart-release/tests/snapshots/triple-depth-workspace/crate-a-released-force-bump/Cargo.toml b/cargo-smart-release/tests/snapshots/triple-depth-workspace/crate-a-released-force-bump/Cargo.toml deleted file mode 100644 index e7d118ceaa3..00000000000 --- a/cargo-smart-release/tests/snapshots/triple-depth-workspace/crate-a-released-force-bump/Cargo.toml +++ /dev/null @@ -1,2 +0,0 @@ -[workspace] -members = ["a", "b", "c"] diff --git a/cargo-smart-release/tests/snapshots/triple-depth-workspace/crate-a-released-force-bump/a/CHANGELOG.md b/cargo-smart-release/tests/snapshots/triple-depth-workspace/crate-a-released-force-bump/a/CHANGELOG.md deleted file mode 100644 index b301c837584..00000000000 --- a/cargo-smart-release/tests/snapshots/triple-depth-workspace/crate-a-released-force-bump/a/CHANGELOG.md +++ /dev/null @@ -1,29 +0,0 @@ -# Changelog - -All notable changes to this project will be documented in this file. - -The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), -and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). - -## v0.9.0 (2021-09-09) - -### Commit Statistics - - - - - 1 commit contributed to the release. - - 0 commits were understood as [conventional](https://www.conventionalcommits.org). - - 0 issues like '(#ID)' were seen in commit messages - -### Commit Details - - - -
view details - - * **Uncategorized** - - Initial (b07fabe) -
- -## v0.8.0 (2021-09-09) - diff --git a/cargo-smart-release/tests/snapshots/triple-depth-workspace/crate-a-released-force-bump/a/Cargo.toml b/cargo-smart-release/tests/snapshots/triple-depth-workspace/crate-a-released-force-bump/a/Cargo.toml deleted file mode 100644 index 39925fc6a14..00000000000 --- a/cargo-smart-release/tests/snapshots/triple-depth-workspace/crate-a-released-force-bump/a/Cargo.toml +++ /dev/null @@ -1,8 +0,0 @@ -[package] -name = "a" -version = "0.9.0" -edition = "2018" - -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - -[dependencies] diff --git a/cargo-smart-release/tests/snapshots/triple-depth-workspace/crate-a-released-force-bump/a/src/lib.rs b/cargo-smart-release/tests/snapshots/triple-depth-workspace/crate-a-released-force-bump/a/src/lib.rs deleted file mode 100644 index 31e1bb209f9..00000000000 --- a/cargo-smart-release/tests/snapshots/triple-depth-workspace/crate-a-released-force-bump/a/src/lib.rs +++ /dev/null @@ -1,7 +0,0 @@ -#[cfg(test)] -mod tests { - #[test] - fn it_works() { - assert_eq!(2 + 2, 4); - } -} diff --git a/cargo-smart-release/tests/snapshots/triple-depth-workspace/crate-a-released-force-bump/b/CHANGELOG.md b/cargo-smart-release/tests/snapshots/triple-depth-workspace/crate-a-released-force-bump/b/CHANGELOG.md deleted file mode 100644 index a4f7c30e063..00000000000 --- a/cargo-smart-release/tests/snapshots/triple-depth-workspace/crate-a-released-force-bump/b/CHANGELOG.md +++ /dev/null @@ -1,9 +0,0 @@ -# Changelog - -All notable changes to this project will be documented in this file. - -The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), -and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). - -## Unreleased - diff --git a/cargo-smart-release/tests/snapshots/triple-depth-workspace/crate-a-released-force-bump/b/Cargo.toml b/cargo-smart-release/tests/snapshots/triple-depth-workspace/crate-a-released-force-bump/b/Cargo.toml deleted file mode 100644 index 4f20ad0180d..00000000000 --- a/cargo-smart-release/tests/snapshots/triple-depth-workspace/crate-a-released-force-bump/b/Cargo.toml +++ /dev/null @@ -1,9 +0,0 @@ -[package] -name = "b" -version = "0.9.0" -edition = "2018" - -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - -[dependencies] -a = { path = "../a", version = "^0.9.0" } diff --git a/cargo-smart-release/tests/snapshots/triple-depth-workspace/crate-a-released-force-bump/b/src/lib.rs b/cargo-smart-release/tests/snapshots/triple-depth-workspace/crate-a-released-force-bump/b/src/lib.rs deleted file mode 100644 index 31e1bb209f9..00000000000 --- a/cargo-smart-release/tests/snapshots/triple-depth-workspace/crate-a-released-force-bump/b/src/lib.rs +++ /dev/null @@ -1,7 +0,0 @@ -#[cfg(test)] -mod tests { - #[test] - fn it_works() { - assert_eq!(2 + 2, 4); - } -} diff --git a/cargo-smart-release/tests/snapshots/triple-depth-workspace/crate-a-released-force-bump/c/Cargo.toml b/cargo-smart-release/tests/snapshots/triple-depth-workspace/crate-a-released-force-bump/c/Cargo.toml deleted file mode 100644 index b61d3e187ed..00000000000 --- a/cargo-smart-release/tests/snapshots/triple-depth-workspace/crate-a-released-force-bump/c/Cargo.toml +++ /dev/null @@ -1,9 +0,0 @@ -[package] -name = "c" -version = "9.0.0" -edition = "2018" - -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - -[dependencies] -b = { path = "../b", version = "^0.9.0" } diff --git a/cargo-smart-release/tests/snapshots/triple-depth-workspace/crate-a-released-force-bump/c/src/main.rs b/cargo-smart-release/tests/snapshots/triple-depth-workspace/crate-a-released-force-bump/c/src/main.rs deleted file mode 100644 index e7a11a969c0..00000000000 --- a/cargo-smart-release/tests/snapshots/triple-depth-workspace/crate-a-released-force-bump/c/src/main.rs +++ /dev/null @@ -1,3 +0,0 @@ -fn main() { - println!("Hello, world!"); -} diff --git a/cargo-smart-release/tests/snapshots/triple-depth-workspace/crate-a-released/.gitignore b/cargo-smart-release/tests/snapshots/triple-depth-workspace/crate-a-released/.gitignore deleted file mode 100644 index 2f7896d1d13..00000000000 --- a/cargo-smart-release/tests/snapshots/triple-depth-workspace/crate-a-released/.gitignore +++ /dev/null @@ -1 +0,0 @@ -target/ diff --git a/cargo-smart-release/tests/snapshots/triple-depth-workspace/crate-a-released/.package-cache b/cargo-smart-release/tests/snapshots/triple-depth-workspace/crate-a-released/.package-cache deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/cargo-smart-release/tests/snapshots/triple-depth-workspace/crate-a-released/Cargo.lock b/cargo-smart-release/tests/snapshots/triple-depth-workspace/crate-a-released/Cargo.lock deleted file mode 100644 index 9c6afe3e40d..00000000000 --- a/cargo-smart-release/tests/snapshots/triple-depth-workspace/crate-a-released/Cargo.lock +++ /dev/null @@ -1,21 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 3 - -[[package]] -name = "a" -version = "0.8.0" - -[[package]] -name = "b" -version = "0.8.0" -dependencies = [ - "a", -] - -[[package]] -name = "c" -version = "8.0.0" -dependencies = [ - "b", -] diff --git a/cargo-smart-release/tests/snapshots/triple-depth-workspace/crate-a-released/Cargo.toml b/cargo-smart-release/tests/snapshots/triple-depth-workspace/crate-a-released/Cargo.toml deleted file mode 100644 index e7d118ceaa3..00000000000 --- a/cargo-smart-release/tests/snapshots/triple-depth-workspace/crate-a-released/Cargo.toml +++ /dev/null @@ -1,2 +0,0 @@ -[workspace] -members = ["a", "b", "c"] diff --git a/cargo-smart-release/tests/snapshots/triple-depth-workspace/crate-a-released/a/CHANGELOG.md b/cargo-smart-release/tests/snapshots/triple-depth-workspace/crate-a-released/a/CHANGELOG.md deleted file mode 100644 index 512a83c7317..00000000000 --- a/cargo-smart-release/tests/snapshots/triple-depth-workspace/crate-a-released/a/CHANGELOG.md +++ /dev/null @@ -1,27 +0,0 @@ -# Changelog - -All notable changes to this project will be documented in this file. - -The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), -and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). - -## v0.8.0 (2021-09-09) - -### Commit Statistics - - - - - 1 commit contributed to the release. - - 0 commits were understood as [conventional](https://www.conventionalcommits.org). - - 0 issues like '(#ID)' were seen in commit messages - -### Commit Details - - - -
view details - - * **Uncategorized** - - Initial (0519584) -
- diff --git a/cargo-smart-release/tests/snapshots/triple-depth-workspace/crate-a-released/a/Cargo.toml b/cargo-smart-release/tests/snapshots/triple-depth-workspace/crate-a-released/a/Cargo.toml deleted file mode 100644 index e435f869e89..00000000000 --- a/cargo-smart-release/tests/snapshots/triple-depth-workspace/crate-a-released/a/Cargo.toml +++ /dev/null @@ -1,8 +0,0 @@ -[package] -name = "a" -version = "0.8.0" -edition = "2018" - -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - -[dependencies] diff --git a/cargo-smart-release/tests/snapshots/triple-depth-workspace/crate-a-released/a/src/lib.rs b/cargo-smart-release/tests/snapshots/triple-depth-workspace/crate-a-released/a/src/lib.rs deleted file mode 100644 index 31e1bb209f9..00000000000 --- a/cargo-smart-release/tests/snapshots/triple-depth-workspace/crate-a-released/a/src/lib.rs +++ /dev/null @@ -1,7 +0,0 @@ -#[cfg(test)] -mod tests { - #[test] - fn it_works() { - assert_eq!(2 + 2, 4); - } -} diff --git a/cargo-smart-release/tests/snapshots/triple-depth-workspace/crate-a-released/b/CHANGELOG.md b/cargo-smart-release/tests/snapshots/triple-depth-workspace/crate-a-released/b/CHANGELOG.md deleted file mode 100644 index a4f7c30e063..00000000000 --- a/cargo-smart-release/tests/snapshots/triple-depth-workspace/crate-a-released/b/CHANGELOG.md +++ /dev/null @@ -1,9 +0,0 @@ -# Changelog - -All notable changes to this project will be documented in this file. - -The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), -and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). - -## Unreleased - diff --git a/cargo-smart-release/tests/snapshots/triple-depth-workspace/crate-a-released/b/Cargo.toml b/cargo-smart-release/tests/snapshots/triple-depth-workspace/crate-a-released/b/Cargo.toml deleted file mode 100644 index 7a9657507f9..00000000000 --- a/cargo-smart-release/tests/snapshots/triple-depth-workspace/crate-a-released/b/Cargo.toml +++ /dev/null @@ -1,9 +0,0 @@ -[package] -name = "b" -version = "0.8.0" -edition = "2018" - -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - -[dependencies] -a = { path = "../a", version = "^0.8.0" } diff --git a/cargo-smart-release/tests/snapshots/triple-depth-workspace/crate-a-released/b/src/lib.rs b/cargo-smart-release/tests/snapshots/triple-depth-workspace/crate-a-released/b/src/lib.rs deleted file mode 100644 index 31e1bb209f9..00000000000 --- a/cargo-smart-release/tests/snapshots/triple-depth-workspace/crate-a-released/b/src/lib.rs +++ /dev/null @@ -1,7 +0,0 @@ -#[cfg(test)] -mod tests { - #[test] - fn it_works() { - assert_eq!(2 + 2, 4); - } -} diff --git a/cargo-smart-release/tests/snapshots/triple-depth-workspace/crate-a-released/c/Cargo.toml b/cargo-smart-release/tests/snapshots/triple-depth-workspace/crate-a-released/c/Cargo.toml deleted file mode 100644 index 8f5c510ee03..00000000000 --- a/cargo-smart-release/tests/snapshots/triple-depth-workspace/crate-a-released/c/Cargo.toml +++ /dev/null @@ -1,9 +0,0 @@ -[package] -name = "c" -version = "8.0.0" -edition = "2018" - -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - -[dependencies] -b = { path = "../b", version = "0.8.0" } diff --git a/cargo-smart-release/tests/snapshots/triple-depth-workspace/crate-a-released/c/src/main.rs b/cargo-smart-release/tests/snapshots/triple-depth-workspace/crate-a-released/c/src/main.rs deleted file mode 100644 index e7a11a969c0..00000000000 --- a/cargo-smart-release/tests/snapshots/triple-depth-workspace/crate-a-released/c/src/main.rs +++ /dev/null @@ -1,3 +0,0 @@ -fn main() { - println!("Hello, world!"); -} diff --git a/cargo-smart-release/tests/utilities.sh b/cargo-smart-release/tests/utilities.sh deleted file mode 100644 index f49fd1278bb..00000000000 --- a/cargo-smart-release/tests/utilities.sh +++ /dev/null @@ -1,182 +0,0 @@ -#!/bin/bash - -WHITE="$(tput setaf 9 2>/dev/null || echo -n '')" -YELLOW="$(tput setaf 3 2>/dev/null || echo -n '')" -GREEN="$(tput setaf 2 2>/dev/null || echo -n '')" -RED="$(tput setaf 1 2>/dev/null || echo -n '')" -OFFSET=( ) -STEP=" " - -function with_program () { - local program="${1:?}" - hash "$program" &>/dev/null || { - function expect_run () { - echo 1>&2 "${WHITE} - skipped (missing program)" - } - function expect_run_sh () { - echo 1>&2 "${WHITE} - skipped (missing program)" - } - } -} - -function on_ci () { - [ -n "${CI-}" ] || { - function expect_run () { - echo 1>&2 "${WHITE} - skipped (runs only on CI)" - } - function expect_run_sh () { - echo 1>&2 "${WHITE} - skipped (runs only on CI)" - } - } -} - -function not_on_ci () { - [ -z "${CI-}" ] || { - function expect_run () { - echo 1>&2 "${WHITE} - skipped (runs only locally)" - } - function expect_run_sh () { - echo 1>&2 "${WHITE} - skipped (runs only locally)" - } - } -} - -function title () { - echo "$WHITE-----------------------------------------------------" - echo "${GREEN}$*" - echo "$WHITE-----------------------------------------------------" -} - -function _context () { - local name="${1:?}" - shift - echo 1>&2 "${YELLOW}${OFFSET[*]:-}[$name] $*" - OFFSET+=("$STEP") -} - -function step () { - _note step "${WHITE}" "$*" -} - -function stepn () { - step "$*" $'\n' -} - -function with () { - _context with "$*" -} - -function when () { - _context when "$*" -} - -function _note () { - local name="${1:?}" - local color="${2:-}" - shift 2 - echo 1>&2 -n "${OFFSET[*]:-}${color}[$name] ${*// /}" -} - -function it () { - _note it "${GREEN}" "$*" -} - -function precondition () { - _note precondition "${WHITE}" "$*" -} - -function shortcoming () { - _note shortcoming "${RED}" "$*" -} - -function step () { - _note step "${WHITE}" "$*" -} - -function stepn () { - step "$*" $'\n' -} - -function fail () { - echo 1>&2 "${RED} $*" - exit 1 -} - -function sandbox () { - sandbox_tempdir="$(mktemp -t sandbox.XXXXXX -d)" - # shellcheck disable=2064 - trap "popd >/dev/null" EXIT - pushd "$sandbox_tempdir" >/dev/null \ - || fail "Could not change directory into temporary directory." - - local custom_init="${1:-}" - if [ -n "$custom_init" ]; then - eval "$custom_init" - fi -} - -function expect_equals () { - expect_run 0 test "${1:?}" = "${2:?}" -} - -function expect_exists () { - expect_run 0 test -e "${1:?}" -} - -function expect_run_sh () { - expect_run "${1:?}" bash -c -eu -o pipefail "${2:?}" -} - -function expect_snapshot () { - local expected=${1:?} - local actual=${2:?} - if ! [ -e "$expected" ]; then - mkdir -p "${expected%/*}" - cp -R "$actual" "$expected" - fi - expect_run 0 diff -r -N "$expected" "$actual" -} - -function expect_run () { - local expected_exit_code=$1 - shift - local output= - set +e - if [[ -n "${SNAPSHOT_FILTER-}" ]]; then - output="$("$@" 2>&1 | "$SNAPSHOT_FILTER")" - else - output="$("$@" 2>&1)" - fi - - local actual_exit_code=$? - if [[ "$actual_exit_code" == "$expected_exit_code" ]]; then - if [[ -n "${WITH_SNAPSHOT-}" ]]; then - local expected="$WITH_SNAPSHOT" - if ! [ -f "$expected" ]; then - mkdir -p "${expected%/*}" - echo -n "$output" > "$expected" || exit 1 - fi - if ! diff "$expected" <(echo -n "$output"); then - echo 1>&2 "${RED} - FAIL" - echo 1>&2 "${WHITE}\$ $*" - echo 1>&2 "Output snapshot did not match snapshot at '$expected'" - echo 1>&2 "$output" - if [ -n "${ON_ERROR:-}" ]; then - eval "$ON_ERROR" - fi - exit 1 - fi - fi - echo 1>&2 - else - echo 1>&2 "${RED} - FAIL" - echo 1>&2 "${WHITE}\$ $*" - echo 1>&2 "${RED}Expected actual status $actual_exit_code to be $expected_exit_code" - echo 1>&2 "$output" - if [ -n "${ON_ERROR:-}" ]; then - eval "$ON_ERROR" - fi - exit 1 - fi - set -e -} From fb8fa13931000480e19b1a3801ebcb95658a81f9 Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Tue, 22 Aug 2023 15:29:42 +0200 Subject: [PATCH 0011/1077] remove remaining mentions of cargo-smart-release --- .github/workflows/ci.yml | 2 -- Cargo.toml | 3 --- etc/check-package-size.sh | 1 - justfile | 12 ++---------- 4 files changed, 2 insertions(+), 16 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b88d43f8e56..ae34fec04a2 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -133,8 +133,6 @@ jobs: run: vcpkg install zlib:x64-windows-static-md - name: "Installation from crates.io: gitoxide" run: cargo +${{ matrix.rust }} install --target ${{ matrix.target }} --target-dir install-artifacts --debug --force gitoxide - - name: "Installation from crates.io: cargo-smart-release" - run: cargo +${{ matrix.rust }} install --target ${{ matrix.target }} --target-dir install-artifacts --debug --force cargo-smart-release lint: runs-on: ubuntu-latest diff --git a/Cargo.toml b/Cargo.toml index e2e90e86279..c79cf19e1d6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -290,9 +290,6 @@ members = [ "gix-config/tests", "gix-traverse/tests", ] -exclude = ["cargo-smart-release/tests/fixtures/tri-depth-workspace/a", - "cargo-smart-release/tests/fixtures/tri-depth-workspace/b", - "cargo-smart-release/tests/fixtures/tri-depth-workspace/c"] [package.metadata.docs.rs] features = ["document-features", "max"] diff --git a/etc/check-package-size.sh b/etc/check-package-size.sh index 80839dad988..425e03d623a 100755 --- a/etc/check-package-size.sh +++ b/etc/check-package-size.sh @@ -15,7 +15,6 @@ function indent () { } echo "in root: gitoxide CLI" -(enter cargo-smart-release && indent cargo diet -n --package-size-limit 110KB) (enter gix-actor && indent cargo diet -n --package-size-limit 5KB) (enter gix-archive && indent cargo diet -n --package-size-limit 10KB) (enter gix-worktree-stream && indent cargo diet -n --package-size-limit 40KB) diff --git a/justfile b/justfile index 6d0f990df90..96b89f25e05 100755 --- a/justfile +++ b/justfile @@ -9,10 +9,10 @@ alias t := test alias c := check # run all tests, clippy, including journey tests, try building docs -test: clippy check doc unit-tests journey-tests-pure journey-tests-small journey-tests-async journey-tests journey-tests-smart-release +test: clippy check doc unit-tests journey-tests-pure journey-tests-small journey-tests-async journey-tests # run all tests, without clippy, including journey tests, try building docs (and clear target on CI) -ci-test: check doc unit-tests clear-target journey-tests-pure journey-tests-small journey-tests-async journey-tests journey-tests-smart-release +ci-test: check doc unit-tests clear-target journey-tests-pure journey-tests-small journey-tests-async journey-tests clear-target: cargo clean @@ -110,7 +110,6 @@ check: cargo check -p gix --no-default-features --features progress-tree cargo check -p gix --no-default-features cargo check -p gix-odb --features serde - cargo check -p cargo-smart-release --all cargo check --no-default-features --features max-control # Run cargo doc on all crates @@ -187,13 +186,6 @@ journey-tests-async: cargo build -p gix-testtools ./tests/journey.sh {{ ein }} {{ gix }} {{ jtt }} async -cargo-smart-release := `cargo metadata --manifest-path ./cargo-smart-release/Cargo.toml --format-version 1 | jq -r .target_directory` / "debug/cargo-smart-release" - -# run journey tests (cargo-smart-release) -journey-tests-smart-release: - cd cargo-smart-release && cargo build --bin cargo-smart-release - cd cargo-smart-release && ./tests/journey.sh {{ cargo-smart-release }} - # Run cargo-diet on all crates to see that they are still in bound check-size: ./etc/check-package-size.sh From b663ba7c31e2671fb4cbc9cd7fcccd87b4a8eb69 Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Tue, 22 Aug 2023 15:54:18 +0200 Subject: [PATCH 0012/1077] upgrade reqwest to avoid vulnerability --- Cargo.lock | 42 ++++++++++-------------------------------- 1 file changed, 10 insertions(+), 32 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index ac4799abee6..85a3dc125fd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2862,7 +2862,7 @@ dependencies = [ "socket2 0.5.3", "widestring", "windows-sys", - "winreg 0.50.0", + "winreg", ] [[package]] @@ -3683,9 +3683,9 @@ checksum = "e5ea92a5b6195c6ef2a0295ea818b312502c6fc94dde986c5553242e18fd4ce2" [[package]] name = "reqwest" -version = "0.11.18" +version = "0.11.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cde824a14b7c14f85caff81225f411faacc04a2013f41670f41443742b1c1c55" +checksum = "20b9b67e2ca7dd9e9f9285b759de30ff538aab981abaaf7bc9bd90b84a0126c3" dependencies = [ "base64", "bytes", @@ -3721,7 +3721,7 @@ dependencies = [ "wasm-bindgen-futures", "web-sys", "webpki-roots", - "winreg 0.10.1", + "winreg", ] [[package]] @@ -3798,9 +3798,9 @@ dependencies = [ [[package]] name = "rustls" -version = "0.21.5" +version = "0.21.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79ea77c539259495ce8ca47f53e66ae0330a8819f67e23ac96ca02f50e7b7d36" +checksum = "1d1feddffcfcc0b33f5c6ce9a29e341e4cd59c3f78e7ee45f4a40c038b1d6cbb" dependencies = [ "log", "ring", @@ -3819,9 +3819,9 @@ dependencies = [ [[package]] name = "rustls-webpki" -version = "0.101.1" +version = "0.101.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "15f36a6828982f422756984e47912a7a51dcbc2a197aa791158f8ca61cd8204e" +checksum = "7d93931baf2d282fff8d3a532bbfd7653f734643161b87e3e01e59a04439bf0d" dependencies = [ "ring", "untrusted", @@ -4658,24 +4658,11 @@ dependencies = [ "wasm-bindgen", ] -[[package]] -name = "webpki" -version = "0.22.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f095d78192e208183081cc07bc5515ef55216397af48b873e5edcd72637fa1bd" -dependencies = [ - "ring", - "untrusted", -] - [[package]] name = "webpki-roots" -version = "0.22.6" +version = "0.25.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6c71e40d7d2c34a5106301fb632274ca37242cd0c9d3e64dbece371a40a2d87" -dependencies = [ - "webpki", -] +checksum = "14247bb57be4f377dfb94c72830b8ce8fc6beac03cf4bf7b9732eadd414123fc" [[package]] name = "widestring" @@ -4864,15 +4851,6 @@ dependencies = [ "memchr", ] -[[package]] -name = "winreg" -version = "0.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "80d0f4e272c85def139476380b12f9ac60926689dd2e01d4923222f40580869d" -dependencies = [ - "winapi", -] - [[package]] name = "winreg" version = "0.50.0" From aa227e39d362ffb983351f42e50e4612bd7352f8 Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Tue, 22 Aug 2023 16:00:17 +0200 Subject: [PATCH 0013/1077] update prodash to a version that doesn't trigger a warning due to `atty` --- Cargo.lock | 38 +++++++++----------------------------- 1 file changed, 9 insertions(+), 29 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 85a3dc125fd..a06040137e0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -267,17 +267,6 @@ version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1181e1e0d1fce796a03db1ae795d67167da795f9cf4a39c37589e85ef57f26d3" -[[package]] -name = "atty" -version = "0.2.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" -dependencies = [ - "hermit-abi 0.1.19", - "libc", - "winapi", -] - [[package]] name = "autocfg" version = "1.1.0" @@ -1148,7 +1137,7 @@ dependencies = [ "is-terminal", "once_cell", "owo-colors", - "prodash 25.0.1", + "prodash 25.0.2", "serde_derive", "tabled", "time", @@ -1248,7 +1237,7 @@ dependencies = [ "log", "once_cell", "parking_lot", - "prodash 25.0.1", + "prodash 25.0.2", "regex", "reqwest", "serde", @@ -1581,7 +1570,7 @@ dependencies = [ "libc", "once_cell", "parking_lot", - "prodash 25.0.1", + "prodash 25.0.2", "sha1", "sha1_smol", "thiserror", @@ -2644,15 +2633,6 @@ version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" -[[package]] -name = "hermit-abi" -version = "0.1.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" -dependencies = [ - "libc", -] - [[package]] name = "hermit-abi" version = "0.3.2" @@ -2848,7 +2828,7 @@ version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "eae7b9aee968036d54dce06cebaefd919e4472e753296daccd6d344e3e2df0c2" dependencies = [ - "hermit-abi 0.3.2", + "hermit-abi", "libc", "windows-sys", ] @@ -2886,7 +2866,7 @@ version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cb0889898416213fab133e1d33a0e5858a48177452750691bde3666d0fdbaf8b" dependencies = [ - "hermit-abi 0.3.2", + "hermit-abi", "rustix 0.38.4", "windows-sys", ] @@ -3275,7 +3255,7 @@ version = "1.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" dependencies = [ - "hermit-abi 0.3.2", + "hermit-abi", "libc", ] @@ -3523,18 +3503,18 @@ checksum = "9516b775656bc3e8985e19cd4b8c0c0de045095074e453d2c0a513b5f978392d" [[package]] name = "prodash" -version = "25.0.1" +version = "25.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c236e70b7f9b9ea00d33c69f63ec1ae6e9ae96118923cd37bd4e9c7396f0b107" +checksum = "1d67eb4220992a4a052a4bb03cf776e493ecb1a3a36bab551804153d63486af7" dependencies = [ "async-io", - "atty", "bytesize", "crosstermion", "futures-core", "futures-lite", "human_format", "humantime", + "is-terminal", "log", "parking_lot", "ratatui", From 6194ebe1fb10dedc22f1937b91df858dffc50db3 Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Tue, 22 Aug 2023 16:47:24 +0200 Subject: [PATCH 0014/1077] imrpove git2 mapping by using aliases. Thanks so much, @epage, it's a game-changer. --- gix/src/lib.rs | 17 ++++++----------- gix/src/open/repository.rs | 1 + gix/src/pathspec.rs | 8 ++++++++ gix/src/repository/object.rs | 1 + gix/src/repository/pathspec.rs | 1 + gix/src/repository/revision.rs | 3 +++ gix/src/repository/submodule.rs | 1 + gix/src/submodule/mod.rs | 1 + 8 files changed, 22 insertions(+), 11 deletions(-) diff --git a/gix/src/lib.rs b/gix/src/lib.rs index 7d4349891cb..2215695fb47 100644 --- a/gix/src/lib.rs +++ b/gix/src/lib.rs @@ -56,19 +56,12 @@ //! //! ### `libgit2` API to `gix` //! -//! This section is a 'striving to be complete' mapping from `libgit2` APIs to the respective methods in `gix`. +//! This doc-aliases are used to help finding methods under a possibly changed name. Just search in the docs. +//! Entering `git2` into the search field will also surface all methods with such annotations. //! -//! * [`git2::Repository::open()`](https://docs.rs/git2/*/git2/struct.Repository.html#method.open) ➡ [`open()`] -//! * [`git2::Repository::open_bare()`](https://docs.rs/git2/*/git2/struct.Repository.html#method.open_bare) ➡ ❌ -//! * [`git2::Repository::open_from_env()`](https://docs.rs/git2/*/git2/struct.Repository.html#method.open_from_env) ➡ [`ThreadSafeRepository::open_with_environment_overrides()`] -//! * [`git2::Repository::open_ext()`](https://docs.rs/git2/*/git2/struct.Repository.html#method.open_ext) ➡ [`open_opts()`] -//! * [`git2::Repository::revparse()`](https://docs.rs/git2/*/git2/struct.Repository.html#method.revparse) ➡ [`Repository::rev_parse()`] -//! * [`git2::Repository::revparse_single()`](https://docs.rs/git2/*/git2/struct.Repository.html#method.revparse_single) ➡ [`Repository::rev_parse_single()`] -//! * [`git2::Repository::revwalk()`](https://docs.rs/git2/*/git2/struct.Repository.html#method.revwalk) ➡ [`Repository::rev_walk()`] +//! What follows is a list of methods you might be missing, along with workarounds if available. +//! * [`git2::Repository::open_bare()`](https://docs.rs/git2/*/git2/struct.Repository.html#method.open_bare) ➡ ❌ - use [`open()`] and discard it is not bare. //! * [`git2::build::CheckoutBuilder::disable_filters()](https://docs.rs/git2/*/git2/build/struct.CheckoutBuilder.html#method.disable_filters) ➡ ❌ *(filters are always applied during checkouts)* -//! * [`git2::Odb::read_header()`](https://docs.rs/git2/*/git2/struct.Odb.html#method.read_header) ➡ [`Repository::find_header()`] -//! * [`git2::Repository::submodules()`](https://docs.rs/git2/*/git2/struct.Repository.html#method.submodules) ➡ [`Repository::submodules()`] -//! * [`git2::Repository::submodules()`](https://docs.rs/git2/*/git2/struct.Repository.html#method.submodules) ➡ [`Repository::submodules()`] //! * [`git2::Repository::submodule_status()`](https://docs.rs/git2/*/git2/struct.Repository.html#method.submodule_status) ➡ [`Submodule::state()`] - status provides more information and conveniences though, and an actual worktree status isn't performed. //! //! ## Feature Flags @@ -234,12 +227,14 @@ fn open_opts_with_git_binary_config() -> open::Options { /// See [`ThreadSafeRepository::open()`], but returns a [`Repository`] instead. #[allow(clippy::result_large_err)] +#[doc(alias = "git2")] pub fn open(directory: impl Into) -> Result { ThreadSafeRepository::open(directory).map(Into::into) } /// See [`ThreadSafeRepository::open_opts()`], but returns a [`Repository`] instead. #[allow(clippy::result_large_err)] +#[doc(alias = "open_ext", alias = "git2")] pub fn open_opts(directory: impl Into, options: open::Options) -> Result { ThreadSafeRepository::open_opts(directory, options).map(Into::into) } diff --git a/gix/src/open/repository.rs b/gix/src/open/repository.rs index 4c4348c2722..f533770c5b2 100644 --- a/gix/src/open/repository.rs +++ b/gix/src/open/repository.rs @@ -108,6 +108,7 @@ impl ThreadSafeRepository { // TODO: The following vars should end up as overrides of the respective configuration values (see git-config). // GIT_PROXY_SSL_CERT, GIT_PROXY_SSL_KEY, GIT_PROXY_SSL_CERT_PASSWORD_PROTECTED. // GIT_PROXY_SSL_CAINFO, GIT_SSL_CIPHER_LIST, GIT_HTTP_MAX_REQUESTS, GIT_CURL_FTP_NO_EPSV, + #[doc(alias = "open_from_env", alias = "git2")] pub fn open_with_environment_overrides( fallback_directory: impl Into, trust_map: gix_sec::trust::Mapping, diff --git a/gix/src/pathspec.rs b/gix/src/pathspec.rs index f701f210961..f5af7b3228e 100644 --- a/gix/src/pathspec.rs +++ b/gix/src/pathspec.rs @@ -84,6 +84,14 @@ impl<'repo> Pathspec<'repo> { /// Return the first [`Match`](search::Match) of `relative_path`, or `None`. /// Note that the match might [be excluded](search::Match::is_excluded()). /// `is_dir` is true if `relative_path` is a directory. + #[doc( + alias = "match_diff", + alias = "match_tree", + alias = "match_index", + alias = "match_workdir", + alias = "matches_path", + alias = "git2" + )] pub fn pattern_matching_relative_path<'a>( &mut self, relative_path: impl Into<&'a BStr>, diff --git a/gix/src/repository/object.rs b/gix/src/repository/object.rs index 62deb600383..bab7d1b5c50 100644 --- a/gix/src/repository/object.rs +++ b/gix/src/repository/object.rs @@ -39,6 +39,7 @@ impl crate::Repository { /// Obtain information about an object without fully decoding it, or fail if the object doesn't exist. /// /// Note that despite being cheaper than [`Self::find_object()`], there is still some effort traversing delta-chains. + #[doc(alias = "read_header", alias = "git2")] pub fn find_header(&self, id: impl Into) -> Result { let id = id.into(); if id == gix_hash::ObjectId::empty_tree(self.object_hash()) { diff --git a/gix/src/repository/pathspec.rs b/gix/src/repository/pathspec.rs index 729ff0ecb91..c8d3695a662 100644 --- a/gix/src/repository/pathspec.rs +++ b/gix/src/repository/pathspec.rs @@ -11,6 +11,7 @@ impl Repository { /// /// It will be initialized exactly how it would, and attribute matching will be conducted by reading the worktree first if available. /// If that is not desirable, consider calling [`Pathspec::new()`] directly. + #[doc(alias = "Pathspec", alias = "git2")] pub fn pathspec( &self, patterns: impl IntoIterator>, diff --git a/gix/src/repository/revision.rs b/gix/src/repository/revision.rs index 3018c2be856..4eedf0867e2 100644 --- a/gix/src/repository/revision.rs +++ b/gix/src/repository/revision.rs @@ -8,6 +8,7 @@ impl crate::Repository { /// /// - `@` actually stands for `HEAD`, whereas `git` resolves it to the object pointed to by `HEAD` without making the /// `HEAD` ref available for lookups. + #[doc(alias = "revparse", alias = "git2")] pub fn rev_parse<'a>(&self, spec: impl Into<&'a BStr>) -> Result, revision::spec::parse::Error> { revision::Spec::from_bstr( spec, @@ -20,6 +21,7 @@ impl crate::Repository { } /// Parse a revision specification and return single object id as represented by this instance. + #[doc(alias = "revparse_single", alias = "git2")] pub fn rev_parse_single<'repo, 'a>( &'repo self, spec: impl Into<&'a BStr>, @@ -33,6 +35,7 @@ impl crate::Repository { /// Create the baseline for a revision walk by initializing it with the `tips` to start iterating on. /// /// It can be configured further before starting the actual walk. + #[doc(alias = "revwalk", alias = "git2")] pub fn rev_walk( &self, tips: impl IntoIterator>, diff --git a/gix/src/repository/submodule.rs b/gix/src/repository/submodule.rs index 78e43825e0d..a605bfbd322 100644 --- a/gix/src/repository/submodule.rs +++ b/gix/src/repository/submodule.rs @@ -73,6 +73,7 @@ impl Repository { } /// Return the list of available submodules, or `None` if there is no submodule configuration. + #[doc(alias = "git2")] pub fn submodules(&self) -> Result>>, submodule::modules::Error> { let modules = match self.modules()? { None => return Ok(None), diff --git a/gix/src/submodule/mod.rs b/gix/src/submodule/mod.rs index 6ebe3f07118..68263318e17 100644 --- a/gix/src/submodule/mod.rs +++ b/gix/src/submodule/mod.rs @@ -226,6 +226,7 @@ impl<'repo> Submodule<'repo> { } /// Query various parts of the submodule and assemble it into state information. + #[doc(alias = "status", alias = "git2")] pub fn state(&self) -> Result { let maybe_old_path = self.git_dir_try_old_form()?; let git_dir = self.git_dir(); From 524000a5ea559e4eb7f4d217608fa209cb050d2e Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Tue, 22 Aug 2023 19:18:39 +0200 Subject: [PATCH 0015/1077] colors for CI --- .github/workflows/ci.yml | 5 +++++ .github/workflows/release.yml | 6 +++++- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index ae34fec04a2..c1419cf2769 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,5 +1,10 @@ name: ci +env: + RUST_BACKTRACE: 1 + CARGO_TERM_COLOR: always + CLICOLOR: 1 + on: push: branches: [ main ] diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 8616ced7d09..3cb6d99c6f0 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -12,6 +12,11 @@ name: release +env: + RUST_BACKTRACE: 1 + CARGO_TERM_COLOR: always + CLICOLOR: 1 + on: workflow_dispatch: push: @@ -77,7 +82,6 @@ jobs: EXE_NAME: ein strategy: matrix: -# build: [ linux, linux-arm, macos, win-msvc, win-gnu, win32-msvc ] build: [ linux, linux-arm, macos, win-msvc, win-gnu, win32-msvc ] feature: [ "small", "lean", "max", "max-pure" ] include: From 8af79ec98d82f3d2542fc43928103a20c2e4fc1a Mon Sep 17 00:00:00 2001 From: Niklas Wimmer Date: Thu, 24 Aug 2023 10:59:37 +0200 Subject: [PATCH 0016/1077] Return errors for empty paths and relative urls --- gix-url/src/parse/mod.rs | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/gix-url/src/parse/mod.rs b/gix-url/src/parse/mod.rs index 2a3ba670ca4..b2c50d38ce5 100644 --- a/gix-url/src/parse/mod.rs +++ b/gix-url/src/parse/mod.rs @@ -101,6 +101,19 @@ fn parse_url(input: &BStr) -> Result { source, })?; + let scheme = url.scheme().into(); + + if matches!(scheme, crate::Scheme::Git | crate::Scheme::Ssh) && url.path().is_empty() { + return Err(Error::MissingRepositoryPath { + url: input.to_owned().into(), + kind: UrlKind::Url, + }); + } + + if url.cannot_be_a_base() { + return Err(Error::RelativeUrl { url: input.to_owned() }); + } + Ok(crate::Url { serialize_alternative_form: false, scheme: url.scheme().into(), @@ -127,6 +140,13 @@ fn parse_scp(input: &BStr, colon: usize) -> Result { let (host, path) = input.split_at(colon); let path = &path[1..]; // remove leading `:` + if path.is_empty() { + return Err(Error::MissingRepositoryPath { + url: input.to_owned().into(), + kind: UrlKind::Scp, + }); + } + // The path returned by the parsed url often has the wrong number of leading `/` characters but // should never differ in any other way (ssh URLs should not contain a query or fragment part). // To avoid the various off-by-one errors caused by the `/` characters, we keep using the path @@ -153,6 +173,13 @@ fn parse_scp(input: &BStr, colon: usize) -> Result { } fn parse_local(input: &BStr) -> Result { + if input.is_empty() { + return Err(Error::MissingRepositoryPath { + url: input.to_owned(), + kind: UrlKind::Local, + }); + } + Ok(crate::Url { serialize_alternative_form: true, scheme: crate::scheme::Scheme::File, From 679a7f46e8121b5a0a5a396c2ce89f6706068507 Mon Sep 17 00:00:00 2001 From: Niklas Wimmer Date: Thu, 24 Aug 2023 11:00:08 +0200 Subject: [PATCH 0017/1077] Use same logic for file urls and local file paths --- gix-url/src/parse/mod.rs | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/gix-url/src/parse/mod.rs b/gix-url/src/parse/mod.rs index b2c50d38ce5..702163f386f 100644 --- a/gix-url/src/parse/mod.rs +++ b/gix-url/src/parse/mod.rs @@ -83,9 +83,13 @@ fn find_scheme(input: &BStr) -> InputScheme { /// For file-paths, we don't expect UTF8 encoding either. pub fn parse(input: &BStr) -> Result { match find_scheme(input) { + InputScheme::Local => parse_local(input, false), + InputScheme::Url { protocol_end } if input[..protocol_end].eq_ignore_ascii_case(b"file") => { + // strip the protocol part + parse_local(&input[protocol_end + 3..], true) + } InputScheme::Url { .. } => parse_url(input), InputScheme::Scp { colon } => parse_scp(input, colon), - InputScheme::Local => parse_local(input), } } @@ -172,7 +176,7 @@ fn parse_scp(input: &BStr, colon: usize) -> Result { }) } -fn parse_local(input: &BStr) -> Result { +fn parse_local(input: &BStr, was_in_url_format: bool) -> Result { if input.is_empty() { return Err(Error::MissingRepositoryPath { url: input.to_owned(), @@ -180,8 +184,10 @@ fn parse_local(input: &BStr) -> Result { }); } + // TODO: handle relative paths, Git does weird stuff + Ok(crate::Url { - serialize_alternative_form: true, + serialize_alternative_form: !was_in_url_format, scheme: crate::scheme::Scheme::File, password: None, user: None, From 5044c3b87456cf58ebfbbd00f23c9ba671cb290c Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Thu, 24 Aug 2023 18:48:39 +0200 Subject: [PATCH 0018/1077] thanks clippy For v1.72.0 --- .cargo/config.toml | 2 +- gitoxide-core/src/corpus/db.rs | 4 +- gitoxide-core/src/repository/submodule.rs | 4 +- gix-config/src/parse/nom/tests.rs | 7 ++-- gix-config/src/parse/section/header.rs | 2 +- .../includes/conditional/gitdir/mod.rs | 4 +- gix-config/tests/file/mutable/section.rs | 4 +- gix-config/tests/parse/section.rs | 2 +- gix-config/tests/value/normalize.rs | 4 +- gix-date/tests/time/parse.rs | 6 +-- gix-mailmap/tests/snapshot/mod.rs | 2 +- gix-odb/src/lib.rs | 2 +- gix-packetline/tests/read/mod.rs | 2 +- .../tests/spec/parse/anchor/colon_symbol.rs | 2 +- .../tests/spec/parse/navigate/caret_symbol.rs | 42 +++++++++---------- gix-worktree-state/tests/state/checkout.rs | 9 ++-- gix/src/config/cache/access.rs | 3 +- gix/src/config/tree/sections/protocol.rs | 2 +- gix/src/object/tree/diff/for_each.rs | 5 ++- 19 files changed, 53 insertions(+), 55 deletions(-) diff --git a/.cargo/config.toml b/.cargo/config.toml index 3e6810586b8..87d8b21363d 100644 --- a/.cargo/config.toml +++ b/.cargo/config.toml @@ -5,7 +5,6 @@ rustflags = [ # Clippy lints "-W", "clippy::cloned_instead_of_copied", - "-W", "clippy::explicit_iter_loop", "-W", "clippy::map_unwrap_or", "-W", "clippy::redundant_closure_for_method_calls", "-W", "clippy::unnested_or_patterns", @@ -14,6 +13,7 @@ rustflags = [ # Rejected for now, and why # "-W" "clippy::default_trait_access" - sometimes makes imports necessary, just for a default value. It's good for more explicit typing though. # "-W" "clippy::range_plus_one" - useful, but caused too many false positives as we use range types directly quite a lot + # "-W", "clippy::explicit_iter_loop", - the cases I saw turned `foo.iter_mut()` into `&mut *foo` # Rustdoc lints diff --git a/gitoxide-core/src/corpus/db.rs b/gitoxide-core/src/corpus/db.rs index f2e9230bffb..f56275bd4c3 100644 --- a/gitoxide-core/src/corpus/db.rs +++ b/gitoxide-core/src/corpus/db.rs @@ -92,7 +92,7 @@ pub fn create(path: impl AsRef) -> anyhow::Result) -> anyhow::Result Cow<'_, BStr> { let mut buf = Vec::with_capacity(name.len()); for b in name.iter().copied() { match b { - b'\\' => buf.push_str(br#"\\"#), + b'\\' => buf.push_str(br"\\"), b'"' => buf.push_str(br#"\""#), _ => buf.push(b), } diff --git a/gix-config/tests/file/init/from_paths/includes/conditional/gitdir/mod.rs b/gix-config/tests/file/init/from_paths/includes/conditional/gitdir/mod.rs index f8b125b69d1..b9488402845 100644 --- a/gix-config/tests/file/init/from_paths/includes/conditional/gitdir/mod.rs +++ b/gix-config/tests/file/init/from_paths/includes/conditional/gitdir/mod.rs @@ -189,14 +189,14 @@ fn case_insensitive_matches_any_case() -> crate::Result { #[test] fn pattern_with_escaped_backslash() -> crate::Result { assert_section_value( - original_value_on_windows(Condition::new(r#"gitdir:\\work\\tree\\/"#)), + original_value_on_windows(Condition::new(r"gitdir:\\work\\tree\\/")), GitEnv::repo_name("worktree")?, ) } #[test] fn pattern_with_backslash() -> crate::Result { - assert_section_value(Condition::new(r#"gitdir:work\tree/"#), GitEnv::repo_name("worktree")?) + assert_section_value(Condition::new(r"gitdir:work\tree/"), GitEnv::repo_name("worktree")?) } #[test] diff --git a/gix-config/tests/file/mutable/section.rs b/gix-config/tests/file/mutable/section.rs index 7a4493360f9..ea17ce7a401 100644 --- a/gix-config/tests/file/mutable/section.rs +++ b/gix-config/tests/file/mutable/section.rs @@ -260,7 +260,7 @@ mod set_leading_whitespace { } fn multi_value_section() -> gix_config::File<'static> { - r#" + r" [a] a = v b = @@ -268,7 +268,7 @@ fn multi_value_section() -> gix_config::File<'static> { d e =a \ b \ - c"# + c" .parse() .unwrap() } diff --git a/gix-config/tests/parse/section.rs b/gix-config/tests/parse/section.rs index 700f847c65d..872052e9031 100644 --- a/gix-config/tests/parse/section.rs +++ b/gix-config/tests/parse/section.rs @@ -22,7 +22,7 @@ mod header { #[test] fn subsection_backslashes_and_quotes_are_escaped() -> crate::Result { assert_eq!( - section::Header::new("core", cow_section(r#"a\b"#))?.to_bstring(), + section::Header::new("core", cow_section(r"a\b"))?.to_bstring(), r#"[core "a\\b"]"# ); assert_eq!( diff --git a/gix-config/tests/value/normalize.rs b/gix-config/tests/value/normalize.rs index d0daa0db9f2..0179e408412 100644 --- a/gix-config/tests/value/normalize.rs +++ b/gix-config/tests/value/normalize.rs @@ -69,7 +69,7 @@ fn inner_quotes_are_removed() { #[test] fn newline_tab_backspace_are_escapable() { - assert_eq!(normalize_bstr(r#"\n\ta\b"#), cow_str("\n\t")); + assert_eq!(normalize_bstr(r"\n\ta\b"), cow_str("\n\t")); } #[test] @@ -80,7 +80,7 @@ fn tabs_are_not_resolved_to_spaces_unlike_what_git_does() { #[test] fn other_escapes_are_ignored_entirely() { assert_eq!( - normalize_bstr(r#"\x"#), + normalize_bstr(r"\x"), cow_str("x"), "however, these would cause failure on parsing level so we ignore it similar to subsections" ); diff --git a/gix-date/tests/time/parse.rs b/gix-date/tests/time/parse.rs index 20cf74b6c51..5b23fe1077a 100644 --- a/gix-date/tests/time/parse.rs +++ b/gix-date/tests/time/parse.rs @@ -148,11 +148,11 @@ mod relative { #[test] fn various() { - let now = Some(SystemTime::now()); - let two_weeks_ago = gix_date::parse("2 weeks ago", now).unwrap(); + let now = SystemTime::now(); + let two_weeks_ago = gix_date::parse("2 weeks ago", Some(now)).unwrap(); assert_eq!(Sign::Plus, two_weeks_ago.sign); assert_eq!(0, two_weeks_ago.offset); - let expected = OffsetDateTime::from(now.unwrap()).saturating_sub(Duration::weeks(2)); + let expected = OffsetDateTime::from(now).saturating_sub(Duration::weeks(2)); // account for the loss of precision when creating `Time` with seconds let expected = expected.replace_nanosecond(0).unwrap(); assert_eq!( diff --git a/gix-mailmap/tests/snapshot/mod.rs b/gix-mailmap/tests/snapshot/mod.rs index e231665ce46..408ad49b083 100644 --- a/gix-mailmap/tests/snapshot/mod.rs +++ b/gix-mailmap/tests/snapshot/mod.rs @@ -65,7 +65,7 @@ fn non_name_and_name_mappings_will_not_clash() { "old-email", ), ]; - for entries in vec![entries.clone().into_iter().rev().collect::>(), entries] { + for entries in [entries.clone().into_iter().rev().collect::>(), entries] { let snapshot = Snapshot::new(entries); assert_eq!( diff --git a/gix-odb/src/lib.rs b/gix-odb/src/lib.rs index e0beac54848..682c63c86ea 100644 --- a/gix-odb/src/lib.rs +++ b/gix-odb/src/lib.rs @@ -148,5 +148,5 @@ pub fn at_opts( /// Create a new cached handle to the object store. pub fn at(objects_dir: impl Into) -> std::io::Result { - at_opts(objects_dir, Vec::new().into_iter(), Default::default()) + at_opts(objects_dir, Vec::new(), Default::default()) } diff --git a/gix-packetline/tests/read/mod.rs b/gix-packetline/tests/read/mod.rs index d487239f7e4..8420af08ff4 100644 --- a/gix-packetline/tests/read/mod.rs +++ b/gix-packetline/tests/read/mod.rs @@ -174,7 +174,7 @@ pub mod streaming_peek_iter { #[maybe_async::test(feature = "blocking-io", async(feature = "async-io", async_std::test))] async fn read_from_file_and_reader_advancement() -> crate::Result { let mut bytes = fixture_bytes("v1/fetch/01-many-refs.response"); - bytes.extend(fixture_bytes("v1/fetch/01-many-refs.response").into_iter()); + bytes.extend(fixture_bytes("v1/fetch/01-many-refs.response")); let mut rd = gix_packetline::StreamingPeekableIter::new(&bytes[..], &[PacketLineRef::Flush]); let res = rd.read_line().await; assert_eq!(res.expect("line")??, first_line()); diff --git a/gix-revision/tests/spec/parse/anchor/colon_symbol.rs b/gix-revision/tests/spec/parse/anchor/colon_symbol.rs index a7674799b03..b8693923a53 100644 --- a/gix-revision/tests/spec/parse/anchor/colon_symbol.rs +++ b/gix-revision/tests/spec/parse/anchor/colon_symbol.rs @@ -55,7 +55,7 @@ fn various_forms_of_regex() { #[test] fn regex_do_not_get_any_backslash_processing() { - for (spec, regex) in [(r#":/{"#, "{"), (r#":/\{\}"#, r#"\{\}"#), (r#":/\\\\\}"#, r#"\\\\\}"#)] { + for (spec, regex) in [(r#":/{"#, "{"), (r":/\{\}", r"\{\}"), (r":/\\\\\}", r"\\\\\}")] { let rec = parse(spec); assert_eq!(rec.patterns, vec![(regex.into(), false)]); diff --git a/gix-revision/tests/spec/parse/navigate/caret_symbol.rs b/gix-revision/tests/spec/parse/navigate/caret_symbol.rs index aaf7792090c..ea80adb643a 100644 --- a/gix-revision/tests/spec/parse/navigate/caret_symbol.rs +++ b/gix-revision/tests/spec/parse/navigate/caret_symbol.rs @@ -105,40 +105,36 @@ fn regex_backslash_rules() { "matching inner parens do not need escaping", ), ( - r#"@^{/with count\{1\}}"#, + r"@^{/with count\{1\}}", r#"with count{1}"#, "escaped parens are entirely ignored", ), - (r#"@^{/1\}}"#, r#"1}"#, "unmatched closing parens need to be escaped"), - (r#"@^{/2\{}"#, r#"2{"#, "unmatched opening parens need to be escaped"), + (r"@^{/1\}}", r#"1}"#, "unmatched closing parens need to be escaped"), + (r"@^{/2\{}", r#"2{"#, "unmatched opening parens need to be escaped"), ( - r#"@^{/3{\{}}"#, + r"@^{/3{\{}}", r#"3{{}"#, "unmatched nested opening parens need to be escaped", ), ( - r#"@^{/4{\}}}"#, + r"@^{/4{\}}}", r#"4{}}"#, "unmatched nested closing parens need to be escaped", ), + (r"@^{/a\b\c}", r"a\b\c", "single backslashes do not need to be escaped"), ( - r#"@^{/a\b\c}"#, - r#"a\b\c"#, - "single backslashes do not need to be escaped", - ), - ( - r#"@^{/a\b\c\\}"#, - r#"a\b\c\"#, + r"@^{/a\b\c\\}", + r"a\b\c\", "single backslashes do not need to be escaped, trailing", ), ( - r#"@^{/a\\b\\c\\}"#, - r#"a\b\c\"#, + r"@^{/a\\b\\c\\}", + r"a\b\c\", "backslashes can be escaped nonetheless, trailing", ), ( - r#"@^{/5\\{}}"#, - r#"5\{}"#, + r"@^{/5\\{}}", + r"5\{}", "backslashes in front of parens must be escaped or they would unbalance the brace pair", ), ] { @@ -196,11 +192,11 @@ fn invalid_object_type() { #[test] fn incomplete_escaped_braces_in_regex_are_invalid() { - let err = try_parse(r#"@^{/a\{1}}"#).unwrap_err(); + let err = try_parse(r"@^{/a\{1}}").unwrap_err(); assert!(matches!(err, spec::parse::Error::UnconsumedInput {input} if input == "}")); - let err = try_parse(r#"@^{/a{1\}}"#).unwrap_err(); - assert!(matches!(err, spec::parse::Error::UnclosedBracePair {input} if input == r#"{/a{1\}}"#)); + let err = try_parse(r"@^{/a{1\}}").unwrap_err(); + assert!(matches!(err, spec::parse::Error::UnclosedBracePair {input} if input == r"{/a{1\}}")); } #[test] @@ -211,11 +207,11 @@ fn regex_with_empty_exclamation_mark_prefix_is_invalid() { #[test] fn bad_escapes_can_cause_brace_mismatch() { - let err = try_parse(r#"@^{\}"#).unwrap_err(); - assert!(matches!(err, spec::parse::Error::UnclosedBracePair {input} if input == r#"{\}"#)); + let err = try_parse(r"@^{\}").unwrap_err(); + assert!(matches!(err, spec::parse::Error::UnclosedBracePair {input} if input == r"{\}")); - let err = try_parse(r#"@^{{\}}"#).unwrap_err(); - assert!(matches!(err, spec::parse::Error::UnclosedBracePair {input} if input == r#"{{\}}"#)); + let err = try_parse(r"@^{{\}}").unwrap_err(); + assert!(matches!(err, spec::parse::Error::UnclosedBracePair {input} if input == r"{{\}}")); } #[test] diff --git a/gix-worktree-state/tests/state/checkout.rs b/gix-worktree-state/tests/state/checkout.rs index 6b57c0a92df..4c2e1f87b5d 100644 --- a/gix-worktree-state/tests/state/checkout.rs +++ b/gix-worktree-state/tests/state/checkout.rs @@ -281,12 +281,11 @@ fn keep_going_collects_results() { opts, "make_mixed_without_submodules", |_id| { - !matches!( - count.fetch_update(Ordering::SeqCst, Ordering::SeqCst, |current| { + count + .fetch_update(Ordering::SeqCst, Ordering::SeqCst, |current| { (current < 2).then_some(current + 1) - }), - Ok(_) - ) + }) + .is_err() }, |_| Ok(()), ) diff --git a/gix/src/config/cache/access.rs b/gix/src/config/cache/access.rs index 5f373362860..e3ba40d4e75 100644 --- a/gix/src/config/cache/access.rs +++ b/gix/src/config/cache/access.rs @@ -75,12 +75,11 @@ impl Cache { const DEFAULT: bool = true; self.resolved .boolean_by_key("core.commitGraph") - .map(|res| { + .map_or(Ok(DEFAULT), |res| { Core::COMMIT_GRAPH .enrich_error(res) .with_lenient_default_value(self.lenient_config, DEFAULT) }) - .unwrap_or(Ok(DEFAULT)) } pub(crate) fn diff_renames( diff --git a/gix/src/config/tree/sections/protocol.rs b/gix/src/config/tree/sections/protocol.rs index a0510f2b8df..7ef2cc8cb7c 100644 --- a/gix/src/config/tree/sections/protocol.rs +++ b/gix/src/config/tree/sections/protocol.rs @@ -127,7 +127,7 @@ mod validate { .to_decimal() .ok_or_else(|| format!("integer {value} cannot be represented as integer"))?; match value { - 0 | 1 | 2 => Ok(()), + 0..=2 => Ok(()), _ => Err(format!("protocol version {value} is unknown").into()), } } diff --git a/gix/src/object/tree/diff/for_each.rs b/gix/src/object/tree/diff/for_each.rs index a72033182b1..3932f902788 100644 --- a/gix/src/object/tree/diff/for_each.rs +++ b/gix/src/object/tree/diff/for_each.rs @@ -75,8 +75,9 @@ impl<'a, 'old> Platform<'a, 'old> { } Err(gix_diff::tree::changes::Error::Cancelled) => delegate .err - .map(|err| Err(Error::ForEach(Box::new(err)))) - .unwrap_or(Err(Error::Diff(gix_diff::tree::changes::Error::Cancelled))), + .map_or(Err(Error::Diff(gix_diff::tree::changes::Error::Cancelled)), |err| { + Err(Error::ForEach(Box::new(err))) + }), Err(err) => Err(err.into()), } } From a71b6deccf4f634dd69d7aa2ae3e7898be944e0e Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Thu, 24 Aug 2023 20:08:51 +0200 Subject: [PATCH 0019/1077] Don't show backtraces as it disturbs journey tests And we don't usually see things crashing like this anyway, so there is no loss. --- .github/workflows/ci.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c1419cf2769..4c266358599 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,7 +1,6 @@ name: ci env: - RUST_BACKTRACE: 1 CARGO_TERM_COLOR: always CLICOLOR: 1 From f05edaef5e8d6a2d90adc84c8dc5c4b5ab0017b6 Mon Sep 17 00:00:00 2001 From: Niklas Wimmer Date: Fri, 25 Aug 2023 09:11:59 +0200 Subject: [PATCH 0020/1077] Handle missing host and path separator in file url --- gix-url/src/parse/mod.rs | 27 +++++++++++++++++++++++---- gix-url/tests/parse/invalid.rs | 6 +++++- 2 files changed, 28 insertions(+), 5 deletions(-) diff --git a/gix-url/src/parse/mod.rs b/gix-url/src/parse/mod.rs index 702163f386f..5e4d7019054 100644 --- a/gix-url/src/parse/mod.rs +++ b/gix-url/src/parse/mod.rs @@ -85,8 +85,7 @@ pub fn parse(input: &BStr) -> Result { match find_scheme(input) { InputScheme::Local => parse_local(input, false), InputScheme::Url { protocol_end } if input[..protocol_end].eq_ignore_ascii_case(b"file") => { - // strip the protocol part - parse_local(&input[protocol_end + 3..], true) + parse_file_url(input, protocol_end) } InputScheme::Url { .. } => parse_url(input), InputScheme::Scp { colon } => parse_scp(input, colon), @@ -176,6 +175,28 @@ fn parse_scp(input: &BStr, colon: usize) -> Result { }) } +fn parse_file_url(input: &BStr, protocol_colon: usize) -> Result { + let input = std::str::from_utf8(input).map_err(|source| Error::Utf8 { + url: input.to_owned(), + kind: UrlKind::Url, + source, + })?; + let url = url::Url::parse(input).map_err(|source| Error::Url { + url: input.to_owned(), + kind: UrlKind::Url, + source, + })?; + + if !input[protocol_colon + 3..].contains('/') { + return Err(Error::MissingRepositoryPath { + url: input.to_owned().into(), + kind: UrlKind::Url, + }); + } + + parse_local(url.path().into(), true) +} + fn parse_local(input: &BStr, was_in_url_format: bool) -> Result { if input.is_empty() { return Err(Error::MissingRepositoryPath { @@ -184,8 +205,6 @@ fn parse_local(input: &BStr, was_in_url_format: bool) -> Result Date: Sat, 26 Aug 2023 22:11:55 +1000 Subject: [PATCH 0021/1077] Add new crate `gix-macros` proc-macro crates, it provides `momo` for de-monomorphization for now. Signed-off-by: Jiahao XU --- Cargo.lock | 9 + Cargo.toml | 1 + gix-macros/Cargo.toml | 22 ++ gix-macros/LICENSE-APACHE | 1 + gix-macros/LICENSE-MIT | 1 + gix-macros/src/lib.rs | 450 ++++++++++++++++++++++++++++++++++++++ gix-macros/tests/test.rs | 286 ++++++++++++++++++++++++ 7 files changed, 770 insertions(+) create mode 100644 gix-macros/Cargo.toml create mode 120000 gix-macros/LICENSE-APACHE create mode 120000 gix-macros/LICENSE-MIT create mode 100644 gix-macros/src/lib.rs create mode 100644 gix-macros/tests/test.rs diff --git a/Cargo.lock b/Cargo.lock index a06040137e0..441417f4cdb 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1795,6 +1795,15 @@ dependencies = [ "thiserror", ] +[[package]] +name = "gix-macros" +version = "0.0.0" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.29", +] + [[package]] name = "gix-mailmap" version = "0.17.0" diff --git a/Cargo.toml b/Cargo.toml index c79cf19e1d6..ec5728c3551 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -244,6 +244,7 @@ members = [ "gix-packetline", "gix-packetline-blocking", "gix-mailmap", + "gix-macros", "gix-note", "gix-negotiate", "gix-fetchhead", diff --git a/gix-macros/Cargo.toml b/gix-macros/Cargo.toml new file mode 100644 index 00000000000..d208d929c1f --- /dev/null +++ b/gix-macros/Cargo.toml @@ -0,0 +1,22 @@ +[package] +name = "gix-macros" +version = "0.0.0" +edition = "2021" +description = "Proc-macro utilities for gix" +authors = [ + "Jiahao XU ", + "Andre Bogus ", + "Sebastian Thiel ", +] +repository = "https://github.com/Byron/gitoxide" +license = "MIT OR Apache-2.0" +include = ["src/**/*", "LICENSE-*", "CHANGELOG.md"] +rust-version = "1.65" + +[lib] +proc_macro = true + +[dependencies] +syn = { version = "2.0", features = ["full", "fold"] } +quote = "1.0" +proc-macro2 = "1.0" diff --git a/gix-macros/LICENSE-APACHE b/gix-macros/LICENSE-APACHE new file mode 120000 index 00000000000..965b606f331 --- /dev/null +++ b/gix-macros/LICENSE-APACHE @@ -0,0 +1 @@ +../LICENSE-APACHE \ No newline at end of file diff --git a/gix-macros/LICENSE-MIT b/gix-macros/LICENSE-MIT new file mode 120000 index 00000000000..76219eb72e8 --- /dev/null +++ b/gix-macros/LICENSE-MIT @@ -0,0 +1 @@ +../LICENSE-MIT \ No newline at end of file diff --git a/gix-macros/src/lib.rs b/gix-macros/src/lib.rs new file mode 100644 index 00000000000..8688ccabaf1 --- /dev/null +++ b/gix-macros/src/lib.rs @@ -0,0 +1,450 @@ +use std::collections::{HashMap, HashSet}; + +use proc_macro::TokenStream; +use quote::quote; +use syn::{fold::Fold, punctuated::Punctuated, spanned::Spanned, *}; + +#[derive(Copy, Clone)] +// All conversions we support. Check references to this type for an idea how to add more. +enum Conversion<'a> { + Into(&'a Type), + TryInto(&'a Type), + AsRef(&'a Type), + AsMut(&'a Type), +} + +impl<'a> Conversion<'a> { + fn target_type(&self) -> Type { + match *self { + Conversion::Into(ty) => ty.clone(), + Conversion::TryInto(ty) => ty.clone(), + Conversion::AsRef(ty) => parse_quote!(&#ty), + Conversion::AsMut(ty) => parse_quote!(&mut #ty), + } + } + + fn conversion_expr(&self, i: Ident) -> Expr { + match *self { + Conversion::Into(_) => parse_quote!(#i.into()), + Conversion::TryInto(_) => parse_quote!(#i.try_into()?), + Conversion::AsRef(_) => parse_quote!(#i.as_ref()), + Conversion::AsMut(_) => parse_quote!(#i.as_mut()), + } + } +} + +fn parse_bounded_type(ty: &Type) -> Option { + if let Type::Path(TypePath { qself: None, ref path }) = ty { + if path.segments.len() == 1 { + return Some(path.segments[0].ident.clone()); + } + } + None +} + +fn parse_bounds(bounds: &Punctuated) -> Option { + if bounds.len() != 1 { + return None; + } + if let TypeParamBound::Trait(ref tb) = bounds.first().unwrap() { + if let Some(seg) = tb.path.segments.iter().last() { + if let PathArguments::AngleBracketed(ref gen_args) = seg.arguments { + if let GenericArgument::Type(ref arg_ty) = gen_args.args.first().unwrap() { + if seg.ident == "Into" { + return Some(Conversion::Into(arg_ty)); + } else if seg.ident == "TryInto" { + return Some(Conversion::TryInto(arg_ty)); + } else if seg.ident == "AsRef" { + return Some(Conversion::AsRef(arg_ty)); + } else if seg.ident == "AsMut" { + return Some(Conversion::AsMut(arg_ty)); + } + } + } + } + } + None +} + +// create a map from generic type to Conversion +fn parse_generics(decl: &Signature) -> (HashMap>, Generics) { + let mut ty_conversions = HashMap::new(); + let mut params = Punctuated::new(); + for gp in decl.generics.params.iter() { + if let GenericParam::Type(ref tp) = gp { + if let Some(conversion) = parse_bounds(&tp.bounds) { + ty_conversions.insert(tp.ident.clone(), conversion); + continue; + } + } + params.push(gp.clone()); + } + let where_clause = if let Some(ref wc) = decl.generics.where_clause { + let mut idents_to_remove = HashSet::new(); + let mut predicates = Punctuated::new(); + for wp in wc.predicates.iter() { + if let WherePredicate::Type(ref pt) = wp { + if let Some(ident) = parse_bounded_type(&pt.bounded_ty) { + if let Some(conversion) = parse_bounds(&pt.bounds) { + idents_to_remove.insert(ident.clone()); + ty_conversions.insert(ident, conversion); + continue; + } + } + } + predicates.push(wp.clone()); + } + params = params + .into_iter() + .filter(|param| { + if let GenericParam::Type(type_param) = param { + !idents_to_remove.contains(&type_param.ident) + } else { + true + } + }) + .collect(); + Some(WhereClause { + predicates, + ..wc.clone() + }) + } else { + None + }; + ( + ty_conversions, + Generics { + params, + where_clause, + ..decl.generics.clone() + }, + ) +} + +fn pat_to_ident(pat: &Pat) -> Ident { + if let Pat::Ident(ref pat_ident) = *pat { + return pat_ident.ident.clone(); + } + unimplemented!("No non-ident patterns for now!"); +} + +fn pat_to_expr(pat: &Pat) -> Expr { + let ident = pat_to_ident(pat); + parse_quote!(#ident) +} + +fn convert<'a>( + inputs: &'a Punctuated, + ty_conversions: &HashMap>, +) -> ( + Punctuated, + Conversions, + Punctuated, + bool, +) { + let mut argtypes = Punctuated::new(); + let mut conversions = Conversions { + intos: Vec::new(), + try_intos: Vec::new(), + as_refs: Vec::new(), + as_muts: Vec::new(), + }; + let mut argexprs = Punctuated::new(); + let mut has_self = false; + inputs.iter().for_each(|input| match input { + FnArg::Receiver(..) => { + has_self = true; + argtypes.push(input.clone()); + } + FnArg::Typed(PatType { + ref pat, + ref ty, + ref colon_token, + .. + }) => match **ty { + Type::ImplTrait(TypeImplTrait { ref bounds, .. }) => { + if let Some(conv) = parse_bounds(bounds) { + argtypes.push(FnArg::Typed(PatType { + attrs: Vec::new(), + pat: pat.clone(), + colon_token: *colon_token, + ty: Box::new(conv.target_type()), + })); + let ident = pat_to_ident(pat); + conversions.add(ident.clone(), conv); + argexprs.push(conv.conversion_expr(ident)); + } else { + argtypes.push(input.clone()); + argexprs.push(pat_to_expr(pat)); + } + } + Type::Path(..) => { + if let Some(conv) = parse_bounded_type(ty).and_then(|ident| ty_conversions.get(&ident)) { + argtypes.push(FnArg::Typed(PatType { + attrs: Vec::new(), + pat: pat.clone(), + colon_token: *colon_token, + ty: Box::new(conv.target_type()), + })); + let ident = pat_to_ident(pat); + conversions.add(ident.clone(), *conv); + argexprs.push(conv.conversion_expr(ident)); + } else { + argtypes.push(input.clone()); + argexprs.push(pat_to_expr(pat)); + } + } + _ => { + argtypes.push(input.clone()); + argexprs.push(pat_to_expr(pat)); + } + }, + }); + (argtypes, conversions, argexprs, has_self) +} + +struct Conversions { + intos: Vec, + try_intos: Vec, + as_refs: Vec, + as_muts: Vec, +} + +impl Conversions { + fn add(&mut self, ident: Ident, conv: Conversion) { + match conv { + Conversion::Into(_) => self.intos.push(ident), + Conversion::TryInto(_) => self.try_intos.push(ident), + Conversion::AsRef(_) => self.as_refs.push(ident), + Conversion::AsMut(_) => self.as_muts.push(ident), + } + } +} + +fn has_conversion(idents: &[Ident], expr: &Expr) -> bool { + if let Expr::Path(ExprPath { ref path, .. }) = *expr { + if path.segments.len() == 1 { + let seg = path.segments.iter().last().unwrap(); + return idents.iter().any(|i| i == &seg.ident); + } + } + false +} + +#[allow(clippy::collapsible_if)] +impl Fold for Conversions { + fn fold_expr(&mut self, expr: Expr) -> Expr { + //TODO: Also catch `Expr::Call` with suitable paths & args + match expr { + Expr::MethodCall(mc) if mc.args.is_empty() => match &*mc.method.to_string() { + "into" if has_conversion(&self.intos, &mc.receiver) => *mc.receiver, + "try_into" if has_conversion(&self.try_intos, &mc.receiver) => *mc.receiver, + + "as_ref" if has_conversion(&self.as_refs, &mc.receiver) => *mc.receiver, + "as_mut" if has_conversion(&self.as_muts, &mc.receiver) => *mc.receiver, + + _ => syn::fold::fold_expr(self, Expr::MethodCall(mc)), + }, + Expr::Call(call) if call.args.len() == 1 => match &*call.func { + Expr::Path(ExprPath { + path: Path { segments, .. }, + .. + }) if segments.len() == 2 => match (&*segments[0].ident.to_string(), &*segments[1].ident.to_string()) { + ("Into", "into") if has_conversion(&self.intos, &call.args[0]) => call.args[0].clone(), + ("TryInto", "try_into") if has_conversion(&self.try_intos, &call.args[0]) => call.args[0].clone(), + + ("AsRef", "as_ref") if matches!(&call.args[0], Expr::Reference(ExprReference { expr, mutability: None, .. }) if has_conversion(&self.as_refs, expr)) => { + if let Expr::Reference(ExprReference { expr, .. }) = &call.args[0] { + (**expr).clone() + } else { + panic!("expr must be Reference") + } + } + ("AsMut", "as_mut") if matches!(&call.args[0], Expr::Reference(ExprReference { expr, mutability: Some(_), .. }) if has_conversion(&self.as_muts, expr)) => { + if let Expr::Reference(ExprReference { expr, .. }) = &call.args[0] { + (**expr).clone() + } else { + panic!("expr must be Reference") + } + } + + _ => syn::fold::fold_expr(self, Expr::Call(call)), + }, + _ => syn::fold::fold_expr(self, Expr::Call(call)), + }, + Expr::Try(expr_try) => match &*expr_try.expr { + Expr::MethodCall(mc) + if mc.args.is_empty() + && mc.method == "try_into" + && has_conversion(&self.try_intos, &mc.receiver) => + { + (*mc.receiver).clone() + } + Expr::Call(call) if call.args.len() == 1 => match &*call.func { + Expr::Path(ExprPath { + path: Path { segments, .. }, + .. + }) if segments.len() == 2 + && segments[0].ident == "TryInto" + && segments[1].ident == "try_into" + && has_conversion(&self.try_intos, &call.args[0]) => + { + call.args[0].clone() + } + _ => syn::fold::fold_expr(self, Expr::Try(expr_try)), + }, + _ => syn::fold::fold_expr(self, Expr::Try(expr_try)), + }, + _ => syn::fold::fold_expr(self, expr), + } + } +} + +fn contains_self_type_path(path: &Path) -> bool { + path.segments.iter().any(|segment| { + segment.ident == "Self" + || match &segment.arguments { + PathArguments::AngleBracketed(AngleBracketedGenericArguments { args, .. }) => { + args.iter().any(|generic_arg| match generic_arg { + GenericArgument::Type(ty) => contains_self_type(ty), + GenericArgument::Const(expr) => contains_self_type_expr(expr), + _ => false, + }) + } + PathArguments::Parenthesized(ParenthesizedGenericArguments { inputs, output, .. }) => { + inputs.iter().any(contains_self_type) + || matches!(output, ReturnType::Type(_, ty) if contains_self_type(ty)) + } + _ => false, + } + }) +} + +fn contains_self_type_expr(expr: &Expr) -> bool { + match expr { + Expr::Path(ExprPath { qself: Some(_), .. }) => true, + Expr::Path(ExprPath { path, .. }) => contains_self_type_path(path), + _ => false, + } +} + +fn contains_self_type(input: &Type) -> bool { + match input { + Type::Array(TypeArray { elem, len, .. }) => { + // Call `matches!` first so that we can do tail call here + // as an optimization. + contains_self_type_expr(len) || contains_self_type(elem) + } + Type::Group(TypeGroup { elem, .. }) => contains_self_type(elem), + Type::Paren(TypeParen { elem, .. }) => contains_self_type(elem), + Type::Ptr(TypePtr { elem, .. }) => contains_self_type(elem), + Type::Reference(TypeReference { elem, .. }) => contains_self_type(elem), + Type::Slice(TypeSlice { elem, .. }) => contains_self_type(elem), + + Type::Tuple(TypeTuple { elems, .. }) => elems.iter().any(contains_self_type), + + Type::Path(TypePath { qself: Some(_), .. }) => true, + Type::Path(TypePath { path, .. }) => contains_self_type_path(path), + + _ => false, + } +} + +fn has_self_type(input: &FnArg) -> bool { + match input { + FnArg::Receiver(_) => true, + FnArg::Typed(PatType { ty, .. }) => contains_self_type(ty), + } +} + +/// Generate lightweight monomorphized wrapper around main implementation. +/// May be applied to functions and methods. +#[proc_macro_attribute] +pub fn momo(_attrs: TokenStream, input: TokenStream) -> TokenStream { + //TODO: alternatively parse ImplItem::Method + momo_inner(input.into()).into() +} + +fn momo_inner(code: proc_macro2::TokenStream) -> proc_macro2::TokenStream { + let fn_item: Item = match syn::parse2(code.clone()) { + Ok(input) => input, + Err(err) => return err.to_compile_error(), + }; + + if let Item::Fn(item_fn) = fn_item { + let (ty_conversions, generics) = parse_generics(&item_fn.sig); + let (argtypes, mut conversions, argexprs, has_self) = convert(&item_fn.sig.inputs, &ty_conversions); + + let uses_self = has_self + || item_fn.sig.inputs.iter().any(has_self_type) + || matches!(&item_fn.sig.output, ReturnType::Type(_, ty) if contains_self_type(ty)); + + let inner_ident = Ident::new( + // Use long qualifier to avoid name colision. + &format!("_{}_inner_generated_by_gix_macro_momo", item_fn.sig.ident), + proc_macro2::Span::call_site(), + ); + + let new_inner_item = Item::Fn(ItemFn { + // Remove doc comment since they will increase compile-time and + // also generates duplicate warning/error messages for the doc, + // especially if it contains doc-tests. + attrs: { + let mut attrs = item_fn.attrs.clone(); + attrs.retain(|attr| { + let segments = &attr.path().segments; + !(segments.len() == 1 && segments[0].ident == "doc") + }); + attrs + }, + vis: Visibility::Inherited, + sig: Signature { + ident: inner_ident.clone(), + generics, + inputs: argtypes, + ..item_fn.sig.clone() + }, + block: Box::new(conversions.fold_block(*item_fn.block)), + }); + + if uses_self { + // We can use `self` or `Self` inside function defined within + // the impl-fn, so instead declare two separate functions. + // + // Since it's an impl block, it's unlikely to have name conflict, + // though this won't work for impl-trait. + // + // This approach also make sure we can call the right function + // using `Self` qualifier. + let new_item = Item::Fn(ItemFn { + attrs: item_fn.attrs, + vis: item_fn.vis, + sig: item_fn.sig, + block: if has_self { + parse_quote!({ self.#inner_ident(#argexprs) }) + } else { + parse_quote!({ Self::#inner_ident(#argexprs) }) + }, + }); + quote!(#new_item #[allow(unused_mut)] #new_inner_item) + } else { + // Put the new inner function within the function block + // to avoid duplicate function name and support associated + // function that doesn't use `self` or `Self`. + let new_item = Item::Fn(ItemFn { + attrs: item_fn.attrs, + vis: item_fn.vis, + sig: item_fn.sig, + block: parse_quote!({ + #[allow(unused_mut)] + #new_inner_item + + #inner_ident(#argexprs) + }), + }); + quote!(#new_item) + } + } else { + Error::new(fn_item.span(), "expect a function").to_compile_error() + } +} diff --git a/gix-macros/tests/test.rs b/gix-macros/tests/test.rs new file mode 100644 index 00000000000..10006bf1be4 --- /dev/null +++ b/gix-macros/tests/test.rs @@ -0,0 +1,286 @@ +use gix_macros::momo; +use std::pin::Pin; + +struct Options; + +#[allow(dead_code)] +fn test_open_opts_inner(_dir: impl Into, _options: Options) -> Result<(), ()> { + Ok(()) +} + +/// See if doc are kept +#[allow(dead_code)] +#[momo] +fn test_open_opts(directory: impl Into, options: Options) -> Result<(), ()> { + test_open_opts_inner(directory, options) +} + +#[allow(dead_code)] +#[momo] +fn test_with_try(t: impl TryInto, _options: Options) -> Result<(), ()> { + let t = t.try_into()?; + t.strip_prefix('1').ok_or(())?; + Ok(()) +} + +#[momo] +fn test_fn( + a: impl Into, + b: impl AsRef, + mut c: impl AsMut, + d: impl TryInto, +) -> Result { + let mut s = a.into(); + s += b.as_ref(); + s += c.as_mut(); + s += &d.try_into()?; + + Ok(s) +} + +#[momo] +fn test_fn_call_style( + a: impl Into, + b: impl AsRef, + mut c: impl AsMut, + d: impl TryInto, +) -> Result { + let mut s = Into::into(a); + s += AsRef::as_ref(&b); + s += AsMut::as_mut(&mut c); + s += &TryInto::try_into(d)?; + + Ok(s) +} + +#[momo] +fn test_fn_where(a: A, b: B, mut c: C, d: D) -> Result +where + A: Into, + B: AsRef, + C: AsMut, + D: TryInto, +{ + let mut s = a.into(); + s += b.as_ref(); + s += c.as_mut(); + s += &d.try_into()?; + + Ok(s) +} + +struct TestStruct; + +impl TestStruct { + #[momo] + fn test_method( + self, + a: impl Into, + b: impl AsRef, + mut c: impl AsMut, + d: impl TryInto, + ) -> Result { + let mut s = a.into(); + s += b.as_ref(); + s += c.as_mut(); + s += &d.try_into()?; + + Ok(s) + } + + #[allow(clippy::needless_arbitrary_self_type)] + #[momo] + fn test_method2( + self: Self, + a: impl Into, + b: impl AsRef, + mut c: impl AsMut, + d: impl TryInto, + ) -> Result { + let mut s = a.into(); + s += b.as_ref(); + s += c.as_mut(); + s += &d.try_into()?; + + Ok(s) + } + + #[momo] + fn test_fn( + a: impl Into, + b: impl AsRef, + mut c: impl AsMut, + d: impl TryInto, + _e: (), + ) -> Result { + let mut s = a.into(); + s += b.as_ref(); + s += c.as_mut(); + s += &d.try_into()?; + + Ok(s) + } + + #[momo] + fn test_fn2( + _this: Self, + a: impl Into, + b: impl AsRef, + mut c: impl AsMut, + d: impl TryInto, + _e: (), + _f: (), + ) -> Result { + let mut s = a.into(); + s += b.as_ref(); + s += c.as_mut(); + s += &d.try_into()?; + + Ok(s) + } + + #[momo] + fn test_fn3( + _this: Pin<&mut Self>, + a: impl Into, + b: impl AsRef, + mut c: impl AsMut, + d: impl TryInto, + _e: (), + _f: (), + ) -> Result { + let mut s = a.into(); + s += b.as_ref(); + s += c.as_mut(); + s += &d.try_into()?; + + Ok(s) + } + + #[allow(unused)] + #[momo] + fn test_fn_ret( + _this: Pin<&mut Self>, + a: impl Into, + b: impl AsRef, + mut c: impl AsMut, + d: impl TryInto, + _e: (), + _f: (), + ) -> Result { + let mut s = a.into(); + s += b.as_ref(); + s += c.as_mut(); + s += &d.try_into()?; + + drop(s); + + Ok(Self) + } +} + +struct S(bool); +impl TryInto for S { + type Error = (); + + fn try_into(self) -> Result { + if self.0 { + Ok(String::from("!2345")) + } else { + Err(()) + } + } +} + +#[test] +fn test_basic_fn() { + assert_eq!( + test_fn("12345", "12345", String::from("12345"), S(true)).unwrap(), + "123451234512345!2345" + ); + + test_fn("12345", "12345", String::from("12345"), S(false)).unwrap_err(); + + assert_eq!( + test_fn_call_style("12345", "12345", String::from("12345"), S(true)).unwrap(), + "123451234512345!2345" + ); + + test_fn_call_style("12345", "12345", String::from("12345"), S(false)).unwrap_err(); + + assert_eq!( + test_fn_where("12345", "12345", String::from("12345"), S(true)).unwrap(), + "123451234512345!2345" + ); + + test_fn_where("12345", "12345", String::from("12345"), S(false)).unwrap_err(); +} + +#[test] +fn test_struct_method() { + // Test test_method + assert_eq!( + TestStruct + .test_method("12345", "12345", String::from("12345"), S(true)) + .unwrap(), + "123451234512345!2345" + ); + + TestStruct + .test_method("12345", "12345", String::from("12345"), S(false)) + .unwrap_err(); + + // Test test_method2 + assert_eq!( + TestStruct + .test_method2("12345", "12345", String::from("12345"), S(true)) + .unwrap(), + "123451234512345!2345" + ); + + TestStruct + .test_method2("12345", "12345", String::from("12345"), S(false)) + .unwrap_err(); +} + +#[test] +fn test_struct_fn() { + assert_eq!( + TestStruct::test_fn("12345", "12345", String::from("12345"), S(true), ()).unwrap(), + "123451234512345!2345" + ); + + TestStruct::test_fn("12345", "12345", String::from("12345"), S(false), ()).unwrap_err(); + + assert_eq!( + TestStruct::test_fn2(TestStruct, "12345", "12345", String::from("12345"), S(true), (), ()).unwrap(), + "123451234512345!2345" + ); + + TestStruct::test_fn2(TestStruct, "12345", "12345", String::from("12345"), S(false), (), ()).unwrap_err(); + + assert_eq!( + TestStruct::test_fn3( + Pin::new(&mut TestStruct), + "12345", + "12345", + String::from("12345"), + S(true), + (), + () + ) + .unwrap(), + "123451234512345!2345" + ); + + TestStruct::test_fn3( + Pin::new(&mut TestStruct), + "12345", + "12345", + String::from("12345"), + S(false), + (), + (), + ) + .unwrap_err(); +} From 58fbb08461064d96dd9816e2fb6911cf76b6badc Mon Sep 17 00:00:00 2001 From: Jiahao XU Date: Sat, 26 Aug 2023 22:15:20 +1000 Subject: [PATCH 0022/1077] Apply `momo` to mod `gix::discover` to: - `ThreadSafeRepository::discover_opts` - `ThreadSafeRepository::discover_with_environment_overrides_opts` Signed-off-by: Jiahao XU --- gix/Cargo.toml | 1 + gix/src/discover.rs | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/gix/Cargo.toml b/gix/Cargo.toml index 7c3fe382cde..11af7e57621 100644 --- a/gix/Cargo.toml +++ b/gix/Cargo.toml @@ -126,6 +126,7 @@ fast-sha1 = [ "gix-features/fast-sha1" ] [dependencies] +gix-macros = { version = "^0.0.0", path = "../gix-macros" } gix-utils = { version = "^0.1.5", path = "../gix-utils" } gix-fs = { version = "^0.5.0", path = "../gix-fs" } gix-ref = { version = "^0.35.0", path = "../gix-ref" } diff --git a/gix/src/discover.rs b/gix/src/discover.rs index da43092c318..a5a3b8a4ad4 100644 --- a/gix/src/discover.rs +++ b/gix/src/discover.rs @@ -2,6 +2,7 @@ use std::path::Path; pub use gix_discover::*; +use gix_macros::momo; use crate::{bstr::BString, ThreadSafeRepository}; @@ -31,6 +32,7 @@ impl ThreadSafeRepository { /// if the directory that is discovered can indeed be trusted (or else they'd have to implement the discovery themselves /// and be sure that no attacker ever gets access to a directory structure. The cost of this is a permission check, which /// seems acceptable). + #[momo] pub fn discover_opts( directory: impl AsRef, options: upwards::Options<'_>, @@ -61,6 +63,8 @@ impl ThreadSafeRepository { /// /// Finally, use the `trust_map` to determine which of our own repository options to use /// based on the trust level of the effective repository directory. + #[momo] + #[allow(unused_mut)] pub fn discover_with_environment_overrides_opts( directory: impl AsRef, mut options: upwards::Options<'_>, From 46a9dfe12dedc1cbf997ea408d1f1d2c5d673ba5 Mon Sep 17 00:00:00 2001 From: Jiahao XU Date: Sat, 26 Aug 2023 22:17:28 +1000 Subject: [PATCH 0023/1077] Apply `momo` to mod `gix::init` to: - `ThreadSafeRepository::init` - `ThreadSafeRepository::init_opts` Signed-off-by: Jiahao XU --- gix/src/init.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/gix/src/init.rs b/gix/src/init.rs index bffd5fc5b8f..9b9cb5a61b0 100644 --- a/gix/src/init.rs +++ b/gix/src/init.rs @@ -1,6 +1,7 @@ #![allow(clippy::result_large_err)] use std::{borrow::Cow, convert::TryInto, path::Path}; +use gix_macros::momo; use gix_ref::{ store::WriteReflog, transaction::{PreviousValue, RefEdit}, @@ -40,6 +41,7 @@ impl ThreadSafeRepository { /// /// Fails without action if there is already a `.git` repository inside of `directory`, but /// won't mind if the `directory` otherwise is non-empty. + #[momo] pub fn init( directory: impl AsRef, kind: crate::create::Kind, @@ -56,6 +58,8 @@ impl ThreadSafeRepository { /// /// Instead of naming the default branch `master`, we name it `main` unless configured explicitly using the `init.defaultBranch` /// configuration key. + #[momo] + #[allow(unused_mut)] pub fn init_opts( directory: impl AsRef, kind: crate::create::Kind, From d8355267fd64dbcf22a01a11cb29d93e75f0fb4c Mon Sep 17 00:00:00 2001 From: Jiahao XU Date: Sat, 26 Aug 2023 22:22:02 +1000 Subject: [PATCH 0024/1077] Apply `momo` to `gix::object::tree` to: - `Tree<'_>::lookup_entry_by_path` - `Tree<'_>::peel_to_entry_by_path` Signed-off-by: Jiahao XU --- gix/src/object/tree/mod.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/gix/src/object/tree/mod.rs b/gix/src/object/tree/mod.rs index 62a7d02e1e8..888621bf109 100644 --- a/gix/src/object/tree/mod.rs +++ b/gix/src/object/tree/mod.rs @@ -1,4 +1,5 @@ use gix_hash::ObjectId; +use gix_macros::momo; pub use gix_object::tree::EntryMode; use gix_object::{bstr::BStr, TreeRefIter}; use gix_odb::FindExt; @@ -132,6 +133,7 @@ impl<'repo> Tree<'repo> { /// /// If any path component contains illformed UTF-8 and thus can't be converted to bytes on platforms which can't do so natively, /// the returned component will be empty which makes the lookup fail. + #[momo] pub fn lookup_entry_by_path( &self, relative_path: impl AsRef, @@ -154,6 +156,7 @@ impl<'repo> Tree<'repo> { /// /// If any path component contains illformed UTF-8 and thus can't be converted to bytes on platforms which can't do so natively, /// the returned component will be empty which makes the lookup fail. + #[momo] pub fn peel_to_entry_by_path( &mut self, relative_path: impl AsRef, From 3ce014499a86e4e8bb57ffe7caa540792c1c0a47 Mon Sep 17 00:00:00 2001 From: Jiahao XU Date: Sat, 26 Aug 2023 22:23:04 +1000 Subject: [PATCH 0025/1077] Apply `momo` to mod `gix::open::repository` to: - `ThreadSafeRepository::open_opts` - `ThreadSafeRepository::open_with_environment_overrides` Signed-off-by: Jiahao XU --- gix/src/open/repository.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/gix/src/open/repository.rs b/gix/src/open/repository.rs index f533770c5b2..df096a4e3dd 100644 --- a/gix/src/open/repository.rs +++ b/gix/src/open/repository.rs @@ -2,6 +2,7 @@ use std::{borrow::Cow, path::PathBuf}; use gix_features::threading::OwnShared; +use gix_macros::momo; use super::{Error, Options}; use crate::{ @@ -58,6 +59,8 @@ impl ThreadSafeRepository { /// /// Note that opening a repository for implementing custom hooks is also handle specifically in /// [`open_with_environment_overrides()`][Self::open_with_environment_overrides()]. + #[momo] + #[allow(unused_mut)] pub fn open_opts(path: impl Into, mut options: Options) -> Result { let _span = gix_trace::coarse!("ThreadSafeRepository::open()"); let (path, kind) = { @@ -109,6 +112,7 @@ impl ThreadSafeRepository { // GIT_PROXY_SSL_CERT, GIT_PROXY_SSL_KEY, GIT_PROXY_SSL_CERT_PASSWORD_PROTECTED. // GIT_PROXY_SSL_CAINFO, GIT_SSL_CIPHER_LIST, GIT_HTTP_MAX_REQUESTS, GIT_CURL_FTP_NO_EPSV, #[doc(alias = "open_from_env", alias = "git2")] + #[momo] pub fn open_with_environment_overrides( fallback_directory: impl Into, trust_map: gix_sec::trust::Mapping, From 767ec2dcfd1fadaca93390770604494d03f88ab3 Mon Sep 17 00:00:00 2001 From: Jiahao XU Date: Sat, 26 Aug 2023 22:24:43 +1000 Subject: [PATCH 0026/1077] Apply `momo` to `gix::pathspec` to: - `Pathspec<'_>::pattern_matching_relative_path` - `Pathspec<'_>::is_included` Signed-off-by: Jiahao XU --- gix/src/pathspec.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/gix/src/pathspec.rs b/gix/src/pathspec.rs index f5af7b3228e..01445601a4f 100644 --- a/gix/src/pathspec.rs +++ b/gix/src/pathspec.rs @@ -1,4 +1,5 @@ //! Pathspec plumbing and abstractions +use gix_macros::momo; use gix_odb::FindExt; pub use gix_pathspec::*; @@ -92,6 +93,8 @@ impl<'repo> Pathspec<'repo> { alias = "matches_path", alias = "git2" )] + #[momo] + #[allow(clippy::needless_lifetimes)] pub fn pattern_matching_relative_path<'a>( &mut self, relative_path: impl Into<&'a BStr>, @@ -111,6 +114,8 @@ impl<'repo> Pathspec<'repo> { /// The simplified version of [`pattern_matching_relative_path()`](Self::pattern_matching_relative_path()) which returns /// `true` if `relative_path` is included in the set of positive pathspecs, while not being excluded. + #[momo] + #[allow(clippy::needless_lifetimes)] pub fn is_included<'a>(&mut self, relative_path: impl Into<&'a BStr>, is_dir: Option) -> bool { self.pattern_matching_relative_path(relative_path, is_dir) .map_or(false, |m| !m.is_excluded()) From 3c205abbdc0a80090b9f0f5681ce0949497e770f Mon Sep 17 00:00:00 2001 From: Jiahao XU Date: Sat, 26 Aug 2023 22:25:49 +1000 Subject: [PATCH 0027/1077] Apply `momo` to `gix::reference` to: - `set_target_id` - `Platform<'_>::prefixed` Signed-off-by: Jiahao XU --- gix/src/reference/edits.rs | 5 +++-- gix/src/reference/iter.rs | 2 ++ 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/gix/src/reference/edits.rs b/gix/src/reference/edits.rs index c6510c2e00b..20834077001 100644 --- a/gix/src/reference/edits.rs +++ b/gix/src/reference/edits.rs @@ -1,8 +1,8 @@ /// pub mod set_target_id { - use gix_ref::{transaction::PreviousValue, Target}; - use crate::{bstr::BString, Reference}; + use gix_macros::momo; + use gix_ref::{transaction::PreviousValue, Target}; mod error { use gix_ref::FullName; @@ -28,6 +28,7 @@ pub mod set_target_id { /// If multiple reference should be changed, use [`Repository::edit_references()`][crate::Repository::edit_references()] /// or the lower level reference database instead. #[allow(clippy::result_large_err)] + #[momo] pub fn set_target_id( &mut self, id: impl Into, diff --git a/gix/src/reference/iter.rs b/gix/src/reference/iter.rs index a2b022f64df..983a3803fc0 100644 --- a/gix/src/reference/iter.rs +++ b/gix/src/reference/iter.rs @@ -1,6 +1,7 @@ //! use std::path::Path; +use gix_macros::momo; use gix_odb::pack::Find; use gix_ref::file::ReferenceExt; @@ -42,6 +43,7 @@ impl<'r> Platform<'r> { /// These are of the form `refs/heads` or `refs/remotes/origin`, and must not contain relative paths components like `.` or `..`. // TODO: Create a custom `Path` type that enforces the requirements of git naturally, this type is surprising possibly on windows // and when not using a trailing '/' to signal directories. + #[momo] pub fn prefixed(&self, prefix: impl AsRef) -> Result, init::Error> { Ok(Iter::new(self.repo, self.platform.prefixed(prefix)?)) } From ea5c2dbabe9d3c1eb1ab5f15a578ec9f9c36a5d8 Mon Sep 17 00:00:00 2001 From: Jiahao XU Date: Sat, 26 Aug 2023 22:28:01 +1000 Subject: [PATCH 0028/1077] Apply `momo` to mod `remote::connection::fetch::receive_pack` to `receive` Signed-off-by: Jiahao XU --- gix/src/remote/connection/fetch/receive_pack.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/gix/src/remote/connection/fetch/receive_pack.rs b/gix/src/remote/connection/fetch/receive_pack.rs index 089fe295721..1df1a7174f3 100644 --- a/gix/src/remote/connection/fetch/receive_pack.rs +++ b/gix/src/remote/connection/fetch/receive_pack.rs @@ -73,6 +73,7 @@ where /// - `gitoxide.userAgent` is read to obtain the application user agent for git servers and for HTTP servers as well. /// #[gix_protocol::maybe_async::maybe_async] + #[allow(clippy::drop_non_drop)] pub async fn receive

(mut self, mut progress: P, should_interrupt: &AtomicBool) -> Result where P: Progress, From 5a505377199730354c2a6b6b7b060184558bb9c4 Mon Sep 17 00:00:00 2001 From: Jiahao XU Date: Sat, 26 Aug 2023 22:30:57 +1000 Subject: [PATCH 0029/1077] Apply `momo` to mod `gix::repository` to: - `Repository::transport_options` - `Repository::find_object` - `Repository::try_find_object` - `Repository::find_head` - `Repository::try_find_head` - `Repository::tag` - `Repository::tag_reference` - `Repository::try_find_remote` - `Repository::try_find_remote_without_url_rewrite` - `Repository::rev_parse` - `Repository::worktree_stream` Signed-off-by: Jiahao XU --- Cargo.lock | 1 + gix/src/repository/config/transport.rs | 8 ++++++-- gix/src/repository/object.rs | 16 +++++++++------- gix/src/repository/reference.rs | 6 ++++-- gix/src/repository/remote.rs | 4 ++++ gix/src/repository/revision.rs | 3 +++ gix/src/repository/worktree.rs | 2 +- 7 files changed, 28 insertions(+), 12 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 441417f4cdb..e73076b78bc 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1208,6 +1208,7 @@ dependencies = [ "gix-ignore 0.6.0", "gix-index 0.22.0", "gix-lock 8.0.0", + "gix-macros", "gix-mailmap", "gix-negotiate", "gix-object 0.35.0", diff --git a/gix/src/repository/config/transport.rs b/gix/src/repository/config/transport.rs index 81107076c31..d43fffaf560 100644 --- a/gix/src/repository/config/transport.rs +++ b/gix/src/repository/config/transport.rs @@ -1,6 +1,8 @@ #![allow(clippy::result_large_err)] use std::any::Any; +use gix_macros::momo; + use crate::bstr::BStr; impl crate::Repository { @@ -21,12 +23,14 @@ impl crate::Repository { )), allow(unused_variables) )] + #[allow(clippy::needless_lifetimes)] + #[momo] pub fn transport_options<'a>( &self, url: impl Into<&'a BStr>, remote_name: Option<&BStr>, ) -> Result>, crate::config::transport::Error> { - let url = gix_url::parse(url.into())?; + let url = gix_url::parse(url)?; use gix_url::Scheme::*; match &url.scheme { @@ -270,7 +274,7 @@ impl crate::Repository { .proxy .as_deref() .filter(|url| !url.is_empty()) - .map(|url| gix_url::parse(url.into())) + .map(|url| gix_url::parse(<&BStr>::from(url))) .transpose()? .filter(|url| url.user().is_some()) .map(|url| -> Result<_, config::transport::http::Error> { diff --git a/gix/src/repository/object.rs b/gix/src/repository/object.rs index bab7d1b5c50..2dafe6b4245 100644 --- a/gix/src/repository/object.rs +++ b/gix/src/repository/object.rs @@ -2,6 +2,7 @@ use std::{convert::TryInto, ops::DerefMut}; use gix_hash::ObjectId; +use gix_macros::momo; use gix_odb::{Find, FindExt, Header, HeaderExt, Write}; use gix_ref::{ transaction::{LogChange, PreviousValue, RefLog}, @@ -21,8 +22,8 @@ impl crate::Repository { /// /// In order to get the kind of the object, is must be fully decoded from storage if it is packed with deltas. /// Loose object could be partially decoded, even though that's not implemented. + #[momo] pub fn find_object(&self, id: impl Into) -> Result, object::find::existing::Error> { - let id = id.into(); if id == gix_hash::ObjectId::empty_tree(self.object_hash()) { return Ok(Object { id, @@ -40,8 +41,8 @@ impl crate::Repository { /// /// Note that despite being cheaper than [`Self::find_object()`], there is still some effort traversing delta-chains. #[doc(alias = "read_header", alias = "git2")] + #[momo] pub fn find_header(&self, id: impl Into) -> Result { - let id = id.into(); if id == gix_hash::ObjectId::empty_tree(self.object_hash()) { return Ok(gix_odb::find::Header::Loose { kind: gix_object::Kind::Tree, @@ -54,11 +55,11 @@ impl crate::Repository { /// Obtain information about an object without fully decoding it, or `None` if the object doesn't exist. /// /// Note that despite being cheaper than [`Self::try_find_object()`], there is still some effort traversing delta-chains. + #[momo] pub fn try_find_header( &self, id: impl Into, ) -> Result, object::find::Error> { - let id = id.into(); if id == gix_hash::ObjectId::empty_tree(self.object_hash()) { return Ok(Some(gix_odb::find::Header::Loose { kind: gix_object::Kind::Tree, @@ -69,8 +70,8 @@ impl crate::Repository { } /// Try to find the object with `id` or return `None` if it wasn't found. + #[momo] pub fn try_find_object(&self, id: impl Into) -> Result>, object::find::Error> { - let id = id.into(); if id == gix_hash::ObjectId::empty_tree(self.object_hash()) { return Ok(Some(Object { id, @@ -163,6 +164,7 @@ impl crate::Repository { /// /// It will be created with `constraint` which is most commonly to [only create it][PreviousValue::MustNotExist] /// or to [force overwriting a possibly existing tag](PreviousValue::Any). + #[momo] pub fn tag( &self, name: impl AsRef, @@ -173,11 +175,11 @@ impl crate::Repository { constraint: PreviousValue, ) -> Result, tag::Error> { let tag = gix_object::Tag { - target: target.as_ref().into(), + target: target.into(), target_kind, - name: name.as_ref().into(), + name: name.into(), tagger: tagger.map(|t| t.to_owned()), - message: message.as_ref().into(), + message: message.into(), pgp_signature: None, }; let tag_id = self.write_object(&tag)?; diff --git a/gix/src/repository/reference.rs b/gix/src/repository/reference.rs index 0428699e533..6c8274e2f68 100644 --- a/gix/src/repository/reference.rs +++ b/gix/src/repository/reference.rs @@ -1,6 +1,7 @@ use std::convert::TryInto; use gix_hash::ObjectId; +use gix_macros::momo; use gix_ref::{ transaction::{Change, LogChange, PreviousValue, RefEdit, RefLog}, FullName, PartialNameRef, Target, @@ -14,20 +15,21 @@ impl crate::Repository { /// /// It will be created with `constraint` which is most commonly to [only create it][PreviousValue::MustNotExist] /// or to [force overwriting a possibly existing tag](PreviousValue::Any). + #[momo] pub fn tag_reference( &self, name: impl AsRef, target: impl Into, constraint: PreviousValue, ) -> Result, reference::edit::Error> { - let id = target.into(); + let id = target; let mut edits = self.edit_reference(RefEdit { change: Change::Update { log: Default::default(), expected: constraint, new: Target::Peeled(id), }, - name: format!("refs/tags/{}", name.as_ref()).try_into()?, + name: format!("refs/tags/{name}").try_into()?, deref: false, })?; assert_eq!(edits.len(), 1, "reference splits should ever happen"); diff --git a/gix/src/repository/remote.rs b/gix/src/repository/remote.rs index 74ebbaea027..50f0e733dd1 100644 --- a/gix/src/repository/remote.rs +++ b/gix/src/repository/remote.rs @@ -1,6 +1,8 @@ #![allow(clippy::result_large_err)] use std::convert::TryInto; +use gix_macros::momo; + use crate::{bstr::BStr, config, remote, remote::find, Remote}; impl crate::Repository { @@ -61,6 +63,7 @@ impl crate::Repository { /// as negations/excludes are applied after includes. /// /// We will only include information if we deem it [trustworthy][crate::open::Options::filter_config_section()]. + #[momo] pub fn try_find_remote<'a>(&self, name_or_url: impl Into<&'a BStr>) -> Option, find::Error>> { self.try_find_remote_inner(name_or_url, true) } @@ -68,6 +71,7 @@ impl crate::Repository { /// Similar to [`try_find_remote()`][Self::try_find_remote()], but removes a failure mode if rewritten URLs turn out to be invalid /// as it skips rewriting them. /// Use this in conjunction with [`Remote::rewrite_urls()`] to non-destructively apply the rules and keep the failed urls unchanged. + #[momo] pub fn try_find_remote_without_url_rewrite<'a>( &self, name_or_url: impl Into<&'a BStr>, diff --git a/gix/src/repository/revision.rs b/gix/src/repository/revision.rs index 4eedf0867e2..27aeb38e194 100644 --- a/gix/src/repository/revision.rs +++ b/gix/src/repository/revision.rs @@ -1,4 +1,5 @@ use crate::{bstr::BStr, revision, Id}; +use gix_macros::momo; /// Methods for resolving revisions by spec or working with the commit graph. impl crate::Repository { @@ -9,6 +10,8 @@ impl crate::Repository { /// - `@` actually stands for `HEAD`, whereas `git` resolves it to the object pointed to by `HEAD` without making the /// `HEAD` ref available for lookups. #[doc(alias = "revparse", alias = "git2")] + #[allow(clippy::needless_lifetimes)] + #[momo] pub fn rev_parse<'a>(&self, spec: impl Into<&'a BStr>) -> Result, revision::spec::parse::Error> { revision::Spec::from_bstr( spec, diff --git a/gix/src/repository/worktree.rs b/gix/src/repository/worktree.rs index 17db1c0ebda..4773c6cd8e1 100644 --- a/gix/src/repository/worktree.rs +++ b/gix/src/repository/worktree.rs @@ -57,12 +57,12 @@ impl crate::Repository { /// The entries will look exactly like they would if one would check them out, with filters applied. /// The `export-ignore` attribute is used to skip blobs or directories to which it applies. #[cfg(feature = "worktree-stream")] + #[gix_macros::momo] pub fn worktree_stream( &self, id: impl Into, ) -> Result<(gix_worktree_stream::Stream, gix_index::File), crate::repository::worktree_stream::Error> { use gix_odb::{FindExt, HeaderExt}; - let id = id.into(); let header = self.objects.header(id)?; if !header.kind().is_tree() { return Err(crate::repository::worktree_stream::Error::NotATree { From ff210d82573cebfdf4edbfb39beaef08979c058f Mon Sep 17 00:00:00 2001 From: Jiahao XU Date: Sun, 27 Aug 2023 09:28:52 +1000 Subject: [PATCH 0030/1077] Fix clippy lints in `gix/src/repository/remote.rs` Signed-off-by: Jiahao XU --- gix/src/repository/remote.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/gix/src/repository/remote.rs b/gix/src/repository/remote.rs index 50f0e733dd1..2110affbc4e 100644 --- a/gix/src/repository/remote.rs +++ b/gix/src/repository/remote.rs @@ -64,6 +64,7 @@ impl crate::Repository { /// /// We will only include information if we deem it [trustworthy][crate::open::Options::filter_config_section()]. #[momo] + #[allow(clippy::needless_lifetimes)] pub fn try_find_remote<'a>(&self, name_or_url: impl Into<&'a BStr>) -> Option, find::Error>> { self.try_find_remote_inner(name_or_url, true) } @@ -72,6 +73,7 @@ impl crate::Repository { /// as it skips rewriting them. /// Use this in conjunction with [`Remote::rewrite_urls()`] to non-destructively apply the rules and keep the failed urls unchanged. #[momo] + #[allow(clippy::needless_lifetimes)] pub fn try_find_remote_without_url_rewrite<'a>( &self, name_or_url: impl Into<&'a BStr>, From dbf778cfe5423c4769123e8b7cf5efc4dce30db7 Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Sun, 27 Aug 2023 08:59:45 +0200 Subject: [PATCH 0031/1077] feat: `gix remote` and `gix fetch` now fallback to the only available remote if necessary. (#1003) Just like `git`, but we fail loudly if there are more than one remotes. --- gitoxide-core/src/repository/remote.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/gitoxide-core/src/repository/remote.rs b/gitoxide-core/src/repository/remote.rs index 7a3f44be7a1..f1533086a62 100644 --- a/gitoxide-core/src/repository/remote.rs +++ b/gitoxide-core/src/repository/remote.rs @@ -346,6 +346,9 @@ pub(crate) fn by_name_or_url<'repo>( None => repo .head()? .into_remote(gix::remote::Direction::Fetch) - .context("Cannot find a remote for unborn branch")??, + .transpose()? + .map(Ok) + .or_else(|| repo.find_default_remote(gix::remote::Direction::Fetch)) + .context("There was no remote available or too many to choose from")??, }) } From d22b7fb1304cce3b2aabac42cc58fe7c5911f276 Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Sun, 27 Aug 2023 09:35:07 +0200 Subject: [PATCH 0032/1077] feat: provide `Repository::find_fetch_remote()` to obtain a remote just like git would. --- gix/src/remote/errors.rs | 23 +++++++++++++++++-- gix/src/repository/remote.rs | 38 ++++++++++++++++++++++++++++---- gix/tests/head/mod.rs | 10 +++++++++ gix/tests/reference/remote.rs | 7 ++++++ gix/tests/repository/remote.rs | 40 ++++++++++++++++++++++++++++++++++ 5 files changed, 112 insertions(+), 6 deletions(-) diff --git a/gix/src/remote/errors.rs b/gix/src/remote/errors.rs index 20060cedf5e..34ed8246b24 100644 --- a/gix/src/remote/errors.rs +++ b/gix/src/remote/errors.rs @@ -2,7 +2,7 @@ pub mod find { use crate::{bstr::BString, config, remote}; - /// The error returned by [`Repository::find_remote(…)`][crate::Repository::find_remote()]. + /// The error returned by [`Repository::find_remote(…)`](crate::Repository::find_remote()). #[derive(Debug, thiserror::Error)] #[allow(missing_docs)] pub enum Error { @@ -30,7 +30,7 @@ pub mod find { pub mod existing { use crate::bstr::BString; - /// The error returned by [`Repository::find_remote(…)`][crate::Repository::find_remote()]. + /// The error returned by [`Repository::find_remote(…)`](crate::Repository::find_remote()). #[derive(Debug, thiserror::Error)] #[allow(missing_docs)] pub enum Error { @@ -42,4 +42,23 @@ pub mod find { NotFound { name: BString }, } } + + /// + pub mod for_fetch { + /// The error returned by [`Repository::find_fetch_remote(…)`](crate::Repository::find_fetch_remote()). + #[derive(Debug, thiserror::Error)] + #[allow(missing_docs)] + pub enum Error { + #[error(transparent)] + FindExisting(#[from] super::existing::Error), + #[error(transparent)] + FindExistingReferences(#[from] crate::reference::find::existing::Error), + #[error("Could not initialize a URL remote")] + Init(#[from] crate::remote::init::Error), + #[error("remote name could not be parsed as URL")] + UrlParse(#[from] gix_url::parse::Error), + #[error("No configured remote could be found, or too many were available")] + ExactlyOneRemoteNotAvailable, + } + } } diff --git a/gix/src/repository/remote.rs b/gix/src/repository/remote.rs index 74ebbaea027..9d535e3a5b0 100644 --- a/gix/src/repository/remote.rs +++ b/gix/src/repository/remote.rs @@ -28,7 +28,8 @@ impl crate::Repository { Remote::from_fetch_url(url, false, self) } - /// Find the remote with the given `name_or_url` or report an error, similar to [`try_find_remote(…)`][Self::try_find_remote()]. + /// Find the configured remote with the given `name_or_url` or report an error, + /// similar to [`try_find_remote(…)`][Self::try_find_remote()]. /// /// Note that we will obtain remotes only if we deem them [trustworthy][crate::open::Options::filter_config_section()]. pub fn find_remote<'a>(&self, name_or_url: impl Into<&'a BStr>) -> Result, find::existing::Error> { @@ -42,7 +43,7 @@ impl crate::Repository { /// Find the default remote as configured, or `None` if no such configuration could be found. /// - /// See [`remote_default_name()`][Self::remote_default_name()] for more information on the `direction` parameter. + /// See [`remote_default_name()`](Self::remote_default_name()) for more information on the `direction` parameter. pub fn find_default_remote( &self, direction: remote::Direction, @@ -51,8 +52,8 @@ impl crate::Repository { .map(|name| self.find_remote(name.as_ref())) } - /// Find the remote with the given `name_or_url` or return `None` if it doesn't exist, for the purpose of fetching or pushing - /// data to a remote. + /// Find the configured remote with the given `name_or_url` or return `None` if it doesn't exist, + /// for the purpose of fetching or pushing data. /// /// There are various error kinds related to partial information or incorrectly formatted URLs or ref-specs. /// Also note that the created `Remote` may have neither fetch nor push ref-specs set at all. @@ -65,6 +66,35 @@ impl crate::Repository { self.try_find_remote_inner(name_or_url, true) } + /// This method emulate what `git fetch ` does in order to obtain a remote to fetch from. + /// + /// As such, with `name_or_url` being `Some`, it will: + /// + /// * use `name_or_url` verbatim if it is a URL, creating a new remote in memory as needed. + /// * find the named remote if `name_or_url` is a remote name + /// + /// If `name_or_url` is `None`: + /// + /// * use the current `HEAD` branch to find a configured remote + /// * fall back to either a generally configured remote or the only configured remote. + /// + /// Fail if no remote could be found despite all of the above. + pub fn find_fetch_remote(&self, name_or_url: Option<&BStr>) -> Result, find::for_fetch::Error> { + Ok(match name_or_url { + Some(name) => match self.try_find_remote(name).and_then(Result::ok) { + Some(remote) => remote, + None => self.remote_at(gix_url::parse(name)?)?, + }, + None => self + .head()? + .into_remote(remote::Direction::Fetch) + .transpose()? + .map(Ok) + .or_else(|| self.find_default_remote(remote::Direction::Fetch)) + .ok_or_else(|| find::for_fetch::Error::ExactlyOneRemoteNotAvailable)??, + }) + } + /// Similar to [`try_find_remote()`][Self::try_find_remote()], but removes a failure mode if rewritten URLs turn out to be invalid /// as it skips rewriting them. /// Use this in conjunction with [`Remote::rewrite_urls()`] to non-destructively apply the rules and keep the failed urls unchanged. diff --git a/gix/tests/head/mod.rs b/gix/tests/head/mod.rs index b8508a4c70f..14da5604804 100644 --- a/gix/tests/head/mod.rs +++ b/gix/tests/head/mod.rs @@ -9,6 +9,11 @@ mod into_remote { repo.head()?.into_remote(gix::remote::Direction::Fetch).transpose()?, None ); + assert_eq!( + repo.find_fetch_remote(None)?.name().expect("present").as_ref(), + "origin", + "we can fallback to the only available remote" + ); Ok(()) } @@ -19,6 +24,11 @@ mod into_remote { repo.head()?.into_remote(gix::remote::Direction::Fetch).transpose()?, None ); + assert_eq!( + repo.find_fetch_remote(None)?.name().expect("present").as_ref(), + "origin", + "we can fallback to the only available remote" + ); Ok(()) } } diff --git a/gix/tests/reference/remote.rs b/gix/tests/reference/remote.rs index 8e8a09392aa..e75cc6e4ea8 100644 --- a/gix/tests/reference/remote.rs +++ b/gix/tests/reference/remote.rs @@ -78,6 +78,13 @@ fn not_configured() -> crate::Result { assert_eq!(branch.remote_name(gix::remote::Direction::Fetch), None); assert_eq!(branch.remote(gix::remote::Direction::Fetch).transpose()?, None); assert_eq!(head.into_remote(gix::remote::Direction::Fetch).transpose()?, None); + assert!( + matches!( + repo.find_fetch_remote(None), + Err(gix::remote::find::for_fetch::Error::ExactlyOneRemoteNotAvailable) + ), + "there is no remote to be found" + ); Ok(()) } diff --git a/gix/tests/repository/remote.rs b/gix/tests/repository/remote.rs index ae31fd8f737..d72ab61d000 100644 --- a/gix/tests/repository/remote.rs +++ b/gix/tests/repository/remote.rs @@ -291,6 +291,46 @@ mod find_remote { } } +mod find_fetch_remote { + use crate::remote; + + #[test] + fn symbol_name() -> crate::Result { + let repo = remote::repo("clone-no-tags"); + assert_eq!( + repo.find_fetch_remote(Some("origin".into()))? + .name() + .expect("set") + .as_bstr(), + "origin" + ); + Ok(()) + } + + #[test] + fn urls() -> crate::Result { + let repo = remote::repo("clone-no-tags"); + for url in [ + "some-path", + "https://example.com/repo", + "other/path", + "ssh://host/ssh-aliased-repo", + ] { + let remote = repo.find_fetch_remote(Some(url.into()))?; + assert_eq!(remote.name(), None, "this remote is anonymous"); + assert_eq!( + remote + .url(gix::remote::Direction::Fetch) + .expect("url is set") + .to_bstring(), + url, + "if it's not a configured remote, we take it as URL" + ); + } + Ok(()) + } +} + mod find_default_remote { use crate::remote; From e2c0912cfede044431c17ae81ddae02746650ae4 Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Sun, 27 Aug 2023 10:19:10 +0200 Subject: [PATCH 0033/1077] Use new `gix` method to obtain the fetch remote (instead of implementing it by hand) --- gitoxide-core/src/repository/remote.rs | 18 +----------------- gix/src/head/mod.rs | 6 ++++-- 2 files changed, 5 insertions(+), 19 deletions(-) diff --git a/gitoxide-core/src/repository/remote.rs b/gitoxide-core/src/repository/remote.rs index f1533086a62..ad10bceb6d4 100644 --- a/gitoxide-core/src/repository/remote.rs +++ b/gitoxide-core/src/repository/remote.rs @@ -334,21 +334,5 @@ pub(crate) fn by_name_or_url<'repo>( repo: &'repo gix::Repository, name_or_url: Option<&str>, ) -> anyhow::Result> { - use anyhow::Context; - Ok(match name_or_url { - Some(name) => { - if name.contains('/') || name.contains('.') { - repo.remote_at(gix::url::parse(name.into())?)? - } else { - repo.find_remote(name)? - } - } - None => repo - .head()? - .into_remote(gix::remote::Direction::Fetch) - .transpose()? - .map(Ok) - .or_else(|| repo.find_default_remote(gix::remote::Direction::Fetch)) - .context("There was no remote available or too many to choose from")??, - }) + repo.find_fetch_remote(name_or_url.map(Into::into)).map_err(Into::into) } diff --git a/gix/src/head/mod.rs b/gix/src/head/mod.rs index 094e78a8642..399b872ba95 100644 --- a/gix/src/head/mod.rs +++ b/gix/src/head/mod.rs @@ -101,8 +101,10 @@ mod remote { /// This is equivalent to calling [`Reference::remote(…)`][crate::Reference::remote()] and /// [`Repository::remote_default_name()`][crate::Repository::remote_default_name()] in order. /// - /// Combine it with [`find_default_remote()`][crate::Repository::find_default_remote()] as fallback to handle detached heads, - /// i.e. obtain a remote even in case of detached heads. + /// Combine it with [`Repository::find_default_remote()`][crate::Repository::find_default_remote()] as fallback to + /// handle detached heads, i.e. obtain a remote even in case of detached heads, + /// or call [`Repository::find_fetch_remote(…)`](crate::Repository::find_fetch_remote()) for the highest-level way of finding + /// the right remote, just like `git fetch` does. pub fn into_remote( self, direction: remote::Direction, From b310d044ac5c2bb1c874d0cfe701411e4aef47be Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Sun, 27 Aug 2023 11:07:40 +0200 Subject: [PATCH 0034/1077] fix!: skip the null-hash when validating the index. This is needed for compatibility with `index.skipHash`, which may skip producing the hash at the end of the index file, just filling in the null-hash. --- gix-index/src/decode/mod.rs | 11 +++--- gix-index/src/file/init.rs | 11 +++--- gix-index/src/file/verify.rs | 33 +++++++++--------- .../fixtures/loose_index/skip_hash.git-index | Bin 0 -> 97 bytes gix-index/tests/index/file/read.rs | 22 ++++++++++++ 5 files changed, 50 insertions(+), 27 deletions(-) create mode 100644 gix-index/tests/fixtures/loose_index/skip_hash.git-index diff --git a/gix-index/src/decode/mod.rs b/gix-index/src/decode/mod.rs index 70a65a880b0..12c8c53e404 100644 --- a/gix-index/src/decode/mod.rs +++ b/gix-index/src/decode/mod.rs @@ -54,7 +54,7 @@ pub struct Options { impl State { /// Decode an index state from `data` and store `timestamp` in the resulting instance for pass-through, assuming `object_hash` - /// to be used through the file. + /// to be used through the file. Also return the stored hash over all bytes in `data` or `None` if none was written due to `index.skipHash`. pub fn from_bytes( data: &[u8], timestamp: FileTime, @@ -64,7 +64,7 @@ impl State { min_extension_block_in_bytes_for_threading, expected_checksum, }: Options, - ) -> Result<(Self, gix_hash::ObjectId), Error> { + ) -> Result<(Self, Option), Error> { let _span = gix_features::trace::detail!("gix_index::State::from_bytes()"); let (version, num_entries, post_header_data) = header::decode(data, object_hash)?; let start_of_extensions = extension::end_of_index_entry::decode(data, object_hash); @@ -214,10 +214,11 @@ impl State { } let checksum = gix_hash::ObjectId::from(data); - if let Some(expected_checksum) = expected_checksum { - if checksum != expected_checksum { + let checksum = (!checksum.is_null()).then_some(checksum); + if let Some((expected_checksum, actual_checksum)) = expected_checksum.zip(checksum) { + if actual_checksum != expected_checksum { return Err(Error::ChecksumMismatch { - actual_checksum: checksum, + actual_checksum, expected_checksum, }); } diff --git a/gix-index/src/file/init.rs b/gix-index/src/file/init.rs index a61c7cfff60..1448de3dd4a 100644 --- a/gix-index/src/file/init.rs +++ b/gix-index/src/file/init.rs @@ -45,6 +45,9 @@ impl File { } /// Open an index file at `path` with `options`, assuming `object_hash` is used throughout the file. + /// + /// Note that the verification of the file hash depends on `options`, and even then it's performed after the file was read and not + /// before it is read. That way, invalid files would see a more descriptive error message as we try to parse them. pub fn at(path: impl Into, object_hash: gix_hash::Kind, options: decode::Options) -> Result { let _span = gix_features::trace::detail!("gix_index::File::at()"); let path = path.into(); @@ -57,11 +60,7 @@ impl File { }; let (state, checksum) = State::from_bytes(&data, mtime, object_hash, options)?; - let mut file = File { - state, - path, - checksum: Some(checksum), - }; + let mut file = File { state, path, checksum }; if let Some(mut link) = file.link.take() { link.dissolve_into(&mut file, object_hash, options)?; } @@ -72,7 +71,7 @@ impl File { /// Consume `state` and pretend it was read from `path`, setting our checksum to `null`. /// /// `File` instances created like that should be written to disk to set the correct checksum via `[File::write()]`. - pub fn from_state(state: crate::State, path: impl Into) -> Self { + pub fn from_state(state: State, path: impl Into) -> Self { File { state, path: path.into(), diff --git a/gix-index/src/file/verify.rs b/gix-index/src/file/verify.rs index a9680845c0e..3890acd9524 100644 --- a/gix-index/src/file/verify.rs +++ b/gix-index/src/file/verify.rs @@ -14,8 +14,6 @@ mod error { actual: gix_hash::ObjectId, expected: gix_hash::ObjectId, }, - #[error("Checksum of in-memory index wasn't computed yet")] - NoChecksum, } } pub use error::Error; @@ -24,19 +22,22 @@ impl File { /// Verify the integrity of the index to assure its consistency. pub fn verify_integrity(&self) -> Result<(), Error> { let _span = gix_features::trace::coarse!("gix_index::File::verify_integrity()"); - let checksum = self.checksum.ok_or(Error::NoChecksum)?; - let num_bytes_to_hash = self.path.metadata()?.len() - checksum.as_bytes().len() as u64; - let should_interrupt = AtomicBool::new(false); - let actual = gix_features::hash::bytes_of_file( - &self.path, - num_bytes_to_hash as usize, - checksum.kind(), - &mut gix_features::progress::Discard, - &should_interrupt, - )?; - (actual == checksum).then_some(()).ok_or(Error::ChecksumMismatch { - actual, - expected: checksum, - }) + if let Some(checksum) = self.checksum { + let num_bytes_to_hash = self.path.metadata()?.len() - checksum.as_bytes().len() as u64; + let should_interrupt = AtomicBool::new(false); + let actual = gix_features::hash::bytes_of_file( + &self.path, + num_bytes_to_hash as usize, + checksum.kind(), + &mut gix_features::progress::Discard, + &should_interrupt, + )?; + (actual == checksum).then_some(()).ok_or(Error::ChecksumMismatch { + actual, + expected: checksum, + }) + } else { + Ok(()) + } } } diff --git a/gix-index/tests/fixtures/loose_index/skip_hash.git-index b/gix-index/tests/fixtures/loose_index/skip_hash.git-index new file mode 100644 index 0000000000000000000000000000000000000000..8a755bd4d6c6cedebf6877d9c8f6d07caf3c327d GIT binary patch literal 97 zcmZ?q402{*U|<4bhL9jvS0E+HV4z^Y<=qr}%;|LA&IJiiy?$$ literal 0 HcmV?d00001 diff --git a/gix-index/tests/index/file/read.rs b/gix-index/tests/index/file/read.rs index 5cbae8b7bc3..d6fd6b78757 100644 --- a/gix-index/tests/index/file/read.rs +++ b/gix-index/tests/index/file/read.rs @@ -75,6 +75,28 @@ fn v2_empty() { assert!(tree.name.is_empty()); assert!(tree.children.is_empty()); assert_eq!(tree.id, hex_to_id("4b825dc642cb6eb9a060e54bf8d69288fbee4904")); + assert_eq!( + file.checksum(), + Some(hex_to_id("72d53f787d86a932a25a8537cee236d81846a8f1")), + "checksums are read but not validated by default" + ); +} + +#[test] +fn v2_empty_skip_hash() { + let file = loose_file("skip_hash"); + assert_eq!(file.version(), Version::V2); + assert_eq!(file.entries().len(), 0); + let tree = file.tree().unwrap(); + assert_eq!(tree.num_entries.unwrap_or_default(), 0); + assert!(tree.name.is_empty()); + assert!(tree.children.is_empty()); + assert_eq!(tree.id, hex_to_id("4b825dc642cb6eb9a060e54bf8d69288fbee4904")); + assert_eq!( + file.checksum(), + None, + "unset checksums are represented in the type system" + ); } #[test] From 773b6e3d5b69f819805fc77e963ec2a059bf40be Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Sun, 27 Aug 2023 13:37:54 +0200 Subject: [PATCH 0035/1077] add more configuration variables prior to potentially using them; remove `index.skipHash` --- src/plumbing/progress.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/plumbing/progress.rs b/src/plumbing/progress.rs index 08c3e70f607..21b56fa71d8 100644 --- a/src/plumbing/progress.rs +++ b/src/plumbing/progress.rs @@ -173,7 +173,7 @@ static GIT_CONFIG: &[Record] = &[ usage: NotApplicable {reason: "parallelism is efficient enough to always run with benefit"}, }, Record { - config: "feature.manyFile", + config: "feature.manyFiles", usage: Planned {note: Some("big repositories are on the roadmap")}, }, Record { @@ -196,10 +196,6 @@ static GIT_CONFIG: &[Record] = &[ config: "index.sparse", usage: Planned {note: Some("we can read sparse indices and support for it will be added early on")}, }, - Record { - config: "index.skipHash", - usage: Planned {note: Some("important to not unnecessarily reject indices just because they are missing a hash (or it is null)")}, - }, Record { config: "merge.renormalize", usage: Planned {note: Some("once merging is being implemented, renormalization should be respected")}, @@ -504,6 +500,10 @@ static GIT_CONFIG: &[Record] = &[ config: "status.renames", usage: Planned { note: Some("the same as diff.renames") } }, + Record { + config: "transfer.credentialsInUrl", + usage: Planned { note: Some("currently we are likely to expose passwords in errors or in other places, and it's better to by default not do that") } + }, Record { config: "diff.*.textconv", usage: Planned { note: None } From d3ac691446c9d029eb4f04d111887fa06720939d Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Sun, 27 Aug 2023 15:33:34 +0200 Subject: [PATCH 0036/1077] refactor: both `ein` and `gix` now share some code via the `gitoxide` library. (#992) This can slightly improve compile times as well, even though it wasn't measured. --- src/ein.rs | 5 +--- src/lib.rs | 6 ++++- src/plumbing/main.rs | 4 +-- src/plumbing/options/free.rs | 2 +- src/plumbing/options/mod.rs | 26 +++++++++---------- src/porcelain/main.rs | 16 +++++------- src/porcelain/options.rs | 4 +-- .../panic-behaviour/expected-failure | 2 +- .../expected-failure-in-thread | 2 +- .../expected-failure-in-thread-with-progress | 2 +- 10 files changed, 34 insertions(+), 35 deletions(-) diff --git a/src/ein.rs b/src/ein.rs index bfb4ba4716d..ebcfa5a9965 100644 --- a/src/ein.rs +++ b/src/ein.rs @@ -1,11 +1,8 @@ #![deny(rust_2018_idioms, unsafe_code)] mod porcelain; -mod shared; -use anyhow::Result; - -fn main() -> Result<()> { +fn main() -> anyhow::Result<()> { porcelain::main() } diff --git a/src/lib.rs b/src/lib.rs index 3f478012391..9a3286676da 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -20,5 +20,9 @@ cfg_attr(doc, doc = ::document_features::document_features!()) )] #![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg))] -#![deny(rust_2018_idioms, missing_docs)] +#![deny(rust_2018_idioms)] +#![allow(missing_docs)] #![forbid(unsafe_code)] + +/// everything in common beteween the `gix` and `ein` binaries. +pub mod shared; diff --git a/src/plumbing/main.rs b/src/plumbing/main.rs index 38b6ba261b8..6383bc195bc 100644 --- a/src/plumbing/main.rs +++ b/src/plumbing/main.rs @@ -26,7 +26,7 @@ use crate::{ #[cfg(feature = "gitoxide-core-async-client")] pub mod async_util { - use crate::shared::ProgressRange; + use gitoxide::shared::ProgressRange; #[cfg(not(feature = "prodash-render-line"))] compile_error!("BUG: Need at least a line renderer in async mode"); @@ -39,7 +39,7 @@ pub mod async_util { Option, gix_features::progress::DoOrDiscard, ) { - use crate::shared::{self, STANDARD_RANGE}; + use gitoxide::shared::{self, STANDARD_RANGE}; shared::init_env_logger(); if verbose { diff --git a/src/plumbing/options/free.rs b/src/plumbing/options/free.rs index 9f945c5c640..625204bcf80 100644 --- a/src/plumbing/options/free.rs +++ b/src/plumbing/options/free.rs @@ -39,7 +39,7 @@ pub mod index { #[derive(Debug, clap::Parser)] pub struct Platform { /// The object format to assume when reading files that don't inherently know about it, or when writing files. - #[clap(long, default_value_t = gix::hash::Kind::default(), value_parser = crate::shared::AsHashKind)] + #[clap(long, default_value_t = gix::hash::Kind::default(), value_parser = gitoxide::shared::AsHashKind)] pub object_hash: gix::hash::Kind, /// The path to the index file. diff --git a/src/plumbing/options/mod.rs b/src/plumbing/options/mod.rs index 048bc60a6e9..0ff3c1980d3 100644 --- a/src/plumbing/options/mod.rs +++ b/src/plumbing/options/mod.rs @@ -16,7 +16,7 @@ pub struct Args { /// /// For example, if `key` is `core.abbrev`, set configuration like `[core] abbrev = key`, /// or `remote.origin.url = foo` to set `[remote "origin"] url = foo`. - #[clap(long, short = 'c', value_parser = crate::shared::AsBString)] + #[clap(long, short = 'c', value_parser = gitoxide::shared::AsBString)] pub config: Vec, #[clap(long, short = 't')] @@ -63,12 +63,12 @@ pub struct Args { long, short = 'f', default_value = "human", - value_parser = crate::shared::AsOutputFormat + value_parser = gitoxide::shared::AsOutputFormat )] pub format: core::OutputFormat, /// The object format to assume when reading files that don't inherently know about it, or when writing files. - #[clap(long, default_value_t = gix::hash::Kind::default(), value_parser = crate::shared::AsHashKind)] + #[clap(long, default_value_t = gix::hash::Kind::default(), value_parser = gitoxide::shared::AsHashKind)] pub object_hash: gix::hash::Kind, #[clap(subcommand)] @@ -237,7 +237,7 @@ pub mod config { /// /// Typical filters are `branch` or `remote.origin` or `remote.or*` - git-style globs are supported /// and comparisons are case-insensitive. - #[clap(value_parser = crate::shared::AsBString)] + #[clap(value_parser = gitoxide::shared::AsBString)] pub filter: Vec, } } @@ -276,7 +276,7 @@ pub mod fetch { pub remote: Option, /// Override the built-in and configured ref-specs with one or more of the given ones. - #[clap(value_parser = crate::shared::AsBString)] + #[clap(value_parser = gitoxide::shared::AsBString)] pub ref_spec: Vec, } @@ -291,11 +291,11 @@ pub mod fetch { pub deepen: Option, /// Cutoff all history past the given date. Can be combined with shallow-exclude. - #[clap(long, help_heading = Some("SHALLOW"), value_parser = crate::shared::AsTime, value_name = "DATE", conflicts_with_all = ["depth", "deepen", "unshallow"])] + #[clap(long, help_heading = Some("SHALLOW"), value_parser = gitoxide::shared::AsTime, value_name = "DATE", conflicts_with_all = ["depth", "deepen", "unshallow"])] pub shallow_since: Option, /// Cutoff all history past the tag-name or ref-name. Can be combined with shallow-since. - #[clap(long, help_heading = Some("SHALLOW"), value_parser = crate::shared::AsPartialRefName, value_name = "REF_NAME", conflicts_with_all = ["depth", "deepen", "unshallow"])] + #[clap(long, help_heading = Some("SHALLOW"), value_parser = gitoxide::shared::AsPartialRefName, value_name = "REF_NAME", conflicts_with_all = ["depth", "deepen", "unshallow"])] pub shallow_exclude: Vec, /// Remove the shallow boundary and fetch the entire history available on the remote. @@ -362,11 +362,11 @@ pub mod clone { pub depth: Option, /// Cutoff all history past the given date. Can be combined with shallow-exclude. - #[clap(long, help_heading = Some("SHALLOW"), value_parser = crate::shared::AsTime, value_name = "DATE")] + #[clap(long, help_heading = Some("SHALLOW"), value_parser = gitoxide::shared::AsTime, value_name = "DATE")] pub shallow_since: Option, /// Cutoff all history past the tag-name or ref-name. Can be combined with shallow-since. - #[clap(long, help_heading = Some("SHALLOW"), value_parser = crate::shared::AsPartialRefName, value_name = "REF_NAME")] + #[clap(long, help_heading = Some("SHALLOW"), value_parser = gitoxide::shared::AsPartialRefName, value_name = "REF_NAME")] pub shallow_exclude: Vec, } @@ -418,7 +418,7 @@ pub mod remote { #[clap(long, short = 'u')] show_unmapped_remote_refs: bool, /// Override the built-in and configured ref-specs with one or more of the given ones. - #[clap(value_parser = crate::shared::AsBString)] + #[clap(value_parser = gitoxide::shared::AsBString)] ref_spec: Vec, }, } @@ -594,7 +594,7 @@ pub mod revision { pub mod attributes { use gix::bstr::BString; - use crate::shared::CheckPathSpec; + use gitoxide::shared::CheckPathSpec; #[derive(Debug, clap::Subcommand)] pub enum Subcommands { @@ -625,7 +625,7 @@ pub mod exclude { use gix::bstr::BString; - use crate::shared::CheckPathSpec; + use gitoxide::shared::CheckPathSpec; #[derive(Debug, clap::Subcommand)] pub enum Subcommands { @@ -656,7 +656,7 @@ pub mod index { use gix::bstr::BString; - use crate::shared::CheckPathSpec; + use gitoxide::shared::CheckPathSpec; pub mod entries { #[derive(Default, Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, clap::ValueEnum)] diff --git a/src/porcelain/main.rs b/src/porcelain/main.rs index abd21e1cf67..6f7224e2b98 100644 --- a/src/porcelain/main.rs +++ b/src/porcelain/main.rs @@ -7,10 +7,8 @@ use anyhow::Result; use clap::Parser; use gitoxide_core as core; -use crate::{ - porcelain::options::{Args, Subcommands}, - shared::pretty::prepare_and_run, -}; +use crate::porcelain::options::{Args, Subcommands}; +use gitoxide::shared::pretty::prepare_and_run; pub fn main() -> Result<()> { let args: Args = Args::parse_from(gix::env::args_os()); @@ -39,7 +37,7 @@ pub fn main() -> Result<()> { verbose, progress, progress_keep_open, - crate::shared::STANDARD_RANGE, + gitoxide::shared::STANDARD_RANGE, move |_progress, _out, _err| panic!("something went very wrong"), ), Subcommands::Init { directory } => core::repository::init(directory).map(|_| ()), @@ -59,7 +57,7 @@ pub fn main() -> Result<()> { verbose, progress, progress_keep_open, - crate::shared::STANDARD_RANGE, + gitoxide::shared::STANDARD_RANGE, move |mut progress, out, mut err| { let engine = query::prepare( &repo_dir, @@ -99,7 +97,7 @@ pub fn main() -> Result<()> { verbose, progress, progress_keep_open, - crate::shared::STANDARD_RANGE, + gitoxide::shared::STANDARD_RANGE, move |progress, out, _err| { hours::estimate( &working_dir, @@ -126,7 +124,7 @@ pub fn main() -> Result<()> { verbose, progress, progress_keep_open, - crate::shared::STANDARD_RANGE, + gitoxide::shared::STANDARD_RANGE, move |progress, out, _err| { organize::discover( root.unwrap_or_else(|| [std::path::Component::CurDir].iter().collect()), @@ -150,7 +148,7 @@ pub fn main() -> Result<()> { verbose, progress, progress_keep_open, - crate::shared::STANDARD_RANGE, + gitoxide::shared::STANDARD_RANGE, move |progress, _out, _err| { organize::run( if execute { diff --git a/src/porcelain/options.rs b/src/porcelain/options.rs index 7c583fe4ced..32533ad890f 100644 --- a/src/porcelain/options.rs +++ b/src/porcelain/options.rs @@ -116,7 +116,7 @@ pub mod tools { #[cfg(feature = "gitoxide-core-tools-query")] pub mod query { - use crate::shared::AsPathSpec; + use gitoxide::shared::AsPathSpec; #[derive(Debug, clap::Subcommand)] pub enum Command { @@ -143,7 +143,7 @@ pub mod tools { #[clap(default_value = ".")] pub working_dir: PathBuf, /// The name of the revision as spec, like 'HEAD' or 'main' at which to start iterating the commit graph. - #[clap(default_value("HEAD"), value_parser = crate::shared::AsBString)] + #[clap(default_value("HEAD"), value_parser = gitoxide::shared::AsBString)] pub rev_spec: BString, /// Ignore github bots which match the `[bot]` search string. #[clap(short = 'b', long)] diff --git a/tests/snapshots/panic-behaviour/expected-failure b/tests/snapshots/panic-behaviour/expected-failure index c09ee20e7bb..1dafa93b97b 100644 --- a/tests/snapshots/panic-behaviour/expected-failure +++ b/tests/snapshots/panic-behaviour/expected-failure @@ -1,2 +1,2 @@ -thread 'main' panicked at 'something went very wrong', src/porcelain/main.rs:43:42 +thread 'main' panicked at 'something went very wrong', src/porcelain/main.rs:41:42 note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace \ No newline at end of file diff --git a/tests/snapshots/panic-behaviour/expected-failure-in-thread b/tests/snapshots/panic-behaviour/expected-failure-in-thread index 3c81842d3fe..b99a2650670 100644 --- a/tests/snapshots/panic-behaviour/expected-failure-in-thread +++ b/tests/snapshots/panic-behaviour/expected-failure-in-thread @@ -1,3 +1,3 @@ -thread 'main' panicked at 'something went very wrong', src/porcelain/main.rs:43:42 +thread 'main' panicked at 'something went very wrong', src/porcelain/main.rs:41:42 note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace  \ No newline at end of file diff --git a/tests/snapshots/panic-behaviour/expected-failure-in-thread-with-progress b/tests/snapshots/panic-behaviour/expected-failure-in-thread-with-progress index c1649532e46..c892c1ea47d 100644 --- a/tests/snapshots/panic-behaviour/expected-failure-in-thread-with-progress +++ b/tests/snapshots/panic-behaviour/expected-failure-in-thread-with-progress @@ -1,3 +1,3 @@ -[?1049h[?25lthread '' panicked at 'something went very wrong', src/porcelain/main.rs:43:42 +[?1049h[?25lthread '' panicked at 'something went very wrong', src/porcelain/main.rs:41:42 note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace [?25h[?1049l \ No newline at end of file From 2f42132410ef47a7c274030811452ef40701c8a0 Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Sun, 27 Aug 2023 16:07:25 +0200 Subject: [PATCH 0037/1077] feat: add support for `write::Options::skip_hash`. With it, a hash will not be produced for indices. --- gix-index/src/file/write.rs | 27 ++++++++++++--------- gix-index/src/write.rs | 17 +++++++++++-- gix-index/tests/index/file/write.rs | 37 ++++++++++++++++++++++++++++- 3 files changed, 67 insertions(+), 14 deletions(-) diff --git a/gix-index/src/file/write.rs b/gix-index/src/file/write.rs index 1e8afc07dc5..47a4cde9661 100644 --- a/gix-index/src/file/write.rs +++ b/gix-index/src/file/write.rs @@ -22,23 +22,28 @@ impl File { mut out: impl std::io::Write, options: write::Options, ) -> std::io::Result<(Version, gix_hash::ObjectId)> { - let mut hasher = hash::Write::new(&mut out, self.state.object_hash); - let version = self.state.write_to(&mut hasher, options)?; - - let hash = hasher.hash.digest(); - out.write_all(&hash)?; - Ok((version, gix_hash::ObjectId::from(hash))) + let (version, hash) = if options.skip_hash { + let out: &mut dyn std::io::Write = &mut out; + let version = self.state.write_to(out, options)?; + (version, self.state.object_hash.null()) + } else { + let mut hasher = hash::Write::new(&mut out, self.state.object_hash); + let out: &mut dyn std::io::Write = &mut hasher; + let version = self.state.write_to(out, options)?; + (version, gix_hash::ObjectId::from(hasher.hash.digest())) + }; + out.write_all(hash.as_slice())?; + Ok((version, hash)) } /// Write ourselves to the path we were read from after acquiring a lock, using `options`. /// /// Note that the hash produced will be stored which is why we need to be mutable. pub fn write(&mut self, options: write::Options) -> Result<(), Error> { - let mut lock = std::io::BufWriter::new(gix_lock::File::acquire_to_update_resource( - &self.path, - gix_lock::acquire::Fail::Immediately, - None, - )?); + let mut lock = std::io::BufWriter::with_capacity( + 64 * 1024, + gix_lock::File::acquire_to_update_resource(&self.path, gix_lock::acquire::Fail::Immediately, None)?, + ); let (version, digest) = self.write_to(&mut lock, options)?; match lock.into_inner() { Ok(lock) => lock.commit()?, diff --git a/gix-index/src/write.rs b/gix-index/src/write.rs index 29066a35e9a..2050ed80941 100644 --- a/gix-index/src/write.rs +++ b/gix-index/src/write.rs @@ -48,13 +48,26 @@ impl Extensions { /// Note that default options write either index V2 or V3 depending on the content of the entries. #[derive(Debug, Default, Clone, Copy)] pub struct Options { - /// Configures which extensions to write + /// Configures which extensions to write. pub extensions: Extensions, + /// Set the trailing hash of the produced index to all zeroes to save some time. + /// + /// This value is typically controlled by `index.skipHash` and is respected when the index is written + /// via [`File::write()`](crate::File::write()) and [`File::write_to()`](crate::File::write_to()). + /// Note that + pub skip_hash: bool, } impl State { /// Serialize this instance to `out` with [`options`][Options]. - pub fn write_to(&self, out: impl std::io::Write, Options { extensions }: Options) -> std::io::Result { + pub fn write_to( + &self, + out: impl std::io::Write, + Options { + extensions, + skip_hash: _, + }: Options, + ) -> std::io::Result { let _span = gix_features::trace::detail!("gix_index::State::write()"); let version = self.detect_required_version(); diff --git a/gix-index/tests/index/file/write.rs b/gix-index/tests/index/file/write.rs index 42646042491..ad418c0f3d0 100644 --- a/gix-index/tests/index/file/write.rs +++ b/gix-index/tests/index/file/write.rs @@ -37,6 +37,37 @@ fn roundtrips() -> crate::Result { Ok(()) } +#[test] +fn skip_hash() -> crate::Result { + let tmp = gix_testtools::tempfile::TempDir::new()?; + let path = tmp.path().join("index"); + let mut expected = Loose("conflicting-file").open(); + assert!(expected.checksum().is_some()); + + expected.set_path(&path); + expected.write(Options { + extensions: Default::default(), + skip_hash: false, + })?; + + let actual = gix_index::File::at(&path, expected.checksum().expect("present").kind(), Default::default())?; + assert_eq!( + actual.checksum(), + expected.checksum(), + "a hash is written by default and it matches" + ); + + expected.write(Options { + extensions: Default::default(), + skip_hash: true, + })?; + + let actual = gix_index::File::at(&path, expected.checksum().expect("present").kind(), Default::default())?; + assert_eq!(actual.checksum(), None, "no hash is produced in this case"); + + Ok(()) +} + #[test] fn roundtrips_sparse_index() -> crate::Result { // NOTE: I initially tried putting these fixtures into the main roundtrip test above, @@ -253,9 +284,13 @@ fn only_tree_ext() -> Options { end_of_index_entry: false, tree_cache: true, }, + skip_hash: false, } } fn options_with(extensions: write::Extensions) -> Options { - Options { extensions } + Options { + extensions, + skip_hash: false, + } } From 3ff5ac0cda9e3e089dc79fdfbff5ff619ee60b1f Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Sun, 27 Aug 2023 17:03:47 +0200 Subject: [PATCH 0038/1077] feat: `gix free index from-list` and `gix index from-tree` gain `--skip-hash`. This flag can be derived from options, but thus far we have no higher-level writing of the index so this has to do to see the difference in performance. --- gitoxide-core/src/repository/index/mod.rs | 27 ++++++++++++++++------- src/plumbing/main.rs | 14 ++++++++++-- src/plumbing/options/free.rs | 3 +++ src/plumbing/options/mod.rs | 3 +++ 4 files changed, 37 insertions(+), 10 deletions(-) diff --git a/gitoxide-core/src/repository/index/mod.rs b/gitoxide-core/src/repository/index/mod.rs index 17ba656b16f..63b359e331a 100644 --- a/gitoxide-core/src/repository/index/mod.rs +++ b/gitoxide-core/src/repository/index/mod.rs @@ -1,19 +1,23 @@ use std::{ffi::OsString, path::PathBuf}; use anyhow::bail; -use gix::prelude::FindExt; pub fn from_tree( + repo: gix::Repository, mut spec: OsString, index_path: Option, force: bool, - repo: gix::Repository, + skip_hash: bool, ) -> anyhow::Result<()> { spec.push("^{tree}"); let spec = gix::path::os_str_into_bstr(&spec)?; let tree = repo.rev_parse_single(spec)?; - let index = gix::index::State::from_tree(&tree, |oid, buf| repo.objects.find_tree_iter(oid, buf).ok())?; - let options = gix::index::write::Options::default(); + + let mut index = repo.index_from_tree(&tree)?; + let options = gix::index::write::Options { + skip_hash, + ..Default::default() + }; match index_path { Some(index_path) => { @@ -23,11 +27,10 @@ pub fn from_tree( index_path.display() ); } - let mut index = gix::index::File::from_state(index, index_path); + index.set_path(index_path); index.write(options)?; } None => { - let index = gix::index::File::from_state(index, std::path::PathBuf::new()); let mut out = Vec::with_capacity(512 * 1024); index.write_to(&mut out, options)?; } @@ -36,7 +39,12 @@ pub fn from_tree( Ok(()) } -pub fn from_list(entries_file: PathBuf, index_path: Option, force: bool) -> anyhow::Result<()> { +pub fn from_list( + entries_file: PathBuf, + index_path: Option, + force: bool, + skip_hash: bool, +) -> anyhow::Result<()> { use std::io::BufRead; let object_hash = gix::hash::Kind::Sha1; @@ -57,7 +65,10 @@ pub fn from_list(entries_file: PathBuf, index_path: Option, force: bool } index.sort_entries(); - let options = gix::index::write::Options::default(); + let options = gix::index::write::Options { + skip_hash, + ..Default::default() + }; match index_path { Some(index_path) => { if index_path.is_file() && !force { diff --git a/src/plumbing/main.rs b/src/plumbing/main.rs index 6383bc195bc..542fb402b4f 100644 --- a/src/plumbing/main.rs +++ b/src/plumbing/main.rs @@ -447,6 +447,7 @@ pub fn main() -> Result<()> { free::index::Subcommands::FromList { force, index_output_path, + skip_hash, file, } => prepare_and_run( "index-from-list", @@ -455,7 +456,9 @@ pub fn main() -> Result<()> { progress, progress_keep_open, None, - move |_progress, _out, _err| core::repository::index::from_list(file, index_output_path, force), + move |_progress, _out, _err| { + core::repository::index::from_list(file, index_output_path, force, skip_hash) + }, ), free::index::Subcommands::CheckoutExclusive { directory, @@ -1164,6 +1167,7 @@ pub fn main() -> Result<()> { index::Subcommands::FromTree { force, index_output_path, + skip_hash, spec, } => prepare_and_run( "index-from-tree", @@ -1173,7 +1177,13 @@ pub fn main() -> Result<()> { progress_keep_open, None, move |_progress, _out, _err| { - core::repository::index::from_tree(spec, index_output_path, force, repository(Mode::Strict)?) + core::repository::index::from_tree( + repository(Mode::Strict)?, + spec, + index_output_path, + force, + skip_hash, + ) }, ), }, diff --git a/src/plumbing/options/free.rs b/src/plumbing/options/free.rs index 625204bcf80..64aa443d4de 100644 --- a/src/plumbing/options/free.rs +++ b/src/plumbing/options/free.rs @@ -63,6 +63,9 @@ pub mod index { /// back by default, but that requires us to write more of the index to work. #[clap(long, short = 'i')] index_output_path: Option, + /// Don't write the trailing hash for a performance gain. + #[clap(long, short = 's')] + skip_hash: bool, /// The file to read the index entries from, one path per line. file: PathBuf, }, diff --git a/src/plumbing/options/mod.rs b/src/plumbing/options/mod.rs index 0ff3c1980d3..54a6d8db3c8 100644 --- a/src/plumbing/options/mod.rs +++ b/src/plumbing/options/mod.rs @@ -705,6 +705,9 @@ pub mod index { /// back by default, but that requires us to write more of the index to work. #[clap(long, short = 'i')] index_output_path: Option, + /// Don't write the trailing hash for a performance gain. + #[clap(long, short = 's')] + skip_hash: bool, /// A revspec that points to the to generate the index from. spec: std::ffi::OsString, }, From 61c2e34b10c2ad5c92edd4ec1d5d1be2317ac481 Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Sun, 27 Aug 2023 19:37:28 +0200 Subject: [PATCH 0039/1077] feat!: Check the hash when reading via `File::at()` just like `git`, or skip the check. Note that indices written with `index.skipHash=true` will be vastly faster to read by a factor of 2 or more. --- gix-index/src/access/mod.rs | 2 +- gix-index/src/extension/link.rs | 2 ++ gix-index/src/file/init.rs | 49 +++++++++++++++++++++++++---- gix-index/tests/index/file/init.rs | 4 ++- gix-index/tests/index/file/read.rs | 18 ++++++++--- gix-index/tests/index/file/write.rs | 14 +++++++-- gix-index/tests/index/mod.rs | 2 +- 7 files changed, 76 insertions(+), 15 deletions(-) diff --git a/gix-index/src/access/mod.rs b/gix-index/src/access/mod.rs index 26990f495e1..3aaa1ca5ca0 100644 --- a/gix-index/src/access/mod.rs +++ b/gix-index/src/access/mod.rs @@ -344,7 +344,7 @@ mod tests { let file = PathBuf::from("tests") .join("fixtures") .join(Path::new("loose_index").join("conflicting-file.git-index")); - let file = crate::File::at(file, gix_hash::Kind::Sha1, Default::default()).expect("valid file"); + let file = crate::File::at(file, gix_hash::Kind::Sha1, false, Default::default()).expect("valid file"); assert_eq!( file.entries().len(), 3, diff --git a/gix-index/src/extension/link.rs b/gix-index/src/extension/link.rs index 20ce9cb217c..5fed2f960a4 100644 --- a/gix-index/src/extension/link.rs +++ b/gix-index/src/extension/link.rs @@ -72,6 +72,7 @@ impl Link { self, split_index: &mut crate::File, object_hash: gix_hash::Kind, + skip_hash: bool, options: crate::decode::Options, ) -> Result<(), crate::file::init::Error> { let shared_index_path = split_index @@ -82,6 +83,7 @@ impl Link { let mut shared_index = crate::File::at( &shared_index_path, object_hash, + skip_hash, crate::decode::Options { expected_checksum: self.shared_index_checksum.into(), ..options diff --git a/gix-index/src/file/init.rs b/gix-index/src/file/init.rs index 1448de3dd4a..68c6c14a356 100644 --- a/gix-index/src/file/init.rs +++ b/gix-index/src/file/init.rs @@ -26,16 +26,18 @@ pub use error::Error; /// Initialization impl File { /// Try to open the index file at `path` with `options`, assuming `object_hash` is used throughout the file, or create a new - /// index that merely exists in memory and is empty. + /// index that merely exists in memory and is empty. `skip_hash` will increase the performance by a factor of 2, at the cost of + /// possibly not detecting corruption. /// /// Note that the `path` will not be written if it doesn't exist. pub fn at_or_default( path: impl Into, object_hash: gix_hash::Kind, + skip_hash: bool, options: decode::Options, ) -> Result { let path = path.into(); - Ok(match Self::at(&path, object_hash, options) { + Ok(match Self::at(&path, object_hash, skip_hash, options) { Ok(f) => f, Err(Error::Io(err)) if err.kind() == std::io::ErrorKind::NotFound => { File::from_state(State::new(object_hash), path) @@ -44,25 +46,60 @@ impl File { }) } - /// Open an index file at `path` with `options`, assuming `object_hash` is used throughout the file. + /// Open an index file at `path` with `options`, assuming `object_hash` is used throughout the file. If `skip_hash` is `true`, + /// we will not get or compare the checksum of the index at all, which generally increases performance of this method by a factor + /// of 2 or more. /// /// Note that the verification of the file hash depends on `options`, and even then it's performed after the file was read and not /// before it is read. That way, invalid files would see a more descriptive error message as we try to parse them. - pub fn at(path: impl Into, object_hash: gix_hash::Kind, options: decode::Options) -> Result { + pub fn at( + path: impl Into, + object_hash: gix_hash::Kind, + skip_hash: bool, + options: decode::Options, + ) -> Result { let _span = gix_features::trace::detail!("gix_index::File::at()"); let path = path.into(); let (data, mtime) = { - // SAFETY: we have to take the risk of somebody changing the file underneath. Git never writes into the same file. let file = std::fs::File::open(&path)?; + // SAFETY: we have to take the risk of somebody changing the file underneath. Git never writes into the same file. #[allow(unsafe_code)] let data = unsafe { Mmap::map(&file)? }; + + if !skip_hash { + // Note that even though it's trivial to offload this into a thread, which is worth it for all but the smallest + // index files, we choose more safety here just like git does and don't even try to decode the index if the hashes + // don't match. + // Thanks to `skip_hash`, we can get performance and it's under caller control, at the cost of some safety. + let expected = gix_hash::ObjectId::from(&data[data.len() - object_hash.len_in_bytes()..]); + if !expected.is_null() { + let _span = gix_features::trace::detail!("gix::open_index::hash_index", path = ?path); + let meta = file.metadata()?; + let num_bytes_to_hash = meta.len() - object_hash.len_in_bytes() as u64; + let actual_hash = gix_features::hash::bytes( + &file, + num_bytes_to_hash as usize, + object_hash, + &mut gix_features::progress::Discard, + &Default::default(), + )?; + + if actual_hash != expected { + return Err(Error::Decode(decode::Error::ChecksumMismatch { + actual_checksum: actual_hash, + expected_checksum: expected, + })); + } + } + } + (data, filetime::FileTime::from_last_modification_time(&file.metadata()?)) }; let (state, checksum) = State::from_bytes(&data, mtime, object_hash, options)?; let mut file = File { state, path, checksum }; if let Some(mut link) = file.link.take() { - link.dissolve_into(&mut file, object_hash, options)?; + link.dissolve_into(&mut file, object_hash, skip_hash, options)?; } Ok(file) diff --git a/gix-index/tests/index/file/init.rs b/gix-index/tests/index/file/init.rs index 3695df73d0c..063640497e1 100644 --- a/gix-index/tests/index/file/init.rs +++ b/gix-index/tests/index/file/init.rs @@ -6,6 +6,7 @@ mod at_or_new { gix_index::File::at_or_default( Generated("v4_more_files_IEOT").to_path(), gix_hash::Kind::Sha1, + false, Default::default(), ) .expect("file exists and can be opened"); @@ -16,6 +17,7 @@ mod at_or_new { let index = gix_index::File::at_or_default( "__definitely no file that exists ever__", gix_hash::Kind::Sha1, + false, Default::default(), ) .expect("file is defaulting to a new one"); @@ -46,7 +48,7 @@ mod from_state { let new_index_path = tmp.path().join(fixture.to_name()); assert!(!new_index_path.exists()); - let index = gix_index::File::at(fixture.to_path(), gix_hash::Kind::Sha1, Default::default())?; + let index = gix_index::File::at(fixture.to_path(), gix_hash::Kind::Sha1, false, Default::default())?; let mut index = gix_index::File::from_state(index.into(), new_index_path.clone()); assert!(index.checksum().is_none()); assert_eq!(index.path(), new_index_path); diff --git a/gix-index/tests/index/file/read.rs b/gix-index/tests/index/file/read.rs index d6fd6b78757..ae2b7ace9dc 100644 --- a/gix-index/tests/index/file/read.rs +++ b/gix-index/tests/index/file/read.rs @@ -19,13 +19,14 @@ fn verify(index: gix_index::File) -> gix_index::File { pub(crate) fn loose_file(name: &str) -> gix_index::File { let path = loose_file_path(name); - let file = gix_index::File::at(path, gix_hash::Kind::Sha1, Default::default()).unwrap(); + let file = gix_index::File::at(path, gix_hash::Kind::Sha1, false, Default::default()).unwrap(); verify(file) } pub(crate) fn try_file(name: &str) -> Result { let file = gix_index::File::at( crate::fixture_index_path(name), gix_hash::Kind::Sha1, + false, Default::default(), )?; Ok(verify(file)) @@ -34,7 +35,7 @@ pub(crate) fn file(name: &str) -> gix_index::File { try_file(name).unwrap() } fn file_opt(name: &str, opts: gix_index::decode::Options) -> gix_index::File { - let file = gix_index::File::at(crate::fixture_index_path(name), gix_hash::Kind::Sha1, opts).unwrap(); + let file = gix_index::File::at(crate::fixture_index_path(name), gix_hash::Kind::Sha1, false, opts).unwrap(); verify(file) } @@ -140,6 +141,7 @@ fn split_index_without_any_extension() { let file = gix_index::File::at( find_shared_index_for(crate::fixture_index_path("v2_split_index")), gix_hash::Kind::Sha1, + false, Default::default(), ) .unwrap(); @@ -337,8 +339,15 @@ fn split_index_and_regular_index_of_same_content_are_indeed_the_same() { ) .unwrap(); - let split = - verify(gix_index::File::at(base.join("split/.git/index"), gix_hash::Kind::Sha1, Default::default()).unwrap()); + let split = verify( + gix_index::File::at( + base.join("split/.git/index"), + gix_hash::Kind::Sha1, + false, + Default::default(), + ) + .unwrap(), + ); assert!( split.link().is_none(), @@ -349,6 +358,7 @@ fn split_index_and_regular_index_of_same_content_are_indeed_the_same() { gix_index::File::at( base.join("regular/.git/index"), gix_hash::Kind::Sha1, + false, Default::default(), ) .unwrap(), diff --git a/gix-index/tests/index/file/write.rs b/gix-index/tests/index/file/write.rs index ad418c0f3d0..b3c01b21de6 100644 --- a/gix-index/tests/index/file/write.rs +++ b/gix-index/tests/index/file/write.rs @@ -50,7 +50,12 @@ fn skip_hash() -> crate::Result { skip_hash: false, })?; - let actual = gix_index::File::at(&path, expected.checksum().expect("present").kind(), Default::default())?; + let actual = gix_index::File::at( + &path, + expected.checksum().expect("present").kind(), + false, + Default::default(), + )?; assert_eq!( actual.checksum(), expected.checksum(), @@ -62,7 +67,12 @@ fn skip_hash() -> crate::Result { skip_hash: true, })?; - let actual = gix_index::File::at(&path, expected.checksum().expect("present").kind(), Default::default())?; + let actual = gix_index::File::at( + &path, + expected.checksum().expect("present").kind(), + false, + Default::default(), + )?; assert_eq!(actual.checksum(), None, "no hash is produced in this case"); Ok(()) diff --git a/gix-index/tests/index/mod.rs b/gix-index/tests/index/mod.rs index ae39f453eb9..5b2c2634ed8 100644 --- a/gix-index/tests/index/mod.rs +++ b/gix-index/tests/index/mod.rs @@ -50,7 +50,7 @@ impl Fixture { } pub fn open(&self) -> gix_index::File { - gix_index::File::at(self.to_path(), gix_hash::Kind::Sha1, Default::default()) + gix_index::File::at(self.to_path(), gix_hash::Kind::Sha1, false, Default::default()) .expect("fixtures are always readable") } } From 713cd59f0b1eff6397b80f1e1fceec278532fd59 Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Sun, 27 Aug 2023 18:31:58 +0200 Subject: [PATCH 0040/1077] adapt to changes in `gix-index` and pass skip-hash through for performance.. --- gitoxide-core/src/index/mod.rs | 2 +- gix-status/tests/status/index_as_worktree.rs | 6 ++++-- gix-worktree-state/tests/state/checkout.rs | 2 +- gix-worktree/tests/worktree/stack/ignore.rs | 2 +- gix/src/config/tree/sections/index.rs | 5 ++++- gix/src/repository/index.rs | 17 ++++++++++++++--- gix/src/worktree/mod.rs | 4 ++++ src/shared.rs | 8 ++++---- 8 files changed, 33 insertions(+), 13 deletions(-) diff --git a/gitoxide-core/src/index/mod.rs b/gitoxide-core/src/index/mod.rs index df75cf541b6..4b6b50b36ef 100644 --- a/gitoxide-core/src/index/mod.rs +++ b/gitoxide-core/src/index/mod.rs @@ -8,7 +8,7 @@ pub struct Options { pub mod information; fn parse_file(index_path: impl AsRef, object_hash: gix::hash::Kind) -> anyhow::Result { - gix::index::File::at(index_path.as_ref(), object_hash, Default::default()).map_err(Into::into) + gix::index::File::at(index_path.as_ref(), object_hash, false, Default::default()).map_err(Into::into) } pub mod checkout_exclusive { diff --git a/gix-status/tests/status/index_as_worktree.rs b/gix-status/tests/status/index_as_worktree.rs index c075f96a0b8..2629c3e1033 100644 --- a/gix-status/tests/status/index_as_worktree.rs +++ b/gix-status/tests/status/index_as_worktree.rs @@ -31,7 +31,8 @@ const TEST_OPTIONS: index::entry::stat::Options = index::entry::stat::Options { fn fixture(name: &str, expected_status: &[(&BStr, Option, bool)]) { let worktree = fixture_path(name); let git_dir = worktree.join(".git"); - let mut index = gix_index::File::at(git_dir.join("index"), gix_hash::Kind::Sha1, Default::default()).unwrap(); + let mut index = + gix_index::File::at(git_dir.join("index"), gix_hash::Kind::Sha1, false, Default::default()).unwrap(); let mut recorder = Recorder::default(); index_as_worktree( &mut index, @@ -139,7 +140,8 @@ fn racy_git() { let worktree = dir.path(); let git_dir = worktree.join(".git"); let fs = gix_fs::Capabilities::probe(&git_dir); - let mut index = gix_index::File::at(git_dir.join("index"), gix_hash::Kind::Sha1, Default::default()).unwrap(); + let mut index = + gix_index::File::at(git_dir.join("index"), gix_hash::Kind::Sha1, false, Default::default()).unwrap(); #[derive(Clone)] struct CountCalls(Arc, FastEq); diff --git a/gix-worktree-state/tests/state/checkout.rs b/gix-worktree-state/tests/state/checkout.rs index 4c2e1f87b5d..9fa590667f0 100644 --- a/gix-worktree-state/tests/state/checkout.rs +++ b/gix-worktree-state/tests/state/checkout.rs @@ -492,7 +492,7 @@ fn checkout_index_in_tmp_dir_opts( ) -> crate::Result<(PathBuf, TempDir, gix_index::File, gix_worktree_state::checkout::Outcome)> { let source_tree = fixture_path(name); let git_dir = source_tree.join(".git"); - let mut index = gix_index::File::at(git_dir.join("index"), gix_hash::Kind::Sha1, Default::default())?; + let mut index = gix_index::File::at(git_dir.join("index"), gix_hash::Kind::Sha1, false, Default::default())?; let odb = gix_odb::at(git_dir.join("objects"))?.into_inner().into_arc()?; let destination = gix_testtools::tempfile::tempdir_in(std::env::current_dir()?)?; prep_dest(destination.path()).expect("preparation must succeed"); diff --git a/gix-worktree/tests/worktree/stack/ignore.rs b/gix-worktree/tests/worktree/stack/ignore.rs index f20092b76b0..9173cb1f5f1 100644 --- a/gix-worktree/tests/worktree/stack/ignore.rs +++ b/gix-worktree/tests/worktree/stack/ignore.rs @@ -89,7 +89,7 @@ fn check_against_baseline() -> crate::Result { // Due to the way our setup differs from gits dynamic stack (which involves trying to read files from disk // by path) we can only test one case baseline, so we require multiple platforms (or filesystems) to run this. let case = probe_case()?; - let mut index = gix_index::File::at(git_dir.join("index"), gix_hash::Kind::Sha1, Default::default())?; + let mut index = gix_index::File::at(git_dir.join("index"), gix_hash::Kind::Sha1, false, Default::default())?; let odb = gix_odb::at(git_dir.join("objects"))?; let state = gix_worktree::stack::State::for_add( Default::default(), diff --git a/gix/src/config/tree/sections/index.rs b/gix/src/config/tree/sections/index.rs index 08f7ec1bd41..026f35b6daf 100644 --- a/gix/src/config/tree/sections/index.rs +++ b/gix/src/config/tree/sections/index.rs @@ -7,6 +7,9 @@ impl Index { /// The `index.threads` key. pub const THREADS: IndexThreads = IndexThreads::new_with_validate("threads", &config::Tree::INDEX, validate::IndexThreads); + /// The `index.skipHash` key. + pub const SKIP_HASH: keys::Boolean = keys::Boolean::new_boolean("skipHash", &config::Tree::INDEX) + .with_deviation("also used to skip the hash when reading, even if a hash exists in the index file"); } /// The `index.threads` key. @@ -47,7 +50,7 @@ impl Section for Index { } fn keys(&self) -> &[&dyn Key] { - &[&Self::THREADS] + &[&Self::THREADS, &Self::SKIP_HASH] } } diff --git a/gix/src/repository/index.rs b/gix/src/repository/index.rs index e823d233e57..a21b138a569 100644 --- a/gix/src/repository/index.rs +++ b/gix/src/repository/index.rs @@ -16,16 +16,27 @@ impl crate::Repository { .map(|value| crate::config::tree::Index::THREADS.try_into_index_threads(value)) .transpose() .with_lenient_default(self.config.lenient_config)?; - gix_index::File::at( + let skip_hash = self + .config + .resolved + .boolean("index", None, "skipHash") + .map(|res| crate::config::tree::Index::SKIP_HASH.enrich_error(res)) + .transpose() + .with_lenient_default(self.config.lenient_config)? + .unwrap_or_default(); + + let index = gix_index::File::at( self.index_path(), self.object_hash(), + skip_hash, gix_index::decode::Options { thread_limit, min_extension_block_in_bytes_for_threading: 0, expected_checksum: None, }, - ) - .map_err(Into::into) + )?; + + Ok(index) } /// Return a shared worktree index which is updated automatically if the in-memory snapshot has become stale as the underlying file diff --git a/gix/src/worktree/mod.rs b/gix/src/worktree/mod.rs index 18be6dc1fe6..c780d8838e5 100644 --- a/gix/src/worktree/mod.rs +++ b/gix/src/worktree/mod.rs @@ -90,7 +90,11 @@ pub mod open_index { #[error(transparent)] ConfigIndexThreads(#[from] crate::config::key::GenericErrorWithValue), #[error(transparent)] + ConfigSkipHash(#[from] crate::config::boolean::Error), + #[error(transparent)] IndexFile(#[from] gix_index::file::init::Error), + #[error(transparent)] + IndexCorrupt(#[from] gix_index::file::verify::Error), } impl<'repo> crate::Worktree<'repo> { diff --git a/src/shared.rs b/src/shared.rs index 892e14c034b..179229af1e4 100644 --- a/src/shared.rs +++ b/src/shared.rs @@ -101,7 +101,7 @@ pub mod pretty { enable: bool, reverse_lines: bool, progress: &gix::progress::prodash::tree::Root, - ) -> anyhow::Result { + ) -> anyhow::Result<()> { Ok(if enable { let processor = tracing_forest::Printer::new().formatter({ let progress = std::sync::Mutex::new(progress.add_child("tracing")); @@ -124,9 +124,9 @@ pub mod pretty { }); use tracing_subscriber::layer::SubscriberExt; let subscriber = tracing_subscriber::Registry::default().with(tracing_forest::ForestLayer::from(processor)); - tracing::subscriber::set_default(subscriber) + tracing::subscriber::set_global_default(subscriber)?; } else { - tracing::subscriber::set_default(tracing_subscriber::Registry::default()) + tracing::subscriber::set_global_default(tracing_subscriber::Registry::default())?; }) } @@ -158,7 +158,7 @@ pub mod pretty { use crate::shared::{self, STANDARD_RANGE}; let progress = shared::progress_tree(); let sub_progress = progress.add_child(name); - let _trace = init_tracing(trace, false, &progress)?; + init_tracing(trace, false, &progress)?; let handle = shared::setup_line_renderer_range(&progress, range.into().unwrap_or(STANDARD_RANGE)); From 0d6d4ec8030d2e8f4c7a9d6f421d54776c4b67fb Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Sun, 27 Aug 2023 20:50:07 +0200 Subject: [PATCH 0041/1077] thanks clippy --- gix/src/lib.rs | 1 + src/shared.rs | 5 +++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/gix/src/lib.rs b/gix/src/lib.rs index 2215695fb47..e68037e9780 100644 --- a/gix/src/lib.rs +++ b/gix/src/lib.rs @@ -71,6 +71,7 @@ )] #![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg))] #![deny(missing_docs, rust_2018_idioms, unsafe_code)] +#![allow(clippy::result_large_err)] // Re-exports to make this a potential one-stop shop crate avoiding people from having to reference various crates themselves. // This also means that their major version changes affect our major version, but that's alright as we directly expose their diff --git a/src/shared.rs b/src/shared.rs index 179229af1e4..550c6c6c5ab 100644 --- a/src/shared.rs +++ b/src/shared.rs @@ -102,7 +102,7 @@ pub mod pretty { reverse_lines: bool, progress: &gix::progress::prodash::tree::Root, ) -> anyhow::Result<()> { - Ok(if enable { + if enable { let processor = tracing_forest::Printer::new().formatter({ let progress = std::sync::Mutex::new(progress.add_child("tracing")); move |tree: &tracing_forest::tree::Tree| -> Result { @@ -127,7 +127,8 @@ pub mod pretty { tracing::subscriber::set_global_default(subscriber)?; } else { tracing::subscriber::set_global_default(tracing_subscriber::Registry::default())?; - }) + } + Ok(()) } #[cfg(not(feature = "small"))] From e7602257662cd9ddb4cfe41ef26cdf28cc007be7 Mon Sep 17 00:00:00 2001 From: Jiahao XU Date: Mon, 28 Aug 2023 22:05:27 +1000 Subject: [PATCH 0042/1077] Manually de-`momo` `Repository::try_find_remote_{without_url_rewrite}` Since the `try_find_remote_inner` is already a separate function, there's no need to use `momo`. Signed-off-by: Jiahao XU --- gix/src/repository/remote.rs | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/gix/src/repository/remote.rs b/gix/src/repository/remote.rs index 2110affbc4e..ebd0f52f3a1 100644 --- a/gix/src/repository/remote.rs +++ b/gix/src/repository/remote.rs @@ -1,8 +1,6 @@ #![allow(clippy::result_large_err)] use std::convert::TryInto; -use gix_macros::momo; - use crate::{bstr::BStr, config, remote, remote::find, Remote}; impl crate::Repository { @@ -63,22 +61,18 @@ impl crate::Repository { /// as negations/excludes are applied after includes. /// /// We will only include information if we deem it [trustworthy][crate::open::Options::filter_config_section()]. - #[momo] - #[allow(clippy::needless_lifetimes)] pub fn try_find_remote<'a>(&self, name_or_url: impl Into<&'a BStr>) -> Option, find::Error>> { - self.try_find_remote_inner(name_or_url, true) + self.try_find_remote_inner(name_or_url.into(), true) } /// Similar to [`try_find_remote()`][Self::try_find_remote()], but removes a failure mode if rewritten URLs turn out to be invalid /// as it skips rewriting them. /// Use this in conjunction with [`Remote::rewrite_urls()`] to non-destructively apply the rules and keep the failed urls unchanged. - #[momo] - #[allow(clippy::needless_lifetimes)] pub fn try_find_remote_without_url_rewrite<'a>( &self, name_or_url: impl Into<&'a BStr>, ) -> Option, find::Error>> { - self.try_find_remote_inner(name_or_url, false) + self.try_find_remote_inner(name_or_url.into(), false) } fn try_find_remote_inner<'a>( From 71b7422302b33235581b32f680e9b3db7b6145ad Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Tue, 29 Aug 2023 07:33:51 +0200 Subject: [PATCH 0043/1077] update memchr for potentailly faster object parsing However, in my tests the effect wasn't visible for some reason. Maybe the target CPU wasn't set correctly. --- Cargo.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index a06040137e0..6bdceb90a90 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3106,9 +3106,9 @@ dependencies = [ [[package]] name = "memchr" -version = "2.5.0" +version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" +checksum = "76fc44e2588d5b436dbc3c6cf62aef290f90dab6235744a93dfe1cc18f451e2c" [[package]] name = "memmap2" From 95a16264b0a6f8c7d8e2acded3a4c9c170c2729b Mon Sep 17 00:00:00 2001 From: Jiahao XU Date: Tue, 29 Aug 2023 21:10:18 +1000 Subject: [PATCH 0044/1077] Remove `TryInto` support from `gix_macros::momo` Part of the reason is that `impl TryInto` isn't as common as `AsRef`, `AsMut` or `Into`, but also because its error handling logic is much harder to parse and replace in the inner function. Signed-off-by: Jiahao XU --- gix-macros/src/lib.rs | 33 --------------------------------- 1 file changed, 33 deletions(-) diff --git a/gix-macros/src/lib.rs b/gix-macros/src/lib.rs index 8688ccabaf1..b485f60e625 100644 --- a/gix-macros/src/lib.rs +++ b/gix-macros/src/lib.rs @@ -8,7 +8,6 @@ use syn::{fold::Fold, punctuated::Punctuated, spanned::Spanned, *}; // All conversions we support. Check references to this type for an idea how to add more. enum Conversion<'a> { Into(&'a Type), - TryInto(&'a Type), AsRef(&'a Type), AsMut(&'a Type), } @@ -17,7 +16,6 @@ impl<'a> Conversion<'a> { fn target_type(&self) -> Type { match *self { Conversion::Into(ty) => ty.clone(), - Conversion::TryInto(ty) => ty.clone(), Conversion::AsRef(ty) => parse_quote!(&#ty), Conversion::AsMut(ty) => parse_quote!(&mut #ty), } @@ -26,7 +24,6 @@ impl<'a> Conversion<'a> { fn conversion_expr(&self, i: Ident) -> Expr { match *self { Conversion::Into(_) => parse_quote!(#i.into()), - Conversion::TryInto(_) => parse_quote!(#i.try_into()?), Conversion::AsRef(_) => parse_quote!(#i.as_ref()), Conversion::AsMut(_) => parse_quote!(#i.as_mut()), } @@ -52,8 +49,6 @@ fn parse_bounds(bounds: &Punctuated) -> Option( let mut argtypes = Punctuated::new(); let mut conversions = Conversions { intos: Vec::new(), - try_intos: Vec::new(), as_refs: Vec::new(), as_muts: Vec::new(), }; @@ -205,7 +199,6 @@ fn convert<'a>( struct Conversions { intos: Vec, - try_intos: Vec, as_refs: Vec, as_muts: Vec, } @@ -214,7 +207,6 @@ impl Conversions { fn add(&mut self, ident: Ident, conv: Conversion) { match conv { Conversion::Into(_) => self.intos.push(ident), - Conversion::TryInto(_) => self.try_intos.push(ident), Conversion::AsRef(_) => self.as_refs.push(ident), Conversion::AsMut(_) => self.as_muts.push(ident), } @@ -238,7 +230,6 @@ impl Fold for Conversions { match expr { Expr::MethodCall(mc) if mc.args.is_empty() => match &*mc.method.to_string() { "into" if has_conversion(&self.intos, &mc.receiver) => *mc.receiver, - "try_into" if has_conversion(&self.try_intos, &mc.receiver) => *mc.receiver, "as_ref" if has_conversion(&self.as_refs, &mc.receiver) => *mc.receiver, "as_mut" if has_conversion(&self.as_muts, &mc.receiver) => *mc.receiver, @@ -251,7 +242,6 @@ impl Fold for Conversions { .. }) if segments.len() == 2 => match (&*segments[0].ident.to_string(), &*segments[1].ident.to_string()) { ("Into", "into") if has_conversion(&self.intos, &call.args[0]) => call.args[0].clone(), - ("TryInto", "try_into") if has_conversion(&self.try_intos, &call.args[0]) => call.args[0].clone(), ("AsRef", "as_ref") if matches!(&call.args[0], Expr::Reference(ExprReference { expr, mutability: None, .. }) if has_conversion(&self.as_refs, expr)) => { if let Expr::Reference(ExprReference { expr, .. }) = &call.args[0] { @@ -272,29 +262,6 @@ impl Fold for Conversions { }, _ => syn::fold::fold_expr(self, Expr::Call(call)), }, - Expr::Try(expr_try) => match &*expr_try.expr { - Expr::MethodCall(mc) - if mc.args.is_empty() - && mc.method == "try_into" - && has_conversion(&self.try_intos, &mc.receiver) => - { - (*mc.receiver).clone() - } - Expr::Call(call) if call.args.len() == 1 => match &*call.func { - Expr::Path(ExprPath { - path: Path { segments, .. }, - .. - }) if segments.len() == 2 - && segments[0].ident == "TryInto" - && segments[1].ident == "try_into" - && has_conversion(&self.try_intos, &call.args[0]) => - { - call.args[0].clone() - } - _ => syn::fold::fold_expr(self, Expr::Try(expr_try)), - }, - _ => syn::fold::fold_expr(self, Expr::Try(expr_try)), - }, _ => syn::fold::fold_expr(self, expr), } } From c72eaa05697a3e34adaa3ee90584dce4b5c00120 Mon Sep 17 00:00:00 2001 From: Jiahao XU Date: Tue, 29 Aug 2023 21:38:33 +1000 Subject: [PATCH 0045/1077] Dramatically simplify `gix_macros::momo` And make applying support of `gix_macros::momo` truly painless by making it work out-of-the-box. Signed-off-by: Jiahao XU --- gix-macros/src/lib.rs | 167 ++----------------------- gix/src/repository/config/transport.rs | 3 +- gix/src/repository/object.rs | 10 +- gix/src/repository/reference.rs | 4 +- gix/src/repository/worktree.rs | 3 +- 5 files changed, 24 insertions(+), 163 deletions(-) diff --git a/gix-macros/src/lib.rs b/gix-macros/src/lib.rs index b485f60e625..f2503e9b332 100644 --- a/gix-macros/src/lib.rs +++ b/gix-macros/src/lib.rs @@ -1,8 +1,8 @@ -use std::collections::{HashMap, HashSet}; +use std::collections::HashMap; use proc_macro::TokenStream; use quote::quote; -use syn::{fold::Fold, punctuated::Punctuated, spanned::Spanned, *}; +use syn::{punctuated::Punctuated, spanned::Spanned, *}; #[derive(Copy, Clone)] // All conversions we support. Check references to this type for an idea how to add more. @@ -13,14 +13,6 @@ enum Conversion<'a> { } impl<'a> Conversion<'a> { - fn target_type(&self) -> Type { - match *self { - Conversion::Into(ty) => ty.clone(), - Conversion::AsRef(ty) => parse_quote!(&#ty), - Conversion::AsMut(ty) => parse_quote!(&mut #ty), - } - } - fn conversion_expr(&self, i: Ident) -> Expr { match *self { Conversion::Into(_) => parse_quote!(#i.into()), @@ -62,9 +54,8 @@ fn parse_bounds(bounds: &Punctuated) -> Option (HashMap>, Generics) { +fn parse_generics(decl: &Signature) -> HashMap> { let mut ty_conversions = HashMap::new(); - let mut params = Punctuated::new(); for gp in decl.generics.params.iter() { if let GenericParam::Type(ref tp) = gp { if let Some(conversion) = parse_bounds(&tp.bounds) { @@ -72,48 +63,20 @@ fn parse_generics(decl: &Signature) -> (HashMap>, Generics continue; } } - params.push(gp.clone()); } - let where_clause = if let Some(ref wc) = decl.generics.where_clause { - let mut idents_to_remove = HashSet::new(); - let mut predicates = Punctuated::new(); + if let Some(ref wc) = decl.generics.where_clause { for wp in wc.predicates.iter() { if let WherePredicate::Type(ref pt) = wp { if let Some(ident) = parse_bounded_type(&pt.bounded_ty) { if let Some(conversion) = parse_bounds(&pt.bounds) { - idents_to_remove.insert(ident.clone()); ty_conversions.insert(ident, conversion); continue; } } } - predicates.push(wp.clone()); } - params = params - .into_iter() - .filter(|param| { - if let GenericParam::Type(type_param) = param { - !idents_to_remove.contains(&type_param.ident) - } else { - true - } - }) - .collect(); - Some(WhereClause { - predicates, - ..wc.clone() - }) - } else { - None - }; - ( - ty_conversions, - Generics { - params, - where_clause, - ..decl.generics.clone() - }, - ) + } + ty_conversions } fn pat_to_ident(pat: &Pat) -> Ident { @@ -131,140 +94,36 @@ fn pat_to_expr(pat: &Pat) -> Expr { fn convert<'a>( inputs: &'a Punctuated, ty_conversions: &HashMap>, -) -> ( - Punctuated, - Conversions, - Punctuated, - bool, -) { - let mut argtypes = Punctuated::new(); - let mut conversions = Conversions { - intos: Vec::new(), - as_refs: Vec::new(), - as_muts: Vec::new(), - }; +) -> (Punctuated, bool) { let mut argexprs = Punctuated::new(); let mut has_self = false; inputs.iter().for_each(|input| match input { FnArg::Receiver(..) => { has_self = true; - argtypes.push(input.clone()); } - FnArg::Typed(PatType { - ref pat, - ref ty, - ref colon_token, - .. - }) => match **ty { + FnArg::Typed(PatType { ref pat, ref ty, .. }) => match **ty { Type::ImplTrait(TypeImplTrait { ref bounds, .. }) => { if let Some(conv) = parse_bounds(bounds) { - argtypes.push(FnArg::Typed(PatType { - attrs: Vec::new(), - pat: pat.clone(), - colon_token: *colon_token, - ty: Box::new(conv.target_type()), - })); let ident = pat_to_ident(pat); - conversions.add(ident.clone(), conv); argexprs.push(conv.conversion_expr(ident)); } else { - argtypes.push(input.clone()); argexprs.push(pat_to_expr(pat)); } } Type::Path(..) => { if let Some(conv) = parse_bounded_type(ty).and_then(|ident| ty_conversions.get(&ident)) { - argtypes.push(FnArg::Typed(PatType { - attrs: Vec::new(), - pat: pat.clone(), - colon_token: *colon_token, - ty: Box::new(conv.target_type()), - })); let ident = pat_to_ident(pat); - conversions.add(ident.clone(), *conv); argexprs.push(conv.conversion_expr(ident)); } else { - argtypes.push(input.clone()); argexprs.push(pat_to_expr(pat)); } } _ => { - argtypes.push(input.clone()); argexprs.push(pat_to_expr(pat)); } }, }); - (argtypes, conversions, argexprs, has_self) -} - -struct Conversions { - intos: Vec, - as_refs: Vec, - as_muts: Vec, -} - -impl Conversions { - fn add(&mut self, ident: Ident, conv: Conversion) { - match conv { - Conversion::Into(_) => self.intos.push(ident), - Conversion::AsRef(_) => self.as_refs.push(ident), - Conversion::AsMut(_) => self.as_muts.push(ident), - } - } -} - -fn has_conversion(idents: &[Ident], expr: &Expr) -> bool { - if let Expr::Path(ExprPath { ref path, .. }) = *expr { - if path.segments.len() == 1 { - let seg = path.segments.iter().last().unwrap(); - return idents.iter().any(|i| i == &seg.ident); - } - } - false -} - -#[allow(clippy::collapsible_if)] -impl Fold for Conversions { - fn fold_expr(&mut self, expr: Expr) -> Expr { - //TODO: Also catch `Expr::Call` with suitable paths & args - match expr { - Expr::MethodCall(mc) if mc.args.is_empty() => match &*mc.method.to_string() { - "into" if has_conversion(&self.intos, &mc.receiver) => *mc.receiver, - - "as_ref" if has_conversion(&self.as_refs, &mc.receiver) => *mc.receiver, - "as_mut" if has_conversion(&self.as_muts, &mc.receiver) => *mc.receiver, - - _ => syn::fold::fold_expr(self, Expr::MethodCall(mc)), - }, - Expr::Call(call) if call.args.len() == 1 => match &*call.func { - Expr::Path(ExprPath { - path: Path { segments, .. }, - .. - }) if segments.len() == 2 => match (&*segments[0].ident.to_string(), &*segments[1].ident.to_string()) { - ("Into", "into") if has_conversion(&self.intos, &call.args[0]) => call.args[0].clone(), - - ("AsRef", "as_ref") if matches!(&call.args[0], Expr::Reference(ExprReference { expr, mutability: None, .. }) if has_conversion(&self.as_refs, expr)) => { - if let Expr::Reference(ExprReference { expr, .. }) = &call.args[0] { - (**expr).clone() - } else { - panic!("expr must be Reference") - } - } - ("AsMut", "as_mut") if matches!(&call.args[0], Expr::Reference(ExprReference { expr, mutability: Some(_), .. }) if has_conversion(&self.as_muts, expr)) => { - if let Expr::Reference(ExprReference { expr, .. }) = &call.args[0] { - (**expr).clone() - } else { - panic!("expr must be Reference") - } - } - - _ => syn::fold::fold_expr(self, Expr::Call(call)), - }, - _ => syn::fold::fold_expr(self, Expr::Call(call)), - }, - _ => syn::fold::fold_expr(self, expr), - } - } + (argexprs, has_self) } fn contains_self_type_path(path: &Path) -> bool { @@ -339,8 +198,8 @@ fn momo_inner(code: proc_macro2::TokenStream) -> proc_macro2::TokenStream { }; if let Item::Fn(item_fn) = fn_item { - let (ty_conversions, generics) = parse_generics(&item_fn.sig); - let (argtypes, mut conversions, argexprs, has_self) = convert(&item_fn.sig.inputs, &ty_conversions); + let ty_conversions = parse_generics(&item_fn.sig); + let (argexprs, has_self) = convert(&item_fn.sig.inputs, &ty_conversions); let uses_self = has_self || item_fn.sig.inputs.iter().any(has_self_type) @@ -367,11 +226,9 @@ fn momo_inner(code: proc_macro2::TokenStream) -> proc_macro2::TokenStream { vis: Visibility::Inherited, sig: Signature { ident: inner_ident.clone(), - generics, - inputs: argtypes, ..item_fn.sig.clone() }, - block: Box::new(conversions.fold_block(*item_fn.block)), + block: item_fn.block, }); if uses_self { diff --git a/gix/src/repository/config/transport.rs b/gix/src/repository/config/transport.rs index d43fffaf560..811848a5dc9 100644 --- a/gix/src/repository/config/transport.rs +++ b/gix/src/repository/config/transport.rs @@ -23,14 +23,13 @@ impl crate::Repository { )), allow(unused_variables) )] - #[allow(clippy::needless_lifetimes)] #[momo] pub fn transport_options<'a>( &self, url: impl Into<&'a BStr>, remote_name: Option<&BStr>, ) -> Result>, crate::config::transport::Error> { - let url = gix_url::parse(url)?; + let url = gix_url::parse(url.into())?; use gix_url::Scheme::*; match &url.scheme { diff --git a/gix/src/repository/object.rs b/gix/src/repository/object.rs index 2dafe6b4245..e7300a6250a 100644 --- a/gix/src/repository/object.rs +++ b/gix/src/repository/object.rs @@ -24,6 +24,7 @@ impl crate::Repository { /// Loose object could be partially decoded, even though that's not implemented. #[momo] pub fn find_object(&self, id: impl Into) -> Result, object::find::existing::Error> { + let id = id.into(); if id == gix_hash::ObjectId::empty_tree(self.object_hash()) { return Ok(Object { id, @@ -43,6 +44,7 @@ impl crate::Repository { #[doc(alias = "read_header", alias = "git2")] #[momo] pub fn find_header(&self, id: impl Into) -> Result { + let id = id.into(); if id == gix_hash::ObjectId::empty_tree(self.object_hash()) { return Ok(gix_odb::find::Header::Loose { kind: gix_object::Kind::Tree, @@ -60,6 +62,7 @@ impl crate::Repository { &self, id: impl Into, ) -> Result, object::find::Error> { + let id = id.into(); if id == gix_hash::ObjectId::empty_tree(self.object_hash()) { return Ok(Some(gix_odb::find::Header::Loose { kind: gix_object::Kind::Tree, @@ -72,6 +75,7 @@ impl crate::Repository { /// Try to find the object with `id` or return `None` if it wasn't found. #[momo] pub fn try_find_object(&self, id: impl Into) -> Result>, object::find::Error> { + let id = id.into(); if id == gix_hash::ObjectId::empty_tree(self.object_hash()) { return Ok(Some(Object { id, @@ -175,11 +179,11 @@ impl crate::Repository { constraint: PreviousValue, ) -> Result, tag::Error> { let tag = gix_object::Tag { - target: target.into(), + target: target.as_ref().into(), target_kind, - name: name.into(), + name: name.as_ref().into(), tagger: tagger.map(|t| t.to_owned()), - message: message.into(), + message: message.as_ref().into(), pgp_signature: None, }; let tag_id = self.write_object(&tag)?; diff --git a/gix/src/repository/reference.rs b/gix/src/repository/reference.rs index 6c8274e2f68..4fd6aeb9f69 100644 --- a/gix/src/repository/reference.rs +++ b/gix/src/repository/reference.rs @@ -22,14 +22,14 @@ impl crate::Repository { target: impl Into, constraint: PreviousValue, ) -> Result, reference::edit::Error> { - let id = target; + let id = target.into(); let mut edits = self.edit_reference(RefEdit { change: Change::Update { log: Default::default(), expected: constraint, new: Target::Peeled(id), }, - name: format!("refs/tags/{name}").try_into()?, + name: format!("refs/tags/{}", name.as_ref()).try_into()?, deref: false, })?; assert_eq!(edits.len(), 1, "reference splits should ever happen"); diff --git a/gix/src/repository/worktree.rs b/gix/src/repository/worktree.rs index 4773c6cd8e1..af2ff10434c 100644 --- a/gix/src/repository/worktree.rs +++ b/gix/src/repository/worktree.rs @@ -63,10 +63,11 @@ impl crate::Repository { id: impl Into, ) -> Result<(gix_worktree_stream::Stream, gix_index::File), crate::repository::worktree_stream::Error> { use gix_odb::{FindExt, HeaderExt}; + let id = id.into(); let header = self.objects.header(id)?; if !header.kind().is_tree() { return Err(crate::repository::worktree_stream::Error::NotATree { - id: id.to_owned(), + id, actual: header.kind(), }); } From e1b9d51acd137cdea7680584451702e52aab775f Mon Sep 17 00:00:00 2001 From: Jiahao XU Date: Tue, 29 Aug 2023 21:43:40 +1000 Subject: [PATCH 0046/1077] Remove unnecessary `#[allow(clippy::needless_lifetimes)]` Thanks for new internal of `gix_macros::momo`! Signed-off-by: Jiahao XU --- gix/src/pathspec.rs | 2 -- gix/src/repository/revision.rs | 1 - 2 files changed, 3 deletions(-) diff --git a/gix/src/pathspec.rs b/gix/src/pathspec.rs index 01445601a4f..4c56be28e81 100644 --- a/gix/src/pathspec.rs +++ b/gix/src/pathspec.rs @@ -94,7 +94,6 @@ impl<'repo> Pathspec<'repo> { alias = "git2" )] #[momo] - #[allow(clippy::needless_lifetimes)] pub fn pattern_matching_relative_path<'a>( &mut self, relative_path: impl Into<&'a BStr>, @@ -115,7 +114,6 @@ impl<'repo> Pathspec<'repo> { /// The simplified version of [`pattern_matching_relative_path()`](Self::pattern_matching_relative_path()) which returns /// `true` if `relative_path` is included in the set of positive pathspecs, while not being excluded. #[momo] - #[allow(clippy::needless_lifetimes)] pub fn is_included<'a>(&mut self, relative_path: impl Into<&'a BStr>, is_dir: Option) -> bool { self.pattern_matching_relative_path(relative_path, is_dir) .map_or(false, |m| !m.is_excluded()) diff --git a/gix/src/repository/revision.rs b/gix/src/repository/revision.rs index 27aeb38e194..bb9b56d57ac 100644 --- a/gix/src/repository/revision.rs +++ b/gix/src/repository/revision.rs @@ -10,7 +10,6 @@ impl crate::Repository { /// - `@` actually stands for `HEAD`, whereas `git` resolves it to the object pointed to by `HEAD` without making the /// `HEAD` ref available for lookups. #[doc(alias = "revparse", alias = "git2")] - #[allow(clippy::needless_lifetimes)] #[momo] pub fn rev_parse<'a>(&self, spec: impl Into<&'a BStr>) -> Result, revision::spec::parse::Error> { revision::Spec::from_bstr( From 86b8e50fafa7e5d57989acb9e8b848fd95d271a9 Mon Sep 17 00:00:00 2001 From: Jiahao XU Date: Tue, 29 Aug 2023 21:47:44 +1000 Subject: [PATCH 0047/1077] Remove unnecessary change in `repository/config/transport.rs` Signed-off-by: Jiahao XU --- gix/src/repository/config/transport.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gix/src/repository/config/transport.rs b/gix/src/repository/config/transport.rs index 811848a5dc9..99b5a7f47ff 100644 --- a/gix/src/repository/config/transport.rs +++ b/gix/src/repository/config/transport.rs @@ -273,7 +273,7 @@ impl crate::Repository { .proxy .as_deref() .filter(|url| !url.is_empty()) - .map(|url| gix_url::parse(<&BStr>::from(url))) + .map(|url| gix_url::parse(url.into())) .transpose()? .filter(|url| url.user().is_some()) .map(|url| -> Result<_, config::transport::http::Error> { From b5f78be06792153cd981c316a486974c000f1fd8 Mon Sep 17 00:00:00 2001 From: Jiahao XU Date: Tue, 29 Aug 2023 22:51:59 +1000 Subject: [PATCH 0048/1077] feat `momo`: Support parsing pattern in params So that we can slap it on more functions. Signed-off-by: Jiahao XU --- gix-macros/src/lib.rs | 118 ++++++++++++++++++++++++--------------- gix-macros/tests/test.rs | 19 +++++++ 2 files changed, 91 insertions(+), 46 deletions(-) diff --git a/gix-macros/src/lib.rs b/gix-macros/src/lib.rs index f2503e9b332..e6c9b4dfe79 100644 --- a/gix-macros/src/lib.rs +++ b/gix-macros/src/lib.rs @@ -13,7 +13,7 @@ enum Conversion<'a> { } impl<'a> Conversion<'a> { - fn conversion_expr(&self, i: Ident) -> Expr { + fn conversion_expr(&self, i: &Ident) -> Expr { match *self { Conversion::Into(_) => parse_quote!(#i.into()), Conversion::AsRef(_) => parse_quote!(#i.as_ref()), @@ -23,12 +23,10 @@ impl<'a> Conversion<'a> { } fn parse_bounded_type(ty: &Type) -> Option { - if let Type::Path(TypePath { qself: None, ref path }) = ty { - if path.segments.len() == 1 { - return Some(path.segments[0].ident.clone()); - } + match &ty { + Type::Path(TypePath { qself: None, path }) if path.segments.len() == 1 => Some(path.segments[0].ident.clone()), + _ => None, } - None } fn parse_bounds(bounds: &Punctuated) -> Option { @@ -60,7 +58,6 @@ fn parse_generics(decl: &Signature) -> HashMap> { if let GenericParam::Type(ref tp) = gp { if let Some(conversion) = parse_bounds(&tp.bounds) { ty_conversions.insert(tp.ident.clone(), conversion); - continue; } } } @@ -70,7 +67,6 @@ fn parse_generics(decl: &Signature) -> HashMap> { if let Some(ident) = parse_bounded_type(&pt.bounded_ty) { if let Some(conversion) = parse_bounds(&pt.bounds) { ty_conversions.insert(ident, conversion); - continue; } } } @@ -79,51 +75,76 @@ fn parse_generics(decl: &Signature) -> HashMap> { ty_conversions } -fn pat_to_ident(pat: &Pat) -> Ident { - if let Pat::Ident(ref pat_ident) = *pat { - return pat_ident.ident.clone(); - } - unimplemented!("No non-ident patterns for now!"); -} - -fn pat_to_expr(pat: &Pat) -> Expr { - let ident = pat_to_ident(pat); - parse_quote!(#ident) -} - fn convert<'a>( inputs: &'a Punctuated, ty_conversions: &HashMap>, -) -> (Punctuated, bool) { +) -> (Punctuated, Punctuated, bool) { + let mut argtypes = Punctuated::new(); let mut argexprs = Punctuated::new(); let mut has_self = false; - inputs.iter().for_each(|input| match input { - FnArg::Receiver(..) => { + inputs.iter().enumerate().for_each(|(i, input)| match input.clone() { + FnArg::Receiver(receiver) => { has_self = true; + argtypes.push(FnArg::Receiver(receiver)); } - FnArg::Typed(PatType { ref pat, ref ty, .. }) => match **ty { - Type::ImplTrait(TypeImplTrait { ref bounds, .. }) => { - if let Some(conv) = parse_bounds(bounds) { - let ident = pat_to_ident(pat); - argexprs.push(conv.conversion_expr(ident)); - } else { - argexprs.push(pat_to_expr(pat)); + FnArg::Typed(mut pat_type) => { + let pat_ident = match &mut *pat_type.pat { + Pat::Ident(pat_ident) if pat_ident.by_ref.is_none() && pat_ident.subpat.is_none() => pat_ident, + _ => { + pat_type.pat = Box::new(Pat::Ident(PatIdent { + ident: Ident::new(&format!("arg_{i}_gen_by_momo_"), proc_macro2::Span::call_site()), + attrs: Default::default(), + by_ref: None, + mutability: None, + subpat: None, + })); + + if let Pat::Ident(pat_ident) = &mut *pat_type.pat { + pat_ident + } else { + panic!() + } } - } - Type::Path(..) => { - if let Some(conv) = parse_bounded_type(ty).and_then(|ident| ty_conversions.get(&ident)) { - let ident = pat_to_ident(pat); - argexprs.push(conv.conversion_expr(ident)); - } else { - argexprs.push(pat_to_expr(pat)); + }; + // Outer function type argument pat does not need mut unless its + // type is `impl AsMut`. + pat_ident.mutability = None; + + let ident = &pat_ident.ident; + + let to_expr = || parse_quote!(#ident); + + match *pat_type.ty { + Type::ImplTrait(TypeImplTrait { ref bounds, .. }) => { + if let Some(conv) = parse_bounds(bounds) { + argexprs.push(conv.conversion_expr(ident)); + if let Conversion::AsMut(_) = conv { + pat_ident.mutability = Some(Default::default()); + } + } else { + argexprs.push(to_expr()); + } + } + Type::Path(..) => { + if let Some(conv) = parse_bounded_type(&pat_type.ty).and_then(|ident| ty_conversions.get(&ident)) { + argexprs.push(conv.conversion_expr(ident)); + if let Conversion::AsMut(_) = conv { + pat_ident.mutability = Some(Default::default()); + } + } else { + argexprs.push(to_expr()); + } + } + _ => { + argexprs.push(to_expr()); } } - _ => { - argexprs.push(pat_to_expr(pat)); - } - }, + + // Now that mutability is decided, push the type into argtypes + argtypes.push(FnArg::Typed(pat_type)); + } }); - (argexprs, has_self) + (argtypes, argexprs, has_self) } fn contains_self_type_path(path: &Path) -> bool { @@ -199,7 +220,7 @@ fn momo_inner(code: proc_macro2::TokenStream) -> proc_macro2::TokenStream { if let Item::Fn(item_fn) = fn_item { let ty_conversions = parse_generics(&item_fn.sig); - let (argexprs, has_self) = convert(&item_fn.sig.inputs, &ty_conversions); + let (argtypes, argexprs, has_self) = convert(&item_fn.sig.inputs, &ty_conversions); let uses_self = has_self || item_fn.sig.inputs.iter().any(has_self_type) @@ -211,6 +232,11 @@ fn momo_inner(code: proc_macro2::TokenStream) -> proc_macro2::TokenStream { proc_macro2::Span::call_site(), ); + let outer_sig = Signature { + inputs: argtypes, + ..item_fn.sig.clone() + }; + let new_inner_item = Item::Fn(ItemFn { // Remove doc comment since they will increase compile-time and // also generates duplicate warning/error messages for the doc, @@ -226,7 +252,7 @@ fn momo_inner(code: proc_macro2::TokenStream) -> proc_macro2::TokenStream { vis: Visibility::Inherited, sig: Signature { ident: inner_ident.clone(), - ..item_fn.sig.clone() + ..item_fn.sig }, block: item_fn.block, }); @@ -243,7 +269,7 @@ fn momo_inner(code: proc_macro2::TokenStream) -> proc_macro2::TokenStream { let new_item = Item::Fn(ItemFn { attrs: item_fn.attrs, vis: item_fn.vis, - sig: item_fn.sig, + sig: outer_sig, block: if has_self { parse_quote!({ self.#inner_ident(#argexprs) }) } else { @@ -258,7 +284,7 @@ fn momo_inner(code: proc_macro2::TokenStream) -> proc_macro2::TokenStream { let new_item = Item::Fn(ItemFn { attrs: item_fn.attrs, vis: item_fn.vis, - sig: item_fn.sig, + sig: outer_sig, block: parse_quote!({ #[allow(unused_mut)] #new_inner_item diff --git a/gix-macros/tests/test.rs b/gix-macros/tests/test.rs index 10006bf1be4..51c522c1fae 100644 --- a/gix-macros/tests/test.rs +++ b/gix-macros/tests/test.rs @@ -192,6 +192,25 @@ impl TryInto for S { } } +#[allow(unused)] +#[momo] +fn test_fn_pat( + a: impl Into, + b: impl AsRef, + mut c: impl AsMut, + d: impl TryInto, + S(_g): S, +) -> Result<(), E> { + let mut s = a.into(); + s += b.as_ref(); + s += c.as_mut(); + s += &d.try_into()?; + + drop(s); + + Ok(()) +} + #[test] fn test_basic_fn() { assert_eq!( From b6194568e1d3042305f472103e1c00549cc4ccb9 Mon Sep 17 00:00:00 2001 From: Jiahao XU Date: Tue, 29 Aug 2023 22:56:31 +1000 Subject: [PATCH 0049/1077] feat `momo`: Rm unnecessary `#[allow(unused_mut)]` on generated inner fn Now that the inner function is actually identical to the original function before passed into `momo`, except for visibility, function name and the lack of function doc. Signed-off-by: Jiahao XU --- gix-macros/src/lib.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/gix-macros/src/lib.rs b/gix-macros/src/lib.rs index e6c9b4dfe79..dcfa6ad5d70 100644 --- a/gix-macros/src/lib.rs +++ b/gix-macros/src/lib.rs @@ -276,7 +276,7 @@ fn momo_inner(code: proc_macro2::TokenStream) -> proc_macro2::TokenStream { parse_quote!({ Self::#inner_ident(#argexprs) }) }, }); - quote!(#new_item #[allow(unused_mut)] #new_inner_item) + quote!(#new_item #new_inner_item) } else { // Put the new inner function within the function block // to avoid duplicate function name and support associated @@ -286,7 +286,6 @@ fn momo_inner(code: proc_macro2::TokenStream) -> proc_macro2::TokenStream { vis: item_fn.vis, sig: outer_sig, block: parse_quote!({ - #[allow(unused_mut)] #new_inner_item #inner_ident(#argexprs) From 89ae797c7f1f4d26c48ed54c5d8b31f39599f063 Mon Sep 17 00:00:00 2001 From: Jiahao XU Date: Tue, 29 Aug 2023 23:00:08 +1000 Subject: [PATCH 0050/1077] Rm unnecessary `#[allow(unused_mut)]` put on `momo`ed functions Signed-off-by: Jiahao XU --- gix/src/discover.rs | 1 - gix/src/init.rs | 1 - gix/src/open/repository.rs | 1 - 3 files changed, 3 deletions(-) diff --git a/gix/src/discover.rs b/gix/src/discover.rs index a5a3b8a4ad4..50dcb9fa773 100644 --- a/gix/src/discover.rs +++ b/gix/src/discover.rs @@ -64,7 +64,6 @@ impl ThreadSafeRepository { /// Finally, use the `trust_map` to determine which of our own repository options to use /// based on the trust level of the effective repository directory. #[momo] - #[allow(unused_mut)] pub fn discover_with_environment_overrides_opts( directory: impl AsRef, mut options: upwards::Options<'_>, diff --git a/gix/src/init.rs b/gix/src/init.rs index 9b9cb5a61b0..21c2debd807 100644 --- a/gix/src/init.rs +++ b/gix/src/init.rs @@ -59,7 +59,6 @@ impl ThreadSafeRepository { /// Instead of naming the default branch `master`, we name it `main` unless configured explicitly using the `init.defaultBranch` /// configuration key. #[momo] - #[allow(unused_mut)] pub fn init_opts( directory: impl AsRef, kind: crate::create::Kind, diff --git a/gix/src/open/repository.rs b/gix/src/open/repository.rs index df096a4e3dd..2f9127bbd7d 100644 --- a/gix/src/open/repository.rs +++ b/gix/src/open/repository.rs @@ -60,7 +60,6 @@ impl ThreadSafeRepository { /// Note that opening a repository for implementing custom hooks is also handle specifically in /// [`open_with_environment_overrides()`][Self::open_with_environment_overrides()]. #[momo] - #[allow(unused_mut)] pub fn open_opts(path: impl Into, mut options: Options) -> Result { let _span = gix_trace::coarse!("ThreadSafeRepository::open()"); let (path, kind) = { From cd3c2893b095d38d36f0c969549f0aaadfcef2ee Mon Sep 17 00:00:00 2001 From: Jiahao XU Date: Tue, 29 Aug 2023 23:06:42 +1000 Subject: [PATCH 0051/1077] Apply `momo` to mod `gix::create::into` Signed-off-by: Jiahao XU --- gix/src/create.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/gix/src/create.rs b/gix/src/create.rs index 4cc01402c07..c3839f66fcf 100644 --- a/gix/src/create.rs +++ b/gix/src/create.rs @@ -7,6 +7,7 @@ use std::{ use gix_config::parse::section; use gix_discover::DOT_GIT_DIR; +use gix_macros::momo; /// The error used in [`into()`]. #[derive(Debug, thiserror::Error)] @@ -124,6 +125,7 @@ pub struct Options { /// Note that this is a simple template-based initialization routine which should be accompanied with additional corrections /// to respect git configuration, which is accomplished by [its callers][crate::ThreadSafeRepository::init_opts()] /// that return a [Repository][crate::Repository]. +#[momo] pub fn into( directory: impl Into, kind: Kind, From 25912fe1e5d60765458a2e90c0fa487657b0831c Mon Sep 17 00:00:00 2001 From: Jiahao XU Date: Tue, 29 Aug 2023 23:13:21 +1000 Subject: [PATCH 0052/1077] Apply `momo` to mod `config::snapshot::access` Signed-off-by: Jiahao XU --- gix/src/config/snapshot/access.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/gix/src/config/snapshot/access.rs b/gix/src/config/snapshot/access.rs index 284fe0fb843..0a82d966c00 100644 --- a/gix/src/config/snapshot/access.rs +++ b/gix/src/config/snapshot/access.rs @@ -2,6 +2,7 @@ use std::borrow::Cow; use gix_features::threading::OwnShared; +use gix_macros::momo; use crate::{ bstr::{BStr, BString}, @@ -25,6 +26,7 @@ impl<'repo> Snapshot<'repo> { } /// Like [`boolean()`][Self::boolean()], but it will report an error if the value couldn't be interpreted as boolean. + #[momo] pub fn try_boolean<'a>(&self, key: impl Into<&'a BStr>) -> Option> { self.repo.config.resolved.boolean_by_key(key) } @@ -40,6 +42,7 @@ impl<'repo> Snapshot<'repo> { } /// Like [`integer()`][Self::integer()], but it will report an error if the value couldn't be interpreted as boolean. + #[momo] pub fn try_integer<'a>(&self, key: impl Into<&'a BStr>) -> Option> { self.repo.config.resolved.integer_by_key(key) } @@ -47,6 +50,7 @@ impl<'repo> Snapshot<'repo> { /// Return the string at `key`, or `None` if there is no such value. /// /// Note that this method takes the most recent value at `key` even if it is from a file with reduced trust. + #[momo] pub fn string<'a>(&self, key: impl Into<&'a BStr>) -> Option> { self.repo.config.resolved.string_by_key(key) } @@ -54,6 +58,7 @@ impl<'repo> Snapshot<'repo> { /// Return the trusted and fully interpolated path at `key`, or `None` if there is no such value /// or if no value was found in a trusted file. /// An error occurs if the path could not be interpolated to its final value. + #[momo] pub fn trusted_path<'a>( &self, key: impl Into<&'a BStr>, @@ -101,6 +106,7 @@ impl<'repo> SnapshotMut<'repo> { /// Set the value at `key` to `new_value`, possibly creating the section if it doesn't exist yet, or overriding the most recent existing /// value, which will be returned. + #[momo] pub fn set_value<'b>( &mut self, key: &'static dyn crate::config::tree::Key, @@ -119,6 +125,7 @@ impl<'repo> SnapshotMut<'repo> { /// Set the value at `key` to `new_value` in the given `subsection`, possibly creating the section and sub-section if it doesn't exist yet, /// or overriding the most recent existing value, which will be returned. + #[momo] pub fn set_subsection_value<'a, 'b>( &mut self, key: &'static dyn crate::config::tree::Key, From 1d9030112b54699db9bd8d1125116e46c4a6f71e Mon Sep 17 00:00:00 2001 From: Jiahao XU Date: Tue, 29 Aug 2023 23:16:34 +1000 Subject: [PATCH 0053/1077] Apply `momo` to fn `gix::revision::Spec::from_bstr` Signed-off-by: Jiahao XU --- gix/src/revision/spec/parse/mod.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/gix/src/revision/spec/parse/mod.rs b/gix/src/revision/spec/parse/mod.rs index f69ecc4afb0..950dfa0040b 100644 --- a/gix/src/revision/spec/parse/mod.rs +++ b/gix/src/revision/spec/parse/mod.rs @@ -1,6 +1,7 @@ use std::collections::HashSet; use gix_hash::ObjectId; +use gix_macros::momo; use gix_revision::spec::parse; use crate::{bstr::BStr, revision::Spec, Repository}; @@ -30,6 +31,7 @@ impl<'repo> Spec<'repo> { /// Parse `spec` and use information from `repo` to resolve it, using `opts` to learn how to deal with ambiguity. /// /// Note that it's easier and to use [`repo.rev_parse()`][Repository::rev_parse()] instead. + #[momo] pub fn from_bstr<'a>(spec: impl Into<&'a BStr>, repo: &'repo Repository, opts: Options) -> Result { let mut delegate = Delegate::new(repo, opts); match gix_revision::spec::parse(spec.into(), &mut delegate) { From 875c28757e4a91cf314ec59dd1a0dde779698e53 Mon Sep 17 00:00:00 2001 From: Jiahao XU Date: Tue, 29 Aug 2023 23:18:54 +1000 Subject: [PATCH 0054/1077] Apply `momo` to fn `gix::Remote::save_as_to` Signed-off-by: Jiahao XU --- gix/src/remote/save.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/gix/src/remote/save.rs b/gix/src/remote/save.rs index a61df64c0d6..2a91dfa9c1d 100644 --- a/gix/src/remote/save.rs +++ b/gix/src/remote/save.rs @@ -1,5 +1,7 @@ use std::convert::TryInto; +use gix_macros::momo; + use crate::{ bstr::{BStr, BString}, config, remote, Remote, @@ -111,6 +113,7 @@ impl Remote<'_> { /// If this name is different from the current one, the git configuration will still contain the previous name, /// and the caller should account for that. #[allow(clippy::result_large_err)] + #[momo] pub fn save_as_to( &mut self, name: impl Into, From 616932516d122a24e29fb42c60147fe43c5cead9 Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Thu, 31 Aug 2023 16:14:50 +0200 Subject: [PATCH 0055/1077] fix: `gix-index` prefix matching should now work correctly with conflicting files. It was done in a rush and lacks a lot of tests. At least now it has a greater chance of working, as tests that would truly validate this are still missing for a lack of test date. It can be produced with `git update-index`, but it wasn't yet worth it. --- gix-index/src/access/mod.rs | 30 +++++++++++++++++++++++++++--- 1 file changed, 27 insertions(+), 3 deletions(-) diff --git a/gix-index/src/access/mod.rs b/gix-index/src/access/mod.rs index 3aaa1ca5ca0..f66970e5cfb 100644 --- a/gix-index/src/access/mod.rs +++ b/gix-index/src/access/mod.rs @@ -84,6 +84,30 @@ impl State { self.entry_index_by_idx_and_stage(path, idx, stage, stage_cmp) } + /// Walk as far in `direction` as possible, with [`Ordering::Greater`] towards higher stages, and [`Ordering::Less`] + /// towards lower stages, and return the lowest or highest seen stage. + /// Return `None` if there is no greater or smaller stage. + fn walk_entry_stages(&self, path: &BStr, base: usize, direction: Ordering) -> Option { + match direction { + Ordering::Greater => self + .entries + .get(base + 1..)? + .iter() + .enumerate() + .take_while(|(_, e)| e.path(self) == path) + .last() + .map(|(idx, _)| base + 1 + idx), + Ordering::Equal => Some(base), + Ordering::Less => self.entries[..base] + .iter() + .enumerate() + .rev() + .take_while(|(_, e)| e.path(self) == path) + .last() + .map(|(idx, _)| idx), + } + } + fn entry_index_by_idx_and_stage( &self, path: &BStr, @@ -173,13 +197,13 @@ impl State { let low_entry = &self.entries[low]; if low_entry.stage() != 0 { low = self - .entry_index_by_idx_and_stage(low_entry.path(self), low, 0, low_entry.stage().cmp(&0)) + .walk_entry_stages(low_entry.path(self), low, Ordering::Less) .unwrap_or(low); } if let Some(high_entry) = self.entries.get(high) { - if low_entry.stage() != 2 { + if high_entry.stage() != 3 { high = self - .entry_index_by_idx_and_stage(high_entry.path(self), high, 2, high_entry.stage().cmp(&2)) + .walk_entry_stages(high_entry.path(self), high, Ordering::Greater) .unwrap_or(high); } } From 8b689c222668b0c35c508f1907b03cbd4ba09bba Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Wed, 23 Aug 2023 09:01:40 +0200 Subject: [PATCH 0056/1077] feat: add `State::remove_entries()` and `entry_range()`. This makes it possible to, among other things, delete all occurrences of a particular entry. --- gix-index/src/access/mod.rs | 44 +++++++++++++++++++++++++++++++++ gix-index/tests/index/access.rs | 36 +++++++++++++++++++++++++++ 2 files changed, 80 insertions(+) diff --git a/gix-index/src/access/mod.rs b/gix-index/src/access/mod.rs index f66970e5cfb..5ed66e1637c 100644 --- a/gix-index/src/access/mod.rs +++ b/gix-index/src/access/mod.rs @@ -1,4 +1,5 @@ use std::cmp::Ordering; +use std::ops::Range; use bstr::{BStr, ByteSlice, ByteVec}; use filetime::FileTime; @@ -223,6 +224,30 @@ impl State { pub fn is_sparse(&self) -> bool { self.is_sparse } + + /// Return the range of entries that exactly match the given `path`, in all available stages, or `None` if no entry with such + /// path exists. + /// + /// The range can be used to access the respective entries via [`entries()`](Self::entries()) or [`entries_mut()](Self::entries_mut()). + pub fn entry_range(&self, path: &BStr) -> Option> { + let mut stage_at_index = 0; + let idx = self + .entries + .binary_search_by(|e| { + let res = e.path(self).cmp(path); + if res.is_eq() { + stage_at_index = e.stage(); + } + res + }) + .ok()?; + + let (start, end) = ( + self.walk_entry_stages(path, idx, Ordering::Less).unwrap_or(idx), + self.walk_entry_stages(path, idx, Ordering::Greater).unwrap_or(idx) + 1, + ); + Some(start..end) + } } /// Mutation @@ -333,6 +358,25 @@ impl State { .then_with(|| compare(a, b)) }); } + + /// Physically remove all entries for which `should_remove(idx, path, entry)` returns `true`, traversing them from first to last. + /// + /// Note that the memory used for the removed entries paths is not freed, as it's append-only. + /// + /// ### Performance + /// + /// To implement this operation typically, one would rather add [entry::Flags::REMOVE] to each entry to remove + /// them when [writing the index](Self::write_to()). + pub fn remove_entries(&mut self, mut should_remove: impl FnMut(usize, &BStr, &mut Entry) -> bool) { + let mut index = 0; + let paths = &self.path_backing; + self.entries.retain_mut(|e| { + let path = e.path_in(paths); + let res = !should_remove(index, path, e); + index += 1; + res + }); + } } /// Extensions diff --git a/gix-index/tests/index/access.rs b/gix-index/tests/index/access.rs index df876277850..377e4012a5b 100644 --- a/gix-index/tests/index/access.rs +++ b/gix-index/tests/index/access.rs @@ -29,11 +29,22 @@ fn entry_by_path_with_conflicting_file() { 2, "we always find our stage while in a merge" ); +} + +#[test] +fn prefixed_entries_with_multi_stage_file() { + let file = Fixture::Loose("conflicting-file").open(); + assert_eq!( file.prefixed_entries("fil".into()).expect("present"), file.entries(), "it's possible to get the entire range" ); + assert_eq!( + file.prefixed_entries("file".into()).expect("present"), + file.entries(), + "it's possible to get the entire range even if the same path matches multiple times" + ); assert_eq!( file.prefixed_entries("".into()).expect("present"), file.entries(), @@ -41,6 +52,31 @@ fn entry_by_path_with_conflicting_file() { ); } +#[test] +fn entry_range() { + let file = Fixture::Loose("conflicting-file").open(); + + assert_eq!( + file.entry_range("file".into()), + Some(0..3), + "three stages, all but stage zero" + ); + assert_eq!(file.entry_range("foo".into()), None, "does not exist"); +} + +#[test] +fn remove_entries() { + let mut file = Fixture::Loose("conflicting-file").open(); + + file.remove_entries(|idx, _, _| idx == 0); + assert_eq!(file.entries().len(), 2); + file.remove_entries(|idx, _, _| idx == 0); + assert_eq!(file.entries().len(), 1); + file.remove_entries(|idx, _, _| idx == 0); + assert_eq!(file.entries().len(), 0); + file.remove_entries(|_, _, _| unreachable!("should not be called")); +} + #[test] fn sort_entries() { let mut file = Fixture::Generated("v4_more_files_IEOT").open(); From cfbfa43069c8d82fbd74b8296f63fc050a5ba02a Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Thu, 31 Aug 2023 17:13:39 +0200 Subject: [PATCH 0057/1077] feat: add `State::prefixed_range()` to obtain a range of entries matching a prefix. This makes it easier to make changes to entries of a certain prefix. --- gix-index/src/access/mod.rs | 15 ++++++++++++--- gix-index/tests/index/access.rs | 2 ++ 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/gix-index/src/access/mod.rs b/gix-index/src/access/mod.rs index 5ed66e1637c..a67d1b5e6e3 100644 --- a/gix-index/src/access/mod.rs +++ b/gix-index/src/access/mod.rs @@ -184,9 +184,18 @@ impl State { } /// Return the slice of entries which all share the same `prefix`, or `None` if there isn't a single such entry. + /// + /// If `prefix` is empty, all entries are returned. pub fn prefixed_entries(&self, prefix: &BStr) -> Option<&[Entry]> { + self.prefixed_entries_range(prefix).map(|range| &self.entries[range]) + } + + /// Return the range of entries which all share the same `prefix`, or `None` if there isn't a single such entry. + /// + /// If `prefix` is empty, the range will include all entries. + pub fn prefixed_entries_range(&self, prefix: &BStr) -> Option> { if prefix.is_empty() { - return Some(self.entries()); + return Some(0..self.entries.len()); } let prefix_len = prefix.len(); let mut low = self @@ -195,7 +204,7 @@ impl State { let mut high = low + self.entries[low..].partition_point(|e| e.path(self).get(..prefix_len).map_or(false, |p| p <= prefix)); - let low_entry = &self.entries[low]; + let low_entry = &self.entries.get(low)?; if low_entry.stage() != 0 { low = self .walk_entry_stages(low_entry.path(self), low, Ordering::Less) @@ -208,7 +217,7 @@ impl State { .unwrap_or(high); } } - (low != high).then_some(low..high).map(|range| &self.entries[range]) + (low != high).then_some(low..high) } /// Return the entry at `idx` or _panic_ if the index is out of bounds. diff --git a/gix-index/tests/index/access.rs b/gix-index/tests/index/access.rs index 377e4012a5b..3544f5921a1 100644 --- a/gix-index/tests/index/access.rs +++ b/gix-index/tests/index/access.rs @@ -50,6 +50,8 @@ fn prefixed_entries_with_multi_stage_file() { file.entries(), "empty prefix matches all" ); + assert_eq!(file.prefixed_entries_range("".into()), Some(0..3)); + assert_eq!(file.prefixed_entries_range("foo".into()), None); } #[test] From 6fdbc667c20f10734390341b435c15c73b7cd227 Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Fri, 1 Sep 2023 08:40:34 +0200 Subject: [PATCH 0058/1077] prepare `gix-index` release --- gix-date/CHANGELOG.md | 33 +++++++++++++++++++++- gix-index/CHANGELOG.md | 63 +++++++++++++++++++++++++++++++++++++++++- 2 files changed, 94 insertions(+), 2 deletions(-) diff --git a/gix-date/CHANGELOG.md b/gix-date/CHANGELOG.md index 014b4d3abb2..7c654b442d4 100644 --- a/gix-date/CHANGELOG.md +++ b/gix-date/CHANGELOG.md @@ -5,6 +5,36 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## Unreleased + +A maintenance release without user-facing changes. + +### Commit Statistics + + + + - 2 commits contributed to the release over the course of 9 calendar days. + - 9 days passed between releases. + - 0 commits were understood as [conventional](https://www.conventionalcommits.org). + - 0 issues like '(#ID)' were seen in commit messages + +### Thanks Clippy + + + +[Clippy](https://github.com/rust-lang/rust-clippy) helped 1 time to make code idiomatic. + +### Commit Details + + + +

view details + + * **Uncategorized** + - Thanks clippy ([`5044c3b`](https://github.com/Byron/gitoxide/commit/5044c3b87456cf58ebfbbd00f23c9ba671cb290c)) + - Merge branch 'gix-submodule' ([`363ee77`](https://github.com/Byron/gitoxide/commit/363ee77400805f473c9ad66eadad9214e7ab66f4)) +
+ ## 0.7.3 (2023-08-22) @@ -17,7 +47,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - - 2 commits contributed to the release over the course of 4 calendar days. + - 3 commits contributed to the release over the course of 4 calendar days. - 15 days passed between releases. - 1 commit was understood as [conventional](https://www.conventionalcommits.org). - 0 issues like '(#ID)' were seen in commit messages @@ -29,6 +59,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
view details * **Uncategorized** + - Release gix-date v0.7.3, gix-hash v0.12.0, gix-features v0.33.0, gix-actor v0.25.0, gix-object v0.35.0, gix-path v0.9.0, gix-glob v0.11.0, gix-quote v0.4.7, gix-attributes v0.17.0, gix-command v0.2.9, gix-packetline-blocking v0.16.5, gix-filter v0.3.0, gix-fs v0.5.0, gix-commitgraph v0.19.0, gix-hashtable v0.3.0, gix-revwalk v0.6.0, gix-traverse v0.31.0, gix-worktree-stream v0.3.0, gix-archive v0.3.0, gix-config-value v0.13.0, gix-tempfile v8.0.0, gix-lock v8.0.0, gix-ref v0.35.0, gix-sec v0.9.0, gix-config v0.28.0, gix-prompt v0.6.0, gix-url v0.22.0, gix-credentials v0.18.0, gix-diff v0.34.0, gix-discover v0.23.0, gix-ignore v0.6.0, gix-bitmap v0.2.7, gix-index v0.22.0, gix-mailmap v0.17.0, gix-negotiate v0.6.0, gix-pack v0.41.0, gix-odb v0.51.0, gix-pathspec v0.1.0, gix-packetline v0.16.5, gix-transport v0.35.0, gix-protocol v0.38.0, gix-revision v0.20.0, gix-refspec v0.16.0, gix-submodule v0.2.0, gix-worktree v0.24.0, gix-worktree-state v0.1.0, gix v0.52.0, gitoxide-core v0.31.0, gitoxide v0.29.0, safety bump 41 crates ([`30b2761`](https://github.com/Byron/gitoxide/commit/30b27615047692d3ced1b2d9c2ac15a80f79fbee)) - Update changelogs prior to release ([`f23ea88`](https://github.com/Byron/gitoxide/commit/f23ea8828f2d9ba7559973daca388c9591bcc5fc)) - Don't call crate 'WIP' in manifest anymore. ([`229bd48`](https://github.com/Byron/gitoxide/commit/229bd4899213f749a7cc124aa2b82a1368fba40f))
diff --git a/gix-index/CHANGELOG.md b/gix-index/CHANGELOG.md index 8cbbe1ed442..036f43c332e 100644 --- a/gix-index/CHANGELOG.md +++ b/gix-index/CHANGELOG.md @@ -5,6 +5,65 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## Unreleased + +### New Features + + - add `State::prefixed_range()` to obtain a range of entries matching a prefix. + This makes it easier to make changes to entries of a certain prefix. + - add `State::remove_entries()` and `entry_range()`. + This makes it possible to, among other things, delete all + occurrences of a particular entry. + - add support for `write::Options::skip_hash`. + With it, a hash will not be produced for indices. + +### Bug Fixes + + - `gix-index` prefix matching should now work correctly with conflicting files. + It was done in a rush and lacks a lot of tests. At least now it + has a greater chance of working, as tests that would truly validate + this are still missing for a lack of test date. It can be produced + with `git update-index`, but it wasn't yet worth it. + +### New Features (BREAKING) + + - Check the hash when reading via `File::at()` just like `git`, or skip the check. + Note that indices written with `index.skipHash=true` will be vastly + faster to read by a factor of 2 or more. + +### Bug Fixes (BREAKING) + + - skip the null-hash when validating the index. + This is needed for compatibility with `index.skipHash`, which may skip + producing the hash at the end of the index file, just filling in the + null-hash. + +### Commit Statistics + + + + - 8 commits contributed to the release over the course of 9 calendar days. + - 9 days passed between releases. + - 6 commits were understood as [conventional](https://www.conventionalcommits.org). + - 0 issues like '(#ID)' were seen in commit messages + +### Commit Details + + + +
view details + + * **Uncategorized** + - Add `State::prefixed_range()` to obtain a range of entries matching a prefix. ([`cfbfa43`](https://github.com/Byron/gitoxide/commit/cfbfa43069c8d82fbd74b8296f63fc050a5ba02a)) + - Add `State::remove_entries()` and `entry_range()`. ([`8b689c2`](https://github.com/Byron/gitoxide/commit/8b689c222668b0c35c508f1907b03cbd4ba09bba)) + - `gix-index` prefix matching should now work correctly with conflicting files. ([`6169325`](https://github.com/Byron/gitoxide/commit/616932516d122a24e29fb42c60147fe43c5cead9)) + - Merge branch 'fixes' ([`4bfd1cc`](https://github.com/Byron/gitoxide/commit/4bfd1cc8f7922a8c4de6b9d078d54b93e78f51ff)) + - Check the hash when reading via `File::at()` just like `git`, or skip the check. ([`61c2e34`](https://github.com/Byron/gitoxide/commit/61c2e34b10c2ad5c92edd4ec1d5d1be2317ac481)) + - Add support for `write::Options::skip_hash`. ([`2f42132`](https://github.com/Byron/gitoxide/commit/2f42132410ef47a7c274030811452ef40701c8a0)) + - Skip the null-hash when validating the index. ([`b310d04`](https://github.com/Byron/gitoxide/commit/b310d044ac5c2bb1c874d0cfe701411e4aef47be)) + - Merge branch 'gix-submodule' ([`363ee77`](https://github.com/Byron/gitoxide/commit/363ee77400805f473c9ad66eadad9214e7ab66f4)) +
+ ## 0.22.0 (2023-08-22) @@ -26,7 +85,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - - 11 commits contributed to the release over the course of 18 calendar days. + - 13 commits contributed to the release over the course of 18 calendar days. - 30 days passed between releases. - 3 commits were understood as [conventional](https://www.conventionalcommits.org). - 0 issues like '(#ID)' were seen in commit messages @@ -38,8 +97,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
view details * **Uncategorized** + - Release gix-url v0.22.0, gix-credentials v0.18.0, gix-diff v0.34.0, gix-discover v0.23.0, gix-ignore v0.6.0, gix-bitmap v0.2.7, gix-index v0.22.0, gix-mailmap v0.17.0, gix-negotiate v0.6.0, gix-pack v0.41.0, gix-odb v0.51.0, gix-pathspec v0.1.0, gix-packetline v0.16.5, gix-transport v0.35.0, gix-protocol v0.38.0, gix-revision v0.20.0, gix-refspec v0.16.0, gix-submodule v0.2.0, gix-worktree v0.24.0, gix-worktree-state v0.1.0, gix v0.52.0, gitoxide-core v0.31.0, gitoxide v0.29.0 ([`6c62e74`](https://github.com/Byron/gitoxide/commit/6c62e748240ac0980fc23fdf30f8477dea8b9bc3)) - Release gix-date v0.7.3, gix-hash v0.12.0, gix-features v0.33.0, gix-actor v0.25.0, gix-object v0.35.0, gix-path v0.9.0, gix-glob v0.11.0, gix-quote v0.4.7, gix-attributes v0.17.0, gix-command v0.2.9, gix-packetline-blocking v0.16.5, gix-filter v0.3.0, gix-fs v0.5.0, gix-commitgraph v0.19.0, gix-hashtable v0.3.0, gix-revwalk v0.6.0, gix-traverse v0.31.0, gix-worktree-stream v0.3.0, gix-archive v0.3.0, gix-config-value v0.13.0, gix-tempfile v8.0.0, gix-lock v8.0.0, gix-ref v0.35.0, gix-sec v0.9.0, gix-config v0.28.0, gix-prompt v0.6.0, gix-url v0.22.0, gix-credentials v0.18.0, gix-diff v0.34.0, gix-discover v0.23.0, gix-ignore v0.6.0, gix-bitmap v0.2.7, gix-index v0.22.0, gix-mailmap v0.17.0, gix-negotiate v0.6.0, gix-pack v0.41.0, gix-odb v0.51.0, gix-pathspec v0.1.0, gix-packetline v0.16.5, gix-transport v0.35.0, gix-protocol v0.38.0, gix-revision v0.20.0, gix-refspec v0.16.0, gix-submodule v0.2.0, gix-worktree v0.24.0, gix-worktree-state v0.1.0, gix v0.52.0, gitoxide-core v0.31.0, gitoxide v0.29.0, safety bump 41 crates ([`30b2761`](https://github.com/Byron/gitoxide/commit/30b27615047692d3ced1b2d9c2ac15a80f79fbee)) - Update changelogs prior to release ([`f23ea88`](https://github.com/Byron/gitoxide/commit/f23ea8828f2d9ba7559973daca388c9591bcc5fc)) + - Merge branch 'gix-submodule' ([`8f3f358`](https://github.com/Byron/gitoxide/commit/8f3f358800f1fe77d7ba7ebd396a90b692d3c0c1)) - More cleanup of test crates ([`73c685a`](https://github.com/Byron/gitoxide/commit/73c685a67debcfa26a940f37bbca69cb3a4af57e)) - Split tests off into their own crate to allow feature toggles. ([`93feea2`](https://github.com/Byron/gitoxide/commit/93feea269eebd114e866e6f29f4a73c0096df9e0)) - Merge branch 'submodule-in-gix' ([`36f7b78`](https://github.com/Byron/gitoxide/commit/36f7b783c67b8a087076a130f5ee9b90b23bc3cc)) From 3be2b1ccfe30eeae45711c64b88efc522a2b51b7 Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Fri, 1 Sep 2023 08:41:39 +0200 Subject: [PATCH 0059/1077] Release gix-date v0.7.4, gix-index v0.23.0, safety bump 5 crates SAFETY BUMP: gix-worktree v0.25.0, gix-worktree-state v0.2.0, gix v0.53.0, gitoxide-core v0.32.0, gitoxide v0.30.0 --- Cargo.lock | 72 +++++++++++++++++------------------ Cargo.toml | 6 +-- gitoxide-core/Cargo.toml | 4 +- gix-archive/Cargo.toml | 2 +- gix-date/CHANGELOG.md | 5 ++- gix-date/Cargo.toml | 2 +- gix-index/CHANGELOG.md | 5 ++- gix-index/Cargo.toml | 2 +- gix-mailmap/Cargo.toml | 2 +- gix-negotiate/Cargo.toml | 2 +- gix-odb/Cargo.toml | 2 +- gix-protocol/Cargo.toml | 2 +- gix-ref/Cargo.toml | 2 +- gix-revision/Cargo.toml | 2 +- gix-status/Cargo.toml | 2 +- gix-worktree-state/Cargo.toml | 6 +-- gix-worktree/Cargo.toml | 4 +- gix/Cargo.toml | 10 ++--- 18 files changed, 67 insertions(+), 65 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 6bdceb90a90..ee4cb6d4287 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1123,7 +1123,7 @@ checksum = "b6c80984affa11d98d1b88b66ac8853f143217b399d3c74116778ff8fdb4ed2e" [[package]] name = "gitoxide" -version = "0.29.0" +version = "0.30.0" dependencies = [ "anyhow", "clap", @@ -1148,7 +1148,7 @@ dependencies = [ [[package]] name = "gitoxide-core" -version = "0.31.0" +version = "0.32.0" dependencies = [ "anyhow", "async-io", @@ -1185,7 +1185,7 @@ dependencies = [ [[package]] name = "gix" -version = "0.52.0" +version = "0.53.0" dependencies = [ "anyhow", "async-std", @@ -1196,7 +1196,7 @@ dependencies = [ "gix-commitgraph", "gix-config", "gix-credentials", - "gix-date 0.7.3", + "gix-date 0.7.4", "gix-diff", "gix-discover 0.23.0", "gix-features 0.33.0", @@ -1206,7 +1206,7 @@ dependencies = [ "gix-hash 0.12.0", "gix-hashtable 0.3.0", "gix-ignore 0.6.0", - "gix-index 0.22.0", + "gix-index 0.23.0", "gix-lock 8.0.0", "gix-mailmap", "gix-negotiate", @@ -1230,7 +1230,7 @@ dependencies = [ "gix-url", "gix-utils 0.1.5", "gix-validate 0.8.0", - "gix-worktree 0.24.0", + "gix-worktree 0.25.0", "gix-worktree-state", "gix-worktree-stream", "is_ci", @@ -1270,7 +1270,7 @@ dependencies = [ "bstr", "btoi", "document-features", - "gix-date 0.7.3", + "gix-date 0.7.4", "gix-features 0.33.0", "gix-hash 0.12.0", "gix-testtools", @@ -1289,14 +1289,14 @@ dependencies = [ "document-features", "flate2", "gix-attributes 0.17.0", - "gix-date 0.7.3", + "gix-date 0.7.4", "gix-filter", "gix-hash 0.12.0", "gix-object 0.35.0", "gix-odb", "gix-path 0.9.0", "gix-testtools", - "gix-worktree 0.24.0", + "gix-worktree 0.25.0", "gix-worktree-stream", "tar", "thiserror", @@ -1379,7 +1379,7 @@ dependencies = [ "bstr", "document-features", "gix-chunk", - "gix-date 0.7.3", + "gix-date 0.7.4", "gix-features 0.33.0", "gix-hash 0.12.0", "gix-testtools", @@ -1469,7 +1469,7 @@ dependencies = [ [[package]] name = "gix-date" -version = "0.7.3" +version = "0.7.4" dependencies = [ "bstr", "document-features", @@ -1596,7 +1596,7 @@ dependencies = [ "gix-quote 0.4.7", "gix-testtools", "gix-trace 0.1.3", - "gix-worktree 0.24.0", + "gix-worktree 0.25.0", "once_cell", "smallvec", "thiserror", @@ -1736,7 +1736,7 @@ dependencies = [ [[package]] name = "gix-index" -version = "0.22.0" +version = "0.23.0" dependencies = [ "bitflags 2.3.3", "bstr", @@ -1766,7 +1766,7 @@ dependencies = [ "gix", "gix-features 0.33.0", "gix-hash 0.12.0", - "gix-index 0.22.0", + "gix-index 0.23.0", "gix-testtools", ] @@ -1802,7 +1802,7 @@ dependencies = [ "bstr", "document-features", "gix-actor 0.25.0", - "gix-date 0.7.3", + "gix-date 0.7.4", "gix-testtools", "serde", "thiserror", @@ -1814,7 +1814,7 @@ version = "0.6.0" dependencies = [ "bitflags 2.3.3", "gix-commitgraph", - "gix-date 0.7.3", + "gix-date 0.7.4", "gix-hash 0.12.0", "gix-object 0.35.0", "gix-odb", @@ -1857,7 +1857,7 @@ dependencies = [ "criterion", "document-features", "gix-actor 0.25.0", - "gix-date 0.7.3", + "gix-date 0.7.4", "gix-features 0.33.0", "gix-hash 0.12.0", "gix-testtools", @@ -1876,7 +1876,7 @@ version = "0.51.0" dependencies = [ "arc-swap", "document-features", - "gix-date 0.7.3", + "gix-date 0.7.4", "gix-features 0.33.0", "gix-hash 0.12.0", "gix-object 0.35.0", @@ -1895,7 +1895,7 @@ version = "0.0.0" dependencies = [ "filetime", "gix-actor 0.25.0", - "gix-date 0.7.3", + "gix-date 0.7.4", "gix-features 0.33.0", "gix-hash 0.12.0", "gix-object 0.35.0", @@ -2042,7 +2042,7 @@ dependencies = [ "futures-io", "futures-lite", "gix-credentials", - "gix-date 0.7.3", + "gix-date 0.7.4", "gix-features 0.33.0", "gix-hash 0.12.0", "gix-packetline", @@ -2104,7 +2104,7 @@ version = "0.35.0" dependencies = [ "document-features", "gix-actor 0.25.0", - "gix-date 0.7.3", + "gix-date 0.7.4", "gix-features 0.33.0", "gix-fs 0.5.0", "gix-hash 0.12.0", @@ -2125,7 +2125,7 @@ name = "gix-ref-tests" version = "0.0.0" dependencies = [ "gix-actor 0.25.0", - "gix-date 0.7.3", + "gix-date 0.7.4", "gix-discover 0.23.0", "gix-features 0.33.0", "gix-fs 0.5.0", @@ -2158,7 +2158,7 @@ dependencies = [ "bstr", "document-features", "gix-commitgraph", - "gix-date 0.7.3", + "gix-date 0.7.4", "gix-hash 0.12.0", "gix-hashtable 0.3.0", "gix-object 0.35.0", @@ -2175,7 +2175,7 @@ name = "gix-revwalk" version = "0.6.0" dependencies = [ "gix-commitgraph", - "gix-date 0.7.3", + "gix-date 0.7.4", "gix-hash 0.12.0", "gix-hashtable 0.3.0", "gix-object 0.35.0", @@ -2221,7 +2221,7 @@ dependencies = [ "gix-features 0.33.0", "gix-fs 0.5.0", "gix-hash 0.12.0", - "gix-index 0.22.0", + "gix-index 0.23.0", "gix-object 0.35.0", "gix-path 0.9.0", "thiserror", @@ -2236,7 +2236,7 @@ dependencies = [ "gix-features 0.33.0", "gix-fs 0.5.0", "gix-hash 0.12.0", - "gix-index 0.22.0", + "gix-index 0.23.0", "gix-object 0.35.0", "gix-status", "gix-testtools", @@ -2373,7 +2373,7 @@ name = "gix-traverse" version = "0.31.0" dependencies = [ "gix-commitgraph", - "gix-date 0.7.3", + "gix-date 0.7.4", "gix-hash 0.12.0", "gix-hashtable 0.3.0", "gix-object 0.35.0", @@ -2472,7 +2472,7 @@ dependencies = [ [[package]] name = "gix-worktree" -version = "0.24.0" +version = "0.25.0" dependencies = [ "bstr", "document-features", @@ -2482,7 +2482,7 @@ dependencies = [ "gix-glob 0.11.0", "gix-hash 0.12.0", "gix-ignore 0.6.0", - "gix-index 0.22.0", + "gix-index 0.23.0", "gix-object 0.35.0", "gix-path 0.9.0", "serde", @@ -2490,7 +2490,7 @@ dependencies = [ [[package]] name = "gix-worktree-state" -version = "0.1.0" +version = "0.2.0" dependencies = [ "bstr", "gix-features 0.33.0", @@ -2498,10 +2498,10 @@ dependencies = [ "gix-fs 0.5.0", "gix-glob 0.11.0", "gix-hash 0.12.0", - "gix-index 0.22.0", + "gix-index 0.23.0", "gix-object 0.35.0", "gix-path 0.9.0", - "gix-worktree 0.24.0", + "gix-worktree 0.25.0", "io-close", "thiserror", ] @@ -2515,7 +2515,7 @@ dependencies = [ "gix-filter", "gix-fs 0.5.0", "gix-hash 0.12.0", - "gix-index 0.22.0", + "gix-index 0.23.0", "gix-object 0.35.0", "gix-odb", "gix-testtools", @@ -2539,7 +2539,7 @@ dependencies = [ "gix-path 0.9.0", "gix-testtools", "gix-traverse 0.31.0", - "gix-worktree 0.24.0", + "gix-worktree 0.25.0", "parking_lot", "thiserror", ] @@ -2556,12 +2556,12 @@ dependencies = [ "gix-glob 0.11.0", "gix-hash 0.12.0", "gix-ignore 0.6.0", - "gix-index 0.22.0", + "gix-index 0.23.0", "gix-object 0.35.0", "gix-odb", "gix-path 0.9.0", "gix-testtools", - "gix-worktree 0.24.0", + "gix-worktree 0.25.0", "symlink", ] diff --git a/Cargo.toml b/Cargo.toml index c79cf19e1d6..c9f8cf70d4d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,7 +5,7 @@ repository = "https://github.com/Byron/gitoxide" authors = ["Sebastian Thiel "] edition = "2021" license = "MIT OR Apache-2.0" -version = "0.29.0" +version = "0.30.0" default-run = "gix" include = ["src/**/*", "LICENSE-*", "README.md", "CHANGELOG.md"] resolver = "2" @@ -162,9 +162,9 @@ gitoxide-core-async-client = ["gitoxide-core/async-client", "futures-lite"] [dependencies] anyhow = "1.0.42" -gitoxide-core = { version = "^0.31.0", path = "gitoxide-core" } +gitoxide-core = { version = "^0.32.0", path = "gitoxide-core" } gix-features = { version = "^0.33.0", path = "gix-features" } -gix = { version = "^0.52.0", path = "gix", default-features = false } +gix = { version = "^0.53.0", path = "gix", default-features = false } time = "0.3.23" clap = { version = "4.1.1", features = ["derive", "cargo"] } diff --git a/gitoxide-core/Cargo.toml b/gitoxide-core/Cargo.toml index 1d76bcc0a84..2b1873d704d 100644 --- a/gitoxide-core/Cargo.toml +++ b/gitoxide-core/Cargo.toml @@ -2,7 +2,7 @@ name = "gitoxide-core" description = "The library implementing all capabilities of the gitoxide CLI" repository = "https://github.com/Byron/gitoxide" -version = "0.31.0" +version = "0.32.0" authors = ["Sebastian Thiel "] license = "MIT OR Apache-2.0" edition = "2021" @@ -44,7 +44,7 @@ serde = ["gix/serde", "dep:serde_json", "dep:serde", "bytesize/serde"] [dependencies] # deselect everything else (like "performance") as this should be controllable by the parent application. -gix = { version = "^0.52.0", path = "../gix", default-features = false } +gix = { version = "^0.53.0", path = "../gix", default-features = false } gix-pack-for-configuration-only = { package = "gix-pack", version = "^0.41.0", path = "../gix-pack", default-features = false, features = ["pack-cache-lru-dynamic", "pack-cache-lru-static"] } gix-transport-configuration-only = { package = "gix-transport", version = "^0.35.0", path = "../gix-transport", default-features = false } gix-archive-for-configuration-only = { package = "gix-archive", version = "^0.3.0", path = "../gix-archive", optional = true, features = ["tar", "tar_gz"] } diff --git a/gix-archive/Cargo.toml b/gix-archive/Cargo.toml index 16475c54346..f63bc1532b8 100644 --- a/gix-archive/Cargo.toml +++ b/gix-archive/Cargo.toml @@ -27,7 +27,7 @@ zip = ["dep:zip", "dep:time"] gix-worktree-stream = { version = "^0.3.0", path = "../gix-worktree-stream" } gix-object = { version = "^0.35.0", path = "../gix-object" } gix-path = { version = "^0.9.0", path = "../gix-path", optional = true } -gix-date = { version = "^0.7.3", path = "../gix-date" } +gix-date = { version = "^0.7.4", path = "../gix-date" } flate2 = { version = "1.0.26", optional = true } zip = { version = "0.6.6", optional = true, default-features = false, features = ["deflate", "time"] } diff --git a/gix-date/CHANGELOG.md b/gix-date/CHANGELOG.md index 7c654b442d4..29fd659b8b9 100644 --- a/gix-date/CHANGELOG.md +++ b/gix-date/CHANGELOG.md @@ -5,7 +5,7 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). -## Unreleased +## 0.7.4 (2023-09-01) A maintenance release without user-facing changes. @@ -13,7 +13,7 @@ A maintenance release without user-facing changes. - - 2 commits contributed to the release over the course of 9 calendar days. + - 3 commits contributed to the release over the course of 9 calendar days. - 9 days passed between releases. - 0 commits were understood as [conventional](https://www.conventionalcommits.org). - 0 issues like '(#ID)' were seen in commit messages @@ -31,6 +31,7 @@ A maintenance release without user-facing changes.
view details * **Uncategorized** + - Prepare `gix-index` release ([`6fdbc66`](https://github.com/Byron/gitoxide/commit/6fdbc667c20f10734390341b435c15c73b7cd227)) - Thanks clippy ([`5044c3b`](https://github.com/Byron/gitoxide/commit/5044c3b87456cf58ebfbbd00f23c9ba671cb290c)) - Merge branch 'gix-submodule' ([`363ee77`](https://github.com/Byron/gitoxide/commit/363ee77400805f473c9ad66eadad9214e7ab66f4))
diff --git a/gix-date/Cargo.toml b/gix-date/Cargo.toml index 7a6e46c79c4..5a58c241537 100644 --- a/gix-date/Cargo.toml +++ b/gix-date/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "gix-date" -version = "0.7.3" +version = "0.7.4" repository = "https://github.com/Byron/gitoxide" license = "MIT OR Apache-2.0" description = "A crate of the gitoxide project parsing dates the way git does" diff --git a/gix-index/CHANGELOG.md b/gix-index/CHANGELOG.md index 036f43c332e..80926a18076 100644 --- a/gix-index/CHANGELOG.md +++ b/gix-index/CHANGELOG.md @@ -5,7 +5,7 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). -## Unreleased +## 0.23.0 (2023-09-01) ### New Features @@ -42,7 +42,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - - 8 commits contributed to the release over the course of 9 calendar days. + - 9 commits contributed to the release over the course of 9 calendar days. - 9 days passed between releases. - 6 commits were understood as [conventional](https://www.conventionalcommits.org). - 0 issues like '(#ID)' were seen in commit messages @@ -54,6 +54,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
view details * **Uncategorized** + - Prepare `gix-index` release ([`6fdbc66`](https://github.com/Byron/gitoxide/commit/6fdbc667c20f10734390341b435c15c73b7cd227)) - Add `State::prefixed_range()` to obtain a range of entries matching a prefix. ([`cfbfa43`](https://github.com/Byron/gitoxide/commit/cfbfa43069c8d82fbd74b8296f63fc050a5ba02a)) - Add `State::remove_entries()` and `entry_range()`. ([`8b689c2`](https://github.com/Byron/gitoxide/commit/8b689c222668b0c35c508f1907b03cbd4ba09bba)) - `gix-index` prefix matching should now work correctly with conflicting files. ([`6169325`](https://github.com/Byron/gitoxide/commit/616932516d122a24e29fb42c60147fe43c5cead9)) diff --git a/gix-index/Cargo.toml b/gix-index/Cargo.toml index d37d1f95d50..deeda403f74 100644 --- a/gix-index/Cargo.toml +++ b/gix-index/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "gix-index" -version = "0.22.0" +version = "0.23.0" repository = "https://github.com/Byron/gitoxide" license = "MIT OR Apache-2.0" description = "A work-in-progress crate of the gitoxide project dedicated implementing the git index file" diff --git a/gix-mailmap/Cargo.toml b/gix-mailmap/Cargo.toml index cf2496155c6..68d077b131e 100644 --- a/gix-mailmap/Cargo.toml +++ b/gix-mailmap/Cargo.toml @@ -17,7 +17,7 @@ serde= ["dep:serde", "bstr/serde", "gix-actor/serde"] [dependencies] gix-actor = { version = "^0.25.0", path = "../gix-actor" } -gix-date = { version = "^0.7.3", path = "../gix-date" } +gix-date = { version = "^0.7.4", path = "../gix-date" } bstr = { version = "1.3.0", default-features = false, features = ["std", "unicode"]} thiserror = "1.0.38" serde = { version = "1.0.114", optional = true, default-features = false, features = ["derive"]} diff --git a/gix-negotiate/Cargo.toml b/gix-negotiate/Cargo.toml index 72f567a3f5c..75e19b1f3aa 100644 --- a/gix-negotiate/Cargo.toml +++ b/gix-negotiate/Cargo.toml @@ -15,7 +15,7 @@ test = false [dependencies] gix-hash = { version = "^0.12.0", path = "../gix-hash" } gix-object = { version = "^0.35.0", path = "../gix-object" } -gix-date = { version = "^0.7.3", path = "../gix-date" } +gix-date = { version = "^0.7.4", path = "../gix-date" } gix-commitgraph = { version = "^0.19.0", path = "../gix-commitgraph" } gix-revwalk = { version = "^0.6.0", path = "../gix-revwalk" } thiserror = "1.0.40" diff --git a/gix-odb/Cargo.toml b/gix-odb/Cargo.toml index 31ccdb1f0e2..6227447dd61 100644 --- a/gix-odb/Cargo.toml +++ b/gix-odb/Cargo.toml @@ -20,7 +20,7 @@ serde= ["dep:serde", "gix-hash/serde", "gix-object/serde", "gix-pack/serde"] [dependencies] gix-features = { version = "^0.33.0", path = "../gix-features", features = ["rustsha1", "walkdir", "zlib", "crc32" ] } gix-hash = { version = "^0.12.0", path = "../gix-hash" } -gix-date = { version = "^0.7.3", path = "../gix-date" } +gix-date = { version = "^0.7.4", path = "../gix-date" } gix-path = { version = "^0.9.0", path = "../gix-path" } gix-quote = { version = "^0.4.7", path = "../gix-quote" } gix-object = { version = "^0.35.0", path = "../gix-object" } diff --git a/gix-protocol/Cargo.toml b/gix-protocol/Cargo.toml index bbe40e8ca8a..b92650c2814 100644 --- a/gix-protocol/Cargo.toml +++ b/gix-protocol/Cargo.toml @@ -43,7 +43,7 @@ required-features = ["async-client"] gix-features = { version = "^0.33.0", path = "../gix-features", features = ["progress"] } gix-transport = { version = "^0.35.0", path = "../gix-transport" } gix-hash = { version = "^0.12.0", path = "../gix-hash" } -gix-date = { version = "^0.7.3", path = "../gix-date" } +gix-date = { version = "^0.7.4", path = "../gix-date" } gix-credentials = { version = "^0.18.0", path = "../gix-credentials" } thiserror = "1.0.32" diff --git a/gix-ref/Cargo.toml b/gix-ref/Cargo.toml index a0b4d71b039..522792ae055 100644 --- a/gix-ref/Cargo.toml +++ b/gix-ref/Cargo.toml @@ -23,7 +23,7 @@ gix-features = { version = "^0.33.0", path = "../gix-features", features = ["wal gix-fs = { version = "^0.5.0", path = "../gix-fs" } gix-path = { version = "^0.9.0", path = "../gix-path" } gix-hash = { version = "^0.12.0", path = "../gix-hash" } -gix-date = { version = "^0.7.3", path = "../gix-date" } +gix-date = { version = "^0.7.4", path = "../gix-date" } gix-object = { version = "^0.35.0", path = "../gix-object" } gix-validate = { version = "^0.8.0", path = "../gix-validate" } gix-actor = { version = "^0.25.0", path = "../gix-actor" } diff --git a/gix-revision/Cargo.toml b/gix-revision/Cargo.toml index e55a5fd8fdb..538c18ef869 100644 --- a/gix-revision/Cargo.toml +++ b/gix-revision/Cargo.toml @@ -19,7 +19,7 @@ serde = [ "dep:serde", "gix-hash/serde", "gix-object/serde" ] [dependencies] gix-hash = { version = "^0.12.0", path = "../gix-hash" } gix-object = { version = "^0.35.0", path = "../gix-object" } -gix-date = { version = "^0.7.3", path = "../gix-date" } +gix-date = { version = "^0.7.4", path = "../gix-date" } gix-hashtable = { version = "^0.3.0", path = "../gix-hashtable" } gix-revwalk = { version = "^0.6.0", path = "../gix-revwalk" } gix-trace = { version = "^0.1.3", path = "../gix-trace" } diff --git a/gix-status/Cargo.toml b/gix-status/Cargo.toml index 51a385b10b9..fe310e937ba 100644 --- a/gix-status/Cargo.toml +++ b/gix-status/Cargo.toml @@ -14,7 +14,7 @@ autotests = false doctest = false [dependencies] -gix-index = { version = "^0.22.0", path = "../gix-index" } +gix-index = { version = "^0.23.0", path = "../gix-index" } gix-fs = { version = "^0.5.0", path = "../gix-fs" } gix-hash = { version = "^0.12.0", path = "../gix-hash" } gix-object = { version = "^0.35.0", path = "../gix-object" } diff --git a/gix-worktree-state/Cargo.toml b/gix-worktree-state/Cargo.toml index 3aa1876a755..d93bd350f7c 100644 --- a/gix-worktree-state/Cargo.toml +++ b/gix-worktree-state/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "gix-worktree-state" -version = "0.1.0" +version = "0.2.0" repository = "https://github.com/Byron/gitoxide" license = "MIT OR Apache-2.0" description = "A crate of the gitoxide project implementing setting the worktree to a particular state" @@ -14,8 +14,8 @@ autotests = false doctest = false [dependencies] -gix-worktree = { version = "^0.24.0", path = "../gix-worktree" } -gix-index = { version = "^0.22.0", path = "../gix-index" } +gix-worktree = { version = "^0.25.0", path = "../gix-worktree" } +gix-index = { version = "^0.23.0", path = "../gix-index" } gix-fs = { version = "^0.5.0", path = "../gix-fs" } gix-hash = { version = "^0.12.0", path = "../gix-hash" } gix-object = { version = "^0.35.0", path = "../gix-object" } diff --git a/gix-worktree/Cargo.toml b/gix-worktree/Cargo.toml index 547bf26cabb..ef8b7af5eed 100644 --- a/gix-worktree/Cargo.toml +++ b/gix-worktree/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "gix-worktree" -version = "0.24.0" +version = "0.25.0" repository = "https://github.com/Byron/gitoxide" license = "MIT OR Apache-2.0" description = "A crate of the gitoxide project for shared worktree related types and utilities." @@ -18,7 +18,7 @@ doctest = false serde = [ "dep:serde", "bstr/serde", "gix-index/serde", "gix-hash/serde", "gix-object/serde", "gix-attributes/serde", "gix-ignore/serde" ] [dependencies] -gix-index = { version = "^0.22.0", path = "../gix-index" } +gix-index = { version = "^0.23.0", path = "../gix-index" } gix-fs = { version = "^0.5.0", path = "../gix-fs" } gix-hash = { version = "^0.12.0", path = "../gix-hash" } gix-object = { version = "^0.35.0", path = "../gix-object" } diff --git a/gix/Cargo.toml b/gix/Cargo.toml index 7c3fe382cde..a3df037b248 100644 --- a/gix/Cargo.toml +++ b/gix/Cargo.toml @@ -3,7 +3,7 @@ name = "gix" repository = "https://github.com/Byron/gitoxide" description = "Interact with git repositories just like git would" license = "MIT OR Apache-2.0" -version = "0.52.0" +version = "0.53.0" authors = ["Sebastian Thiel "] edition = "2021" include = ["src/**/*", "LICENSE-*", "CHANGELOG.md"] @@ -134,7 +134,7 @@ gix-tempfile = { version = "^8.0.0", path = "../gix-tempfile", default-features gix-lock = { version = "^8.0.0", path = "../gix-lock" } gix-validate = { version = "^0.8.0", path = "../gix-validate" } gix-sec = { version = "^0.9.0", path = "../gix-sec" } -gix-date = { version = "^0.7.3", path = "../gix-date" } +gix-date = { version = "^0.7.4", path = "../gix-date" } gix-refspec = { version = "^0.16.0", path = "../gix-refspec" } gix-filter = { version = "^0.3.0", path = "../gix-filter" } @@ -160,9 +160,9 @@ gix-ignore = { version = "^0.6.0", path = "../gix-ignore" } gix-glob = { version = "^0.11.0", path = "../gix-glob" } gix-credentials = { version = "^0.18.0", path = "../gix-credentials" } gix-prompt = { version = "^0.6.0", path = "../gix-prompt" } -gix-index = { version = "^0.22.0", path = "../gix-index" } -gix-worktree = { version = "^0.24.0", path = "../gix-worktree" } -gix-worktree-state = { version = "^0.1.0", path = "../gix-worktree-state" } +gix-index = { version = "^0.23.0", path = "../gix-index" } +gix-worktree = { version = "^0.25.0", path = "../gix-worktree" } +gix-worktree-state = { version = "^0.2.0", path = "../gix-worktree-state" } gix-hashtable = { version = "^0.3.0", path = "../gix-hashtable" } gix-commitgraph = { version = "^0.19.0", path = "../gix-commitgraph" } gix-pathspec = { version = "^0.1.0", path = "../gix-pathspec" } From 6a8314bb99099e2a3f5364a5761a5254aa36393a Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Fri, 1 Sep 2023 15:40:11 +0200 Subject: [PATCH 0060/1077] fix: `prefixed_entries_range()` now works correctly with directory prefixes. Previously, not all directory prefixes would work as expected due to incorrect search criteria. --- gix-index/src/access/mod.rs | 12 +++++++----- gix-index/tests/index/access.rs | 31 ++++++++++++++++++++++++++++--- 2 files changed, 35 insertions(+), 8 deletions(-) diff --git a/gix-index/src/access/mod.rs b/gix-index/src/access/mod.rs index a67d1b5e6e3..08cb2302011 100644 --- a/gix-index/src/access/mod.rs +++ b/gix-index/src/access/mod.rs @@ -198,9 +198,11 @@ impl State { return Some(0..self.entries.len()); } let prefix_len = prefix.len(); - let mut low = self - .entries - .partition_point(|e| e.path(self).get(..prefix_len).map_or(true, |p| p < prefix)); + let mut low = self.entries.partition_point(|e| { + e.path(self) + .get(..prefix_len) + .map_or_else(|| e.path(self) <= &prefix[..e.path.len()], |p| p < prefix) + }); let mut high = low + self.entries[low..].partition_point(|e| e.path(self).get(..prefix_len).map_or(false, |p| p <= prefix)); @@ -211,9 +213,9 @@ impl State { .unwrap_or(low); } if let Some(high_entry) = self.entries.get(high) { - if high_entry.stage() != 3 { + if high_entry.stage() != 0 { high = self - .walk_entry_stages(high_entry.path(self), high, Ordering::Greater) + .walk_entry_stages(high_entry.path(self), high, Ordering::Less) .unwrap_or(high); } } diff --git a/gix-index/tests/index/access.rs b/gix-index/tests/index/access.rs index 3544f5921a1..b5f65797964 100644 --- a/gix-index/tests/index/access.rs +++ b/gix-index/tests/index/access.rs @@ -114,7 +114,6 @@ fn sort_entries() { "we can find the correct entry now" ); - check_prefix(&file, "a", &["a", "an initially incorrectly ordered entry"]); check_prefix( &file, "d", @@ -126,18 +125,44 @@ fn sort_entries() { &["d/a", "d/b", "d/c", "d/last/123", "d/last/34", "d/last/6"], ); check_prefix(&file, "d/last", &["d/last/123", "d/last/34", "d/last/6"]); + check_prefix(&file, "d/last/", &["d/last/123", "d/last/34", "d/last/6"]); check_prefix(&file, "d/las", &["d/last/123", "d/last/34", "d/last/6"]); + check_prefix(&file, "d/last/123", &["d/last/123"]); + check_prefix(&file, "d/last/34", &["d/last/34"]); + check_prefix(&file, "d/last/6", &["d/last/6"]); + check_prefix(&file, "x", &["x"]); + check_prefix(&file, "a", &["a", "an initially incorrectly ordered entry"]); +} + +#[test] +fn prefixed_entries() { + let mut file = Fixture::Generated("v4_more_files_IEOT").open(); + let entry = file.entry(0).clone(); + let new_entry_path = "an initially incorrectly ordered entry".into(); + file.dangerously_push_entry(entry.stat, entry.id, entry.flags, entry.mode, new_entry_path); + file.sort_entries(); + + check_prefix(&file, "a", &["a", "an initially incorrectly ordered entry"]); + check_prefix(&file, "an", &["an initially incorrectly ordered entry"]); + check_prefix( + &file, + "an initially incorrectly ordered entry", + &["an initially incorrectly ordered entry"], + ); check_prefix(&file, "x", &["x"]); + check_prefix(&file, "b", &["b"]); + check_prefix(&file, "c", &["c"]); } fn check_prefix(index: &gix_index::State, prefix: &str, expected: &[&str]) { assert_eq!( index .prefixed_entries(prefix.into()) - .expect("present") + .unwrap_or_else(|| panic!("{prefix:?} must match at least one entry")) .iter() .map(|e| e.path(index)) .collect::>(), - expected + expected, + "{prefix:?}" ); } From 11b9c71311df978ebb20cca0d765cf249c8eedcf Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Fri, 1 Sep 2023 18:02:21 +0200 Subject: [PATCH 0061/1077] Release gix-index v0.23.1 --- Cargo.lock | 18 +++++++++--------- gix-index/CHANGELOG.md | 29 ++++++++++++++++++++++++++++- gix-index/Cargo.toml | 2 +- gix-status/Cargo.toml | 2 +- gix-worktree-state/Cargo.toml | 2 +- gix-worktree/Cargo.toml | 2 +- gix/Cargo.toml | 2 +- 7 files changed, 42 insertions(+), 15 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index ee4cb6d4287..1663ffecdf3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1206,7 +1206,7 @@ dependencies = [ "gix-hash 0.12.0", "gix-hashtable 0.3.0", "gix-ignore 0.6.0", - "gix-index 0.23.0", + "gix-index 0.23.1", "gix-lock 8.0.0", "gix-mailmap", "gix-negotiate", @@ -1736,7 +1736,7 @@ dependencies = [ [[package]] name = "gix-index" -version = "0.23.0" +version = "0.23.1" dependencies = [ "bitflags 2.3.3", "bstr", @@ -1766,7 +1766,7 @@ dependencies = [ "gix", "gix-features 0.33.0", "gix-hash 0.12.0", - "gix-index 0.23.0", + "gix-index 0.23.1", "gix-testtools", ] @@ -2221,7 +2221,7 @@ dependencies = [ "gix-features 0.33.0", "gix-fs 0.5.0", "gix-hash 0.12.0", - "gix-index 0.23.0", + "gix-index 0.23.1", "gix-object 0.35.0", "gix-path 0.9.0", "thiserror", @@ -2236,7 +2236,7 @@ dependencies = [ "gix-features 0.33.0", "gix-fs 0.5.0", "gix-hash 0.12.0", - "gix-index 0.23.0", + "gix-index 0.23.1", "gix-object 0.35.0", "gix-status", "gix-testtools", @@ -2482,7 +2482,7 @@ dependencies = [ "gix-glob 0.11.0", "gix-hash 0.12.0", "gix-ignore 0.6.0", - "gix-index 0.23.0", + "gix-index 0.23.1", "gix-object 0.35.0", "gix-path 0.9.0", "serde", @@ -2498,7 +2498,7 @@ dependencies = [ "gix-fs 0.5.0", "gix-glob 0.11.0", "gix-hash 0.12.0", - "gix-index 0.23.0", + "gix-index 0.23.1", "gix-object 0.35.0", "gix-path 0.9.0", "gix-worktree 0.25.0", @@ -2515,7 +2515,7 @@ dependencies = [ "gix-filter", "gix-fs 0.5.0", "gix-hash 0.12.0", - "gix-index 0.23.0", + "gix-index 0.23.1", "gix-object 0.35.0", "gix-odb", "gix-testtools", @@ -2556,7 +2556,7 @@ dependencies = [ "gix-glob 0.11.0", "gix-hash 0.12.0", "gix-ignore 0.6.0", - "gix-index 0.23.0", + "gix-index 0.23.1", "gix-object 0.35.0", "gix-odb", "gix-path 0.9.0", diff --git a/gix-index/CHANGELOG.md b/gix-index/CHANGELOG.md index 80926a18076..00bb5ae54f0 100644 --- a/gix-index/CHANGELOG.md +++ b/gix-index/CHANGELOG.md @@ -5,6 +5,32 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## 0.23.1 (2023-09-01) + +### Bug Fixes + + - `prefixed_entries_range()` now works correctly with directory prefixes. + Previously, not all directory prefixes would work as expected due to incorrect + search criteria. + +### Commit Statistics + + + + - 1 commit contributed to the release. + - 1 commit was understood as [conventional](https://www.conventionalcommits.org). + - 0 issues like '(#ID)' were seen in commit messages + +### Commit Details + + + +
view details + + * **Uncategorized** + - `prefixed_entries_range()` now works correctly with directory prefixes. ([`6a8314b`](https://github.com/Byron/gitoxide/commit/6a8314bb99099e2a3f5364a5761a5254aa36393a)) +
+ ## 0.23.0 (2023-09-01) ### New Features @@ -42,7 +68,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - - 9 commits contributed to the release over the course of 9 calendar days. + - 10 commits contributed to the release over the course of 9 calendar days. - 9 days passed between releases. - 6 commits were understood as [conventional](https://www.conventionalcommits.org). - 0 issues like '(#ID)' were seen in commit messages @@ -54,6 +80,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
view details * **Uncategorized** + - Release gix-date v0.7.4, gix-index v0.23.0, safety bump 5 crates ([`3be2b1c`](https://github.com/Byron/gitoxide/commit/3be2b1ccfe30eeae45711c64b88efc522a2b51b7)) - Prepare `gix-index` release ([`6fdbc66`](https://github.com/Byron/gitoxide/commit/6fdbc667c20f10734390341b435c15c73b7cd227)) - Add `State::prefixed_range()` to obtain a range of entries matching a prefix. ([`cfbfa43`](https://github.com/Byron/gitoxide/commit/cfbfa43069c8d82fbd74b8296f63fc050a5ba02a)) - Add `State::remove_entries()` and `entry_range()`. ([`8b689c2`](https://github.com/Byron/gitoxide/commit/8b689c222668b0c35c508f1907b03cbd4ba09bba)) diff --git a/gix-index/Cargo.toml b/gix-index/Cargo.toml index deeda403f74..d4e69c1afce 100644 --- a/gix-index/Cargo.toml +++ b/gix-index/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "gix-index" -version = "0.23.0" +version = "0.23.1" repository = "https://github.com/Byron/gitoxide" license = "MIT OR Apache-2.0" description = "A work-in-progress crate of the gitoxide project dedicated implementing the git index file" diff --git a/gix-status/Cargo.toml b/gix-status/Cargo.toml index fe310e937ba..e80e69dc7d1 100644 --- a/gix-status/Cargo.toml +++ b/gix-status/Cargo.toml @@ -14,7 +14,7 @@ autotests = false doctest = false [dependencies] -gix-index = { version = "^0.23.0", path = "../gix-index" } +gix-index = { version = "^0.23.1", path = "../gix-index" } gix-fs = { version = "^0.5.0", path = "../gix-fs" } gix-hash = { version = "^0.12.0", path = "../gix-hash" } gix-object = { version = "^0.35.0", path = "../gix-object" } diff --git a/gix-worktree-state/Cargo.toml b/gix-worktree-state/Cargo.toml index d93bd350f7c..72f5d75f9cf 100644 --- a/gix-worktree-state/Cargo.toml +++ b/gix-worktree-state/Cargo.toml @@ -15,7 +15,7 @@ doctest = false [dependencies] gix-worktree = { version = "^0.25.0", path = "../gix-worktree" } -gix-index = { version = "^0.23.0", path = "../gix-index" } +gix-index = { version = "^0.23.1", path = "../gix-index" } gix-fs = { version = "^0.5.0", path = "../gix-fs" } gix-hash = { version = "^0.12.0", path = "../gix-hash" } gix-object = { version = "^0.35.0", path = "../gix-object" } diff --git a/gix-worktree/Cargo.toml b/gix-worktree/Cargo.toml index ef8b7af5eed..8d66efef872 100644 --- a/gix-worktree/Cargo.toml +++ b/gix-worktree/Cargo.toml @@ -18,7 +18,7 @@ doctest = false serde = [ "dep:serde", "bstr/serde", "gix-index/serde", "gix-hash/serde", "gix-object/serde", "gix-attributes/serde", "gix-ignore/serde" ] [dependencies] -gix-index = { version = "^0.23.0", path = "../gix-index" } +gix-index = { version = "^0.23.1", path = "../gix-index" } gix-fs = { version = "^0.5.0", path = "../gix-fs" } gix-hash = { version = "^0.12.0", path = "../gix-hash" } gix-object = { version = "^0.35.0", path = "../gix-object" } diff --git a/gix/Cargo.toml b/gix/Cargo.toml index a3df037b248..e63f2504e83 100644 --- a/gix/Cargo.toml +++ b/gix/Cargo.toml @@ -160,7 +160,7 @@ gix-ignore = { version = "^0.6.0", path = "../gix-ignore" } gix-glob = { version = "^0.11.0", path = "../gix-glob" } gix-credentials = { version = "^0.18.0", path = "../gix-credentials" } gix-prompt = { version = "^0.6.0", path = "../gix-prompt" } -gix-index = { version = "^0.23.0", path = "../gix-index" } +gix-index = { version = "^0.23.1", path = "../gix-index" } gix-worktree = { version = "^0.25.0", path = "../gix-worktree" } gix-worktree-state = { version = "^0.2.0", path = "../gix-worktree-state" } gix-hashtable = { version = "^0.3.0", path = "../gix-hashtable" } From 4ef9a32307a5e91868161a5f683b6b97ad9ebbdd Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Sat, 2 Sep 2023 08:12:43 +0200 Subject: [PATCH 0062/1077] use a multi-call binary ('uni') to have only one build step (#987) This increases installation size, but should decrease build time as symbols and optimizations can be shared more. Once deduplication of generics has happened, these wins should increase even more. However, as it probably increases compile times for CI as it will take longer to build each binary with different compile time flags. Thus I just leave the `uni.rs` file for reference. --- Cargo.toml | 2 +- src/gix.rs | 1 - src/plumbing/main.rs | 14 ++++++-------- src/uni.rs | 28 ++++++++++++++++++++++++++++ 4 files changed, 35 insertions(+), 10 deletions(-) create mode 100644 src/uni.rs diff --git a/Cargo.toml b/Cargo.toml index c9f8cf70d4d..baec8272c27 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,8 +12,8 @@ resolver = "2" [[bin]] name = "ein" -doc = false path = "src/ein.rs" +doc = false test = false doctest = false diff --git a/src/gix.rs b/src/gix.rs index 7e78175060b..8527e57926a 100644 --- a/src/gix.rs +++ b/src/gix.rs @@ -1,7 +1,6 @@ #![deny(unsafe_code, rust_2018_idioms)] mod plumbing; -mod shared; use anyhow::Result; diff --git a/src/plumbing/main.rs b/src/plumbing/main.rs index 542fb402b4f..5ae9a9e3e78 100644 --- a/src/plumbing/main.rs +++ b/src/plumbing/main.rs @@ -13,16 +13,14 @@ use gitoxide_core as core; use gitoxide_core::{pack::verify, repository::PathsOrPatterns}; use gix::bstr::{io::BufReadExt, BString}; -use crate::{ - plumbing::{ - options::{ - attributes, commit, commitgraph, config, credential, exclude, free, index, mailmap, odb, revision, tree, - Args, Subcommands, - }, - show_progress, +use crate::plumbing::{ + options::{ + attributes, commit, commitgraph, config, credential, exclude, free, index, mailmap, odb, revision, tree, Args, + Subcommands, }, - shared::pretty::prepare_and_run, + show_progress, }; +use gitoxide::shared::pretty::prepare_and_run; #[cfg(feature = "gitoxide-core-async-client")] pub mod async_util { diff --git a/src/uni.rs b/src/uni.rs new file mode 100644 index 00000000000..b4a76ad6846 --- /dev/null +++ b/src/uni.rs @@ -0,0 +1,28 @@ +//! An experiment to see how a multi-call binary could look like. +//! For CI this would mean longer compile times though as it rebuilds `gix` +//! with varying compile flags, which also means that it recompiles all source or `ein`. +//! +//! However, doing this could be interesting for distribution if the files are hard-linked +//! instead of copied, which is why it is left here. +#![deny(unsafe_code, rust_2018_idioms)] + +use anyhow::{bail, Result}; + +mod plumbing; +mod porcelain; + +#[cfg(feature = "pretty-cli")] +fn main() -> Result<()> { + match std::env::current_exe()? + .file_stem() + .and_then(|stem| stem.to_str()) + .unwrap_or("gix") + { + "gix" => plumbing::main(), + "ein" => porcelain::main(), + unknown => bail!("Executable named '{unknown}' cannot be launched. Exe must be named either `gix` or `ein`."), + } +} + +#[cfg(not(feature = "pretty-cli"))] +compile_error!("Please set 'pretty-cli' feature flag"); From 25c5bcebd4dbc4ac189d8af044ed0352c6188ce8 Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Sat, 2 Sep 2023 09:05:35 +0200 Subject: [PATCH 0063/1077] fix!: `IsActivePlatform::is_active()` now only considers the URL in passed configuration Previously, it would consider the presence of `url` in the `.gitmodules` file as well, which is not the way git does it. --- gix-submodule/src/access.rs | 4 +-- gix-submodule/src/is_active_platform.rs | 33 ++++++------------------- gix-submodule/tests/file/mod.rs | 22 ++++++++--------- 3 files changed, 19 insertions(+), 40 deletions(-) diff --git a/gix-submodule/src/access.rs b/gix-submodule/src/access.rs index 4e688aabfb2..cbbeee62c5e 100644 --- a/gix-submodule/src/access.rs +++ b/gix-submodule/src/access.rs @@ -56,13 +56,13 @@ impl File { ) -> bool + 'a, ) -> Result< - impl Iterator)> + 'a, + impl Iterator)> + 'a, crate::is_active_platform::Error, > { let mut platform = self.is_active_platform(config, defaults)?; let iter = self .names() - .map(move |name| (name, platform.is_active(self, config, name, &mut attributes))); + .map(move |name| (name, platform.is_active(config, name, &mut attributes))); Ok(iter) } diff --git a/gix-submodule/src/is_active_platform.rs b/gix-submodule/src/is_active_platform.rs index 2cf45a6a17a..25d64a19aa0 100644 --- a/gix-submodule/src/is_active_platform.rs +++ b/gix-submodule/src/is_active_platform.rs @@ -12,34 +12,19 @@ pub enum Error { ParsePattern(#[from] gix_pathspec::parse::Error), } -/// -pub mod is_active { - /// The error returned by the iterator of [File::names_and_active_state](crate::File::names_and_active_state()). - #[derive(Debug, thiserror::Error)] - #[allow(missing_docs)] - pub enum Error { - #[error("The value of the 'active' field of a submodule could not be decoded")] - ActiveField(#[from] gix_config::value::Error), - #[error(transparent)] - Url(#[from] crate::config::url::Error), - } -} - impl IsActivePlatform { /// Returns `true` if the submodule named `name` is active or `false` otherwise. - /// `modules` is the instance that [is_active_platform()](crate::File::is_active_platform()) was called on, and - /// `config` is the configuration that was passed there as well. - /// `attributes(relative_path, case, is_dir, outcome)` provides a way to resolve the attributes mentioned in `submodule.active` pathspecs - /// that are evaluated in the platforms git configuration. + /// `config` is the configuration that was passed to the originating [modules file](crate::File). + /// `attributes(relative_path, case, is_dir, outcome)` provides a way to resolve the attributes mentioned + /// in `submodule.active` pathspecs that are evaluated in the platforms git configuration. /// /// A submodule's active state is determined in the following order /// - /// * it's `submodule..active` configuration is set + /// * it's `submodule..active` is set in `config` /// * it matches a `submodule.active` pathspec either positively or negatively via `:!` - /// * it's active if it has a `url` + /// * it's active if it has any `url` set in `config` pub fn is_active( &mut self, - modules: &crate::File, config: &gix_config::File<'static>, name: &BStr, attributes: impl FnMut( @@ -48,7 +33,7 @@ impl IsActivePlatform { bool, &mut gix_pathspec::attributes::search::Outcome, ) -> bool, - ) -> Result { + ) -> Result { if let Some(val) = config.boolean("submodule", Some(name), "active").transpose()? { return Ok(val); }; @@ -59,10 +44,6 @@ impl IsActivePlatform { }) { return Ok(val); } - Ok(match modules.url(name) { - Ok(_) => true, - Err(crate::config::url::Error::Missing { .. }) => false, - Err(err) => return Err(err.into()), - }) + Ok(config.string("submodule", Some(name), "url").is_some()) } } diff --git a/gix-submodule/tests/file/mod.rs b/gix-submodule/tests/file/mod.rs index 4969fa4312e..43309c1d712 100644 --- a/gix-submodule/tests/file/mod.rs +++ b/gix-submodule/tests/file/mod.rs @@ -46,25 +46,23 @@ mod is_active_platform { .map(|name| { ( name.to_str().expect("valid"), - platform - .is_active(module, config, name, &mut attributes) - .expect("valid"), + platform.is_active(config, name, &mut attributes).expect("valid"), ) }) .collect()) } #[test] - fn without_any_additional_settings_all_are_active_if_they_have_a_url() -> crate::Result { + fn without_any_additional_settings_all_are_inactive_if_they_have_a_url() -> crate::Result { let module = multi_modules()?; assert_eq!( assume_valid_active_state(&module, &Default::default(), Default::default())?, &[ - ("submodule", true), - ("a/b", true), - (".a/..c", true), - ("a/d\\", true), - ("a\\e", true) + ("submodule", false), + ("a/b", false), + (".a/..c", false), + ("a/d\\", false), + ("a\\e", false) ] ); Ok(()) @@ -77,7 +75,7 @@ mod is_active_platform { assume_valid_active_state( &module, &gix_config::File::from_str( - "[submodule.submodule]\n active = 0\n[submodule \"a/b\"]\n active = false" + "[submodule.submodule]\n active = 0\n url = set \n[submodule \"a/b\"]\n active = false \n url = set \n[submodule \".a/..c\"] active = 1" )?, Default::default() )?, @@ -85,8 +83,8 @@ mod is_active_platform { ("submodule", false), ("a/b", false), (".a/..c", true), - ("a/d\\", true), - ("a\\e", true) + ("a/d\\", false), + ("a\\e", false) ] ); Ok(()) From f8471b11e0d65fdb2617b927a8a207659a161439 Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Sat, 2 Sep 2023 09:21:35 +0200 Subject: [PATCH 0064/1077] adapt to changes in `gix-submodule` --- gix/src/submodule/errors.rs | 2 +- gix/src/submodule/mod.rs | 25 ++++++++++--------------- 2 files changed, 11 insertions(+), 16 deletions(-) diff --git a/gix/src/submodule/errors.rs b/gix/src/submodule/errors.rs index 7f99eedadfe..4e41337de45 100644 --- a/gix/src/submodule/errors.rs +++ b/gix/src/submodule/errors.rs @@ -39,7 +39,7 @@ pub mod is_active { #[error(transparent)] InitIsActivePlatform(#[from] gix_submodule::is_active_platform::Error), #[error(transparent)] - QueryIsActive(#[from] gix_submodule::is_active_platform::is_active::Error), + QueryIsActive(#[from] gix_config::value::Error), #[error(transparent)] InitAttributes(#[from] crate::config::attribute_stack::Error), #[error(transparent)] diff --git a/gix/src/submodule/mod.rs b/gix/src/submodule/mod.rs index 68263318e17..37ba35e6212 100644 --- a/gix/src/submodule/mod.rs +++ b/gix/src/submodule/mod.rs @@ -140,21 +140,16 @@ impl<'repo> Submodule<'repo> { /// Please see the [plumbing crate documentation](gix_submodule::IsActivePlatform::is_active()) for details. pub fn is_active(&self) -> Result { let (mut platform, mut attributes) = self.state.active_state_mut()?; - let is_active = platform.is_active( - &self.state.modules, - &self.state.repo.config.resolved, - self.name.as_ref(), - { - |relative_path, case, is_dir, out| { - attributes - .set_case(case) - .at_entry(relative_path, Some(is_dir), |id, buf| { - self.state.repo.objects.find_blob(id, buf) - }) - .map_or(false, |platform| platform.matching_attributes(out)) - } - }, - )?; + let is_active = platform.is_active(&self.state.repo.config.resolved, self.name.as_ref(), { + |relative_path, case, is_dir, out| { + attributes + .set_case(case) + .at_entry(relative_path, Some(is_dir), |id, buf| { + self.state.repo.objects.find_blob(id, buf) + }) + .map_or(false, |platform| platform.matching_attributes(out)) + } + })?; Ok(is_active) } From 4b74996b19176cb0f00860b3db5a27819d63e7d0 Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Sat, 2 Sep 2023 12:47:21 +0200 Subject: [PATCH 0065/1077] feat!: Make usage of decompression context explicit. That way, the context can be reused which is more efficient than recreating it from scratch for every little delta to decompress. This leads to a performance gain of 1.3%. --- gix-pack/src/bundle/find.rs | 15 +++++--- gix-pack/src/data/file/decode/entry.rs | 41 +++++++++++++++------- gix-pack/src/data/file/decode/header.rs | 13 ++++--- gix-pack/src/index/traverse/mod.rs | 3 ++ gix-pack/src/index/traverse/with_lookup.rs | 5 ++- gix-pack/tests/pack/bundle.rs | 16 +++++++-- gix-pack/tests/pack/data/file.rs | 15 +++++--- gix-pack/tests/pack/index.rs | 2 +- 8 files changed, 81 insertions(+), 29 deletions(-) diff --git a/gix-pack/src/bundle/find.rs b/gix-pack/src/bundle/find.rs index 2fc3357218f..c43d4dc7f72 100644 --- a/gix-pack/src/bundle/find.rs +++ b/gix-pack/src/bundle/find.rs @@ -1,7 +1,10 @@ +use gix_features::zlib; + impl crate::Bundle { - /// Find an object with the given [`ObjectId`][gix_hash::ObjectId] and place its data into `out`. + /// Find an object with the given [`ObjectId`](gix_hash::ObjectId) and place its data into `out`. + /// `inflate` is used to decompress objects, and will be reset before first use, but not after the last use. /// - /// [`cache`][crate::cache::DecodeEntry] is used to accelerate the lookup. + /// [`cache`](crate::cache::DecodeEntry) is used to accelerate the lookup. /// /// **Note** that ref deltas are automatically resolved within this pack only, which makes this implementation unusable /// for thin packs, which by now are expected to be resolved already. @@ -9,17 +12,19 @@ impl crate::Bundle { &self, id: impl AsRef, out: &'a mut Vec, + inflate: &mut zlib::Inflate, cache: &mut impl crate::cache::DecodeEntry, ) -> Result, crate::data::entry::Location)>, crate::data::decode::Error> { let idx = match self.index.lookup(id) { Some(idx) => idx, None => return Ok(None), }; - self.get_object_by_index(idx, out, cache).map(Some) + self.get_object_by_index(idx, out, inflate, cache).map(Some) } /// Special-use function to get an object given an index previously returned from - /// `internal_find_pack_index`. + /// [index::File::](crate::index::File::lookup()). + /// `inflate` is used to decompress objects, and will be reset before first use, but not after the last use. /// /// # Panics /// @@ -28,6 +33,7 @@ impl crate::Bundle { &self, idx: u32, out: &'a mut Vec, + inflate: &mut zlib::Inflate, cache: &mut impl crate::cache::DecodeEntry, ) -> Result<(gix_object::Data<'a>, crate::data::entry::Location), crate::data::decode::Error> { let ofs = self.index.pack_offset_at_index(idx); @@ -37,6 +43,7 @@ impl crate::Bundle { .decode_entry( pack_entry, out, + inflate, |id, _out| { self.index.lookup(id).map(|idx| { crate::data::decode::entry::ResolvedBase::InPack( diff --git a/gix-pack/src/data/file/decode/entry.rs b/gix-pack/src/data/file/decode/entry.rs index dedb31344fb..91da8dd2fa8 100644 --- a/gix-pack/src/data/file/decode/entry.rs +++ b/gix-pack/src/data/file/decode/entry.rs @@ -75,6 +75,7 @@ impl Outcome { /// Decompression of objects impl File { /// Decompress the given `entry` into `out` and return the amount of bytes read from the pack data. + /// Note that `inflate` is not reset after usage, but will be reset before using it. /// /// _Note_ that this method does not resolve deltified objects, but merely decompresses their content /// `out` is expected to be large enough to hold `entry.size` bytes. @@ -82,7 +83,12 @@ impl File { /// # Panics /// /// If `out` isn't large enough to hold the decompressed `entry` - pub fn decompress_entry(&self, entry: &data::Entry, out: &mut [u8]) -> Result { + pub fn decompress_entry( + &self, + entry: &data::Entry, + inflate: &mut zlib::Inflate, + out: &mut [u8], + ) -> Result { assert!( out.len() as u64 >= entry.decompressed_size, "output buffer isn't large enough to hold decompressed result, want {}, have {}", @@ -90,7 +96,7 @@ impl File { out.len() ); - self.decompress_entry_from_data_offset(entry.data_offset, out) + self.decompress_entry_from_data_offset(entry.data_offset, inflate, out) .map_err(Into::into) } @@ -121,12 +127,14 @@ impl File { pub(crate) fn decompress_entry_from_data_offset( &self, data_offset: data::Offset, + inflate: &mut zlib::Inflate, out: &mut [u8], ) -> Result { let offset: usize = data_offset.try_into().expect("offset representable by machine"); assert!(offset < self.data.len(), "entry offset out of bounds"); - zlib::Inflate::default() + inflate.reset(); + inflate .once(&self.data[offset..], out) .map(|(_status, consumed_in, _consumed_out)| consumed_in) } @@ -135,12 +143,14 @@ impl File { pub(crate) fn decompress_entry_from_data_offset_2( &self, data_offset: data::Offset, + inflate: &mut zlib::Inflate, out: &mut [u8], ) -> Result<(usize, usize), zlib::inflate::Error> { let offset: usize = data_offset.try_into().expect("offset representable by machine"); assert!(offset < self.data.len(), "entry offset out of bounds"); - zlib::Inflate::default() + inflate.reset(); + inflate .once(&self.data[offset..], out) .map(|(_status, consumed_in, consumed_out)| (consumed_in, consumed_out)) } @@ -149,6 +159,7 @@ impl File { /// space to hold the result object. /// /// The `entry` determines which object to decode, and is commonly obtained with the help of a pack index file or through pack iteration. + /// `inflate` will be used for decompressing entries, and will not be reset after usage, but before first using it. /// /// `resolve` is a function to lookup objects with the given [`ObjectId`][gix_hash::ObjectId], in case the full object id is used to refer to /// a base object, instead of an in-pack offset. @@ -159,6 +170,7 @@ impl File { &self, entry: data::Entry, out: &mut Vec, + inflate: &mut zlib::Inflate, resolve: impl Fn(&gix_hash::oid, &mut Vec) -> Option, delta_cache: &mut impl cache::DecodeEntry, ) -> Result { @@ -172,15 +184,16 @@ impl File { .expect("size representable by machine"), 0, ); - self.decompress_entry(&entry, out.as_mut_slice()).map(|consumed_input| { - Outcome::from_object_entry( - entry.header.as_kind().expect("a non-delta entry"), - &entry, - consumed_input, - ) - }) + self.decompress_entry(&entry, inflate, out.as_mut_slice()) + .map(|consumed_input| { + Outcome::from_object_entry( + entry.header.as_kind().expect("a non-delta entry"), + &entry, + consumed_input, + ) + }) } - OfsDelta { .. } | RefDelta { .. } => self.resolve_deltas(entry, resolve, out, delta_cache), + OfsDelta { .. } | RefDelta { .. } => self.resolve_deltas(entry, resolve, inflate, out, delta_cache), } } @@ -191,6 +204,7 @@ impl File { &self, last: data::Entry, resolve: impl Fn(&gix_hash::oid, &mut Vec) -> Option, + inflate: &mut zlib::Inflate, out: &mut Vec, cache: &mut impl cache::DecodeEntry, ) -> Result { @@ -278,6 +292,7 @@ impl File { for (delta_idx, delta) in chain.iter_mut().rev().enumerate() { let consumed_from_data_offset = self.decompress_entry_from_data_offset( delta.data_offset, + inflate, &mut instructions[..delta.decompressed_size], )?; let is_last_delta_to_be_applied = delta_idx + 1 == chain_len; @@ -338,7 +353,7 @@ impl File { let base_entry = cursor; debug_assert!(!base_entry.header.is_delta()); object_kind = base_entry.header.as_kind(); - self.decompress_entry_from_data_offset(base_entry.data_offset, out)?; + self.decompress_entry_from_data_offset(base_entry.data_offset, inflate, out)?; } (first_buffer_size, second_buffer_end) diff --git a/gix-pack/src/data/file/decode/header.rs b/gix-pack/src/data/file/decode/header.rs index 0afd6e52abc..2dfe52c9b6b 100644 --- a/gix-pack/src/data/file/decode/header.rs +++ b/gix-pack/src/data/file/decode/header.rs @@ -2,6 +2,7 @@ use crate::{ data, data::{delta, file::decode::Error, File}, }; +use gix_features::zlib; /// A return value of a resolve function, which given an [`ObjectId`][gix_hash::ObjectId] determines where an object can be found. #[derive(Debug, PartialEq, Eq, Hash, Ord, PartialOrd, Clone)] @@ -37,12 +38,14 @@ impl File { /// Resolve the object header information starting at `entry`, following the chain of entries as needed. /// /// The `entry` determines which object to decode, and is commonly obtained with the help of a pack index file or through pack iteration. + /// `inflate` will be used for (partially) decompressing entries, and will be reset before first use, but not after the last use. /// /// `resolve` is a function to lookup objects with the given [`ObjectId`][gix_hash::ObjectId], in case the full object id /// is used to refer to a base object, instead of an in-pack offset. pub fn decode_header( &self, mut entry: data::Entry, + inflate: &mut zlib::Inflate, resolve: impl Fn(&gix_hash::oid) -> Option, ) -> Result { use crate::data::entry::Header::*; @@ -60,14 +63,14 @@ impl File { OfsDelta { base_distance } => { num_deltas += 1; if first_delta_decompressed_size.is_none() { - first_delta_decompressed_size = Some(self.decode_delta_object_size(&entry)?); + first_delta_decompressed_size = Some(self.decode_delta_object_size(inflate, &entry)?); } entry = self.entry(entry.base_pack_offset(base_distance)) } RefDelta { base_id } => { num_deltas += 1; if first_delta_decompressed_size.is_none() { - first_delta_decompressed_size = Some(self.decode_delta_object_size(&entry)?); + first_delta_decompressed_size = Some(self.decode_delta_object_size(inflate, &entry)?); } match resolve(base_id.as_ref()) { Some(ResolvedBase::InPack(base_entry)) => entry = base_entry, @@ -89,9 +92,11 @@ impl File { } #[inline] - fn decode_delta_object_size(&self, entry: &data::Entry) -> Result { + fn decode_delta_object_size(&self, inflate: &mut zlib::Inflate, entry: &data::Entry) -> Result { let mut buf = [0_u8; 32]; - let used = self.decompress_entry_from_data_offset_2(entry.data_offset, &mut buf)?.1; + let used = self + .decompress_entry_from_data_offset_2(entry.data_offset, inflate, &mut buf)? + .1; let buf = &buf[..used]; let (_base_size, offset) = delta::decode_header_size(buf); let (result_size, _offset) = delta::decode_header_size(&buf[offset..]); diff --git a/gix-pack/src/index/traverse/mod.rs b/gix-pack/src/index/traverse/mod.rs index 83173f90454..ee9b6bc3dc2 100644 --- a/gix-pack/src/index/traverse/mod.rs +++ b/gix-pack/src/index/traverse/mod.rs @@ -3,6 +3,7 @@ use std::sync::atomic::AtomicBool; use gix_features::{ parallel, progress::{Progress, RawProgress}, + zlib, }; use crate::index; @@ -155,6 +156,7 @@ impl index::File { pack: &crate::data::File, cache: &mut C, buf: &mut Vec, + inflate: &mut zlib::Inflate, progress: &mut dyn RawProgress, index_entry: &index::Entry, processor: &mut impl FnMut(gix_object::Kind, &[u8], &index::Entry, &dyn RawProgress) -> Result<(), E>, @@ -169,6 +171,7 @@ impl index::File { .decode_entry( pack_entry, buf, + inflate, |id, _| { self.lookup(id).map(|index| { crate::data::decode::entry::ResolvedBase::InPack(pack.entry(self.pack_offset_at_index(index))) diff --git a/gix-pack/src/index/traverse/with_lookup.rs b/gix-pack/src/index/traverse/with_lookup.rs index 0165e4e01db..44f421323ac 100644 --- a/gix-pack/src/index/traverse/with_lookup.rs +++ b/gix-pack/src/index/traverse/with_lookup.rs @@ -4,6 +4,7 @@ use gix_features::{ parallel::{self, in_parallel_if}, progress::{self, Progress}, threading::{lock, Mutable, OwnShared}, + zlib, }; use super::{Error, Reducer}; @@ -131,6 +132,7 @@ impl index::File { ( make_pack_lookup_cache(), Vec::with_capacity(2048), // decode buffer + zlib::Inflate::default(), lock(&reduce_progress) .add_child_with_id(format!("thread {index}"), gix_features::progress::UNKNOWN), // per thread progress ) @@ -143,7 +145,7 @@ impl index::File { thread_limit, state_per_thread, move |entries: &[index::Entry], - (cache, buf, progress)| + (cache, buf, inflate, progress)| -> Result, Error<_>> { progress.init( Some(entries.len()), @@ -157,6 +159,7 @@ impl index::File { pack, cache, buf, + inflate, progress, index_entry, &mut processor, diff --git a/gix-pack/tests/pack/bundle.rs b/gix-pack/tests/pack/bundle.rs index 33bb7431e92..9d511821b10 100644 --- a/gix-pack/tests/pack/bundle.rs +++ b/gix-pack/tests/pack/bundle.rs @@ -1,5 +1,6 @@ mod locate { use bstr::ByteSlice; + use gix_features::zlib; use gix_object::Kind; use gix_odb::pack; @@ -8,13 +9,19 @@ mod locate { fn locate<'a>(hex_id: &str, out: &'a mut Vec) -> gix_object::Data<'a> { let bundle = pack::Bundle::at(fixture_path(SMALL_PACK_INDEX), gix_hash::Kind::Sha1).expect("pack and idx"); bundle - .find(hex_to_id(hex_id), out, &mut pack::cache::Never) + .find( + hex_to_id(hex_id), + out, + &mut zlib::Inflate::default(), + &mut pack::cache::Never, + ) .expect("read success") .expect("id present") .0 } mod locate_and_verify { + use gix_features::zlib; use gix_odb::pack; use crate::{fixture_path, pack::PACKS_AND_INDICES}; @@ -29,7 +36,12 @@ mod locate { let mut buf = Vec::new(); for entry in bundle.index.iter() { let (obj, _location) = bundle - .find(entry.oid, &mut buf, &mut pack::cache::Never)? + .find( + entry.oid, + &mut buf, + &mut zlib::Inflate::default(), + &mut pack::cache::Never, + )? .expect("id present"); obj.verify_checksum(entry.oid)?; } diff --git a/gix-pack/tests/pack/data/file.rs b/gix-pack/tests/pack/data/file.rs index 5681e4e3a06..64cafec9377 100644 --- a/gix-pack/tests/pack/data/file.rs +++ b/gix-pack/tests/pack/data/file.rs @@ -105,8 +105,14 @@ mod decode_entry { let p = pack_at(SMALL_PACK); let entry = p.entry(offset); let mut buf = Vec::new(); - p.decode_entry(entry, &mut buf, resolve_with_panic, &mut cache::Never) - .expect("valid offset provides valid entry"); + p.decode_entry( + entry, + &mut buf, + &mut Default::default(), + resolve_with_panic, + &mut cache::Never, + ) + .expect("valid offset provides valid entry"); buf } } @@ -154,7 +160,7 @@ mod resolve_header { let p = pack_at(SMALL_PACK); let entry = p.entry(offset); - p.decode_header(entry, resolve_with_panic) + p.decode_header(entry, &mut Default::default(), resolve_with_panic) .expect("valid offset provides valid entry") } } @@ -206,7 +212,8 @@ mod decompress_entry { let size = entry.decompressed_size as usize; let mut buf = vec![0; size]; - p.decompress_entry(&entry, &mut buf).expect("valid offset"); + p.decompress_entry(&entry, &mut Default::default(), &mut buf) + .expect("valid offset"); buf.resize(entry.decompressed_size as usize, 0); buf diff --git a/gix-pack/tests/pack/index.rs b/gix-pack/tests/pack/index.rs index fc9fcb22c29..8e23ff6e582 100644 --- a/gix-pack/tests/pack/index.rs +++ b/gix-pack/tests/pack/index.rs @@ -417,7 +417,7 @@ fn pack_lookup() -> Result<(), Box> { entry.pack_offset, "index entry offset and computed pack offset must match" ); - pack.decompress_entry(&pack_entry, &mut buf)?; + pack.decompress_entry(&pack_entry, &mut Default::default(), &mut buf)?; assert_eq!( buf.len() as u64, From 46a4d4d873610ba88d51bce865404b904b2b7cb3 Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Sat, 2 Sep 2023 13:19:32 +0200 Subject: [PATCH 0066/1077] adapt to changes in `gix-pack` --- gix-odb/src/store_impls/dynamic/find.rs | 18 +++++++++++++----- gix-odb/src/store_impls/dynamic/handle.rs | 3 +++ gix-odb/src/store_impls/dynamic/header.rs | 10 +++++++--- gix-odb/src/store_impls/dynamic/mod.rs | 2 ++ 4 files changed, 25 insertions(+), 8 deletions(-) diff --git a/gix-odb/src/store_impls/dynamic/find.rs b/gix-odb/src/store_impls/dynamic/find.rs index e5fe2557dec..1bb140d0b5a 100644 --- a/gix-odb/src/store_impls/dynamic/find.rs +++ b/gix-odb/src/store_impls/dynamic/find.rs @@ -75,6 +75,7 @@ pub(crate) mod error { } } pub use error::Error; +use gix_features::zlib; use crate::{store::types::PackId, Find}; @@ -86,6 +87,7 @@ where &'b self, mut id: &'b gix_hash::oid, buffer: &'a mut Vec, + inflate: &mut zlib::Inflate, pack_cache: &mut impl DecodeEntry, snapshot: &mut load_index::Snapshot, recursion: Option>, @@ -147,6 +149,7 @@ where let res = match pack.decode_entry( entry, buffer, + inflate, |id, _out| { index_file.pack_offset_by_id(id).map(|pack_offset| { gix_pack::data::decode::entry::ResolvedBase::InPack(pack.entry(pack_offset)) @@ -182,6 +185,7 @@ where .try_find_cached_inner( &base_id, &mut buf, + inflate, pack_cache, snapshot, recursion @@ -231,6 +235,7 @@ where pack.decode_entry( entry, buffer, + inflate, |id, out| { index_file .pack_offset_by_id(id) @@ -347,7 +352,8 @@ where ) -> Result, Option)>, Self::Error> { let id = id.as_ref(); let mut snapshot = self.snapshot.borrow_mut(); - self.try_find_cached_inner(id, buffer, pack_cache, &mut snapshot, None) + let mut inflate = self.inflate.borrow_mut(); + self.try_find_cached_inner(id, buffer, &mut inflate, pack_cache, &mut snapshot, None) } fn location_by_oid( @@ -364,6 +370,7 @@ where let id = id.as_ref(); let mut snapshot = self.snapshot.borrow_mut(); + let mut inflate = self.inflate.borrow_mut(); 'outer: loop { { let marker = snapshot.marker; @@ -404,13 +411,14 @@ where buf.resize(entry.decompressed_size.try_into().expect("representable size"), 0); assert_eq!(pack.id, pack_id.to_intrinsic_pack_id(), "both ids must always match"); - let res = pack.decompress_entry(&entry, buf).ok().map(|entry_size_past_header| { - gix_pack::data::entry::Location { + let res = pack + .decompress_entry(&entry, &mut inflate, buf) + .ok() + .map(|entry_size_past_header| gix_pack::data::entry::Location { pack_id: pack.id, pack_offset, entry_size: entry.header_size() + entry_size_past_header, - } - }); + }); if idx != 0 { snapshot.indices.swap(0, idx); diff --git a/gix-odb/src/store_impls/dynamic/handle.rs b/gix-odb/src/store_impls/dynamic/handle.rs index 78efd445134..34938d77a0b 100644 --- a/gix-odb/src/store_impls/dynamic/handle.rs +++ b/gix-odb/src/store_impls/dynamic/handle.rs @@ -257,6 +257,7 @@ impl super::Store { refresh: RefreshMode::default(), ignore_replacements: false, token: Some(token), + inflate: RefCell::new(Default::default()), snapshot: RefCell::new(self.collect_snapshot()), max_recursion_depth: Self::INITIAL_MAX_RECURSION_DEPTH, packed_object_count: Default::default(), @@ -273,6 +274,7 @@ impl super::Store { refresh: Default::default(), ignore_replacements: false, token: Some(token), + inflate: RefCell::new(Default::default()), snapshot: RefCell::new(self.collect_snapshot()), max_recursion_depth: Self::INITIAL_MAX_RECURSION_DEPTH, packed_object_count: Default::default(), @@ -391,6 +393,7 @@ where } .into() }, + inflate: RefCell::new(Default::default()), snapshot: RefCell::new(self.store.collect_snapshot()), max_recursion_depth: self.max_recursion_depth, packed_object_count: Default::default(), diff --git a/gix-odb/src/store_impls/dynamic/header.rs b/gix-odb/src/store_impls/dynamic/header.rs index 202b6ada04b..ad2a8743119 100644 --- a/gix-odb/src/store_impls/dynamic/header.rs +++ b/gix-odb/src/store_impls/dynamic/header.rs @@ -1,3 +1,4 @@ +use gix_features::zlib; use std::ops::Deref; use gix_hash::oid; @@ -15,6 +16,7 @@ where fn try_header_inner<'b>( &'b self, mut id: &'b gix_hash::oid, + inflate: &mut zlib::Inflate, snapshot: &mut load_index::Snapshot, recursion: Option>, ) -> Result, Error> { @@ -71,7 +73,7 @@ where }, }; let entry = pack.entry(pack_offset); - let res = match pack.decode_header(entry, |id| { + let res = match pack.decode_header(entry, inflate, |id| { index_file.pack_offset_by_id(id).map(|pack_offset| { gix_pack::data::decode::header::ResolvedBase::InPack(pack.entry(pack_offset)) }) @@ -85,6 +87,7 @@ where let hdr = self .try_header_inner( &base_id, + inflate, snapshot, recursion .map(DeltaBaseRecursion::inc_depth) @@ -127,7 +130,7 @@ where .as_ref() .expect("pack to still be available like just now"); let entry = pack.entry(pack_offset); - pack.decode_header(entry, |id| { + pack.decode_header(entry, inflate, |id| { index_file .pack_offset_by_id(id) .map(|pack_offset| { @@ -184,6 +187,7 @@ where fn try_header(&self, id: impl AsRef) -> Result, Self::Error> { let id = id.as_ref(); let mut snapshot = self.snapshot.borrow_mut(); - self.try_header_inner(id, &mut snapshot, None) + let mut inflate = self.inflate.borrow_mut(); + self.try_header_inner(id, &mut inflate, &mut snapshot, None) } } diff --git a/gix-odb/src/store_impls/dynamic/mod.rs b/gix-odb/src/store_impls/dynamic/mod.rs index e992fada6fd..35d4f7ca692 100644 --- a/gix-odb/src/store_impls/dynamic/mod.rs +++ b/gix-odb/src/store_impls/dynamic/mod.rs @@ -1,4 +1,5 @@ //! The standard object store which should fit all needs. +use gix_features::zlib; use std::{cell::RefCell, ops::Deref}; use crate::Store; @@ -24,6 +25,7 @@ where pub(crate) token: Option, snapshot: RefCell, + inflate: RefCell, packed_object_count: RefCell>, } From 96a07e08e6090222cf398b46aa8d46b56f81f14d Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Sat, 2 Sep 2023 13:33:38 +0200 Subject: [PATCH 0067/1077] fix: Use `Vec::resize()` instead of set_len() Otherwise it's possible for uninitialized memory to be used as if it was initialized, which can lead to strange behaviour. As the buffer is re-used, it's not actually zeroing that much memory either. --- gix-filter/src/worktree/encode_to_git.rs | 16 +++------------- gix-filter/src/worktree/encode_to_worktree.rs | 16 +++------------- gix-pack/src/cache/delta/traverse/resolve.rs | 19 ++----------------- gix-worktree-stream/src/protocol.rs | 10 +--------- 4 files changed, 9 insertions(+), 52 deletions(-) diff --git a/gix-filter/src/worktree/encode_to_git.rs b/gix-filter/src/worktree/encode_to_git.rs index 34caad7c67d..e9512d4ea81 100644 --- a/gix-filter/src/worktree/encode_to_git.rs +++ b/gix-filter/src/worktree/encode_to_git.rs @@ -26,7 +26,6 @@ pub(crate) mod function { use encoding_rs::DecoderResult; use super::{Error, RoundTripCheck}; - use crate::clear_and_set_capacity; /// Decode `src` according to `src_encoding` to `UTF-8` for storage in git and place it in `buf`. /// Note that the encoding is always applied, there is no conditional even if `src_encoding` already is `UTF-8`. @@ -40,13 +39,8 @@ pub(crate) mod function { let buf_len = decoder .max_utf8_buffer_length_without_replacement(src.len()) .ok_or(Error::Overflow { input_len: src.len() })?; - clear_and_set_capacity(buf, buf_len); - // SAFETY: `clear_and_set_capacity` assure that we have the given `buf_len` allocated, so setting its length is only making available - // what is allocated. Later we will truncate to the amount of actually written bytes. - #[allow(unsafe_code)] - unsafe { - buf.set_len(buf_len); - } + buf.clear(); + buf.resize(buf_len, 0); let (res, read, written) = decoder.decode_to_utf8_without_replacement(src, buf, true); match res { DecoderResult::InputEmpty => { @@ -55,11 +49,7 @@ pub(crate) mod function { "encoding_rs estimates the maximum amount of bytes written correctly" ); assert_eq!(read, src.len(), "input buffer should be fully consumed"); - // SAFETY: we trust that `encoding_rs` reports this number correctly, and truncate everything else. - #[allow(unsafe_code)] - unsafe { - buf.set_len(written); - } + buf.truncate(written); } DecoderResult::OutputFull => { unreachable!("we assure that the output buffer is big enough as per the encoder's estimate") diff --git a/gix-filter/src/worktree/encode_to_worktree.rs b/gix-filter/src/worktree/encode_to_worktree.rs index 3cb90ebbde2..0fddeadc0a1 100644 --- a/gix-filter/src/worktree/encode_to_worktree.rs +++ b/gix-filter/src/worktree/encode_to_worktree.rs @@ -17,7 +17,6 @@ pub(crate) mod function { use encoding_rs::EncoderResult; use super::Error; - use crate::clear_and_set_capacity; /// Encode `src_utf8`, which is assumed to be UTF-8 encoded, according to `worktree_encoding` for placement in the working directory, /// and write it to `buf`, possibly resizing it. @@ -33,13 +32,8 @@ pub(crate) mod function { .ok_or(Error::Overflow { input_len: src_utf8.len(), })?; - clear_and_set_capacity(buf, buf_len); - // SAFETY: `clear_and_set_capacity` assure that we have the given `buf_len` allocated, so setting its length is only making available - // what is allocated. Later we will truncate to the amount of actually written bytes. - #[allow(unsafe_code)] - unsafe { - buf.set_len(buf_len); - } + buf.clear(); + buf.resize(buf_len, 0); let src = std::str::from_utf8(src_utf8)?; let (res, read, written) = encoder.encode_from_utf8_without_replacement(src, buf, true); match res { @@ -49,11 +43,7 @@ pub(crate) mod function { "encoding_rs estimates the maximum amount of bytes written correctly" ); assert_eq!(read, src_utf8.len(), "input buffer should be fully consumed"); - // SAFETY: we trust that `encoding_rs` reports this number correctly, and truncate everything else. - #[allow(unsafe_code)] - unsafe { - buf.set_len(written); - } + buf.truncate(written); } EncoderResult::OutputFull => { unreachable!("we assure that the output buffer is big enough as per the encoder's estimate") diff --git a/gix-pack/src/cache/delta/traverse/resolve.rs b/gix-pack/src/cache/delta/traverse/resolve.rs index b7696918cba..f5a14efb924 100644 --- a/gix-pack/src/cache/delta/traverse/resolve.rs +++ b/gix-pack/src/cache/delta/traverse/resolve.rs @@ -122,7 +122,7 @@ where let (result_size, consumed) = data::delta::decode_header_size(&delta_bytes[consumed..]); header_ofs += consumed; - set_len(fully_resolved_delta_bytes, result_size as usize); + fully_resolved_delta_bytes.resize(result_size as usize, 0); data::delta::apply(&base_bytes, fully_resolved_delta_bytes, &delta_bytes[header_ofs..]); // FIXME: this actually invalidates the "pack_offset()" computation, which is not obvious to consumers @@ -394,28 +394,13 @@ where }) } -fn set_len(v: &mut Vec, new_len: usize) { - if new_len > v.len() { - v.reserve_exact(new_len.saturating_sub(v.capacity()) + (v.capacity() - v.len())); - // SAFETY: - // 1. we have reserved enough capacity to fit `new_len` - // 2. the caller is trusted to write into `v` to completely fill `new_len`. - #[allow(unsafe_code, clippy::uninit_vec)] - unsafe { - v.set_len(new_len); - } - } else { - v.truncate(new_len) - } -} - fn decompress_all_at_once_with( inflate: &mut zlib::Inflate, b: &[u8], decompressed_len: usize, out: &mut Vec, ) -> Result<(), Error> { - set_len(out, decompressed_len); + out.resize(decompressed_len, 0); inflate.reset(); inflate.once(b, out).map_err(|err| Error::ZlibInflate { source: err, diff --git a/gix-worktree-stream/src/protocol.rs b/gix-worktree-stream/src/protocol.rs index 30c6b7daafe..c7ad0286dc0 100644 --- a/gix-worktree-stream/src/protocol.rs +++ b/gix-worktree-stream/src/protocol.rs @@ -126,13 +126,5 @@ fn mode_to_byte(m: gix_object::tree::EntryMode) -> u8 { fn clear_and_set_len(buf: &mut Vec, len: usize) { buf.clear(); - if buf.capacity() < len { - buf.reserve(len); - assert!(buf.capacity() >= len, "{} >= {}", buf.capacity(), len); - } - // SAFETY: we just assured that `buf` has the right capacity to hold `cap` - #[allow(unsafe_code)] - unsafe { - buf.set_len(len); - } + buf.resize(len, 0); } From 48a20888d158b94811074a09a8c57ff5c8410769 Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Sat, 2 Sep 2023 19:37:51 +0200 Subject: [PATCH 0068/1077] refactor --- gix-macros/src/lib.rs | 293 +--------------------- gix-macros/src/momo.rs | 290 +++++++++++++++++++++ gix-macros/tests/macros.rs | 1 + gix-macros/tests/{test.rs => momo/mod.rs} | 7 +- 4 files changed, 297 insertions(+), 294 deletions(-) create mode 100644 gix-macros/src/momo.rs create mode 100644 gix-macros/tests/macros.rs rename gix-macros/tests/{test.rs => momo/mod.rs} (98%) diff --git a/gix-macros/src/lib.rs b/gix-macros/src/lib.rs index dcfa6ad5d70..dee0d581a7c 100644 --- a/gix-macros/src/lib.rs +++ b/gix-macros/src/lib.rs @@ -1,299 +1,12 @@ -use std::collections::HashMap; - +//! A crate of use proc_macro::TokenStream; -use quote::quote; -use syn::{punctuated::Punctuated, spanned::Spanned, *}; - -#[derive(Copy, Clone)] -// All conversions we support. Check references to this type for an idea how to add more. -enum Conversion<'a> { - Into(&'a Type), - AsRef(&'a Type), - AsMut(&'a Type), -} - -impl<'a> Conversion<'a> { - fn conversion_expr(&self, i: &Ident) -> Expr { - match *self { - Conversion::Into(_) => parse_quote!(#i.into()), - Conversion::AsRef(_) => parse_quote!(#i.as_ref()), - Conversion::AsMut(_) => parse_quote!(#i.as_mut()), - } - } -} - -fn parse_bounded_type(ty: &Type) -> Option { - match &ty { - Type::Path(TypePath { qself: None, path }) if path.segments.len() == 1 => Some(path.segments[0].ident.clone()), - _ => None, - } -} - -fn parse_bounds(bounds: &Punctuated) -> Option { - if bounds.len() != 1 { - return None; - } - if let TypeParamBound::Trait(ref tb) = bounds.first().unwrap() { - if let Some(seg) = tb.path.segments.iter().last() { - if let PathArguments::AngleBracketed(ref gen_args) = seg.arguments { - if let GenericArgument::Type(ref arg_ty) = gen_args.args.first().unwrap() { - if seg.ident == "Into" { - return Some(Conversion::Into(arg_ty)); - } else if seg.ident == "AsRef" { - return Some(Conversion::AsRef(arg_ty)); - } else if seg.ident == "AsMut" { - return Some(Conversion::AsMut(arg_ty)); - } - } - } - } - } - None -} - -// create a map from generic type to Conversion -fn parse_generics(decl: &Signature) -> HashMap> { - let mut ty_conversions = HashMap::new(); - for gp in decl.generics.params.iter() { - if let GenericParam::Type(ref tp) = gp { - if 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(ref 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); - } - } - } - } - } - ty_conversions -} - -fn convert<'a>( - inputs: &'a Punctuated, - ty_conversions: &HashMap>, -) -> (Punctuated, Punctuated, bool) { - let mut argtypes = Punctuated::new(); - let mut argexprs = Punctuated::new(); - let mut has_self = false; - inputs.iter().enumerate().for_each(|(i, input)| match input.clone() { - FnArg::Receiver(receiver) => { - has_self = true; - argtypes.push(FnArg::Receiver(receiver)); - } - FnArg::Typed(mut pat_type) => { - let pat_ident = match &mut *pat_type.pat { - Pat::Ident(pat_ident) if pat_ident.by_ref.is_none() && pat_ident.subpat.is_none() => pat_ident, - _ => { - pat_type.pat = Box::new(Pat::Ident(PatIdent { - ident: Ident::new(&format!("arg_{i}_gen_by_momo_"), proc_macro2::Span::call_site()), - attrs: Default::default(), - by_ref: None, - mutability: None, - subpat: None, - })); - - if let Pat::Ident(pat_ident) = &mut *pat_type.pat { - pat_ident - } else { - panic!() - } - } - }; - // Outer function type argument pat does not need mut unless its - // type is `impl AsMut`. - pat_ident.mutability = None; - - let ident = &pat_ident.ident; - - let to_expr = || parse_quote!(#ident); - - match *pat_type.ty { - Type::ImplTrait(TypeImplTrait { ref bounds, .. }) => { - if let Some(conv) = parse_bounds(bounds) { - argexprs.push(conv.conversion_expr(ident)); - if let Conversion::AsMut(_) = conv { - pat_ident.mutability = Some(Default::default()); - } - } else { - argexprs.push(to_expr()); - } - } - Type::Path(..) => { - if let Some(conv) = parse_bounded_type(&pat_type.ty).and_then(|ident| ty_conversions.get(&ident)) { - argexprs.push(conv.conversion_expr(ident)); - if let Conversion::AsMut(_) = conv { - pat_ident.mutability = Some(Default::default()); - } - } else { - argexprs.push(to_expr()); - } - } - _ => { - argexprs.push(to_expr()); - } - } - - // Now that mutability is decided, push the type into argtypes - argtypes.push(FnArg::Typed(pat_type)); - } - }); - (argtypes, argexprs, has_self) -} - -fn contains_self_type_path(path: &Path) -> bool { - path.segments.iter().any(|segment| { - segment.ident == "Self" - || match &segment.arguments { - PathArguments::AngleBracketed(AngleBracketedGenericArguments { args, .. }) => { - args.iter().any(|generic_arg| match generic_arg { - GenericArgument::Type(ty) => contains_self_type(ty), - GenericArgument::Const(expr) => contains_self_type_expr(expr), - _ => false, - }) - } - PathArguments::Parenthesized(ParenthesizedGenericArguments { inputs, output, .. }) => { - inputs.iter().any(contains_self_type) - || matches!(output, ReturnType::Type(_, ty) if contains_self_type(ty)) - } - _ => false, - } - }) -} - -fn contains_self_type_expr(expr: &Expr) -> bool { - match expr { - Expr::Path(ExprPath { qself: Some(_), .. }) => true, - Expr::Path(ExprPath { path, .. }) => contains_self_type_path(path), - _ => false, - } -} - -fn contains_self_type(input: &Type) -> bool { - match input { - Type::Array(TypeArray { elem, len, .. }) => { - // Call `matches!` first so that we can do tail call here - // as an optimization. - contains_self_type_expr(len) || contains_self_type(elem) - } - Type::Group(TypeGroup { elem, .. }) => contains_self_type(elem), - Type::Paren(TypeParen { elem, .. }) => contains_self_type(elem), - Type::Ptr(TypePtr { elem, .. }) => contains_self_type(elem), - Type::Reference(TypeReference { elem, .. }) => contains_self_type(elem), - Type::Slice(TypeSlice { elem, .. }) => contains_self_type(elem), - - Type::Tuple(TypeTuple { elems, .. }) => elems.iter().any(contains_self_type), - - Type::Path(TypePath { qself: Some(_), .. }) => true, - Type::Path(TypePath { path, .. }) => contains_self_type_path(path), - - _ => false, - } -} - -fn has_self_type(input: &FnArg) -> bool { - match input { - FnArg::Receiver(_) => true, - FnArg::Typed(PatType { ty, .. }) => contains_self_type(ty), - } -} /// Generate lightweight monomorphized wrapper around main implementation. /// May be applied to functions and methods. #[proc_macro_attribute] pub fn momo(_attrs: TokenStream, input: TokenStream) -> TokenStream { //TODO: alternatively parse ImplItem::Method - momo_inner(input.into()).into() + momo::inner(input.into()).into() } -fn momo_inner(code: proc_macro2::TokenStream) -> proc_macro2::TokenStream { - let fn_item: Item = match syn::parse2(code.clone()) { - Ok(input) => input, - Err(err) => return err.to_compile_error(), - }; - - if let Item::Fn(item_fn) = fn_item { - let ty_conversions = parse_generics(&item_fn.sig); - let (argtypes, argexprs, has_self) = convert(&item_fn.sig.inputs, &ty_conversions); - - let uses_self = has_self - || item_fn.sig.inputs.iter().any(has_self_type) - || matches!(&item_fn.sig.output, ReturnType::Type(_, ty) if contains_self_type(ty)); - - let inner_ident = Ident::new( - // Use long qualifier to avoid name colision. - &format!("_{}_inner_generated_by_gix_macro_momo", item_fn.sig.ident), - proc_macro2::Span::call_site(), - ); - - let outer_sig = Signature { - inputs: argtypes, - ..item_fn.sig.clone() - }; - - let new_inner_item = Item::Fn(ItemFn { - // Remove doc comment since they will increase compile-time and - // also generates duplicate warning/error messages for the doc, - // especially if it contains doc-tests. - attrs: { - let mut attrs = item_fn.attrs.clone(); - attrs.retain(|attr| { - let segments = &attr.path().segments; - !(segments.len() == 1 && segments[0].ident == "doc") - }); - attrs - }, - vis: Visibility::Inherited, - sig: Signature { - ident: inner_ident.clone(), - ..item_fn.sig - }, - block: item_fn.block, - }); - - if uses_self { - // We can use `self` or `Self` inside function defined within - // the impl-fn, so instead declare two separate functions. - // - // Since it's an impl block, it's unlikely to have name conflict, - // though this won't work for impl-trait. - // - // This approach also make sure we can call the right function - // using `Self` qualifier. - let new_item = Item::Fn(ItemFn { - attrs: item_fn.attrs, - vis: item_fn.vis, - sig: outer_sig, - block: if has_self { - parse_quote!({ self.#inner_ident(#argexprs) }) - } else { - parse_quote!({ Self::#inner_ident(#argexprs) }) - }, - }); - quote!(#new_item #new_inner_item) - } else { - // Put the new inner function within the function block - // to avoid duplicate function name and support associated - // function that doesn't use `self` or `Self`. - let new_item = Item::Fn(ItemFn { - attrs: item_fn.attrs, - vis: item_fn.vis, - sig: outer_sig, - block: parse_quote!({ - #new_inner_item - - #inner_ident(#argexprs) - }), - }); - quote!(#new_item) - } - } else { - Error::new(fn_item.span(), "expect a function").to_compile_error() - } -} +mod momo; diff --git a/gix-macros/src/momo.rs b/gix-macros/src/momo.rs new file mode 100644 index 00000000000..37d52c55e09 --- /dev/null +++ b/gix-macros/src/momo.rs @@ -0,0 +1,290 @@ +use std::collections::HashMap; + +use quote::quote; +use syn::{punctuated::Punctuated, spanned::Spanned, *}; + +pub(crate) fn inner(code: proc_macro2::TokenStream) -> proc_macro2::TokenStream { + let fn_item: Item = match syn::parse2(code.clone()) { + Ok(input) => input, + Err(err) => return err.to_compile_error(), + }; + + if let Item::Fn(item_fn) = fn_item { + let ty_conversions = parse_generics(&item_fn.sig); + let (argtypes, argexprs, has_self) = convert(&item_fn.sig.inputs, &ty_conversions); + + let uses_self = has_self + || item_fn.sig.inputs.iter().any(has_self_type) + || matches!(&item_fn.sig.output, ReturnType::Type(_, ty) if contains_self_type(ty)); + + let inner_ident = Ident::new( + // Use long qualifier to avoid name collision. + &format!("_{}_inner_generated_by_gix_macro_momo", item_fn.sig.ident), + proc_macro2::Span::call_site(), + ); + + let outer_sig = Signature { + inputs: argtypes, + ..item_fn.sig.clone() + }; + + let new_inner_item = Item::Fn(ItemFn { + // Remove doc comment since they will increase compile-time and + // also generates duplicate warning/error messages for the doc, + // especially if it contains doc-tests. + attrs: { + let mut attrs = item_fn.attrs.clone(); + attrs.retain(|attr| { + let segments = &attr.path().segments; + !(segments.len() == 1 && segments[0].ident == "doc") + }); + attrs + }, + vis: Visibility::Inherited, + sig: Signature { + ident: inner_ident.clone(), + ..item_fn.sig + }, + block: item_fn.block, + }); + + if uses_self { + // We can use `self` or `Self` inside function defined within + // the impl-fn, so instead declare two separate functions. + // + // Since it's an impl block, it's unlikely to have name conflict, + // though this won't work for impl-trait. + // + // This approach also make sure we can call the right function + // using `Self` qualifier. + let new_item = Item::Fn(ItemFn { + attrs: item_fn.attrs, + vis: item_fn.vis, + sig: outer_sig, + block: if has_self { + parse_quote!({ self.#inner_ident(#argexprs) }) + } else { + parse_quote!({ Self::#inner_ident(#argexprs) }) + }, + }); + quote!(#new_item #new_inner_item) + } else { + // Put the new inner function within the function block + // to avoid duplicate function name and support associated + // function that doesn't use `self` or `Self`. + let new_item = Item::Fn(ItemFn { + attrs: item_fn.attrs, + vis: item_fn.vis, + sig: outer_sig, + block: parse_quote!({ + #new_inner_item + + #inner_ident(#argexprs) + }), + }); + quote!(#new_item) + } + } else { + Error::new(fn_item.span(), "expect a function").to_compile_error() + } +} + +#[derive(Copy, Clone)] +// All conversions we support. Check references to this type for an idea how to add more. +enum Conversion<'a> { + Into(&'a Type), + AsRef(&'a Type), + AsMut(&'a Type), +} + +impl<'a> Conversion<'a> { + fn conversion_expr(&self, i: &Ident) -> Expr { + match *self { + Conversion::Into(_) => parse_quote!(#i.into()), + Conversion::AsRef(_) => parse_quote!(#i.as_ref()), + Conversion::AsMut(_) => parse_quote!(#i.as_mut()), + } + } +} + +fn parse_bounded_type(ty: &Type) -> Option { + match &ty { + Type::Path(TypePath { qself: None, path }) if path.segments.len() == 1 => Some(path.segments[0].ident.clone()), + _ => None, + } +} + +fn parse_bounds(bounds: &Punctuated) -> Option { + if bounds.len() != 1 { + return None; + } + if let TypeParamBound::Trait(ref tb) = bounds.first().unwrap() { + if let Some(seg) = tb.path.segments.iter().last() { + if let PathArguments::AngleBracketed(ref gen_args) = seg.arguments { + if let GenericArgument::Type(ref arg_ty) = gen_args.args.first().unwrap() { + if seg.ident == "Into" { + return Some(Conversion::Into(arg_ty)); + } else if seg.ident == "AsRef" { + return Some(Conversion::AsRef(arg_ty)); + } else if seg.ident == "AsMut" { + return Some(Conversion::AsMut(arg_ty)); + } + } + } + } + } + None +} + +// create a map from generic type to Conversion +fn parse_generics(decl: &Signature) -> HashMap> { + let mut ty_conversions = HashMap::new(); + for gp in decl.generics.params.iter() { + if let GenericParam::Type(ref tp) = gp { + if 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(ref 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); + } + } + } + } + } + ty_conversions +} + +fn convert<'a>( + inputs: &'a Punctuated, + ty_conversions: &HashMap>, +) -> (Punctuated, Punctuated, bool) { + let mut argtypes = Punctuated::new(); + let mut argexprs = Punctuated::new(); + let mut has_self = false; + inputs.iter().enumerate().for_each(|(i, input)| match input.clone() { + FnArg::Receiver(receiver) => { + has_self = true; + argtypes.push(FnArg::Receiver(receiver)); + } + FnArg::Typed(mut pat_type) => { + let pat_ident = match &mut *pat_type.pat { + Pat::Ident(pat_ident) if pat_ident.by_ref.is_none() && pat_ident.subpat.is_none() => pat_ident, + _ => { + pat_type.pat = Box::new(Pat::Ident(PatIdent { + ident: Ident::new(&format!("arg_{i}_gen_by_momo_"), proc_macro2::Span::call_site()), + attrs: Default::default(), + by_ref: None, + mutability: None, + subpat: None, + })); + + if let Pat::Ident(pat_ident) = &mut *pat_type.pat { + pat_ident + } else { + panic!() + } + } + }; + // Outer function type argument pat does not need mut unless its + // type is `impl AsMut`. + pat_ident.mutability = None; + + let ident = &pat_ident.ident; + + let to_expr = || parse_quote!(#ident); + + match *pat_type.ty { + Type::ImplTrait(TypeImplTrait { ref bounds, .. }) => { + if let Some(conv) = parse_bounds(bounds) { + argexprs.push(conv.conversion_expr(ident)); + if let Conversion::AsMut(_) = conv { + pat_ident.mutability = Some(Default::default()); + } + } else { + argexprs.push(to_expr()); + } + } + Type::Path(..) => { + if let Some(conv) = parse_bounded_type(&pat_type.ty).and_then(|ident| ty_conversions.get(&ident)) { + argexprs.push(conv.conversion_expr(ident)); + if let Conversion::AsMut(_) = conv { + pat_ident.mutability = Some(Default::default()); + } + } else { + argexprs.push(to_expr()); + } + } + _ => { + argexprs.push(to_expr()); + } + } + + // Now that mutability is decided, push the type into argtypes + argtypes.push(FnArg::Typed(pat_type)); + } + }); + (argtypes, argexprs, has_self) +} + +fn contains_self_type_path(path: &Path) -> bool { + path.segments.iter().any(|segment| { + segment.ident == "Self" + || match &segment.arguments { + PathArguments::AngleBracketed(AngleBracketedGenericArguments { args, .. }) => { + args.iter().any(|generic_arg| match generic_arg { + GenericArgument::Type(ty) => contains_self_type(ty), + GenericArgument::Const(expr) => contains_self_type_expr(expr), + _ => false, + }) + } + PathArguments::Parenthesized(ParenthesizedGenericArguments { inputs, output, .. }) => { + inputs.iter().any(contains_self_type) + || matches!(output, ReturnType::Type(_, ty) if contains_self_type(ty)) + } + _ => false, + } + }) +} + +fn contains_self_type_expr(expr: &Expr) -> bool { + match expr { + Expr::Path(ExprPath { qself: Some(_), .. }) => true, + Expr::Path(ExprPath { path, .. }) => contains_self_type_path(path), + _ => false, + } +} + +fn contains_self_type(input: &Type) -> bool { + match input { + Type::Array(TypeArray { elem, len, .. }) => { + // Call `matches!` first so that we can do tail call here + // as an optimization. + contains_self_type_expr(len) || contains_self_type(elem) + } + Type::Group(TypeGroup { elem, .. }) => contains_self_type(elem), + Type::Paren(TypeParen { elem, .. }) => contains_self_type(elem), + Type::Ptr(TypePtr { elem, .. }) => contains_self_type(elem), + Type::Reference(TypeReference { elem, .. }) => contains_self_type(elem), + Type::Slice(TypeSlice { elem, .. }) => contains_self_type(elem), + + Type::Tuple(TypeTuple { elems, .. }) => elems.iter().any(contains_self_type), + + Type::Path(TypePath { qself: Some(_), .. }) => true, + Type::Path(TypePath { path, .. }) => contains_self_type_path(path), + + _ => false, + } +} + +fn has_self_type(input: &FnArg) -> bool { + match input { + FnArg::Receiver(_) => true, + FnArg::Typed(PatType { ty, .. }) => contains_self_type(ty), + } +} diff --git a/gix-macros/tests/macros.rs b/gix-macros/tests/macros.rs new file mode 100644 index 00000000000..821fc9835b0 --- /dev/null +++ b/gix-macros/tests/macros.rs @@ -0,0 +1 @@ +mod momo; diff --git a/gix-macros/tests/test.rs b/gix-macros/tests/momo/mod.rs similarity index 98% rename from gix-macros/tests/test.rs rename to gix-macros/tests/momo/mod.rs index 51c522c1fae..fd4da846627 100644 --- a/gix-macros/tests/test.rs +++ b/gix-macros/tests/momo/mod.rs @@ -212,7 +212,7 @@ fn test_fn_pat( } #[test] -fn test_basic_fn() { +fn basic_fn() { assert_eq!( test_fn("12345", "12345", String::from("12345"), S(true)).unwrap(), "123451234512345!2345" @@ -236,8 +236,7 @@ fn test_basic_fn() { } #[test] -fn test_struct_method() { - // Test test_method +fn struct_method() { assert_eq!( TestStruct .test_method("12345", "12345", String::from("12345"), S(true)) @@ -263,7 +262,7 @@ fn test_struct_method() { } #[test] -fn test_struct_fn() { +fn struct_fn() { assert_eq!( TestStruct::test_fn("12345", "12345", String::from("12345"), S(true), ()).unwrap(), "123451234512345!2345" From 705f2f34f1fa95d767646b154f41d2a6ce65ad10 Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Sat, 2 Sep 2023 20:02:10 +0200 Subject: [PATCH 0069/1077] improve docs --- gix-macros/src/lib.rs | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/gix-macros/src/lib.rs b/gix-macros/src/lib.rs index dee0d581a7c..1329a6b1526 100644 --- a/gix-macros/src/lib.rs +++ b/gix-macros/src/lib.rs @@ -1,8 +1,22 @@ -//! A crate of +//! A crate of useful macros used in `gix` primarily. +//! +//! Note that within `gix-*` crates, monomorphization should never be used for convenience, but only for performance +//! reasons. And in the latter case, manual denomophization should be considered if the trait in questions isn't called +//! often enough or measurements indicate that `&dyn Trait` is increasing the runtime. Thus, `gix-*` crates should probably +//! by default prefer using `&dyn` unless measurements indicate otherwise. use proc_macro::TokenStream; -/// Generate lightweight monomorphized wrapper around main implementation. -/// May be applied to functions and methods. +/// When applied to functions or methods, it will turn it into a wrapper that will immediately call +/// a de-monomorphized implementation (i.e. one that uses `&dyn Trait`). +/// +/// That way, the landing-pads for convenience will be as small as possible which then delegate to a single +/// function or method for implementation. +/// +/// The parameters using the following traits can be de-monomorphized: +/// +/// * `Into` +/// * `AsRef` +/// * `AsMut` #[proc_macro_attribute] pub fn momo(_attrs: TokenStream, input: TokenStream) -> TokenStream { //TODO: alternatively parse ImplItem::Method From c4ed7c180e3ec1ff75cb10d78d4b8eed3b75be2f Mon Sep 17 00:00:00 2001 From: Jiahao XU Date: Sun, 3 Sep 2023 07:37:31 +1000 Subject: [PATCH 0070/1077] Remove `TODO` in `gix-macros/src/lib.rs` Signed-off-by: Jiahao XU --- gix-macros/src/lib.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/gix-macros/src/lib.rs b/gix-macros/src/lib.rs index 1329a6b1526..4693a79e824 100644 --- a/gix-macros/src/lib.rs +++ b/gix-macros/src/lib.rs @@ -19,7 +19,6 @@ use proc_macro::TokenStream; /// * `AsMut` #[proc_macro_attribute] pub fn momo(_attrs: TokenStream, input: TokenStream) -> TokenStream { - //TODO: alternatively parse ImplItem::Method momo::inner(input.into()).into() } From 7df8cf31f794ae75868c606329a5685d198b0f59 Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Sun, 3 Sep 2023 09:42:03 +0200 Subject: [PATCH 0071/1077] feat: make it easier to access the value of `StateRef`. --- gix-attributes/src/state.rs | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/gix-attributes/src/state.rs b/gix-attributes/src/state.rs index ffc0bce41db..80ebcfead56 100644 --- a/gix-attributes/src/state.rs +++ b/gix-attributes/src/state.rs @@ -13,7 +13,7 @@ pub struct Value(KString); #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct ValueRef<'a>(#[cfg_attr(feature = "serde", serde(borrow))] KStringRef<'a>); -/// Conversions +/// Lifecycle impl<'a> ValueRef<'a> { /// Keep `input` as our value. pub fn from_bytes(input: &'a [u8]) -> Self { @@ -25,7 +25,10 @@ impl<'a> ValueRef<'a> { }, )) } +} +/// Access and conversions +impl ValueRef<'_> { /// Access this value as byte string. pub fn as_bstr(&self) -> &BStr { self.0.as_bytes().as_bstr() @@ -79,6 +82,14 @@ impl StateRef<'_> { pub fn is_unset(&self) -> bool { matches!(self, StateRef::Unset) } + + /// Attempt to obtain the string value of this state, or return `None` if there is no such value. + pub fn as_bstr(&self) -> Option<&BStr> { + match self { + StateRef::Value(v) => Some(v.as_bstr()), + _ => None, + } + } } /// Initialization From c79991cde8216271ab854b7574e7d97efd79d07c Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Sun, 3 Sep 2023 13:41:56 +0200 Subject: [PATCH 0072/1077] feat: `Clone` for `ThreadSafeRepository` It is `Sync` and can easily be passed by reference, but sometimes it's nice to be cloning it as well. --- gix/src/types.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/gix/src/types.rs b/gix/src/types.rs index db3c4395fed..5a875f258e0 100644 --- a/gix/src/types.rs +++ b/gix/src/types.rs @@ -150,6 +150,9 @@ pub struct Repository { /// /// Note that this type purposefully isn't very useful until it is converted into a thread-local repository with `to_thread_local()`, /// it's merely meant to be able to exist in a `Sync` context. +/// +/// Note that it can also cheaply be cloned, and it will retain references to all contained resources. +#[derive(Clone)] pub struct ThreadSafeRepository { /// A store for references to point at objects pub refs: crate::RefStore, From 54291fdfc62c7d8a31bc5564713c23eab3865dc5 Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Sun, 3 Sep 2023 16:15:29 +0200 Subject: [PATCH 0073/1077] feat!: Provide a wrapper for `gix_worktree::Stack` for simpler attribute queries. --- gix/src/attribute_stack.rs | 69 ++++++++++++++++++++++++++++++++ gix/src/lib.rs | 4 +- gix/src/pathspec.rs | 23 +++++++---- gix/src/repository/attributes.rs | 42 ++++++++++--------- gix/src/repository/filter.rs | 2 +- gix/src/repository/pathspec.rs | 6 ++- gix/src/repository/worktree.rs | 4 +- gix/src/submodule/mod.rs | 13 +++--- gix/src/types.rs | 8 +++- gix/src/worktree/mod.rs | 6 +-- 10 files changed, 136 insertions(+), 41 deletions(-) create mode 100644 gix/src/attribute_stack.rs diff --git a/gix/src/attribute_stack.rs b/gix/src/attribute_stack.rs new file mode 100644 index 00000000000..1aaca0f2b35 --- /dev/null +++ b/gix/src/attribute_stack.rs @@ -0,0 +1,69 @@ +use crate::bstr::BStr; +use crate::types::AttributeStack; +use crate::Repository; +use gix_odb::FindExt; +use std::ops::{Deref, DerefMut}; + +/// Lifecycle +impl<'repo> AttributeStack<'repo> { + /// Create a new instance from a `repo` and the underlying pre-configured `stack`. + /// + /// Note that this type is typically created by [`Repository::attributes()`] or [`Repository::attributes_only()`]. + pub fn new(stack: gix_worktree::Stack, repo: &'repo Repository) -> Self { + AttributeStack { repo, inner: stack } + } + + /// Detach the repository and return the underlying plumbing datatype. + pub fn detach(self) -> gix_worktree::Stack { + self.inner + } +} + +impl Deref for AttributeStack<'_> { + type Target = gix_worktree::Stack; + + fn deref(&self) -> &Self::Target { + &self.inner + } +} + +impl DerefMut for AttributeStack<'_> { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.inner + } +} + +/// Platform retrieval +impl<'repo> AttributeStack<'repo> { + /// Append the `relative` path to the root directory of the cache and efficiently create leading directories, while assuring that no + /// symlinks are in that path. + /// Unless `is_dir` is known with `Some(…)`, then `relative` points to a directory itself in which case the entire resulting + /// path is created as directory. If it's not known it is assumed to be a file. + /// + /// Provide access to cached information for that `relative` path via the returned platform. + pub fn at_path( + &mut self, + relative: impl AsRef, + is_dir: Option, + ) -> std::io::Result> { + self.inner + .at_path(relative, is_dir, |id, buf| self.repo.objects.find_blob(id, buf)) + } + + /// Obtain a platform for lookups from a repo-`relative` path, typically obtained from an index entry. `is_dir` should reflect + /// whether it's a directory or not, or left at `None` if unknown. + /// + /// If `relative` ends with `/` and `is_dir` is `None`, it is automatically assumed to be a directory. + /// + /// ### Panics + /// + /// - on illformed UTF8 in `relative` + pub fn at_entry<'r>( + &mut self, + relative: impl Into<&'r BStr>, + is_dir: Option, + ) -> std::io::Result> { + self.inner + .at_entry(relative, is_dir, |id, buf| self.repo.objects.find_blob(id, buf)) + } +} diff --git a/gix/src/lib.rs b/gix/src/lib.rs index e68037e9780..0db78f5b635 100644 --- a/gix/src/lib.rs +++ b/gix/src/lib.rs @@ -117,6 +117,8 @@ mod ext; /// pub mod prelude; +mod attribute_stack; + /// pub mod path; @@ -129,7 +131,7 @@ pub(crate) type Config = OwnShared>; mod types; pub use types::{ - Commit, Head, Id, Object, ObjectDetached, Pathspec, Reference, Remote, Repository, Submodule, Tag, + AttributeStack, Commit, Head, Id, Object, ObjectDetached, Pathspec, Reference, Remote, Repository, Submodule, Tag, ThreadSafeRepository, Tree, Worktree, }; diff --git a/gix/src/pathspec.rs b/gix/src/pathspec.rs index f5af7b3228e..ca1b34d3c43 100644 --- a/gix/src/pathspec.rs +++ b/gix/src/pathspec.rs @@ -2,7 +2,7 @@ use gix_odb::FindExt; pub use gix_pathspec::*; -use crate::{bstr::BStr, Pathspec, Repository}; +use crate::{bstr::BStr, AttributeStack, Pathspec, Repository}; /// pub mod init { @@ -59,13 +59,20 @@ impl<'repo> Pathspec<'repo> { )?, )?; let cache = needs_cache.then(make_attributes).transpose()?; - Ok(Self { repo, search, cache }) + Ok(Self { + repo, + search, + stack: cache, + }) } /// Turn ourselves into the functional parts for direct usage. - /// Note that the [`cache`](gix_worktree::Stack) is only set if one of the [`search` patterns](Search) + /// Note that the [`cache`](AttributeStack) is only set if one of the [`search` patterns](Search) /// is specifying attributes to match for. - pub fn into_parts(self) -> (Search, Option) { - (self.search, self.cache) + pub fn into_parts(self) -> (Search, Option>) { + ( + self.search, + self.stack.map(|stack| AttributeStack::new(stack, self.repo)), + ) } } @@ -73,7 +80,7 @@ impl<'repo> Pathspec<'repo> { impl<'repo> Pathspec<'repo> { /// Return the attributes cache which is used when matching attributes in pathspecs, or `None` if none of the pathspecs require that. pub fn attributes(&self) -> Option<&gix_worktree::Stack> { - self.cache.as_ref() + self.stack.as_ref() } /// Return the search itself which can be used for matching paths or accessing the actual patterns that will be used. @@ -99,8 +106,8 @@ impl<'repo> Pathspec<'repo> { ) -> Option> { self.search .pattern_matching_relative_path(relative_path, is_dir, |relative_path, case, is_dir, out| { - let cache = self.cache.as_mut().expect("initialized in advance"); - cache + let stack = self.stack.as_mut().expect("initialized in advance"); + stack .set_case(case) .at_entry(relative_path, Some(is_dir), |id, buf| { self.repo.objects.find_blob(id, buf) diff --git a/gix/src/repository/attributes.rs b/gix/src/repository/attributes.rs index e875ef0b0d8..6a982ee625c 100644 --- a/gix/src/repository/attributes.rs +++ b/gix/src/repository/attributes.rs @@ -1,5 +1,5 @@ //! exclude information -use crate::{config, Repository}; +use crate::{config, AttributeStack, Repository}; /// The error returned by [`Repository::attributes()`]. #[derive(Debug, thiserror::Error)] @@ -24,15 +24,13 @@ impl Repository { /// /// * `$XDG_CONFIG_HOME/…/ignore|attributes` if `core.excludesFile|attributesFile` is *not* set, otherwise use the configured file. /// * `$GIT_DIR/info/exclude|attributes` if present. - // TODO: test, provide higher-level custom Cache wrapper that is much easier to use and doesn't panic when accessing entries - // by non-relative path. pub fn attributes( &self, index: &gix_index::State, attributes_source: gix_worktree::stack::state::attributes::Source, ignore_source: gix_worktree::stack::state::ignore::Source, exclude_overrides: Option, - ) -> Result { + ) -> Result, Error> { let case = if self.config.ignore_case { gix_glob::pattern::Case::Fold } else { @@ -48,13 +46,16 @@ impl Repository { .assemble_exclude_globals(self.git_dir(), exclude_overrides, ignore_source, &mut buf)?; let state = gix_worktree::stack::State::AttributesAndIgnoreStack { attributes, ignore }; let attribute_list = state.id_mappings_from_index(index, index.path_backing(), case); - Ok(gix_worktree::Stack::new( - // this is alright as we don't cause mutation of that directory, it's virtual. - self.work_dir().unwrap_or(self.git_dir()), - state, - case, - buf, - attribute_list, + Ok(AttributeStack::new( + gix_worktree::Stack::new( + // this is alright as we don't cause mutation of that directory, it's virtual. + self.work_dir().unwrap_or(self.git_dir()), + state, + case, + buf, + attribute_list, + ), + self, )) } @@ -63,7 +64,7 @@ impl Repository { &self, index: &gix_index::State, attributes_source: gix_worktree::stack::state::attributes::Source, - ) -> Result { + ) -> Result, config::attribute_stack::Error> { let case = if self.config.ignore_case { gix_glob::pattern::Case::Fold } else { @@ -76,13 +77,16 @@ impl Repository { )?; let state = gix_worktree::stack::State::AttributesStack(attributes); let attribute_list = state.id_mappings_from_index(index, index.path_backing(), case); - Ok(gix_worktree::Stack::new( - // this is alright as we don't cause mutation of that directory, it's virtual. - self.work_dir().unwrap_or(self.git_dir()), - state, - case, - buf, - attribute_list, + Ok(AttributeStack::new( + gix_worktree::Stack::new( + // this is alright as we don't cause mutation of that directory, it's virtual. + self.work_dir().unwrap_or(self.git_dir()), + state, + case, + buf, + attribute_list, + ), + self, )) } diff --git a/gix/src/repository/filter.rs b/gix/src/repository/filter.rs index 6f08309ce0f..3aacb1a3d2c 100644 --- a/gix/src/repository/filter.rs +++ b/gix/src/repository/filter.rs @@ -59,6 +59,6 @@ impl Repository { )?; (cache, IndexPersistedOrInMemory::Persisted(index)) }; - Ok((filter::Pipeline::new(self, cache)?, index)) + Ok((filter::Pipeline::new(self, cache.detach())?, index)) } } diff --git a/gix/src/repository/pathspec.rs b/gix/src/repository/pathspec.rs index c8d3695a662..8e7e9bbe9a4 100644 --- a/gix/src/repository/pathspec.rs +++ b/gix/src/repository/pathspec.rs @@ -1,6 +1,6 @@ use gix_pathspec::MagicSignature; -use crate::{bstr::BStr, config::cache::util::ApplyLeniencyDefault, Pathspec, Repository}; +use crate::{bstr::BStr, config::cache::util::ApplyLeniencyDefault, AttributeStack, Pathspec, Repository}; impl Repository { /// Create a new pathspec abstraction that allows to conduct searches using `patterns`. @@ -20,7 +20,9 @@ impl Repository { attributes_source: gix_worktree::stack::state::attributes::Source, ) -> Result, crate::pathspec::init::Error> { Pathspec::new(self, patterns, inherit_ignore_case, || { - self.attributes_only(index, attributes_source).map_err(Into::into) + self.attributes_only(index, attributes_source) + .map(AttributeStack::detach) + .map_err(Into::into) }) } diff --git a/gix/src/repository/worktree.rs b/gix/src/repository/worktree.rs index 17db1c0ebda..8526e9de503 100644 --- a/gix/src/repository/worktree.rs +++ b/gix/src/repository/worktree.rs @@ -75,7 +75,9 @@ impl crate::Repository { // TODO(perf): when loading a non-HEAD tree, we effectively traverse the tree twice. This is usually fast though, and sharing // an object cache between the copies of the ODB handles isn't trivial and needs a lock. let index = self.index_from_tree(&id)?; - let mut cache = self.attributes_only(&index, gix_worktree::stack::state::attributes::Source::IdMapping)?; + let mut cache = self + .attributes_only(&index, gix_worktree::stack::state::attributes::Source::IdMapping)? + .detach(); let pipeline = gix_filter::Pipeline::new(cache.attributes_collection(), crate::filter::Pipeline::options(self)?); let objects = self.objects.clone().into_arc().expect("TBD error handling"); diff --git a/gix/src/submodule/mod.rs b/gix/src/submodule/mod.rs index 37ba35e6212..505495abb91 100644 --- a/gix/src/submodule/mod.rs +++ b/gix/src/submodule/mod.rs @@ -61,11 +61,14 @@ impl<'repo> SharedState<'repo> { .modules .is_active_platform(&self.repo.config.resolved, self.repo.config.pathspec_defaults()?)?; let index = self.index()?; - let attributes = self.repo.attributes_only( - &index, - gix_worktree::stack::state::attributes::Source::WorktreeThenIdMapping - .adjust_for_bare(self.repo.is_bare()), - )?; + let attributes = self + .repo + .attributes_only( + &index, + gix_worktree::stack::state::attributes::Source::WorktreeThenIdMapping + .adjust_for_bare(self.repo.is_bare()), + )? + .detach(); *state = Some(IsActiveState { platform, attributes }); } Ok(RefMut::map_split(state, |opt| { diff --git a/gix/src/types.rs b/gix/src/types.rs index 5a875f258e0..60629b45f38 100644 --- a/gix/src/types.rs +++ b/gix/src/types.rs @@ -208,7 +208,7 @@ pub struct Remote<'repo> { pub struct Pathspec<'repo> { pub(crate) repo: &'repo Repository, /// The cache to power attribute access. It's only initialized if we have a pattern with attributes. - pub(crate) cache: Option, + pub(crate) stack: Option, /// The prepared search to use for checking matches. pub(crate) search: gix_pathspec::Search, } @@ -219,3 +219,9 @@ pub struct Submodule<'repo> { pub(crate) state: Rc>, pub(crate) name: BString, } + +/// A utility to access `.gitattributes` and `.gitignore` information efficiently. +pub struct AttributeStack<'repo> { + pub(crate) repo: &'repo Repository, + pub(crate) inner: gix_worktree::Stack, +} diff --git a/gix/src/worktree/mod.rs b/gix/src/worktree/mod.rs index c780d8838e5..8365b3c7098 100644 --- a/gix/src/worktree/mod.rs +++ b/gix/src/worktree/mod.rs @@ -145,7 +145,7 @@ pub mod excludes { /// pub mod attributes { - use crate::Worktree; + use crate::{AttributeStack, Worktree}; /// The error returned by [`Worktree::attributes()`]. #[derive(Debug, thiserror::Error)] @@ -164,7 +164,7 @@ pub mod attributes { /// /// * `$XDG_CONFIG_HOME/…/ignore|attributes` if `core.excludesFile|attributesFile` is *not* set, otherwise use the configured file. /// * `$GIT_DIR/info/exclude|attributes` if present. - pub fn attributes(&self, overrides: Option) -> Result { + pub fn attributes(&self, overrides: Option) -> Result, Error> { let index = self.index()?; Ok(self.parent.attributes( &index, @@ -175,7 +175,7 @@ pub mod attributes { } /// Like [attributes()][Self::attributes()], but without access to exclude/ignore information. - pub fn attributes_only(&self) -> Result { + pub fn attributes_only(&self) -> Result, Error> { let index = self.index()?; self.parent .attributes_only( From 9df4929c2508184cb7ab83cc9c7922b2c6874f55 Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Sun, 3 Sep 2023 17:07:05 +0200 Subject: [PATCH 0074/1077] adapt to changes in `gix` --- gitoxide-core/src/hours/core.rs | 8 +--- .../src/repository/attributes/query.rs | 8 ++-- .../attributes/validate_baseline.rs | 6 +-- gitoxide-core/src/repository/index/entries.rs | 45 +++++++++---------- 4 files changed, 29 insertions(+), 38 deletions(-) diff --git a/gitoxide-core/src/hours/core.rs b/gitoxide-core/src/hours/core.rs index eb033f954aa..9d312e20d61 100644 --- a/gitoxide-core/src/hours/core.rs +++ b/gitoxide-core/src/hours/core.rs @@ -6,7 +6,7 @@ use std::{ }, }; -use gix::{bstr::BStr, odb::FindExt}; +use gix::bstr::BStr; use itertools::Itertools; use smallvec::SmallVec; @@ -182,11 +182,7 @@ pub fn spawn_tree_delta_threads<'scope>( (true, true) => { files.modified += 1; if let Some((attrs, matches)) = attributes.as_mut() { - let entry = attrs.at_entry( - change.location, - Some(false), - |id, buf| repo.objects.find_blob(id, buf), - )?; + let entry = attrs.at_entry(change.location, Some(false))?; let is_text_file = if entry.matching_attributes(matches) { let attrs: SmallVec<[_; 2]> = matches.iter_selected().collect(); diff --git a/gitoxide-core/src/repository/attributes/query.rs b/gitoxide-core/src/repository/attributes/query.rs index 83e8bf67f07..223edb64462 100644 --- a/gitoxide-core/src/repository/attributes/query.rs +++ b/gitoxide-core/src/repository/attributes/query.rs @@ -11,7 +11,7 @@ pub(crate) mod function { use std::{io, path::Path}; use anyhow::{anyhow, bail}; - use gix::{bstr::BStr, prelude::FindExt}; + use gix::bstr::BStr; use crate::{ repository::{ @@ -40,7 +40,7 @@ pub(crate) mod function { for path in paths { let is_dir = gix::path::from_bstr(path.as_ref()).metadata().ok().map(|m| m.is_dir()); - let entry = cache.at_entry(path.as_slice(), is_dir, |oid, buf| repo.objects.find_blob(oid, buf))?; + let entry = cache.at_entry(path.as_slice(), is_dir)?; if !entry.matching_attributes(&mut matches) { continue; } @@ -59,7 +59,7 @@ pub(crate) mod function { .index_entries_with_paths(&index) .ok_or_else(|| anyhow!("Pathspec didn't match a single path in the index"))? { - let entry = cache.at_entry(path, Some(false), |oid, buf| repo.objects.find_blob(oid, buf))?; + let entry = cache.at_entry(path, Some(false))?; if !entry.matching_attributes(&mut matches) { continue; } @@ -97,7 +97,7 @@ pub(crate) mod function { pub(crate) fn attributes_cache( repo: &gix::Repository, -) -> anyhow::Result<(gix::worktree::Stack, IndexPersistedOrInMemory)> { +) -> anyhow::Result<(gix::AttributeStack<'_>, IndexPersistedOrInMemory)> { let index = repo.index_or_load_from_head()?; let cache = repo.attributes( &index, diff --git a/gitoxide-core/src/repository/attributes/validate_baseline.rs b/gitoxide-core/src/repository/attributes/validate_baseline.rs index a4645620344..1702c81bcfa 100644 --- a/gitoxide-core/src/repository/attributes/validate_baseline.rs +++ b/gitoxide-core/src/repository/attributes/validate_baseline.rs @@ -18,7 +18,7 @@ pub(crate) mod function { }; use anyhow::{anyhow, bail}; - use gix::{attrs::Assignment, bstr::BString, odb::FindExt, Progress}; + use gix::{attrs::Assignment, bstr::BString, Progress}; use crate::{ repository::attributes::{query::attributes_cache, validate_baseline::Options}, @@ -192,9 +192,7 @@ pub(crate) mod function { ); for (rela_path, baseline) in rx_base { - let entry = cache.at_entry(rela_path.as_str(), Some(false), |oid, buf| { - repo.objects.find_blob(oid, buf) - })?; + let entry = cache.at_entry(rela_path.as_str(), Some(false))?; match baseline { Baseline::Attribute { assignments: expected } => { entry.matching_attributes(&mut matches); diff --git a/gitoxide-core/src/repository/index/entries.rs b/gitoxide-core/src/repository/index/entries.rs index 264735a0209..f5f988660f1 100644 --- a/gitoxide-core/src/repository/index/entries.rs +++ b/gitoxide-core/src/repository/index/entries.rs @@ -25,7 +25,6 @@ pub(crate) mod function { use gix::{ bstr::{BStr, BString}, - odb::FindExt, repository::IndexPersistedOrInMemory, Repository, }; @@ -133,27 +132,25 @@ pub(crate) mod function { .and_then(|(attrs, cache)| { // If the user wants to see assigned attributes, we always have to match. attributes.is_some().then(|| { - cache - .at_entry(entry.path(&index), None, |id, buf| repo.objects.find_blob(id, buf)) - .map(|entry| { - let is_excluded = entry.is_excluded(); - stats.excluded += usize::from(is_excluded); - let attributes: Vec<_> = { - last_match = Some(entry.matching_attributes(attrs)); - attrs.iter().map(|m| m.assignment.to_owned()).collect() - }; - stats.with_attributes += usize::from(!attributes.is_empty()); - stats.max_attributes_per_path = stats.max_attributes_per_path.max(attributes.len()); - if let Some(attrs) = repo_attrs.as_mut() { - attributes.iter().for_each(|attr| { - attrs.insert(attr.clone()); - }); - } - Attrs { - is_excluded, - attributes, - } - }) + cache.at_entry(entry.path(&index), None).map(|entry| { + let is_excluded = entry.is_excluded(); + stats.excluded += usize::from(is_excluded); + let attributes: Vec<_> = { + last_match = Some(entry.matching_attributes(attrs)); + attrs.iter().map(|m| m.assignment.to_owned()).collect() + }; + stats.with_attributes += usize::from(!attributes.is_empty()); + stats.max_attributes_per_path = stats.max_attributes_per_path.max(attributes.len()); + if let Some(attrs) = repo_attrs.as_mut() { + attributes.iter().for_each(|attr| { + attrs.insert(attr.clone()); + }); + } + Attrs { + is_excluded, + attributes, + } + }) }) }) .transpose()?; @@ -173,7 +170,7 @@ pub(crate) mod function { } // The user doesn't want attributes, so we set the cache position on demand only None => cache - .at_entry(rela_path, Some(is_dir), |id, buf| repo.objects.find_blob(id, buf)) + .at_entry(rela_path, Some(is_dir)) .ok() .map(|platform| platform.matching_attributes(out)) .unwrap_or_default(), @@ -251,7 +248,7 @@ pub(crate) mod function { ) -> anyhow::Result<( gix::pathspec::Search, IndexPersistedOrInMemory, - Option<(gix::attrs::search::Outcome, gix::worktree::Stack)>, + Option<(gix::attrs::search::Outcome, gix::AttributeStack<'_>)>, )> { let index = repo.index_or_load_from_head()?; let pathspec = repo.pathspec( From c8e732430f3740348ccedd0dc1a9a28b06a0adee Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Sun, 3 Sep 2023 19:14:23 +0200 Subject: [PATCH 0075/1077] Add test-suite for failure modes Also, discover that apparently `momo` isn't effective where it should be *or* the implementation is more complex. --- Cargo.lock | 31 +++++++++++++++++++ gix-macros/Cargo.toml | 3 ++ gix-macros/src/momo.rs | 8 +++++ gix-macros/tests/momo/mod.rs | 13 ++++++++ .../tests/momo/ux/error_if_ineffective.rs | 3 ++ gix-macros/tests/momo/ux/error_on_struct.rs | 5 +++ .../tests/momo/ux/error_on_struct.stderr | 5 +++ 7 files changed, 68 insertions(+) create mode 100644 gix-macros/tests/momo/ux/error_if_ineffective.rs create mode 100644 gix-macros/tests/momo/ux/error_on_struct.rs create mode 100644 gix-macros/tests/momo/ux/error_on_struct.stderr diff --git a/Cargo.lock b/Cargo.lock index e73076b78bc..7bbfd8861b6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -294,6 +294,15 @@ version = "0.21.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "604178f6c5c21f02dc555784810edfb88d34ac2c73b2eae109655649ee73ce3d" +[[package]] +name = "basic-toml" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7bfc506e7a2370ec239e1d072507b2a80c833083699d3c6fa176fbb4de8448c6" +dependencies = [ + "serde", +] + [[package]] name = "bitflags" version = "1.3.2" @@ -1803,6 +1812,7 @@ dependencies = [ "proc-macro2", "quote", "syn 2.0.29", + "trybuild", ] [[package]] @@ -2575,6 +2585,12 @@ dependencies = [ "symlink", ] +[[package]] +name = "glob" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" + [[package]] name = "gloo-timers" version = "0.2.6" @@ -4428,6 +4444,21 @@ version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3528ecfd12c466c6f163363caf2d02a71161dd5e1cc6ae7b34207ea2d42d81ed" +[[package]] +name = "trybuild" +version = "1.0.83" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6df60d81823ed9c520ee897489573da4b1d79ffbe006b8134f46de1a1aa03555" +dependencies = [ + "basic-toml", + "glob", + "once_cell", + "serde", + "serde_derive", + "serde_json", + "termcolor", +] + [[package]] name = "tui-react" version = "0.20.0" diff --git a/gix-macros/Cargo.toml b/gix-macros/Cargo.toml index d208d929c1f..2cb8bff3600 100644 --- a/gix-macros/Cargo.toml +++ b/gix-macros/Cargo.toml @@ -20,3 +20,6 @@ proc_macro = true syn = { version = "2.0", features = ["full", "fold"] } quote = "1.0" proc-macro2 = "1.0" + +[dev-dependencies] +trybuild = "1.0" diff --git a/gix-macros/src/momo.rs b/gix-macros/src/momo.rs index 37d52c55e09..3e0f2ad20eb 100644 --- a/gix-macros/src/momo.rs +++ b/gix-macros/src/momo.rs @@ -11,6 +11,14 @@ pub(crate) fn inner(code: proc_macro2::TokenStream) -> proc_macro2::TokenStream if let Item::Fn(item_fn) = fn_item { let ty_conversions = parse_generics(&item_fn.sig); + // TODO: uncomment and see it fail in places where it should actually succeed. + // if ty_conversions.is_empty() { + // return Error::new( + // item_fn.span(), + // "Couldn't apply a single conversion - momo is ineffective here", + // ) + // .to_compile_error(); + // } let (argtypes, argexprs, has_self) = convert(&item_fn.sig.inputs, &ty_conversions); let uses_self = has_self diff --git a/gix-macros/tests/momo/mod.rs b/gix-macros/tests/momo/mod.rs index fd4da846627..2e79db76ece 100644 --- a/gix-macros/tests/momo/mod.rs +++ b/gix-macros/tests/momo/mod.rs @@ -302,3 +302,16 @@ fn struct_fn() { ) .unwrap_err(); } + +#[test] +fn ux() { + let t = trybuild::TestCases::new(); + t.compile_fail("tests/momo/ux/error_on_struct.rs"); +} + +#[test] +#[ignore = "needs work"] +fn ux_todo() { + let t = trybuild::TestCases::new(); + t.compile_fail("tests/momo/ux/error_if_ineffective.rs"); +} diff --git a/gix-macros/tests/momo/ux/error_if_ineffective.rs b/gix-macros/tests/momo/ux/error_if_ineffective.rs new file mode 100644 index 00000000000..cf41170c5da --- /dev/null +++ b/gix-macros/tests/momo/ux/error_if_ineffective.rs @@ -0,0 +1,3 @@ +/// If nothing is done, momo should fail. +#[gix_macros::momo] +fn main() {} diff --git a/gix-macros/tests/momo/ux/error_on_struct.rs b/gix-macros/tests/momo/ux/error_on_struct.rs new file mode 100644 index 00000000000..ff8db306c2f --- /dev/null +++ b/gix-macros/tests/momo/ux/error_on_struct.rs @@ -0,0 +1,5 @@ +fn main() {} + +/// Only functions work with momo +#[gix_macros::momo] +struct S; diff --git a/gix-macros/tests/momo/ux/error_on_struct.stderr b/gix-macros/tests/momo/ux/error_on_struct.stderr new file mode 100644 index 00000000000..e54864dcf8f --- /dev/null +++ b/gix-macros/tests/momo/ux/error_on_struct.stderr @@ -0,0 +1,5 @@ +error: expect a function + --> tests/momo/ux/error_on_struct.rs:3:1 + | +3 | /// Only functions work with momo + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ From df15ba10830ae1bb8ab540c1484df72229afbfdc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Miku=C5=82a?= Date: Sun, 3 Sep 2023 22:56:02 +0200 Subject: [PATCH 0076/1077] Add i686-pc-windows-gnu CI --- .github/workflows/ci.yml | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 4c266358599..647fa11c648 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -110,7 +110,7 @@ jobs: installation: strategy: matrix: - build: [ win-msvc, win-gnu, win32-msvc ] + build: [ win-msvc, win-gnu, win32-msvc, win32-gnu ] include: - build: win-msvc os: windows-latest @@ -124,6 +124,10 @@ jobs: os: windows-latest rust: stable target: i686-pc-windows-msvc + - build: win32-gnu + os: windows-latest + rust: stable + target: i686-pc-windows-gnu runs-on: ${{ matrix.os }} steps: - uses: actions/checkout@v3 @@ -133,10 +137,16 @@ jobs: toolchain: ${{ matrix.rust }} targets: ${{ matrix.target }} - uses: Swatinem/rust-cache@v2 + - uses: msys2/setup-msys2@v2 + with: + msystem: MINGW${{ startsWith(matrix.target, 'i686-') && '32' || '64' }} + pacboy: cc:p + path-type: inherit - name: "Install prerequisites" run: vcpkg install zlib:x64-windows-static-md - name: "Installation from crates.io: gitoxide" run: cargo +${{ matrix.rust }} install --target ${{ matrix.target }} --target-dir install-artifacts --debug --force gitoxide + shell: msys2 {0} lint: runs-on: ubuntu-latest From 04494c65df05eef6b24acb68faae939a3d85f510 Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Mon, 4 Sep 2023 09:00:15 +0200 Subject: [PATCH 0077/1077] switch the last crate (gix-package-tests) to edition 2021 --- gix-pack/tests/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gix-pack/tests/Cargo.toml b/gix-pack/tests/Cargo.toml index eac694538dc..1c2dc71a448 100644 --- a/gix-pack/tests/Cargo.toml +++ b/gix-pack/tests/Cargo.toml @@ -5,7 +5,7 @@ repository = "https://github.com/Byron/gitoxide" authors = ["Sebastian Thiel "] license = "MIT OR Apache-2.0" description = "Please use `gix-` instead ('git' -> 'gix')" -edition = "2018" +edition = "2021" rust-version = "1.65" [features] From ed327f6163f54756e58c20f86a563a97efb256ca Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Mon, 4 Sep 2023 14:53:12 +0200 Subject: [PATCH 0078/1077] chore!: update to the latest `prodash` It makes proper usage of `Progress` types easier and allows them to be used as `dyn` traits as well. --- Cargo.lock | 10 +-- Cargo.toml | 2 +- gitoxide-core/src/corpus/engine.rs | 18 +++--- gitoxide-core/src/corpus/trace.rs | 4 +- gitoxide-core/src/hours/core.rs | 33 +++------- gitoxide-core/src/hours/mod.rs | 4 +- gitoxide-core/src/hours/util.rs | 12 ++-- gitoxide-core/src/index/checkout.rs | 4 +- gitoxide-core/src/organize.rs | 6 +- gitoxide-core/src/pack/create.rs | 6 +- gitoxide-core/src/pack/explode.rs | 4 +- gitoxide-core/src/pack/index.rs | 4 +- gitoxide-core/src/pack/multi_index.rs | 10 ++- gitoxide-core/src/pack/receive.rs | 13 ++-- gitoxide-core/src/pack/verify.rs | 4 +- gitoxide-core/src/query/engine/command.rs | 4 +- gitoxide-core/src/query/engine/update.rs | 14 ++-- gitoxide-core/src/query/mod.rs | 2 +- gitoxide-core/src/repository/archive.rs | 4 +- .../attributes/validate_baseline.rs | 9 +-- gitoxide-core/src/repository/clone.rs | 4 +- gitoxide-core/src/repository/fetch.rs | 6 +- gitoxide-core/src/repository/odb.rs | 6 +- gitoxide-core/src/repository/revision/list.rs | 4 +- gitoxide-core/src/repository/verify.rs | 4 +- gix-features/Cargo.toml | 2 +- gix-features/src/progress.rs | 6 +- gix-odb/src/store_impls/dynamic/verify.rs | 4 +- gix-odb/src/store_impls/loose/verify.rs | 4 +- gix-pack/src/bundle/mod.rs | 4 +- gix-pack/src/bundle/write/mod.rs | 11 ++-- gix-pack/src/cache/delta/traverse/mod.rs | 5 +- gix-pack/src/cache/delta/traverse/resolve.rs | 40 +++++------- gix-pack/src/data/output/count/objects/mod.rs | 3 +- .../src/data/output/entry/iter_from_counts.rs | 4 +- gix-pack/src/index/traverse/mod.rs | 19 +++--- gix-pack/src/index/traverse/with_index.rs | 5 +- gix-pack/src/index/traverse/with_lookup.rs | 7 +- gix-pack/src/index/verify.rs | 6 +- gix-pack/src/index/write/encode.rs | 4 +- gix-pack/src/index/write/mod.rs | 4 +- gix-pack/src/multi_index/verify.rs | 10 +-- gix-pack/src/multi_index/write.rs | 8 +-- gix-protocol/src/fetch/delegate.rs | 16 ++--- gix-protocol/src/fetch_fn.rs | 8 +-- gix-protocol/src/handshake/function.rs | 6 +- gix-protocol/src/ls_refs.rs | 2 +- gix-worktree-state/src/checkout/chunk.rs | 64 ++++++------------- gix-worktree-state/src/checkout/function.rs | 30 +++------ gix/Cargo.toml | 2 +- gix/src/clone/checkout.rs | 2 +- gix/src/clone/fetch/mod.rs | 4 +- gix/src/lib.rs | 6 +- .../remote/connection/fetch/receive_pack.rs | 8 +-- gix/src/repository/worktree.rs | 2 +- src/shared.rs | 4 +- 56 files changed, 214 insertions(+), 277 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 1663ffecdf3..dc26aa3b7ea 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1137,7 +1137,7 @@ dependencies = [ "is-terminal", "once_cell", "owo-colors", - "prodash 25.0.2", + "prodash 26.0.0", "serde_derive", "tabled", "time", @@ -1237,7 +1237,7 @@ dependencies = [ "log", "once_cell", "parking_lot", - "prodash 25.0.2", + "prodash 26.0.0", "regex", "reqwest", "serde", @@ -1570,7 +1570,7 @@ dependencies = [ "libc", "once_cell", "parking_lot", - "prodash 25.0.2", + "prodash 26.0.0", "sha1", "sha1_smol", "thiserror", @@ -3503,9 +3503,9 @@ checksum = "9516b775656bc3e8985e19cd4b8c0c0de045095074e453d2c0a513b5f978392d" [[package]] name = "prodash" -version = "25.0.2" +version = "26.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d67eb4220992a4a052a4bb03cf776e493ecb1a3a36bab551804153d63486af7" +checksum = "2c85fe210cada0bbfc863bddeac230f5894e00d1617aa32d924302a36cf3e965" dependencies = [ "async-io", "bytesize", diff --git a/Cargo.toml b/Cargo.toml index baec8272c27..0abeb689d3c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -168,7 +168,7 @@ gix = { version = "^0.53.0", path = "gix", default-features = false } time = "0.3.23" clap = { version = "4.1.1", features = ["derive", "cargo"] } -prodash = { version = "25.0.0", optional = true, default-features = false } +prodash = { version = "26.0.0", optional = true, default-features = false } is-terminal = { version = "0.4.0", optional = true } env_logger = { version = "0.10.0", default-features = false } crosstermion = { version = "0.11.0", optional = true, default-features = false } diff --git a/gitoxide-core/src/corpus/engine.rs b/gitoxide-core/src/corpus/engine.rs index e4f42abd516..5eb32197655 100644 --- a/gitoxide-core/src/corpus/engine.rs +++ b/gitoxide-core/src/corpus/engine.rs @@ -6,7 +6,7 @@ use std::{ use anyhow::{bail, Context}; use bytesize::ByteSize; -use gix::Progress; +use gix::{Count, NestedProgress, Progress}; use rusqlite::params; use super::db; @@ -55,7 +55,7 @@ impl Engine { pub fn refresh(&mut self, corpus_path: PathBuf) -> anyhow::Result<()> { let (corpus_path, corpus_id) = self.prepare_corpus_path(corpus_path)?; let repos = self.refresh_repos(&corpus_path, corpus_id)?; - self.state.progress.set_name("refresh repos"); + self.state.progress.set_name("refresh repos".into()); self.state.progress.info(format!( "Added or updated {} repositories under {corpus_path:?}", repos.len() @@ -87,7 +87,7 @@ impl Engine { repo_progress.init(Some(repos.len()), gix::progress::count("repos")); if task.execute_exclusive || threads == 1 || dry_run { if dry_run { - repo_progress.set_name("WOULD run"); + repo_progress.set_name("WOULD run".into()); for repo in &repos { repo_progress.info(format!( "{}", @@ -202,13 +202,11 @@ impl Engine { task.perform(&mut run, &repo.path, progress, Some(1), should_interrupt); }); if let Some(err) = run.error.as_deref() { - num_errors.fetch_add(1, Ordering::SeqCst); + num_errors.fetch_add(1, Ordering::Relaxed); progress.fail(err.to_owned()); } Self::update_run(con, run)?; - if let Some(counter) = counter.as_ref() { - counter.fetch_add(1, Ordering::SeqCst); - } + counter.fetch_add(1, Ordering::Relaxed); Ok(()) }, || (!gix::interrupt::is_triggered()).then(|| Duration::from_millis(100)), @@ -243,7 +241,7 @@ impl Engine { corpus_id: db::Id, sql_suffix: Option<&str>, ) -> anyhow::Result> { - self.state.progress.set_name("query db-repos"); + self.state.progress.set_name("query db-repos".into()); self.state.progress.init(None, gix::progress::count("repos")); Ok(self @@ -267,7 +265,7 @@ impl Engine { fn refresh_repos(&mut self, corpus_path: &Path, corpus_id: db::Id) -> anyhow::Result> { let start = Instant::now(); - self.state.progress.set_name("refresh"); + self.state.progress.set_name("refresh".into()); self.state.progress.init(None, gix::progress::count("repos")); let repos = std::thread::scope({ @@ -302,7 +300,7 @@ impl Engine { let find_progress = progress.add_child("find"); let write_db = scope.spawn(move || -> anyhow::Result> { - progress.set_name("write to DB"); + progress.set_name("write to DB".into()); progress.init(None, gix::progress::count("repos")); let mut out = Vec::new(); diff --git a/gitoxide-core/src/corpus/trace.rs b/gitoxide-core/src/corpus/trace.rs index c8dd7a78e40..d1dd42b4766 100644 --- a/gitoxide-core/src/corpus/trace.rs +++ b/gitoxide-core/src/corpus/trace.rs @@ -51,11 +51,11 @@ impl tracing_forest::printer::Formatter for StoreTreeToDb { use gix::Progress; if self.reverse_lines { for line in tree.lines().rev() { - progress.info(line); + progress.info(line.into()); } } else { for line in tree.lines() { - progress.info(line); + progress.info(line.into()); } } } diff --git a/gitoxide-core/src/hours/core.rs b/gitoxide-core/src/hours/core.rs index 9d312e20d61..9728f6b5ecd 100644 --- a/gitoxide-core/src/hours/core.rs +++ b/gitoxide-core/src/hours/core.rs @@ -67,11 +67,7 @@ pub fn estimate_hours( } } -type CommitChangeLineCounters = ( - Option>, - Option>, - Option>, -); +type CommitChangeLineCounters = (Arc, Arc, Arc); type SpawnResultWithReturnChannelAndWorkers<'scope> = ( crossbeam_channel::Sender, gix::hash::ObjectId)>>, @@ -95,7 +91,7 @@ pub fn spawn_tree_delta_threads<'scope>( let rx = rx.clone(); move || -> Result<_, anyhow::Error> { let mut out = Vec::new(); - let (commit_counter, change_counter, lines_counter) = stats_counters; + let (commits, changes, lines_count) = stats_counters; let mut attributes = line_stats .then(|| -> anyhow::Result<_> { repo.index_or_load_from_head().map_err(Into::into).and_then(|index| { @@ -115,9 +111,7 @@ pub fn spawn_tree_delta_threads<'scope>( .transpose()?; for chunk in rx { for (commit_idx, parent_commit, commit) in chunk { - if let Some(c) = commit_counter.as_ref() { - c.fetch_add(1, Ordering::SeqCst); - } + commits.fetch_add(1, Ordering::Relaxed); if gix::interrupt::is_triggered() { return Ok(out); } @@ -139,9 +133,7 @@ pub fn spawn_tree_delta_threads<'scope>( .track_rewrites(None) .for_each_to_obtain_tree(&to, |change| { use gix::object::tree::diff::change::Event::*; - if let Some(c) = change_counter.as_ref() { - c.fetch_add(1, Ordering::SeqCst); - } + changes.fetch_add(1, Ordering::Relaxed); match change.event { Rewrite { .. } => { unreachable!("we turned that off") @@ -149,13 +141,13 @@ pub fn spawn_tree_delta_threads<'scope>( Addition { entry_mode, id } => { if entry_mode.is_no_tree() { files.added += 1; - add_lines(line_stats, lines_counter.as_deref(), &mut lines, id); + add_lines(line_stats, &lines_count, &mut lines, id); } } Deletion { entry_mode, id } => { if entry_mode.is_no_tree() { files.removed += 1; - remove_lines(line_stats, lines_counter.as_deref(), &mut lines, id); + remove_lines(line_stats, &lines_count, &mut lines, id); } } Modification { @@ -168,16 +160,11 @@ pub fn spawn_tree_delta_threads<'scope>( (false, false) => {} (false, true) => { files.added += 1; - add_lines(line_stats, lines_counter.as_deref(), &mut lines, id); + add_lines(line_stats, &lines_count, &mut lines, id); } (true, false) => { files.removed += 1; - remove_lines( - line_stats, - lines_counter.as_deref(), - &mut lines, - previous_id, - ); + remove_lines(line_stats, &lines_count, &mut lines, previous_id); } (true, true) => { files.modified += 1; @@ -203,9 +190,7 @@ pub fn spawn_tree_delta_threads<'scope>( nl += counts.insertions as usize + counts.removals as usize; lines.added += counts.insertions as usize; lines.removed += counts.removals as usize; - if let Some(c) = lines_counter.as_ref() { - c.fetch_add(nl, Ordering::SeqCst); - } + lines_count.fetch_add(nl, Ordering::Relaxed); } } } diff --git a/gitoxide-core/src/hours/mod.rs b/gitoxide-core/src/hours/mod.rs index 26e577de1ab..2a814587349 100644 --- a/gitoxide-core/src/hours/mod.rs +++ b/gitoxide-core/src/hours/mod.rs @@ -5,7 +5,7 @@ use gix::{ actor, bstr::{BStr, ByteSlice}, prelude::*, - progress, Progress, + progress, Count, NestedProgress, Progress, }; /// Additional configuration for the hours estimation functionality. @@ -49,7 +49,7 @@ pub fn estimate( ) -> anyhow::Result<()> where W: io::Write, - P: Progress, + P: NestedProgress, { let repo = gix::discover(working_dir)?; let commit_id = repo.rev_parse_single(rev_spec)?.detach(); diff --git a/gitoxide-core/src/hours/util.rs b/gitoxide-core/src/hours/util.rs index f87be1767c1..55eff0cc06e 100644 --- a/gitoxide-core/src/hours/util.rs +++ b/gitoxide-core/src/hours/util.rs @@ -158,22 +158,18 @@ impl LineStats { /// An index able to address any commit pub type CommitIdx = u32; -pub fn add_lines(line_stats: bool, lines_counter: Option<&AtomicUsize>, lines: &mut LineStats, id: gix::Id<'_>) { +pub fn add_lines(line_stats: bool, lines_counter: &AtomicUsize, lines: &mut LineStats, id: gix::Id<'_>) { if let Some(Ok(blob)) = line_stats.then(|| id.object()) { let nl = blob.data.lines_with_terminator().count(); lines.added += nl; - if let Some(c) = lines_counter { - c.fetch_add(nl, Ordering::SeqCst); - } + lines_counter.fetch_add(nl, Ordering::Relaxed); } } -pub fn remove_lines(line_stats: bool, lines_counter: Option<&AtomicUsize>, lines: &mut LineStats, id: gix::Id<'_>) { +pub fn remove_lines(line_stats: bool, lines_counter: &AtomicUsize, lines: &mut LineStats, id: gix::Id<'_>) { if let Some(Ok(blob)) = line_stats.then(|| id.object()) { let nl = blob.data.lines_with_terminator().count(); lines.removed += nl; - if let Some(c) = lines_counter { - c.fetch_add(nl, Ordering::SeqCst); - } + lines_counter.fetch_add(nl, Ordering::Relaxed); } } diff --git a/gitoxide-core/src/index/checkout.rs b/gitoxide-core/src/index/checkout.rs index bdfaa3235f0..5ecb3688860 100644 --- a/gitoxide-core/src/index/checkout.rs +++ b/gitoxide-core/src/index/checkout.rs @@ -4,7 +4,7 @@ use std::{ }; use anyhow::bail; -use gix::{odb::FindExt, worktree::state::checkout, Progress}; +use gix::{odb::FindExt, worktree::state::checkout, NestedProgress, Progress}; use crate::{ index, @@ -16,7 +16,7 @@ pub fn checkout_exclusive( dest_directory: impl AsRef, repo: Option, mut err: impl std::io::Write, - mut progress: impl Progress, + mut progress: impl NestedProgress, should_interrupt: &AtomicBool, index::checkout_exclusive::Options { index: Options { object_hash, .. }, diff --git a/gitoxide-core/src/organize.rs b/gitoxide-core/src/organize.rs index 7a9809ef006..1feed705a18 100644 --- a/gitoxide-core/src/organize.rs +++ b/gitoxide-core/src/organize.rs @@ -3,7 +3,7 @@ use std::{ path::{Path, PathBuf}, }; -use gix::{objs::bstr::ByteSlice, progress, Progress}; +use gix::{objs::bstr::ByteSlice, progress, NestedProgress, Progress}; #[derive(Default, Copy, Clone, Eq, PartialEq)] pub enum Mode { @@ -207,7 +207,7 @@ fn handle( } /// Find all working directories in the given `source_dir` and print them to `out` while providing `progress`. -pub fn discover( +pub fn discover( source_dir: impl AsRef, mut out: impl std::io::Write, mut progress: P, @@ -222,7 +222,7 @@ pub fn discover( Ok(()) } -pub fn run( +pub fn run( mode: Mode, source_dir: impl AsRef, destination: impl AsRef, diff --git a/gitoxide-core/src/pack/create.rs b/gitoxide-core/src/pack/create.rs index 4f8005de39d..7501e22a27f 100644 --- a/gitoxide-core/src/pack/create.rs +++ b/gitoxide-core/src/pack/create.rs @@ -9,7 +9,7 @@ use gix::{ odb::{pack, pack::FindExt}, parallel::InOrderIter, prelude::Finalize, - progress, traverse, Progress, + progress, traverse, Count, NestedProgress, Progress, }; use crate::OutputFormat; @@ -109,7 +109,7 @@ pub fn create( ) -> anyhow::Result<()> where W: std::io::Write, - P: Progress, + P: NestedProgress, P::SubProgress: 'static, { let repo = gix::discover(repository_path)?.into_sync(); @@ -179,7 +179,7 @@ where Some(1) }; if nondeterministic_thread_count.is_some() && !may_use_multiple_threads { - progress.fail("Cannot use multi-threaded counting in tree-diff object expansion mode as it may yield way too many objects."); + progress.fail("Cannot use multi-threaded counting in tree-diff object expansion mode as it may yield way too many objects.".into()); } let (_, _, thread_count) = gix::parallel::optimize_chunk_size_and_thread_limit(50, None, thread_limit, None); let progress = progress::ThroughputOnDrop::new(progress); diff --git a/gitoxide-core/src/pack/explode.rs b/gitoxide-core/src/pack/explode.rs index 39583eb2a0c..5b00f29da0c 100644 --- a/gitoxide-core/src/pack/explode.rs +++ b/gitoxide-core/src/pack/explode.rs @@ -10,7 +10,7 @@ use gix::{ hash::ObjectId, object, objs, odb, odb::{loose, pack, Write}, - Progress, + NestedProgress, }; #[derive(Default, Clone, Eq, PartialEq, Debug)] @@ -137,7 +137,7 @@ pub fn pack_or_pack_index( pack_path: impl AsRef, object_path: Option>, check: SafetyCheck, - progress: impl Progress, + progress: impl NestedProgress, Context { thread_limit, delete_pack, diff --git a/gitoxide-core/src/pack/index.rs b/gitoxide-core/src/pack/index.rs index 15a84141a11..36a69258497 100644 --- a/gitoxide-core/src/pack/index.rs +++ b/gitoxide-core/src/pack/index.rs @@ -1,6 +1,6 @@ use std::{fs, io, path::PathBuf, str::FromStr, sync::atomic::AtomicBool}; -use gix::{odb::pack, Progress}; +use gix::{odb::pack, NestedProgress}; use crate::OutputFormat; @@ -77,7 +77,7 @@ pub fn from_pack

( ctx: Context<'static, impl io::Write>, ) -> anyhow::Result<()> where - P: Progress, + P: NestedProgress, P::SubProgress: 'static, { use anyhow::Context; diff --git a/gitoxide-core/src/pack/multi_index.rs b/gitoxide-core/src/pack/multi_index.rs index da27f7f4730..b8e0603f480 100644 --- a/gitoxide-core/src/pack/multi_index.rs +++ b/gitoxide-core/src/pack/multi_index.rs @@ -1,13 +1,17 @@ use std::{io::BufWriter, path::PathBuf, sync::atomic::AtomicBool}; use anyhow::bail; -use gix::Progress; +use gix::NestedProgress; use crate::OutputFormat; pub const PROGRESS_RANGE: std::ops::RangeInclusive = 1..=3; -pub fn verify(multi_index_path: PathBuf, progress: impl Progress, should_interrupt: &AtomicBool) -> anyhow::Result<()> { +pub fn verify( + multi_index_path: PathBuf, + progress: impl NestedProgress, + should_interrupt: &AtomicBool, +) -> anyhow::Result<()> { gix::odb::pack::multi_index::File::at(multi_index_path)?.verify_integrity_fast(progress, should_interrupt)?; Ok(()) } @@ -15,7 +19,7 @@ pub fn verify(multi_index_path: PathBuf, progress: impl Progress, should_interru pub fn create( index_paths: Vec, output_path: PathBuf, - progress: impl Progress, + progress: impl NestedProgress, should_interrupt: &AtomicBool, object_hash: gix::hash::Kind, ) -> anyhow::Result<()> { diff --git a/gitoxide-core/src/pack/receive.rs b/gitoxide-core/src/pack/receive.rs index 30574a66c66..9e4c009bb54 100644 --- a/gitoxide-core/src/pack/receive.rs +++ b/gitoxide-core/src/pack/receive.rs @@ -120,7 +120,7 @@ mod blocking_io { bstr::BString, protocol, protocol::{fetch::Response, handshake::Ref}, - Progress, + NestedProgress, }; use super::{receive_pack_blocking, CloneDelegate, Context}; @@ -130,7 +130,7 @@ mod blocking_io { fn receive_pack( &mut self, input: impl BufRead, - progress: impl Progress, + progress: impl NestedProgress, refs: &[Ref], _previous_response: &Response, ) -> io::Result<()> { @@ -156,7 +156,7 @@ mod blocking_io { ) -> anyhow::Result<()> where W: std::io::Write, - P: Progress, + P: NestedProgress, P::SubProgress: 'static, { let transport = net::connect( @@ -188,6 +188,7 @@ mod blocking_io { #[cfg(feature = "blocking-client")] pub use blocking_io::receive; use gix::protocol::ls_refs; +use gix::NestedProgress; #[cfg(feature = "async-client")] mod async_io { @@ -211,7 +212,7 @@ mod async_io { async fn receive_pack( &mut self, input: impl AsyncBufRead + Unpin + 'async_trait, - progress: impl Progress, + progress: impl gix::NestedProgress, refs: &[Ref], _previous_response: &Response, ) -> io::Result<()> { @@ -236,7 +237,7 @@ mod async_io { ctx: Context, ) -> anyhow::Result<()> where - P: Progress + 'static, + P: gix::NestedProgress + 'static, W: io::Write + Send + 'static, { let transport = net::connect( @@ -367,7 +368,7 @@ fn receive_pack_blocking( mut refs_directory: Option, ctx: &mut Context, input: impl io::BufRead, - progress: impl Progress, + progress: impl NestedProgress, refs: &[Ref], ) -> io::Result<()> { let options = pack::bundle::write::Options { diff --git a/gitoxide-core/src/pack/verify.rs b/gitoxide-core/src/pack/verify.rs index 5a5db4edfdc..3b40a13858a 100644 --- a/gitoxide-core/src/pack/verify.rs +++ b/gitoxide-core/src/pack/verify.rs @@ -5,7 +5,7 @@ use bytesize::ByteSize; use gix::{ object, odb, odb::{pack, pack::index}, - Progress, + NestedProgress, }; pub use index::verify::Mode; pub const PROGRESS_RANGE: std::ops::RangeInclusive = 1..=2; @@ -87,7 +87,7 @@ impl pack::cache::DecodeEntry for EitherCache { pub fn pack_or_pack_index( path: impl AsRef, - mut progress: impl Progress, + mut progress: impl NestedProgress, Context { mut out, mut err, diff --git a/gitoxide-core/src/query/engine/command.rs b/gitoxide-core/src/query/engine/command.rs index 6245d5472b1..5498af56046 100644 --- a/gitoxide-core/src/query/engine/command.rs +++ b/gitoxide-core/src/query/engine/command.rs @@ -1,7 +1,7 @@ use std::collections::HashMap; use anyhow::{bail, Context}; -use gix::{bstr::ByteSlice, prelude::ObjectIdExt, Progress}; +use gix::{bstr::ByteSlice, prelude::ObjectIdExt, Count, Progress}; use rusqlite::{params, OptionalExtension}; use crate::{ @@ -14,7 +14,7 @@ impl query::Engine { &self, cmd: Command, mut out: impl std::io::Write, - mut progress: impl gix::Progress, + mut progress: impl gix::NestedProgress, ) -> anyhow::Result<()> { match cmd { Command::TracePath { spec } => { diff --git a/gitoxide-core/src/query/engine/update.rs b/gitoxide-core/src/query/engine/update.rs index a9bcf389984..bae1a6d3daa 100644 --- a/gitoxide-core/src/query/engine/update.rs +++ b/gitoxide-core/src/query/engine/update.rs @@ -12,7 +12,7 @@ use gix::{ odb::FindExt, parallel::{InOrderIter, SequenceId}, prelude::ObjectIdExt, - Progress, + Count, Progress, }; use rusqlite::{params, Statement, Transaction}; @@ -21,7 +21,7 @@ use crate::query::Options; pub fn update( repo: &gix::Repository, con: &mut rusqlite::Connection, - progress: &mut impl gix::Progress, + progress: &mut impl gix::NestedProgress, mut err: impl std::io::Write, Options { object_cache_size_mb, @@ -37,28 +37,28 @@ pub fn update( p.init(None, progress::count("commits")); p }; - let stat_counter = stat_progress.counter().expect("shared counter available"); + let stat_counter = stat_progress.counter(); let mut db_progress = { let mut p = progress.add_child("db cache"); p.init(None, progress::count("events")); p }; - let commit_counter = db_progress.counter().expect("shared counter available"); + let commit_counter = db_progress.counter(); let change_progress = { let mut p = progress.add_child("find changes"); p.init(None, progress::count("modified files")); p }; - let change_counter = change_progress.counter().expect("shared counter available"); + let change_counter = change_progress.counter(); let lines_progress = { let mut p = progress.add_child("find changes"); p.init(None, progress::count("diff lines")); p }; - let lines_counter = lines_progress.counter().expect("shared counter available"); + let lines_counter = lines_progress.counter(); let mut traverse_progress = progress.add_child("traverse commit graph"); traverse_progress.init(None, progress::count("commits")); @@ -388,7 +388,7 @@ pub fn update( if saw_new_commits { db_progress.show_throughput(start); } else { - db_progress.info("up to date"); + db_progress.info("up to date".into()); } commits.extend(all_commits); diff --git a/gitoxide-core/src/query/mod.rs b/gitoxide-core/src/query/mod.rs index 9f1a376cef5..e1e2863825e 100644 --- a/gitoxide-core/src/query/mod.rs +++ b/gitoxide-core/src/query/mod.rs @@ -17,7 +17,7 @@ pub use engine::Command; pub fn prepare( repo_dir: &std::path::Path, - mut progress: impl gix::Progress, + mut progress: impl gix::NestedProgress, err: impl std::io::Write, opts: Options, ) -> anyhow::Result { diff --git a/gitoxide-core/src/repository/archive.rs b/gitoxide-core/src/repository/archive.rs index b27a14aab7a..7ef715638fa 100644 --- a/gitoxide-core/src/repository/archive.rs +++ b/gitoxide-core/src/repository/archive.rs @@ -1,7 +1,7 @@ use std::path::{Path, PathBuf}; use anyhow::{anyhow, bail}; -use gix::{worktree::archive, Progress}; +use gix::{worktree::archive, NestedProgress, Progress}; pub struct Options { pub format: Option, @@ -14,7 +14,7 @@ pub fn stream( repo: gix::Repository, destination_path: &Path, rev_spec: Option<&str>, - mut progress: impl Progress, + mut progress: impl NestedProgress, Options { format, prefix, diff --git a/gitoxide-core/src/repository/attributes/validate_baseline.rs b/gitoxide-core/src/repository/attributes/validate_baseline.rs index 1702c81bcfa..f2c92f71a30 100644 --- a/gitoxide-core/src/repository/attributes/validate_baseline.rs +++ b/gitoxide-core/src/repository/attributes/validate_baseline.rs @@ -18,7 +18,7 @@ pub(crate) mod function { }; use anyhow::{anyhow, bail}; - use gix::{attrs::Assignment, bstr::BString, Progress}; + use gix::{attrs::Assignment, bstr::BString, Count, Progress}; use crate::{ repository::attributes::{query::attributes_cache, validate_baseline::Options}, @@ -28,7 +28,7 @@ pub(crate) mod function { pub fn validate_baseline( repo: gix::Repository, paths: Option + Send + 'static>, - mut progress: impl Progress + 'static, + mut progress: impl gix::NestedProgress + 'static, mut out: impl io::Write, mut err: impl io::Write, Options { @@ -249,10 +249,7 @@ pub(crate) mod function { "{}: Validation failed with {} mismatches out of {}", gix::path::realpath(repo.work_dir().unwrap_or(repo.git_dir()))?.display(), mismatches.len(), - progress - .counter() - .map(|a| a.load(Ordering::Relaxed)) - .unwrap_or_default() + progress.counter().load(Ordering::Relaxed) ); } } diff --git a/gitoxide-core/src/repository/clone.rs b/gitoxide-core/src/repository/clone.rs index 6fec5801335..96640c69537 100644 --- a/gitoxide-core/src/repository/clone.rs +++ b/gitoxide-core/src/repository/clone.rs @@ -14,7 +14,7 @@ pub(crate) mod function { use std::ffi::OsStr; use anyhow::{bail, Context}; - use gix::{bstr::BString, remote::fetch::Status, Progress}; + use gix::{bstr::BString, remote::fetch::Status, NestedProgress}; use super::Options; use crate::{repository::fetch::function::print_updates, OutputFormat}; @@ -35,7 +35,7 @@ pub(crate) mod function { }: Options, ) -> anyhow::Result<()> where - P: Progress, + P: NestedProgress, P::SubProgress: 'static, { if format != OutputFormat::Human { diff --git a/gitoxide-core/src/repository/fetch.rs b/gitoxide-core/src/repository/fetch.rs index 35240a3b498..f20525da981 100644 --- a/gitoxide-core/src/repository/fetch.rs +++ b/gitoxide-core/src/repository/fetch.rs @@ -49,7 +49,7 @@ pub(crate) mod function { }: Options, ) -> anyhow::Result<()> where - P: gix::Progress, + P: gix::NestedProgress, P::SubProgress: 'static, { if format != OutputFormat::Human { @@ -134,7 +134,7 @@ pub(crate) mod function { mut progress: impl gix::Progress, ) -> anyhow::Result<()> { progress.init(Some(graph.len()), gix::progress::count("commits")); - progress.set_name("building graph"); + progress.set_name("building graph".into()); let mut map = gix::hashtable::HashMap::default(); let mut vg = layout::topo::layout::VisualGraph::new(Orientation::TopToBottom); @@ -168,7 +168,7 @@ pub(crate) mod function { } let start = std::time::Instant::now(); - progress.set_name("layout graph"); + progress.set_name("layout graph".into()); progress.info(format!("writing {path:?}…")); let mut svg = SVGWriter::new(); vg.do_it(false, false, false, &mut svg); diff --git a/gitoxide-core/src/repository/odb.rs b/gitoxide-core/src/repository/odb.rs index 1d3a08b6232..85c35618db2 100644 --- a/gitoxide-core/src/repository/odb.rs +++ b/gitoxide-core/src/repository/odb.rs @@ -69,7 +69,7 @@ pub fn statistics( } progress.init(None, gix::progress::count("objects")); - progress.set_name("counting"); + progress.set_name("counting".into()); let counter = progress.counter(); let start = std::time::Instant::now(); @@ -169,9 +169,7 @@ pub fn statistics( move |_| (repo.objects.clone().into_inner(), counter), |ids, (handle, counter)| { let ids = ids?; - if let Some(counter) = counter { - counter.fetch_add(ids.len(), std::sync::atomic::Ordering::SeqCst); - } + counter.fetch_add(ids.len(), std::sync::atomic::Ordering::Relaxed); let out = ids .into_iter() .map(|id| handle.header(id)) diff --git a/gitoxide-core/src/repository/revision/list.rs b/gitoxide-core/src/repository/revision/list.rs index 550d6ad9988..d1f80bcf5e5 100644 --- a/gitoxide-core/src/repository/revision/list.rs +++ b/gitoxide-core/src/repository/revision/list.rs @@ -65,7 +65,7 @@ pub(crate) mod function { Format::Text => None, }; progress.init(None, gix::progress::count("commits")); - progress.set_name("traverse"); + progress.set_name("traverse".into()); let start = std::time::Instant::now(); for commit in commits { @@ -116,7 +116,7 @@ pub(crate) mod function { progress.show_throughput(start); if let Some((mut vg, path, _)) = vg { let start = std::time::Instant::now(); - progress.set_name("layout graph"); + progress.set_name("layout graph".into()); progress.info(format!("writing {path:?}…")); let mut svg = SVGWriter::new(); vg.do_it(false, false, false, &mut svg); diff --git a/gitoxide-core/src/repository/verify.rs b/gitoxide-core/src/repository/verify.rs index 7e028fd2510..df5a74c5192 100644 --- a/gitoxide-core/src/repository/verify.rs +++ b/gitoxide-core/src/repository/verify.rs @@ -1,7 +1,5 @@ use std::sync::atomic::AtomicBool; -use gix::Progress; - use crate::{pack, OutputFormat}; /// A general purpose context for many operations provided here @@ -21,7 +19,7 @@ pub const PROGRESS_RANGE: std::ops::RangeInclusive = 1..=3; pub fn integrity( repo: gix::Repository, mut out: impl std::io::Write, - progress: impl Progress, + progress: impl gix::NestedProgress, should_interrupt: &AtomicBool, Context { output_statistics, diff --git a/gix-features/Cargo.toml b/gix-features/Cargo.toml index df27af35d4f..337eaec3ece 100644 --- a/gix-features/Cargo.toml +++ b/gix-features/Cargo.toml @@ -129,7 +129,7 @@ crc32fast = { version = "1.2.1", optional = true } sha1 = { version = "0.10.0", optional = true } # progress -prodash = { version = "25.0.0", optional = true, default-features = false } +prodash = { version = "26.0.0", optional = true, default-features = false } bytesize = { version = "1.0.1", optional = true } # pipe diff --git a/gix-features/src/progress.rs b/gix-features/src/progress.rs index 6a90d84227d..1f13fdab89d 100644 --- a/gix-features/src/progress.rs +++ b/gix-features/src/progress.rs @@ -7,7 +7,7 @@ pub use prodash::{ self, messages::MessageLevel, progress::{Discard, DoOrDiscard, Either, Id, Step, StepShared, Task, ThroughputOnDrop, Value, UNKNOWN}, - unit, Progress, RawProgress, Unit, + unit, Count, NestedProgress, Progress, Unit, }; /// A stub for the portions of the `bytesize` crate that we use internally in `gitoxide`. #[cfg(not(feature = "progress-unit-bytes"))] @@ -77,7 +77,7 @@ pub fn steps() -> Option { Some(unit::dynamic(unit::Range::new("steps"))) } -/// A structure passing every [`read`][std::io::Read::read()] call through to the contained Progress instance using [`inc_by(bytes_read)`][Progress::inc_by()]. +/// A structure passing every [`read`](std::io::Read::read()) call through to the contained Progress instance using [`inc_by(bytes_read)`](Count::inc_by()). pub struct Read { /// The implementor of [`std::io::Read`] to which progress is added pub inner: T, @@ -111,7 +111,7 @@ where } } -/// A structure passing every [`write`][std::io::Write::write()] call through to the contained Progress instance using [`inc_by(bytes_written)`][Progress::inc_by()]. +/// A structure passing every [`write`][std::io::Write::write()] call through to the contained Progress instance using [`inc_by(bytes_written)`](Count::inc_by()). /// /// This is particularly useful if the final size of the bytes to write is known or can be estimated precisely enough. pub struct Write { diff --git a/gix-odb/src/store_impls/dynamic/verify.rs b/gix-odb/src/store_impls/dynamic/verify.rs index d8039cbebcc..b17f102459b 100644 --- a/gix-odb/src/store_impls/dynamic/verify.rs +++ b/gix-odb/src/store_impls/dynamic/verify.rs @@ -4,7 +4,7 @@ use std::{ time::Instant, }; -use gix_features::progress::{MessageLevel, Progress}; +use gix_features::progress::{MessageLevel, NestedProgress, Progress}; use crate::{ pack, @@ -118,7 +118,7 @@ impl super::Store { options: integrity::Options, ) -> Result, integrity::Error> where - P: Progress, + P: NestedProgress, C: pack::cache::DecodeEntry, F: Fn() -> C + Send + Clone, { diff --git a/gix-odb/src/store_impls/loose/verify.rs b/gix-odb/src/store_impls/loose/verify.rs index 8ffbb7105d6..4ba7f13ee1e 100644 --- a/gix-odb/src/store_impls/loose/verify.rs +++ b/gix-odb/src/store_impls/loose/verify.rs @@ -3,7 +3,7 @@ use std::{ time::Instant, }; -use gix_features::progress::Progress; +use gix_features::progress::{Count, NestedProgress, Progress}; use crate::{loose::Store, Write}; @@ -61,7 +61,7 @@ impl Store { /// Check all loose objects for their integrity checking their hash matches the actual data and by decoding them fully. pub fn verify_integrity( &self, - mut progress: impl Progress, + mut progress: impl NestedProgress, should_interrupt: &AtomicBool, ) -> Result { let mut buf = Vec::new(); diff --git a/gix-pack/src/bundle/mod.rs b/gix-pack/src/bundle/mod.rs index 076b355d984..c7ba4312320 100644 --- a/gix-pack/src/bundle/mod.rs +++ b/gix-pack/src/bundle/mod.rs @@ -10,7 +10,7 @@ pub mod write; pub mod verify { use std::sync::atomic::AtomicBool; - use gix_features::progress::Progress; + use gix_features::progress::NestedProgress; /// pub mod integrity { @@ -37,7 +37,7 @@ pub mod verify { options: crate::index::verify::integrity::Options, ) -> Result, crate::index::traverse::Error> where - P: Progress, + P: NestedProgress, C: crate::cache::DecodeEntry, F: Fn() -> C + Send + Clone, { diff --git a/gix-pack/src/bundle/write/mod.rs b/gix-pack/src/bundle/write/mod.rs index fa6e0402ffa..b881379e01f 100644 --- a/gix-pack/src/bundle/write/mod.rs +++ b/gix-pack/src/bundle/write/mod.rs @@ -6,7 +6,10 @@ use std::{ sync::{atomic::AtomicBool, Arc}, }; -use gix_features::{interrupt, progress, progress::Progress}; +use gix_features::{ + interrupt, progress, + progress::{NestedProgress, Progress}, +}; use gix_tempfile::{AutoRemove, ContainingDirectory}; use crate::data; @@ -65,7 +68,7 @@ impl crate::Bundle { pub fn write_to_directory( pack: impl io::BufRead, directory: Option>, - mut progress: impl Progress, + mut progress: impl NestedProgress, should_interrupt: &AtomicBool, thin_pack_base_object_lookup_fn: Option, options: Options, @@ -181,7 +184,7 @@ impl crate::Bundle { options: Options, ) -> Result where - P: Progress, + P: NestedProgress, P::SubProgress: 'static, { let _span = gix_features::trace::coarse!("gix_pack::Bundle::write_to_directory_eagerly()"); @@ -270,7 +273,7 @@ impl crate::Bundle { fn inner_write( directory: Option>, - mut progress: impl Progress, + mut progress: impl NestedProgress, Options { thread_limit, iteration_mode: _, diff --git a/gix-pack/src/cache/delta/traverse/mod.rs b/gix-pack/src/cache/delta/traverse/mod.rs index e933af838b3..d585dff1a72 100644 --- a/gix-pack/src/cache/delta/traverse/mod.rs +++ b/gix-pack/src/cache/delta/traverse/mod.rs @@ -1,5 +1,6 @@ use std::sync::atomic::{AtomicBool, Ordering}; +use gix_features::progress::NestedProgress; use gix_features::{ parallel::in_parallel_with_slice, progress::{self, Progress}, @@ -116,9 +117,9 @@ where where F: for<'r> Fn(EntryRange, &'r R) -> Option<&'r [u8]> + Send + Clone, R: Send + Sync, - P1: Progress, + P1: NestedProgress, P2: Progress, - MBFN: FnMut(&mut T, &::SubProgress, Context<'_>) -> Result<(), E> + Send + Clone, + MBFN: FnMut(&mut T, &::SubProgress, Context<'_>) -> Result<(), E> + Send + Clone, E: std::error::Error + Send + Sync + 'static, { self.set_pack_entries_end_and_resolve_ref_offsets(pack_entries_end)?; diff --git a/gix-pack/src/cache/delta/traverse/resolve.rs b/gix-pack/src/cache/delta/traverse/resolve.rs index f5a14efb924..77b23f94ea5 100644 --- a/gix-pack/src/cache/delta/traverse/resolve.rs +++ b/gix-pack/src/cache/delta/traverse/resolve.rs @@ -28,8 +28,8 @@ pub(crate) struct State { #[allow(clippy::too_many_arguments)] pub(crate) fn deltas( - object_counter: Option, - size_counter: Option, + objects: gix_features::progress::StepShared, + size: gix_features::progress::StepShared, node: &mut Item, State { delta_bytes, @@ -104,10 +104,8 @@ where }, ) .map_err(|err| Box::new(err) as Box)?; - object_counter.as_ref().map(|c| c.fetch_add(1, Ordering::SeqCst)); - size_counter - .as_ref() - .map(|c| c.fetch_add(base_bytes.len(), Ordering::SeqCst)); + objects.fetch_add(1, Ordering::Relaxed); + size.fetch_add(base_bytes.len(), Ordering::Relaxed); } for mut child in base.into_child_iter() { @@ -146,10 +144,8 @@ where }, ) .map_err(|err| Box::new(err) as Box)?; - object_counter.as_ref().map(|c| c.fetch_add(1, Ordering::SeqCst)); - size_counter - .as_ref() - .map(|c| c.fetch_add(base_bytes.len(), Ordering::SeqCst)); + objects.fetch_add(1, Ordering::Relaxed); + size.fetch_add(base_bytes.len(), Ordering::Relaxed); } } @@ -169,8 +165,8 @@ where return deltas_mt( initial_threads, decompressed_bytes_by_pack_offset, - object_counter, - size_counter, + objects, + size, progress, nodes, resolve.clone(), @@ -194,8 +190,8 @@ where pub(crate) fn deltas_mt( mut threads_to_create: isize, decompressed_bytes_by_pack_offset: BTreeMap)>, - object_counter: Option, - size_counter: Option, + objects: gix_features::progress::StepShared, + size: gix_features::progress::StepShared, progress: &P, nodes: Vec<(u16, Node<'_, T>)>, resolve: F, @@ -230,8 +226,8 @@ where let decompressed_bytes_by_pack_offset = &decompressed_bytes_by_pack_offset; let resolve = resolve.clone(); let mut modify_base = modify_base.clone(); - let object_counter = object_counter.as_ref(); - let size_counter = size_counter.as_ref(); + let objects = &objects; + let size = &size; move || -> Result<(), Error> { let mut fully_resolved_delta_bytes = Vec::new(); @@ -282,10 +278,8 @@ where }, ) .map_err(|err| Box::new(err) as Box)?; - object_counter.as_ref().map(|c| c.fetch_add(1, Ordering::SeqCst)); - size_counter - .as_ref() - .map(|c| c.fetch_add(base_bytes.len(), Ordering::SeqCst)); + objects.fetch_add(1, Ordering::Relaxed); + size.fetch_add(base_bytes.len(), Ordering::Relaxed); } for mut child in base.into_child_iter() { @@ -330,10 +324,8 @@ where }, ) .map_err(|err| Box::new(err) as Box)?; - object_counter.as_ref().map(|c| c.fetch_add(1, Ordering::SeqCst)); - size_counter - .as_ref() - .map(|c| c.fetch_add(base_bytes.len(), Ordering::SeqCst)); + objects.fetch_add(1, Ordering::Relaxed); + size.fetch_add(base_bytes.len(), Ordering::Relaxed); } } } diff --git a/gix-pack/src/data/output/count/objects/mod.rs b/gix-pack/src/data/output/count/objects/mod.rs index 1559fa894e9..3f9a28bd162 100644 --- a/gix-pack/src/data/output/count/objects/mod.rs +++ b/gix-pack/src/data/output/count/objects/mod.rs @@ -3,6 +3,7 @@ use std::{ sync::{atomic::AtomicBool, Arc}, }; +use gix_features::progress::NestedProgress; use gix_features::{parallel, progress::Progress}; use gix_hash::ObjectId; @@ -38,7 +39,7 @@ pub type Result = std::result::Result<(Vec, Outcome), Err pub fn objects( db: Find, objects_ids: Iter, - progress: impl Progress, + progress: impl NestedProgress, should_interrupt: &AtomicBool, Options { thread_limit, 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 1ac426f13bd..c8cb7d39e82 100644 --- a/gix-pack/src/data/output/entry/iter_from_counts.rs +++ b/gix-pack/src/data/output/entry/iter_from_counts.rs @@ -1,6 +1,8 @@ pub(crate) mod function { use std::{cmp::Ordering, sync::Arc}; + use gix_features::progress::prodash::Count; + use gix_features::progress::NestedProgress; use gix_features::{parallel, parallel::SequenceId, progress::Progress}; use super::{reduce, util, Error, Mode, Options, Outcome, ProgressId}; @@ -38,7 +40,7 @@ pub(crate) mod function { pub fn iter_from_counts( mut counts: Vec, db: Find, - mut progress: impl Progress + 'static, + mut progress: impl NestedProgress + 'static, Options { version, mode, diff --git a/gix-pack/src/index/traverse/mod.rs b/gix-pack/src/index/traverse/mod.rs index ee9b6bc3dc2..a83da4a70e0 100644 --- a/gix-pack/src/index/traverse/mod.rs +++ b/gix-pack/src/index/traverse/mod.rs @@ -1,10 +1,6 @@ use std::sync::atomic::AtomicBool; -use gix_features::{ - parallel, - progress::{Progress, RawProgress}, - zlib, -}; +use gix_features::{parallel, progress::Progress, zlib}; use crate::index; @@ -17,6 +13,7 @@ use reduce::Reducer; mod error; pub use error::Error; +use gix_features::progress::NestedProgress; mod types; pub use types::{Algorithm, ProgressId, SafetyCheck, Statistics}; @@ -92,10 +89,10 @@ impl index::File { }: Options, ) -> Result, Error> where - P: Progress, + P: NestedProgress, C: crate::cache::DecodeEntry, E: std::error::Error + Send + Sync + 'static, - Processor: FnMut(gix_object::Kind, &[u8], &index::Entry, &dyn RawProgress) -> Result<(), E> + Send + Clone, + Processor: FnMut(gix_object::Kind, &[u8], &index::Entry, &dyn Progress) -> Result<(), E> + Send + Clone, F: Fn() -> C + Send + Clone, { match traversal { @@ -157,9 +154,9 @@ impl index::File { cache: &mut C, buf: &mut Vec, inflate: &mut zlib::Inflate, - progress: &mut dyn RawProgress, + progress: &mut dyn Progress, index_entry: &index::Entry, - processor: &mut impl FnMut(gix_object::Kind, &[u8], &index::Entry, &dyn RawProgress) -> Result<(), E>, + processor: &mut impl FnMut(gix_object::Kind, &[u8], &index::Entry, &dyn Progress) -> Result<(), E>, ) -> Result> where C: crate::cache::DecodeEntry, @@ -208,8 +205,8 @@ fn process_entry( decompressed: &[u8], index_entry: &index::Entry, pack_entry_crc32: impl FnOnce() -> u32, - progress: &dyn RawProgress, - processor: &mut impl FnMut(gix_object::Kind, &[u8], &index::Entry, &dyn RawProgress) -> Result<(), E>, + progress: &dyn Progress, + processor: &mut impl FnMut(gix_object::Kind, &[u8], &index::Entry, &dyn Progress) -> Result<(), E>, ) -> Result<(), Error> where E: std::error::Error + Send + Sync + 'static, diff --git a/gix-pack/src/index/traverse/with_index.rs b/gix-pack/src/index/traverse/with_index.rs index 884277c9dfe..75f9b912831 100644 --- a/gix-pack/src/index/traverse/with_index.rs +++ b/gix-pack/src/index/traverse/with_index.rs @@ -1,5 +1,6 @@ use std::sync::atomic::{AtomicBool, Ordering}; +use gix_features::progress::NestedProgress; use gix_features::{parallel, progress::Progress}; use super::Error; @@ -65,8 +66,8 @@ impl index::File { Options { check, thread_limit }: Options, ) -> Result, Error> where - P: Progress, - Processor: FnMut(gix_object::Kind, &[u8], &index::Entry, &dyn gix_features::progress::RawProgress) -> Result<(), E> + P: NestedProgress, + Processor: FnMut(gix_object::Kind, &[u8], &index::Entry, &dyn gix_features::progress::Progress) -> Result<(), E> + Send + Clone, E: std::error::Error + Send + Sync + 'static, diff --git a/gix-pack/src/index/traverse/with_lookup.rs b/gix-pack/src/index/traverse/with_lookup.rs index 44f421323ac..9aae8a91b65 100644 --- a/gix-pack/src/index/traverse/with_lookup.rs +++ b/gix-pack/src/index/traverse/with_lookup.rs @@ -1,5 +1,6 @@ use std::sync::atomic::{AtomicBool, Ordering}; +use gix_features::progress::{Count, NestedProgress}; use gix_features::{ parallel::{self, in_parallel_if}, progress::{self, Progress}, @@ -79,12 +80,10 @@ impl index::File { }: Options, ) -> Result, Error> where - P: Progress, + P: NestedProgress, C: crate::cache::DecodeEntry, E: std::error::Error + Send + Sync + 'static, - Processor: FnMut(gix_object::Kind, &[u8], &index::Entry, &dyn gix_features::progress::RawProgress) -> Result<(), E> - + Send - + Clone, + Processor: FnMut(gix_object::Kind, &[u8], &index::Entry, &dyn Progress) -> Result<(), E> + Send + Clone, F: Fn() -> C + Send + Clone, { let (verify_result, traversal_result) = parallel::join( diff --git a/gix-pack/src/index/verify.rs b/gix-pack/src/index/verify.rs index 3232329a3f9..de08c327722 100644 --- a/gix-pack/src/index/verify.rs +++ b/gix-pack/src/index/verify.rs @@ -1,6 +1,6 @@ use std::sync::atomic::AtomicBool; -use gix_features::progress::Progress; +use gix_features::progress::{NestedProgress, Progress}; use gix_object::{bstr::ByteSlice, WriteTo}; use crate::index; @@ -175,7 +175,7 @@ impl index::File { should_interrupt: &AtomicBool, ) -> Result, index::traverse::Error> where - P: Progress, + P: NestedProgress, C: crate::cache::DecodeEntry, F: Fn() -> C + Send + Clone, { @@ -239,7 +239,7 @@ impl index::File { object_kind: gix_object::Kind, buf: &[u8], index_entry: &index::Entry, - progress: &dyn gix_features::progress::RawProgress, + progress: &dyn gix_features::progress::Progress, ) -> Result<(), integrity::Error> { if let Mode::HashCrc32Decode | Mode::HashCrc32DecodeEncode = verify_mode { use gix_object::Kind::*; diff --git a/gix-pack/src/index/write/encode.rs b/gix-pack/src/index/write/encode.rs index f1195875c41..35e957f16f2 100644 --- a/gix-pack/src/index/write/encode.rs +++ b/gix-pack/src/index/write/encode.rs @@ -5,7 +5,7 @@ pub(crate) const HIGH_BIT: u32 = 0x8000_0000; use gix_features::{ hash, - progress::{self, Progress}, + progress::{self, NestedProgress}, }; use crate::index::{util::Count, V2_SIGNATURE}; @@ -15,7 +15,7 @@ pub(crate) fn write_to( entries_sorted_by_oid: Vec>, pack_hash: &gix_hash::ObjectId, kind: crate::index::Version, - mut progress: impl Progress, + mut progress: impl NestedProgress, ) -> io::Result { use io::Write; assert_eq!(kind, crate::index::Version::V2, "Can only write V2 packs right now"); diff --git a/gix-pack/src/index/write/mod.rs b/gix-pack/src/index/write/mod.rs index 72a076a851b..1626310aff2 100644 --- a/gix-pack/src/index/write/mod.rs +++ b/gix-pack/src/index/write/mod.rs @@ -1,7 +1,7 @@ use std::{convert::TryInto, io, sync::atomic::AtomicBool}; pub use error::Error; -use gix_features::progress::{self, Progress}; +use gix_features::progress::{self, Count, NestedProgress, Progress}; use crate::cache::delta::{traverse, Tree}; @@ -98,7 +98,7 @@ impl crate::index::File { F: FnOnce() -> io::Result<(F2, R)>, R: Send + Sync, F2: for<'r> Fn(crate::data::EntryRange, &'r R) -> Option<&'r [u8]> + Send + Clone, - P: Progress, + P: NestedProgress, { if version != crate::index::Version::default() { return Err(Error::Unsupported(version)); diff --git a/gix-pack/src/multi_index/verify.rs b/gix-pack/src/multi_index/verify.rs index 856a48501d3..ab84a76e940 100644 --- a/gix-pack/src/multi_index/verify.rs +++ b/gix-pack/src/multi_index/verify.rs @@ -1,6 +1,6 @@ use std::{cmp::Ordering, sync::atomic::AtomicBool, time::Instant}; -use gix_features::progress::Progress; +use gix_features::progress::{Count, NestedProgress, Progress}; use crate::{index, multi_index::File}; @@ -102,7 +102,7 @@ impl File { should_interrupt: &AtomicBool, ) -> Result<(gix_hash::ObjectId, P), integrity::Error> where - P: Progress, + P: NestedProgress, { self.verify_integrity_inner( progress, @@ -127,7 +127,7 @@ impl File { options: index::verify::integrity::Options, ) -> Result, index::traverse::Error> where - P: Progress, + P: NestedProgress, C: crate::cache::DecodeEntry, F: Fn() -> C + Send + Clone, { @@ -142,7 +142,7 @@ impl File { options: index::verify::integrity::Options, ) -> Result, index::traverse::Error> where - P: Progress, + P: NestedProgress, C: crate::cache::DecodeEntry, F: Fn() -> C + Send + Clone, { @@ -325,7 +325,7 @@ impl File { "BUG: our slicing should allow to visit all objects" ); - progress.set_name("Validating multi-pack"); + progress.set_name("Validating multi-pack".into()); progress.show_throughput(operation_start); Ok(integrity::Outcome { diff --git a/gix-pack/src/multi_index/write.rs b/gix-pack/src/multi_index/write.rs index 9002af9eb74..94ad327c382 100644 --- a/gix-pack/src/multi_index/write.rs +++ b/gix-pack/src/multi_index/write.rs @@ -5,7 +5,7 @@ use std::{ time::{Instant, SystemTime}, }; -use gix_features::progress::Progress; +use gix_features::progress::{Count, NestedProgress, Progress}; use crate::multi_index; @@ -87,7 +87,7 @@ impl multi_index::File { Options { object_hash }: Options, ) -> Result, Error> where - P: Progress, + P: NestedProgress, { let out = gix_features::hash::Write::new(out, object_hash); let (index_paths_sorted, index_filenames_sorted) = { @@ -129,7 +129,7 @@ impl multi_index::File { progress.show_throughput(start); let start = Instant::now(); - progress.set_name("Deduplicate"); + progress.set_name("Deduplicate".into()); progress.init(Some(entries.len()), gix_features::progress::count("entries")); entries.sort_by(|l, r| { l.id.cmp(&r.id) @@ -187,7 +187,7 @@ impl multi_index::File { )?; { - progress.set_name("Writing chunks"); + progress.set_name("Writing chunks".into()); progress.init(Some(cf.num_chunks()), gix_features::progress::count("chunks")); let mut chunk_write = cf.into_write(&mut out, bytes_written)?; diff --git a/gix-protocol/src/fetch/delegate.rs b/gix-protocol/src/fetch/delegate.rs index e90022d419e..5f8b86dceef 100644 --- a/gix-protocol/src/fetch/delegate.rs +++ b/gix-protocol/src/fetch/delegate.rs @@ -183,7 +183,7 @@ mod blocking_io { ops::DerefMut, }; - use gix_features::progress::Progress; + use gix_features::progress::NestedProgress; use crate::{ fetch::{DelegateBlocking, Response}, @@ -207,7 +207,7 @@ mod blocking_io { fn receive_pack( &mut self, input: impl io::BufRead, - progress: impl Progress, + progress: impl NestedProgress, refs: &[Ref], previous_response: &Response, ) -> io::Result<()>; @@ -217,7 +217,7 @@ mod blocking_io { fn receive_pack( &mut self, input: impl BufRead, - progress: impl Progress, + progress: impl NestedProgress, refs: &[Ref], previous_response: &Response, ) -> io::Result<()> { @@ -229,7 +229,7 @@ mod blocking_io { fn receive_pack( &mut self, input: impl BufRead, - progress: impl Progress, + progress: impl NestedProgress, refs: &[Ref], previous_response: &Response, ) -> io::Result<()> { @@ -246,7 +246,7 @@ mod async_io { use async_trait::async_trait; use futures_io::AsyncBufRead; - use gix_features::progress::Progress; + use gix_features::progress::NestedProgress; use crate::{ fetch::{DelegateBlocking, Response}, @@ -272,7 +272,7 @@ mod async_io { async fn receive_pack( &mut self, input: impl AsyncBufRead + Unpin + 'async_trait, - progress: impl Progress, + progress: impl NestedProgress, refs: &[Ref], previous_response: &Response, ) -> io::Result<()>; @@ -282,7 +282,7 @@ mod async_io { async fn receive_pack( &mut self, input: impl AsyncBufRead + Unpin + 'async_trait, - progress: impl Progress, + progress: impl NestedProgress, refs: &[Ref], previous_response: &Response, ) -> io::Result<()> { @@ -297,7 +297,7 @@ mod async_io { async fn receive_pack( &mut self, input: impl AsyncBufRead + Unpin + 'async_trait, - progress: impl Progress, + progress: impl NestedProgress, refs: &[Ref], previous_response: &Response, ) -> io::Result<()> { diff --git a/gix-protocol/src/fetch_fn.rs b/gix-protocol/src/fetch_fn.rs index 64d457711b2..be5e9471248 100644 --- a/gix-protocol/src/fetch_fn.rs +++ b/gix-protocol/src/fetch_fn.rs @@ -1,6 +1,6 @@ use std::borrow::Cow; -use gix_features::progress::Progress; +use gix_features::progress::NestedProgress; use gix_transport::client; use maybe_async::maybe_async; @@ -59,7 +59,7 @@ where F: FnMut(credentials::helper::Action) -> credentials::protocol::Result, D: Delegate, T: client::Transport, - P: Progress, + P: NestedProgress, P::SubProgress: 'static, { let crate::handshake::Outcome { @@ -136,7 +136,7 @@ where .await?; previous_response = if response.has_pack() { progress.step(); - progress.set_name("receiving pack"); + progress.set_name("receiving pack".into()); if !sideband_all { setup_remote_progress(&mut progress, &mut reader); } @@ -159,7 +159,7 @@ where fn setup_remote_progress

(progress: &mut P, reader: &mut Box) where - P: Progress, + P: NestedProgress, P::SubProgress: 'static, { reader.set_progress_handler(Some(Box::new({ diff --git a/gix-protocol/src/handshake/function.rs b/gix-protocol/src/handshake/function.rs index 5398a1bedb5..9e75c18d0dc 100644 --- a/gix-protocol/src/handshake/function.rs +++ b/gix-protocol/src/handshake/function.rs @@ -24,7 +24,7 @@ where { let (server_protocol_version, refs, capabilities) = { progress.init(None, progress::steps()); - progress.set_name("handshake"); + progress.set_name("handshake".into()); progress.step(); let extra_parameters: Vec<_> = extra_parameters @@ -43,13 +43,13 @@ where Err(client::Error::Io(ref err)) if err.kind() == std::io::ErrorKind::PermissionDenied => { drop(result); // needed to workaround this: https://github.com/rust-lang/rust/issues/76149 let url = transport.to_url().into_owned(); - progress.set_name("authentication"); + progress.set_name("authentication".into()); let credentials::protocol::Outcome { identity, next } = authenticate(credentials::helper::Action::get_for_url(url.clone()))? .ok_or(Error::EmptyCredentials)?; transport.set_identity(identity)?; progress.step(); - progress.set_name("handshake (authenticated)"); + progress.set_name("handshake (authenticated)".into()); match transport.handshake(service, &extra_parameters).await { Ok(v) => { authenticate(next.store())?; diff --git a/gix-protocol/src/ls_refs.rs b/gix-protocol/src/ls_refs.rs index d0b2e9ba083..c5b71da9337 100644 --- a/gix-protocol/src/ls_refs.rs +++ b/gix-protocol/src/ls_refs.rs @@ -86,7 +86,7 @@ pub(crate) mod function { ); progress.step(); - progress.set_name("list refs"); + progress.set_name("list refs".into()); let mut remote_refs = transport .invoke( ls_refs.as_str(), diff --git a/gix-worktree-state/src/checkout/chunk.rs b/gix-worktree-state/src/checkout/chunk.rs index 930e70b89be..5e5a3c0fb28 100644 --- a/gix-worktree-state/src/checkout/chunk.rs +++ b/gix-worktree-state/src/checkout/chunk.rs @@ -12,21 +12,15 @@ use crate::{checkout, checkout::entry}; mod reduce { use std::marker::PhantomData; - use gix_features::progress::Progress; - use crate::checkout; - pub struct Reduce<'a, 'entry, P1, P2, E> { - pub files: Option<&'a mut P1>, - pub bytes: Option<&'a mut P2>, + pub struct Reduce<'entry, E> { pub aggregate: super::Outcome<'entry>, pub marker: PhantomData, } - impl<'a, 'entry, P1, P2, E> gix_features::parallel::Reduce for Reduce<'a, 'entry, P1, P2, E> + impl<'entry, E> gix_features::parallel::Reduce for Reduce<'entry, E> where - P1: Progress, - P2: Progress, E: std::error::Error + Send + Sync + 'static, { type Input = Result, checkout::Error>; @@ -55,13 +49,6 @@ mod reduce { .delayed_paths_unprocessed .extend(delayed_paths_unprocessed); - if let Some(progress) = self.bytes.as_deref_mut() { - progress.set(self.aggregate.bytes_written as gix_features::progress::Step); - } - if let Some(progress) = self.files.as_deref_mut() { - progress.set(self.aggregate.files); - } - Ok(()) } @@ -121,8 +108,8 @@ impl From<&checkout::Options> for Options { pub fn process<'entry, Find, E>( entries_with_paths: impl Iterator, - files: Option<&AtomicUsize>, - bytes: Option<&AtomicUsize>, + files: &AtomicUsize, + bytes: &AtomicUsize, delayed_filter_results: &mut Vec>, ctx: &mut Context, ) -> Result, checkout::Error> @@ -139,9 +126,7 @@ where for (entry, entry_path) in entries_with_paths { // TODO: write test for that if entry.flags.contains(gix_index::entry::Flags::SKIP_WORKTREE) { - if let Some(files) = files { - files.fetch_add(1, Ordering::SeqCst); - } + files.fetch_add(1, Ordering::Relaxed); files_in_chunk += 1; continue; } @@ -179,8 +164,8 @@ where pub fn process_delayed_filter_results( mut delayed_filter_results: Vec>, - files: Option<&AtomicUsize>, - bytes: Option<&AtomicUsize>, + files: &AtomicUsize, + bytes: &AtomicUsize, out: &mut Outcome<'_>, ctx: &mut Context, ) -> Result<(), checkout::Error> @@ -259,9 +244,7 @@ where }), )?; delayed_files += 1; - if let Some(files) = files { - files.fetch_add(1, Ordering::SeqCst); - } + files.fetch_add(1, Ordering::Relaxed); } } } @@ -286,7 +269,7 @@ where pub struct WriteWithProgress<'a, T> { pub inner: T, - pub progress: Option<&'a AtomicUsize>, + pub progress: &'a AtomicUsize, } impl<'a, T> std::io::Write for WriteWithProgress<'a, T> @@ -295,9 +278,8 @@ where { fn write(&mut self, buf: &[u8]) -> std::io::Result { let written = self.inner.write(buf)?; - if let Some(progress) = self.progress { - progress.fetch_add(written as gix_features::progress::Step, Ordering::SeqCst); - } + self.progress + .fetch_add(written as gix_features::progress::Step, Ordering::SeqCst); Ok(written) } @@ -311,8 +293,8 @@ pub fn checkout_entry_handle_result<'entry, Find, E>( entry_path: &'entry BStr, errors: &mut Vec, collisions: &mut Vec, - files: Option<&AtomicUsize>, - bytes: Option<&AtomicUsize>, + files: &AtomicUsize, + bytes: &AtomicUsize, Context { find, path_cache, @@ -339,12 +321,8 @@ where match res { Ok(out) => { if let Some(num) = out.as_bytes() { - if let Some(bytes) = bytes { - bytes.fetch_add(num, Ordering::SeqCst); - } - if let Some(files) = files { - files.fetch_add(1, Ordering::SeqCst); - } + bytes.fetch_add(num, Ordering::Relaxed); + files.fetch_add(1, Ordering::Relaxed); } Ok(out) } @@ -359,7 +337,7 @@ where fn handle_error( err: E, entry_path: &BStr, - files: Option<&AtomicUsize>, + files: &AtomicUsize, errors: &mut Vec, keep_going: bool, ) -> Result<(), E> @@ -371,9 +349,7 @@ where path: entry_path.into(), error: Box::new(err), }); - if let Some(files) = files { - files.fetch_add(1, Ordering::SeqCst); - } + files.fetch_add(1, Ordering::Relaxed); Ok(()) } else { Err(err) @@ -384,7 +360,7 @@ fn is_collision( err: &std::io::Error, entry_path: &BStr, collisions: &mut Vec, - files: Option<&AtomicUsize>, + files: &AtomicUsize, ) -> bool { if !gix_fs::symlink::is_collision_error(err) { return false; @@ -396,8 +372,6 @@ fn is_collision( path: entry_path.into(), error_kind: err.kind(), }); - if let Some(files) = files { - files.fetch_add(1, Ordering::SeqCst); - } + files.fetch_add(1, Ordering::Relaxed); true } diff --git a/gix-worktree-state/src/checkout/function.rs b/gix-worktree-state/src/checkout/function.rs index 507d59bc5cc..58bafd511ee 100644 --- a/gix-worktree-state/src/checkout/function.rs +++ b/gix-worktree-state/src/checkout/function.rs @@ -89,18 +89,12 @@ where let mut delayed_filter_results = Vec::new(); let mut out = chunk::process( entries_with_paths, - num_files.as_deref(), - num_bytes.as_deref(), + &num_files, + &num_bytes, &mut delayed_filter_results, &mut ctx, )?; - chunk::process_delayed_filter_results( - delayed_filter_results, - num_files.as_deref(), - num_bytes.as_deref(), - &mut out, - &mut ctx, - )?; + chunk::process_delayed_filter_results(delayed_filter_results, &num_files, &num_bytes, &mut out, &mut ctx)?; out } else { let entries_with_paths = interrupt::Iter::new(index.entries_mut_with_paths_in(paths), should_interrupt); @@ -115,28 +109,20 @@ where move |_| (Vec::new(), ctx) }, |chunk, (delayed_filter_results, ctx)| { - chunk::process( - chunk.into_iter(), - num_files.as_deref(), - num_bytes.as_deref(), - delayed_filter_results, - ctx, - ) + chunk::process(chunk.into_iter(), &num_files, &num_bytes, delayed_filter_results, ctx) }, |(delayed_filter_results, mut ctx)| { let mut out = chunk::Outcome::default(); chunk::process_delayed_filter_results( delayed_filter_results, - num_files.as_deref(), - num_bytes.as_deref(), + &num_files, + &num_bytes, &mut out, &mut ctx, )?; Ok(out) }, chunk::Reduce { - files: num_files.is_none().then_some(files), - bytes: num_bytes.is_none().then_some(bytes), aggregate: Default::default(), marker: Default::default(), }, @@ -149,8 +135,8 @@ where entry_path, &mut errors, &mut collisions, - num_files.as_deref(), - num_bytes.as_deref(), + &num_files, + &num_bytes, &mut ctx, )? .as_bytes() diff --git a/gix/Cargo.toml b/gix/Cargo.toml index e63f2504e83..1244c1339fb 100644 --- a/gix/Cargo.toml +++ b/gix/Cargo.toml @@ -176,7 +176,7 @@ gix-protocol = { version = "^0.38.0", path = "../gix-protocol", optional = true gix-transport = { version = "^0.35.0", path = "../gix-transport", optional = true } # Just to get the progress-tree feature -prodash = { version = "25.0", optional = true, default-features = false, features = ["progress-tree"] } +prodash = { version = "26.0", optional = true, default-features = false, features = ["progress-tree"] } once_cell = "1.14.0" signal-hook = { version = "0.3.9", default-features = false } thiserror = "1.0.26" diff --git a/gix/src/clone/checkout.rs b/gix/src/clone/checkout.rs index a51b7197146..f896ee3ebd4 100644 --- a/gix/src/clone/checkout.rs +++ b/gix/src/clone/checkout.rs @@ -67,7 +67,7 @@ pub mod main_worktree { /// if the `head()` of the returned repository is not unborn. pub fn main_worktree( &mut self, - mut progress: impl crate::Progress, + mut progress: impl gix_features::progress::NestedProgress, should_interrupt: &AtomicBool, ) -> Result<(Repository, gix_worktree_state::checkout::Outcome), Error> { let _span = gix_trace::coarse!("gix::clone::PrepareCheckout::main_worktree()"); diff --git a/gix/src/clone/fetch/mod.rs b/gix/src/clone/fetch/mod.rs index 227281eb463..408fcca29cb 100644 --- a/gix/src/clone/fetch/mod.rs +++ b/gix/src/clone/fetch/mod.rs @@ -55,7 +55,7 @@ impl PrepareFetch { should_interrupt: &std::sync::atomic::AtomicBool, ) -> Result<(crate::Repository, crate::remote::fetch::Outcome), Error> where - P: crate::Progress, + P: crate::NestedProgress, P::SubProgress: 'static, { use crate::{bstr::ByteVec, remote, remote::fetch::RefLogMessage}; @@ -156,7 +156,7 @@ impl PrepareFetch { should_interrupt: &std::sync::atomic::AtomicBool, ) -> Result<(crate::clone::PrepareCheckout, crate::remote::fetch::Outcome), Error> where - P: crate::Progress, + P: crate::NestedProgress, P::SubProgress: 'static, { let (repo, fetch_outcome) = self.fetch_only(progress, should_interrupt)?; diff --git a/gix/src/lib.rs b/gix/src/lib.rs index 0db78f5b635..6fcc561894d 100644 --- a/gix/src/lib.rs +++ b/gix/src/lib.rs @@ -83,7 +83,11 @@ pub use gix_credentials as credentials; pub use gix_date as date; pub use gix_features as features; use gix_features::threading::OwnShared; -pub use gix_features::{parallel, progress::Progress, threading}; +pub use gix_features::{ + parallel, + progress::{Count, NestedProgress, Progress}, + threading, +}; pub use gix_fs as fs; pub use gix_glob as glob; pub use gix_hash as hash; diff --git a/gix/src/remote/connection/fetch/receive_pack.rs b/gix/src/remote/connection/fetch/receive_pack.rs index 089fe295721..a0cf2e3b7bc 100644 --- a/gix/src/remote/connection/fetch/receive_pack.rs +++ b/gix/src/remote/connection/fetch/receive_pack.rs @@ -23,7 +23,7 @@ use crate::{ Shallow, Status, }, }, - Progress, Repository, + Repository, }; impl<'remote, 'repo, T> Prepare<'remote, 'repo, T> @@ -75,7 +75,7 @@ where #[gix_protocol::maybe_async::maybe_async] pub async fn receive

(mut self, mut progress: P, should_interrupt: &AtomicBool) -> Result where - P: Progress, + P: gix_features::progress::NestedProgress, P::SubProgress: 'static, { let _span = gix_trace::coarse!("fetch::Prepare::receive()"); @@ -211,7 +211,7 @@ where previous_response = Some(response); if has_pack { progress.step(); - progress.set_name("receiving pack"); + progress.set_name("receiving pack".into()); if !sideband_all { setup_remote_progress(progress, &mut reader, should_interrupt); } @@ -377,7 +377,7 @@ fn setup_remote_progress

( reader: &mut Box, should_interrupt: &AtomicBool, ) where - P: Progress, + P: gix_features::progress::NestedProgress, P::SubProgress: 'static, { use gix_protocol::transport::client::ExtendedBufRead; diff --git a/gix/src/repository/worktree.rs b/gix/src/repository/worktree.rs index 8526e9de503..de5dac4b48d 100644 --- a/gix/src/repository/worktree.rs +++ b/gix/src/repository/worktree.rs @@ -114,7 +114,7 @@ impl crate::Repository { &self, mut stream: gix_worktree_stream::Stream, out: impl std::io::Write + std::io::Seek, - mut blobs: impl gix_features::progress::Progress, + blobs: impl gix_features::progress::Progress, should_interrupt: &std::sync::atomic::AtomicBool, options: gix_archive::Options, ) -> Result<(), crate::repository::worktree_archive::Error> { diff --git a/src/shared.rs b/src/shared.rs index 550c6c6c5ab..6abc14f78cc 100644 --- a/src/shared.rs +++ b/src/shared.rs @@ -112,11 +112,11 @@ pub mod pretty { let tree = tracing_forest::printer::Pretty.fmt(tree)?; if reverse_lines { for line in tree.lines().rev() { - progress.info(line); + progress.info(line.into()); } } else { for line in tree.lines() { - progress.info(line); + progress.info(line.into()); } } Ok(String::new()) From 0e8edef9882eea72a70b8782d8cf6edc8185b097 Mon Sep 17 00:00:00 2001 From: Ed Page Date: Mon, 4 Sep 2023 20:38:21 -0500 Subject: [PATCH 0079/1077] Migrate gix-protocol to winnow --- Cargo.lock | 21 +++++++++++++++------ gix-protocol/Cargo.toml | 2 +- gix-protocol/src/remote_progress.rs | 10 +++++----- 3 files changed, 21 insertions(+), 12 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 1663ffecdf3..0d45560441c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1278,7 +1278,7 @@ dependencies = [ "pretty_assertions", "serde", "thiserror", - "winnow", + "winnow 0.5.14", ] [[package]] @@ -1408,7 +1408,7 @@ dependencies = [ "smallvec", "thiserror", "unicode-bom", - "winnow", + "winnow 0.5.14", ] [[package]] @@ -1867,7 +1867,7 @@ dependencies = [ "serde", "smallvec", "thiserror", - "winnow", + "winnow 0.5.14", ] [[package]] @@ -2049,9 +2049,9 @@ dependencies = [ "gix-testtools", "gix-transport", "maybe-async", - "nom", "serde", "thiserror", + "winnow 0.3.8", ] [[package]] @@ -2117,7 +2117,7 @@ dependencies = [ "memmap2 0.7.1", "serde", "thiserror", - "winnow", + "winnow 0.5.14", ] [[package]] @@ -2305,7 +2305,7 @@ dependencies = [ "parking_lot", "tar", "tempfile", - "winnow", + "winnow 0.5.14", "xz2", ] @@ -4822,6 +4822,15 @@ version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a" +[[package]] +name = "winnow" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da01e24d23aeb852fb05609f2701ce4da9f73d58857239ed3853667cf178f204" +dependencies = [ + "memchr", +] + [[package]] name = "winnow" version = "0.5.14" diff --git a/gix-protocol/Cargo.toml b/gix-protocol/Cargo.toml index b92650c2814..44b6505d2d6 100644 --- a/gix-protocol/Cargo.toml +++ b/gix-protocol/Cargo.toml @@ -49,7 +49,7 @@ gix-credentials = { version = "^0.18.0", path = "../gix-credentials" } thiserror = "1.0.32" serde = { version = "1.0.114", optional = true, default-features = false, features = ["derive"]} bstr = { version = "1.3.0", default-features = false, features = ["std", "unicode"] } -nom = { version = "7", default-features = false, features = ["std"]} +winnow = { version = "0.3.0", features = ["simd"] } btoi = "0.4.2" # for async-client diff --git a/gix-protocol/src/remote_progress.rs b/gix-protocol/src/remote_progress.rs index 538a767fce7..d36ec0344a3 100644 --- a/gix-protocol/src/remote_progress.rs +++ b/gix-protocol/src/remote_progress.rs @@ -1,7 +1,7 @@ use std::convert::TryFrom; use bstr::ByteSlice; -use nom::{ +use winnow::{ bytes::complete::{tag, take_till, take_till1}, combinator::{map_res, opt}, sequence::{preceded, terminated}, @@ -73,11 +73,11 @@ impl<'a> RemoteProgress<'a> { } } -fn parse_number(i: &[u8]) -> nom::IResult<&[u8], usize> { +fn parse_number(i: &[u8]) -> winnow::IResult<&[u8], usize> { map_res(take_till(|c: u8| !c.is_ascii_digit()), btoi::btoi)(i) } -fn next_optional_percentage(i: &[u8]) -> nom::IResult<&[u8], Option> { +fn next_optional_percentage(i: &[u8]) -> winnow::IResult<&[u8], Option> { opt(terminated( preceded( take_till(|c: u8| c.is_ascii_digit()), @@ -87,11 +87,11 @@ fn next_optional_percentage(i: &[u8]) -> nom::IResult<&[u8], Option> { ))(i) } -fn next_optional_number(i: &[u8]) -> nom::IResult<&[u8], Option> { +fn next_optional_number(i: &[u8]) -> winnow::IResult<&[u8], Option> { opt(preceded(take_till(|c: u8| c.is_ascii_digit()), parse_number))(i) } -fn parse_progress(line: &[u8]) -> nom::IResult<&[u8], RemoteProgress<'_>> { +fn parse_progress(line: &[u8]) -> winnow::IResult<&[u8], RemoteProgress<'_>> { let (i, action) = take_till1(|c| c == b':')(line)?; let (i, percent) = next_optional_percentage(i)?; let (i, step) = next_optional_number(i)?; From b46fe9c15f6af4351c6ea7a443f0c79bd0c77969 Mon Sep 17 00:00:00 2001 From: Ed Page Date: Mon, 4 Sep 2023 20:40:54 -0500 Subject: [PATCH 0080/1077] Resolve winnow deprecations in gix-protocol --- gix-protocol/src/remote_progress.rs | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/gix-protocol/src/remote_progress.rs b/gix-protocol/src/remote_progress.rs index d36ec0344a3..85c37efa0e1 100644 --- a/gix-protocol/src/remote_progress.rs +++ b/gix-protocol/src/remote_progress.rs @@ -2,8 +2,9 @@ use std::convert::TryFrom; use bstr::ByteSlice; use winnow::{ - bytes::complete::{tag, take_till, take_till1}, - combinator::{map_res, opt}, + bytes::{tag, take_till0, take_till1}, + combinator::opt, + prelude::*, sequence::{preceded, terminated}, }; @@ -74,21 +75,23 @@ impl<'a> RemoteProgress<'a> { } fn parse_number(i: &[u8]) -> winnow::IResult<&[u8], usize> { - map_res(take_till(|c: u8| !c.is_ascii_digit()), btoi::btoi)(i) + take_till0(|c: u8| !c.is_ascii_digit()) + .map_res(btoi::btoi) + .parse_next(i) } fn next_optional_percentage(i: &[u8]) -> winnow::IResult<&[u8], Option> { opt(terminated( preceded( - take_till(|c: u8| c.is_ascii_digit()), - map_res(parse_number, u32::try_from), + take_till0(|c: u8| c.is_ascii_digit()), + parse_number.map_res(u32::try_from), ), tag(b"%"), ))(i) } fn next_optional_number(i: &[u8]) -> winnow::IResult<&[u8], Option> { - opt(preceded(take_till(|c: u8| c.is_ascii_digit()), parse_number))(i) + opt(preceded(take_till0(|c: u8| c.is_ascii_digit()), parse_number))(i) } fn parse_progress(line: &[u8]) -> winnow::IResult<&[u8], RemoteProgress<'_>> { From 8609aec804a7191b9c5a074595ef16a08e7d0be4 Mon Sep 17 00:00:00 2001 From: Ed Page Date: Mon, 4 Sep 2023 20:42:15 -0500 Subject: [PATCH 0081/1077] Prep for winnow 0.4 upgrade for gix-protocol --- gix-protocol/src/remote_progress.rs | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/gix-protocol/src/remote_progress.rs b/gix-protocol/src/remote_progress.rs index 85c37efa0e1..d817c0fec79 100644 --- a/gix-protocol/src/remote_progress.rs +++ b/gix-protocol/src/remote_progress.rs @@ -87,18 +87,19 @@ fn next_optional_percentage(i: &[u8]) -> winnow::IResult<&[u8], Option> { parse_number.map_res(u32::try_from), ), tag(b"%"), - ))(i) + )) + .parse_next(i) } fn next_optional_number(i: &[u8]) -> winnow::IResult<&[u8], Option> { - opt(preceded(take_till0(|c: u8| c.is_ascii_digit()), parse_number))(i) + opt(preceded(take_till0(|c: u8| c.is_ascii_digit()), parse_number)).parse_next(i) } fn parse_progress(line: &[u8]) -> winnow::IResult<&[u8], RemoteProgress<'_>> { - let (i, action) = take_till1(|c| c == b':')(line)?; - let (i, percent) = next_optional_percentage(i)?; - let (i, step) = next_optional_number(i)?; - let (i, max) = next_optional_number(i)?; + let (i, action) = take_till1(|c| c == b':').parse_next(line)?; + let (i, percent) = next_optional_percentage.parse_next(i)?; + let (i, step) = next_optional_number.parse_next(i)?; + let (i, max) = next_optional_number.parse_next(i)?; Ok(( i, RemoteProgress { From 659ebe9cf3569f40c0d81eb02b802516c428287a Mon Sep 17 00:00:00 2001 From: Ed Page Date: Mon, 4 Sep 2023 20:42:31 -0500 Subject: [PATCH 0082/1077] Upgrade gix-protocol to winnow 0.4 --- Cargo.lock | 6 +++--- gix-protocol/Cargo.toml | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 0d45560441c..6e83dd22b01 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2051,7 +2051,7 @@ dependencies = [ "maybe-async", "serde", "thiserror", - "winnow 0.3.8", + "winnow 0.4.11", ] [[package]] @@ -4824,9 +4824,9 @@ checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a" [[package]] name = "winnow" -version = "0.3.8" +version = "0.4.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da01e24d23aeb852fb05609f2701ce4da9f73d58857239ed3853667cf178f204" +checksum = "656953b22bcbfb1ec8179d60734981d1904494ecc91f8a3f0ee5c7389bb8eb4b" dependencies = [ "memchr", ] diff --git a/gix-protocol/Cargo.toml b/gix-protocol/Cargo.toml index 44b6505d2d6..dca2540acf2 100644 --- a/gix-protocol/Cargo.toml +++ b/gix-protocol/Cargo.toml @@ -49,7 +49,7 @@ gix-credentials = { version = "^0.18.0", path = "../gix-credentials" } thiserror = "1.0.32" serde = { version = "1.0.114", optional = true, default-features = false, features = ["derive"]} bstr = { version = "1.3.0", default-features = false, features = ["std", "unicode"] } -winnow = { version = "0.3.0", features = ["simd"] } +winnow = { version = "0.4.0", features = ["simd"] } btoi = "0.4.2" # for async-client From b213889db2697d27d70b110c863bdfdf71bc0f4f Mon Sep 17 00:00:00 2001 From: Ed Page Date: Mon, 4 Sep 2023 20:43:00 -0500 Subject: [PATCH 0083/1077] Resolve winnow deprecations in gix-protocol --- gix-protocol/src/remote_progress.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/gix-protocol/src/remote_progress.rs b/gix-protocol/src/remote_progress.rs index d817c0fec79..cb17600e96a 100644 --- a/gix-protocol/src/remote_progress.rs +++ b/gix-protocol/src/remote_progress.rs @@ -76,7 +76,7 @@ impl<'a> RemoteProgress<'a> { fn parse_number(i: &[u8]) -> winnow::IResult<&[u8], usize> { take_till0(|c: u8| !c.is_ascii_digit()) - .map_res(btoi::btoi) + .try_map(btoi::btoi) .parse_next(i) } @@ -84,7 +84,7 @@ fn next_optional_percentage(i: &[u8]) -> winnow::IResult<&[u8], Option> { opt(terminated( preceded( take_till0(|c: u8| c.is_ascii_digit()), - parse_number.map_res(u32::try_from), + parse_number.try_map(u32::try_from), ), tag(b"%"), )) From 8c80dba1836394b4d1995580f60e1443a386bdac Mon Sep 17 00:00:00 2001 From: Ed Page Date: Mon, 4 Sep 2023 20:44:15 -0500 Subject: [PATCH 0084/1077] Prep for winnow 0.5 upgrade for gix-protocol --- gix-protocol/src/remote_progress.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/gix-protocol/src/remote_progress.rs b/gix-protocol/src/remote_progress.rs index cb17600e96a..b8114227f25 100644 --- a/gix-protocol/src/remote_progress.rs +++ b/gix-protocol/src/remote_progress.rs @@ -2,10 +2,10 @@ use std::convert::TryFrom; use bstr::ByteSlice; use winnow::{ - bytes::{tag, take_till0, take_till1}, combinator::opt, + combinator::{preceded, terminated}, prelude::*, - sequence::{preceded, terminated}, + token::{tag, take_till0, take_till1}, }; /// The information usually found in remote progress messages as sent by a git server during From 237657ee59a093a65b3157e637f28282290212bb Mon Sep 17 00:00:00 2001 From: Ed Page Date: Mon, 4 Sep 2023 20:46:36 -0500 Subject: [PATCH 0085/1077] Upgrade gix-protocol to winnow 0.5 --- Cargo.lock | 21 +++++------------ gix-protocol/Cargo.toml | 2 +- gix-protocol/src/remote_progress.rs | 35 +++++++++++++---------------- 3 files changed, 23 insertions(+), 35 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 6e83dd22b01..bbb385f8f83 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1278,7 +1278,7 @@ dependencies = [ "pretty_assertions", "serde", "thiserror", - "winnow 0.5.14", + "winnow", ] [[package]] @@ -1408,7 +1408,7 @@ dependencies = [ "smallvec", "thiserror", "unicode-bom", - "winnow 0.5.14", + "winnow", ] [[package]] @@ -1867,7 +1867,7 @@ dependencies = [ "serde", "smallvec", "thiserror", - "winnow 0.5.14", + "winnow", ] [[package]] @@ -2051,7 +2051,7 @@ dependencies = [ "maybe-async", "serde", "thiserror", - "winnow 0.4.11", + "winnow", ] [[package]] @@ -2117,7 +2117,7 @@ dependencies = [ "memmap2 0.7.1", "serde", "thiserror", - "winnow 0.5.14", + "winnow", ] [[package]] @@ -2305,7 +2305,7 @@ dependencies = [ "parking_lot", "tar", "tempfile", - "winnow 0.5.14", + "winnow", "xz2", ] @@ -4822,15 +4822,6 @@ version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a" -[[package]] -name = "winnow" -version = "0.4.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "656953b22bcbfb1ec8179d60734981d1904494ecc91f8a3f0ee5c7389bb8eb4b" -dependencies = [ - "memchr", -] - [[package]] name = "winnow" version = "0.5.14" diff --git a/gix-protocol/Cargo.toml b/gix-protocol/Cargo.toml index dca2540acf2..f33601a8b09 100644 --- a/gix-protocol/Cargo.toml +++ b/gix-protocol/Cargo.toml @@ -49,7 +49,7 @@ gix-credentials = { version = "^0.18.0", path = "../gix-credentials" } thiserror = "1.0.32" serde = { version = "1.0.114", optional = true, default-features = false, features = ["derive"]} bstr = { version = "1.3.0", default-features = false, features = ["std", "unicode"] } -winnow = { version = "0.4.0", features = ["simd"] } +winnow = { version = "0.5.14", features = ["simd"] } btoi = "0.4.2" # for async-client diff --git a/gix-protocol/src/remote_progress.rs b/gix-protocol/src/remote_progress.rs index b8114227f25..491e7b0653d 100644 --- a/gix-protocol/src/remote_progress.rs +++ b/gix-protocol/src/remote_progress.rs @@ -26,8 +26,8 @@ pub struct RemoteProgress<'a> { impl<'a> RemoteProgress<'a> { /// Parse the progress from a typical git progress `line` as sent by the remote. - pub fn from_bytes(line: &[u8]) -> Option> { - parse_progress(line).ok().and_then(|(_, r)| { + pub fn from_bytes(mut line: &[u8]) -> Option> { + parse_progress(&mut line).ok().and_then(|r| { if r.percent.is_none() && r.step.is_none() && r.max.is_none() { None } else { @@ -74,13 +74,13 @@ impl<'a> RemoteProgress<'a> { } } -fn parse_number(i: &[u8]) -> winnow::IResult<&[u8], usize> { +fn parse_number(i: &mut &[u8]) -> PResult { take_till0(|c: u8| !c.is_ascii_digit()) .try_map(btoi::btoi) .parse_next(i) } -fn next_optional_percentage(i: &[u8]) -> winnow::IResult<&[u8], Option> { +fn next_optional_percentage(i: &mut &[u8]) -> PResult> { opt(terminated( preceded( take_till0(|c: u8| c.is_ascii_digit()), @@ -91,22 +91,19 @@ fn next_optional_percentage(i: &[u8]) -> winnow::IResult<&[u8], Option> { .parse_next(i) } -fn next_optional_number(i: &[u8]) -> winnow::IResult<&[u8], Option> { +fn next_optional_number(i: &mut &[u8]) -> PResult> { opt(preceded(take_till0(|c: u8| c.is_ascii_digit()), parse_number)).parse_next(i) } -fn parse_progress(line: &[u8]) -> winnow::IResult<&[u8], RemoteProgress<'_>> { - let (i, action) = take_till1(|c| c == b':').parse_next(line)?; - let (i, percent) = next_optional_percentage.parse_next(i)?; - let (i, step) = next_optional_number.parse_next(i)?; - let (i, max) = next_optional_number.parse_next(i)?; - Ok(( - i, - RemoteProgress { - action: action.into(), - percent, - step, - max, - }, - )) +fn parse_progress<'i>(line: &mut &'i [u8]) -> PResult> { + let action = take_till1(|c| c == b':').parse_next(line)?; + let percent = next_optional_percentage.parse_next(line)?; + let step = next_optional_number.parse_next(line)?; + let max = next_optional_number.parse_next(line)?; + Ok(RemoteProgress { + action: action.into(), + percent, + step, + max, + }) } From 444f970e70e8d24c6593293fec70b3a6f7f2d5bf Mon Sep 17 00:00:00 2001 From: Ed Page Date: Mon, 4 Sep 2023 20:49:47 -0500 Subject: [PATCH 0086/1077] Don't bother with error tracking that is ignored --- gix-protocol/src/remote_progress.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/gix-protocol/src/remote_progress.rs b/gix-protocol/src/remote_progress.rs index 491e7b0653d..b516a06bff1 100644 --- a/gix-protocol/src/remote_progress.rs +++ b/gix-protocol/src/remote_progress.rs @@ -74,13 +74,13 @@ impl<'a> RemoteProgress<'a> { } } -fn parse_number(i: &mut &[u8]) -> PResult { +fn parse_number(i: &mut &[u8]) -> PResult { take_till0(|c: u8| !c.is_ascii_digit()) .try_map(btoi::btoi) .parse_next(i) } -fn next_optional_percentage(i: &mut &[u8]) -> PResult> { +fn next_optional_percentage(i: &mut &[u8]) -> PResult, ()> { opt(terminated( preceded( take_till0(|c: u8| c.is_ascii_digit()), @@ -91,11 +91,11 @@ fn next_optional_percentage(i: &mut &[u8]) -> PResult> { .parse_next(i) } -fn next_optional_number(i: &mut &[u8]) -> PResult> { +fn next_optional_number(i: &mut &[u8]) -> PResult, ()> { opt(preceded(take_till0(|c: u8| c.is_ascii_digit()), parse_number)).parse_next(i) } -fn parse_progress<'i>(line: &mut &'i [u8]) -> PResult> { +fn parse_progress<'i>(line: &mut &'i [u8]) -> PResult, ()> { let action = take_till1(|c| c == b':').parse_next(line)?; let percent = next_optional_percentage.parse_next(line)?; let step = next_optional_number.parse_next(line)?; From 24dd870919ba444aa8099c63a78ea120d47ec28e Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Mon, 4 Sep 2023 19:25:57 +0200 Subject: [PATCH 0087/1077] feat!: use `prodash::Count` to indicate that nothing more than counting is performed, in place of `prodash::Progress` --- Cargo.lock | 10 +-- Cargo.toml | 2 +- gix-features/Cargo.toml | 2 +- gix-features/src/progress.rs | 4 +- gix-pack/src/data/file/verify.rs | 3 +- gix-pack/src/data/output/count/objects/mod.rs | 72 ++++++++----------- .../src/data/output/count/objects/reduce.rs | 21 ++---- .../pack/data/output/count_and_entries.rs | 2 +- gix-protocol/tests/fetch/mod.rs | 16 ++--- gix-worktree-state/src/checkout/function.rs | 10 +-- gix/Cargo.toml | 2 +- gix/src/repository/worktree.rs | 2 +- 12 files changed, 63 insertions(+), 83 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index dc26aa3b7ea..bcf595ff7d9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1137,7 +1137,7 @@ dependencies = [ "is-terminal", "once_cell", "owo-colors", - "prodash 26.0.0", + "prodash 26.2.0", "serde_derive", "tabled", "time", @@ -1237,7 +1237,7 @@ dependencies = [ "log", "once_cell", "parking_lot", - "prodash 26.0.0", + "prodash 26.2.0", "regex", "reqwest", "serde", @@ -1570,7 +1570,7 @@ dependencies = [ "libc", "once_cell", "parking_lot", - "prodash 26.0.0", + "prodash 26.2.0", "sha1", "sha1_smol", "thiserror", @@ -3503,9 +3503,9 @@ checksum = "9516b775656bc3e8985e19cd4b8c0c0de045095074e453d2c0a513b5f978392d" [[package]] name = "prodash" -version = "26.0.0" +version = "26.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c85fe210cada0bbfc863bddeac230f5894e00d1617aa32d924302a36cf3e965" +checksum = "0fdc60e4df7c418baa9fbfc62b5054b06745dfc3a2aee40294ad390b701f6351" dependencies = [ "async-io", "bytesize", diff --git a/Cargo.toml b/Cargo.toml index 0abeb689d3c..3bfc1bda5ee 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -168,7 +168,7 @@ gix = { version = "^0.53.0", path = "gix", default-features = false } time = "0.3.23" clap = { version = "4.1.1", features = ["derive", "cargo"] } -prodash = { version = "26.0.0", optional = true, default-features = false } +prodash = { version = "26.2.0", optional = true, default-features = false } is-terminal = { version = "0.4.0", optional = true } env_logger = { version = "0.10.0", default-features = false } crosstermion = { version = "0.11.0", optional = true, default-features = false } diff --git a/gix-features/Cargo.toml b/gix-features/Cargo.toml index 337eaec3ece..7af19f3a4b7 100644 --- a/gix-features/Cargo.toml +++ b/gix-features/Cargo.toml @@ -129,7 +129,7 @@ crc32fast = { version = "1.2.1", optional = true } sha1 = { version = "0.10.0", optional = true } # progress -prodash = { version = "26.0.0", optional = true, default-features = false } +prodash = { version = "26.2.0", optional = true, default-features = false } bytesize = { version = "1.0.1", optional = true } # pipe diff --git a/gix-features/src/progress.rs b/gix-features/src/progress.rs index 1f13fdab89d..eb3c27959a9 100644 --- a/gix-features/src/progress.rs +++ b/gix-features/src/progress.rs @@ -6,7 +6,9 @@ pub use bytesize; pub use prodash::{ self, messages::MessageLevel, - progress::{Discard, DoOrDiscard, Either, Id, Step, StepShared, Task, ThroughputOnDrop, Value, UNKNOWN}, + progress::{ + AtomicStep, Discard, DoOrDiscard, Either, Id, Step, StepShared, Task, ThroughputOnDrop, Value, UNKNOWN, + }, unit, Count, NestedProgress, Progress, Unit, }; /// A stub for the portions of the `bytesize` crate that we use internally in `gitoxide`. diff --git a/gix-pack/src/data/file/verify.rs b/gix-pack/src/data/file/verify.rs index afec208261a..df4aedf9dbf 100644 --- a/gix-pack/src/data/file/verify.rs +++ b/gix-pack/src/data/file/verify.rs @@ -1,6 +1,5 @@ -use std::sync::atomic::AtomicBool; - use gix_features::progress::Progress; +use std::sync::atomic::AtomicBool; use crate::data::File; diff --git a/gix-pack/src/data/output/count/objects/mod.rs b/gix-pack/src/data/output/count/objects/mod.rs index 3f9a28bd162..02f4b1ea04e 100644 --- a/gix-pack/src/data/output/count/objects/mod.rs +++ b/gix-pack/src/data/output/count/objects/mod.rs @@ -1,10 +1,6 @@ -use std::{ - cell::RefCell, - sync::{atomic::AtomicBool, Arc}, -}; +use std::{cell::RefCell, sync::atomic::AtomicBool}; -use gix_features::progress::NestedProgress; -use gix_features::{parallel, progress::Progress}; +use gix_features::parallel; use gix_hash::ObjectId; use crate::{data::output, find}; @@ -30,8 +26,8 @@ pub type Result = std::result::Result<(Vec, Outcome), Err /// * `objects_ids` /// * A list of objects ids to add to the pack. Duplication checks are performed so no object is ever added to a pack twice. /// * Objects may be expanded based on the provided [`options`][Options] -/// * `progress` -/// * a way to obtain progress information +/// * `objects` +/// * count the amount of objects we encounter /// * `should_interrupt` /// * A flag that is set to true if the operation should stop /// * `options` @@ -39,7 +35,7 @@ pub type Result = std::result::Result<(Vec, Outcome), Err pub fn objects( db: Find, objects_ids: Iter, - progress: impl NestedProgress, + objects: &dyn gix_features::progress::Count, should_interrupt: &AtomicBool, Options { thread_limit, @@ -66,30 +62,23 @@ where size: chunk_size, }; let seen_objs = gix_hashtable::sync::ObjectIdMap::default(); - let progress = Arc::new(parking_lot::Mutex::new(progress)); + let objects = objects.counter(); parallel::in_parallel( chunks, thread_limit, { - let progress = Arc::clone(&progress); - move |n| { + move |_| { ( Vec::new(), // object data buffer Vec::new(), // object data buffer 2 to hold two objects at a time - { - let mut p = progress - .lock() - .add_child_with_id(format!("thread {n}"), gix_features::progress::UNKNOWN); - p.init(None, gix_features::progress::count("objects")); - p - }, + objects.clone(), ) } }, { let seen_objs = &seen_objs; - move |oids: Vec>, (buf1, buf2, progress)| { + move |oids: Vec>, (buf1, buf2, objects)| { expand::this( &db, input_object_expansion, @@ -97,13 +86,13 @@ where oids, buf1, buf2, - progress, + objects, should_interrupt, true, /*allow pack lookups*/ ) } }, - reduce::Statistics::new(progress), + reduce::Statistics::new(), ) } @@ -111,7 +100,7 @@ where pub fn objects_unthreaded( db: Find, object_ids: impl Iterator>, - mut progress: impl Progress, + objects: impl gix_features::progress::Count, should_interrupt: &AtomicBool, input_object_expansion: ObjectExpansion, ) -> Result, IterErr> @@ -130,7 +119,7 @@ where object_ids, &mut buf1, &mut buf2, - &mut progress, + &objects.counter(), should_interrupt, false, /*allow pack lookups*/ ) @@ -139,7 +128,6 @@ where mod expand { use std::sync::atomic::{AtomicBool, Ordering}; - use gix_features::progress::Progress; use gix_hash::{oid, ObjectId}; use gix_object::{CommitRefIter, TagRefIter}; @@ -161,7 +149,7 @@ mod expand { oids: impl IntoIterator>, buf1: &mut Vec, #[allow(clippy::ptr_arg)] buf2: &mut Vec, - progress: &mut impl Progress, + objects: &gix_features::progress::AtomicStep, should_interrupt: &AtomicBool, allow_pack_lookups: bool, ) -> super::Result, IterErr> @@ -197,7 +185,7 @@ mod expand { let mut id = id.to_owned(); loop { - push_obj_count_unique(&mut out, seen_objs, &id, location, progress, stats, false); + push_obj_count_unique(&mut out, seen_objs, &id, location, objects, stats, false); match obj.kind { Tree | Blob => break, Tag => { @@ -228,12 +216,12 @@ mod expand { } let (obj, location) = db.find(tree_id, buf1)?; push_obj_count_unique( - &mut out, seen_objs, &tree_id, location, progress, stats, true, + &mut out, seen_objs, &tree_id, location, objects, stats, true, ); gix_object::TreeRefIter::from_bytes(obj.data) }; - let objects = if parent_commit_ids.is_empty() { + let objects_ref = if parent_commit_ids.is_empty() { traverse_delegate.clear(); gix_traverse::tree::breadthfirst( current_tree_iter, @@ -242,7 +230,7 @@ mod expand { stats.decoded_objects += 1; match db.find(oid, buf).ok() { Some((obj, location)) => { - progress.inc(); + objects.fetch_add(1, Ordering::Relaxed); stats.expanded_objects += 1; out.push(output::Count::from_data(oid, location)); obj.try_into_tree_iter() @@ -260,7 +248,7 @@ mod expand { let (parent_commit_obj, location) = db.find(commit_id, buf2)?; push_obj_count_unique( - &mut out, seen_objs, commit_id, location, progress, stats, true, + &mut out, seen_objs, commit_id, location, objects, stats, true, ); CommitRefIter::from_bytes(parent_commit_obj.data) .tree_id() @@ -273,7 +261,7 @@ mod expand { seen_objs, &parent_tree_id, location, - progress, + objects, stats, true, ); @@ -295,8 +283,8 @@ mod expand { } &changes_delegate.objects }; - for id in objects.iter() { - out.push(id_to_count(db, buf2, id, progress, stats, allow_pack_lookups)); + for id in objects_ref.iter() { + out.push(id_to_count(db, buf2, id, objects, stats, allow_pack_lookups)); } break; } @@ -308,7 +296,7 @@ mod expand { let mut id = id; let mut obj = (obj, location); loop { - push_obj_count_unique(&mut out, seen_objs, &id, obj.1.clone(), progress, stats, false); + push_obj_count_unique(&mut out, seen_objs, &id, obj.1.clone(), objects, stats, false); match obj.0.kind { Tree => { traverse_delegate.clear(); @@ -319,7 +307,7 @@ mod expand { stats.decoded_objects += 1; match db.find(oid, buf).ok() { Some((obj, location)) => { - progress.inc(); + objects.fetch_add(1, Ordering::Relaxed); stats.expanded_objects += 1; out.push(output::Count::from_data(oid, location)); obj.try_into_tree_iter() @@ -331,7 +319,7 @@ mod expand { ) .map_err(Error::TreeTraverse)?; for id in &traverse_delegate.non_trees { - out.push(id_to_count(db, buf1, id, progress, stats, allow_pack_lookups)); + out.push(id_to_count(db, buf1, id, objects, stats, allow_pack_lookups)); } break; } @@ -355,7 +343,7 @@ mod expand { } } } - AsIs => push_obj_count_unique(&mut out, seen_objs, &id, location, progress, stats, false), + AsIs => push_obj_count_unique(&mut out, seen_objs, &id, location, objects, stats, false), } } outcome.total_objects = out.len(); @@ -368,13 +356,13 @@ mod expand { all_seen: &impl util::InsertImmutable, id: &oid, location: Option, - progress: &mut impl Progress, + objects: &gix_features::progress::AtomicStep, statistics: &mut Outcome, count_expanded: bool, ) { let inserted = all_seen.insert(id.to_owned()); if inserted { - progress.inc(); + objects.fetch_add(1, Ordering::Relaxed); statistics.decoded_objects += 1; if count_expanded { statistics.expanded_objects += 1; @@ -388,11 +376,11 @@ mod expand { db: &Find, buf: &mut Vec, id: &oid, - progress: &mut impl Progress, + objects: &gix_features::progress::AtomicStep, statistics: &mut Outcome, allow_pack_lookups: bool, ) -> output::Count { - progress.inc(); + objects.fetch_add(1, Ordering::Relaxed); statistics.expanded_objects += 1; output::Count { id: id.to_owned(), diff --git a/gix-pack/src/data/output/count/objects/reduce.rs b/gix-pack/src/data/output/count/objects/reduce.rs index ebd686570b9..03144b60fd5 100644 --- a/gix-pack/src/data/output/count/objects/reduce.rs +++ b/gix-pack/src/data/output/count/objects/reduce.rs @@ -1,35 +1,27 @@ -use std::{marker::PhantomData, sync::Arc}; +use std::marker::PhantomData; -use gix_features::{parallel, progress::Progress}; +use gix_features::parallel; use super::Outcome; use crate::data::output; -pub struct Statistics { +pub struct Statistics { total: Outcome, counts: Vec, - progress: Arc>, _err: PhantomData, } -impl Statistics -where - P: Progress, -{ - pub fn new(progress: Arc>) -> Self { +impl Statistics { + pub fn new() -> Self { Statistics { total: Default::default(), counts: Default::default(), - progress, _err: PhantomData, } } } -impl parallel::Reduce for Statistics -where - P: Progress, -{ +impl parallel::Reduce for Statistics { type Input = Result<(Vec, Outcome), E>; type FeedProduce = (); type Output = (Vec, Outcome); @@ -38,7 +30,6 @@ where fn feed(&mut self, item: Self::Input) -> Result { let (counts, stats) = item?; self.total.aggregate(stats); - self.progress.lock().inc_by(counts.len()); self.counts.extend(counts); Ok(()) } diff --git a/gix-pack/tests/pack/data/output/count_and_entries.rs b/gix-pack/tests/pack/data/output/count_and_entries.rs index d5bd9bbd474..1cece6a0f1a 100644 --- a/gix-pack/tests/pack/data/output/count_and_entries.rs +++ b/gix-pack/tests/pack/data/output/count_and_entries.rs @@ -264,7 +264,7 @@ fn traversals() -> crate::Result { }))) .filter(|o| !o.is_null()) .map(Ok::<_, Infallible>), - progress::Discard, + &progress::Discard, &AtomicBool::new(false), count::objects::Options { input_object_expansion: expansion_mode, diff --git a/gix-protocol/tests/fetch/mod.rs b/gix-protocol/tests/fetch/mod.rs index 1639ebd0840..4516234ebc4 100644 --- a/gix-protocol/tests/fetch/mod.rs +++ b/gix-protocol/tests/fetch/mod.rs @@ -150,9 +150,9 @@ impl fetch::DelegateBlocking for LsRemoteDelegate { #[cfg(feature = "blocking-client")] mod blocking_io { + use gix_features::progress::NestedProgress; use std::io; - use gix_features::progress::Progress; use gix_protocol::{fetch, fetch::Response, handshake, handshake::Ref}; use crate::fetch::{CloneDelegate, CloneRefInWantDelegate, LsRemoteDelegate}; @@ -161,7 +161,7 @@ mod blocking_io { fn receive_pack( &mut self, mut input: impl io::BufRead, - _progress: impl Progress, + _progress: impl NestedProgress, _refs: &[Ref], _previous_response: &Response, ) -> io::Result<()> { @@ -174,7 +174,7 @@ mod blocking_io { fn receive_pack( &mut self, mut input: impl io::BufRead, - _progress: impl Progress, + _progress: impl NestedProgress, _refs: &[Ref], response: &Response, ) -> io::Result<()> { @@ -193,7 +193,7 @@ mod blocking_io { fn receive_pack( &mut self, _input: impl io::BufRead, - _progress: impl Progress, + _progress: impl NestedProgress, _refs: &[Ref], _previous_response: &Response, ) -> io::Result<()> { @@ -208,7 +208,7 @@ mod async_io { use async_trait::async_trait; use futures_io::AsyncBufRead; - use gix_features::progress::Progress; + use gix_features::progress::NestedProgress; use gix_protocol::{fetch, fetch::Response, handshake, handshake::Ref}; use crate::fetch::{CloneDelegate, CloneRefInWantDelegate, LsRemoteDelegate}; @@ -218,7 +218,7 @@ mod async_io { async fn receive_pack( &mut self, mut input: impl AsyncBufRead + Unpin + 'async_trait, - _progress: impl Progress, + _progress: impl NestedProgress, _refs: &[Ref], _previous_response: &Response, ) -> io::Result<()> { @@ -232,7 +232,7 @@ mod async_io { async fn receive_pack( &mut self, mut input: impl AsyncBufRead + Unpin + 'async_trait, - _progress: impl Progress, + _progress: impl NestedProgress, _refs: &[Ref], response: &Response, ) -> io::Result<()> { @@ -252,7 +252,7 @@ mod async_io { async fn receive_pack( &mut self, _input: impl AsyncBufRead + Unpin + 'async_trait, - _progress: impl Progress, + _progress: impl NestedProgress, _refs: &[Ref], _previous_response: &Response, ) -> io::Result<()> { diff --git a/gix-worktree-state/src/checkout/function.rs b/gix-worktree-state/src/checkout/function.rs index 58bafd511ee..4e3f454ccdd 100644 --- a/gix-worktree-state/src/checkout/function.rs +++ b/gix-worktree-state/src/checkout/function.rs @@ -1,6 +1,6 @@ use std::sync::atomic::AtomicBool; -use gix_features::{interrupt, parallel::in_parallel_with_finalize, progress::Progress}; +use gix_features::{interrupt, parallel::in_parallel_with_finalize}; use gix_hash::oid; use gix_worktree::{stack, Stack}; @@ -21,8 +21,8 @@ pub fn checkout( index: &mut gix_index::State, dir: impl Into, find: Find, - files: &mut impl Progress, - bytes: &mut impl Progress, + files: &dyn gix_features::progress::Count, + bytes: &dyn gix_features::progress::Count, should_interrupt: &AtomicBool, options: crate::checkout::Options, ) -> Result> @@ -42,8 +42,8 @@ fn checkout_inner( paths: &gix_index::PathStorage, dir: impl Into, find: Find, - files: &mut impl Progress, - bytes: &mut impl Progress, + files: &dyn gix_features::progress::Count, + bytes: &dyn gix_features::progress::Count, should_interrupt: &AtomicBool, mut options: crate::checkout::Options, ) -> Result> diff --git a/gix/Cargo.toml b/gix/Cargo.toml index 1244c1339fb..ae052aa527b 100644 --- a/gix/Cargo.toml +++ b/gix/Cargo.toml @@ -176,7 +176,7 @@ gix-protocol = { version = "^0.38.0", path = "../gix-protocol", optional = true gix-transport = { version = "^0.35.0", path = "../gix-transport", optional = true } # Just to get the progress-tree feature -prodash = { version = "26.0", optional = true, default-features = false, features = ["progress-tree"] } +prodash = { version = "26.2", optional = true, default-features = false, features = ["progress-tree"] } once_cell = "1.14.0" signal-hook = { version = "0.3.9", default-features = false } thiserror = "1.0.26" diff --git a/gix/src/repository/worktree.rs b/gix/src/repository/worktree.rs index de5dac4b48d..cf0e98d6094 100644 --- a/gix/src/repository/worktree.rs +++ b/gix/src/repository/worktree.rs @@ -114,7 +114,7 @@ impl crate::Repository { &self, mut stream: gix_worktree_stream::Stream, out: impl std::io::Write + std::io::Seek, - blobs: impl gix_features::progress::Progress, + blobs: impl gix_features::progress::Count, should_interrupt: &std::sync::atomic::AtomicBool, options: gix_archive::Options, ) -> Result<(), crate::repository::worktree_archive::Error> { From 072ee32f693a31161cd6a843da6582d13efbb20b Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Wed, 6 Sep 2023 13:46:41 +0200 Subject: [PATCH 0088/1077] fix!: use `dyn` trait where possible. This reduces compile time due to avoiding duplication. --- Cargo.lock | 10 +- gitoxide-core/src/commitgraph/verify.rs | 2 +- gitoxide-core/src/corpus/run.rs | 3 +- gitoxide-core/src/index/checkout.rs | 8 +- gitoxide-core/src/organize.rs | 4 +- gitoxide-core/src/pack/create.rs | 21 ++-- gitoxide-core/src/pack/explode.rs | 31 +++--- gitoxide-core/src/pack/index.rs | 16 +-- gitoxide-core/src/pack/multi_index.rs | 8 +- gitoxide-core/src/pack/receive.rs | 22 ++-- gitoxide-core/src/pack/verify.rs | 8 +- gitoxide-core/src/repository/archive.rs | 2 +- .../src/repository/attributes/query.rs | 6 +- gitoxide-core/src/repository/clone.rs | 3 +- gitoxide-core/src/repository/exclude.rs | 8 +- gitoxide-core/src/repository/index/entries.rs | 42 +++---- gitoxide-core/src/repository/verify.rs | 8 +- gix-actor/src/identity.rs | 4 +- gix-actor/src/signature/mod.rs | 4 +- gix-actor/tests/signature/mod.rs | 6 +- gix-attributes/src/search/attributes.rs | 15 ++- gix-attributes/src/search/outcome.rs | 11 +- gix-attributes/tests/search/mod.rs | 10 +- gix-commitgraph/src/file/access.rs | 5 +- gix-commitgraph/src/file/verify.rs | 3 +- gix-commitgraph/src/init.rs | 17 ++- gix-commitgraph/src/lib.rs | 2 +- gix-commitgraph/tests/commitgraph.rs | 3 +- gix-config/fuzz/fuzz_targets/parse.rs | 2 +- gix-config/src/file/access/comfort.rs | 31 +++--- gix-config/src/file/access/mutate.rs | 56 ++++++++-- gix-config/src/file/access/raw.rs | 52 +++++++-- gix-config/src/file/access/read_only.rs | 13 +-- gix-config/src/file/init/comfort.rs | 6 +- gix-config/src/file/init/from_paths.rs | 17 +-- gix-config/src/file/mutable/section.rs | 10 +- gix-config/src/file/section/body.rs | 14 +-- gix-config/src/file/section/mod.rs | 2 +- gix-config/src/file/write.rs | 8 +- gix-config/src/parse/event.rs | 2 +- gix-config/src/parse/events.rs | 8 +- gix-config/src/parse/key.rs | 3 +- gix-config/src/parse/nom/mod.rs | 12 +- gix-config/tests/config.rs | 2 +- gix-config/tests/file/init/from_env.rs | 2 +- gix-config/tests/file/mod.rs | 2 +- gix-config/tests/file/mutable/section.rs | 6 +- gix-config/tests/file/write.rs | 2 +- gix-config/tests/parse/key.rs | 8 +- gix-credentials/src/helper/invoke.rs | 7 +- gix-credentials/src/program/mod.rs | 42 +++---- gix-date/src/time/format.rs | 6 +- gix-date/src/time/write.rs | 2 +- gix-date/tests/time/baseline.rs | 2 +- gix-diff/tests/diff.rs | 2 +- gix-diff/tests/tree/mod.rs | 10 +- gix-discover/src/is.rs | 22 ++-- gix-discover/src/path.rs | 8 +- gix-discover/src/repository.rs | 13 +-- gix-discover/src/upwards/mod.rs | 17 ++- gix-discover/src/upwards/util.rs | 4 +- gix-discover/tests/is_git/mod.rs | 12 +- gix-discover/tests/isolated.rs | 16 +-- gix-discover/tests/upwards/ceiling_dirs.rs | 20 ++-- gix-discover/tests/upwards/mod.rs | 28 ++--- gix-features/src/cache.rs | 6 +- gix-features/src/fs.rs | 8 +- gix-features/src/hash.rs | 10 +- gix-features/src/io.rs | 6 +- gix-features/src/progress.rs | 2 +- gix-features/tests/pipe.rs | 4 +- gix-filter/examples/arrow.rs | 2 +- gix-filter/src/driver/apply.rs | 2 +- gix-filter/src/driver/delayed.rs | 8 +- gix-filter/src/driver/process/client.rs | 16 +-- gix-filter/src/driver/process/server.rs | 2 +- gix-filter/src/eol/convert_to_git.rs | 19 ++-- gix-filter/src/pipeline/convert.rs | 20 ++-- gix-filter/src/pipeline/util.rs | 2 +- gix-filter/tests/driver/mod.rs | 12 +- gix-filter/tests/eol/convert_to_git.rs | 32 +++--- gix-filter/tests/filter.rs | 2 +- gix-filter/tests/pipeline/convert_to_git.rs | 23 ++-- .../tests/pipeline/convert_to_worktree.rs | 6 +- gix-filter/tests/pipeline/mod.rs | 7 +- gix-fs/src/capabilities.rs | 11 +- gix-fs/src/dir/create.rs | 14 +-- gix-fs/src/dir/remove.rs | 3 +- gix-fs/src/stack.rs | 10 +- gix-fs/tests/dir/remove.rs | 2 +- gix-fs/tests/stack/mod.rs | 20 ++-- gix-glob/src/pattern.rs | 8 +- gix-glob/src/search/mod.rs | 9 +- gix-glob/src/search/pattern.rs | 10 +- gix-glob/tests/pattern/matching.rs | 4 +- gix-glob/tests/search/pattern.rs | 6 +- gix-glob/tests/wildmatch/mod.rs | 2 +- gix-hash/src/oid.rs | 2 +- gix-hash/src/prefix.rs | 3 +- gix-hash/tests/prefix/mod.rs | 10 +- gix-ignore/src/search.rs | 19 ++-- gix-ignore/tests/search/mod.rs | 12 +- gix-index/src/file/init.rs | 4 +- gix-lock/src/acquire.rs | 6 +- gix-negotiate/src/lib.rs | 4 +- gix-negotiate/tests/baseline/mod.rs | 10 +- gix-negotiate/tests/negotiate.rs | 6 +- gix-object/src/blob.rs | 20 ++-- gix-object/src/commit/write.rs | 4 +- gix-object/src/data.rs | 3 +- gix-object/src/encode.rs | 18 +-- gix-object/src/object/mod.rs | 20 ++-- gix-object/src/tag/write.rs | 12 +- gix-object/src/traits.rs | 12 +- gix-object/src/tree/write.rs | 4 +- gix-object/tests/object.rs | 2 +- gix-odb/src/alternate/mod.rs | 15 +-- gix-odb/src/cache.rs | 30 ++--- gix-odb/src/find.rs | 14 ++- gix-odb/src/lib.rs | 13 ++- gix-odb/src/sink.rs | 14 +-- gix-odb/src/store_impls/dynamic/find.rs | 34 ++---- gix-odb/src/store_impls/dynamic/handle.rs | 4 +- gix-odb/src/store_impls/dynamic/header.rs | 10 +- gix-odb/src/store_impls/dynamic/init.rs | 9 +- gix-odb/src/store_impls/dynamic/load_index.rs | 2 +- gix-odb/src/store_impls/dynamic/prefix.rs | 4 +- gix-odb/src/store_impls/dynamic/verify.rs | 42 +++---- gix-odb/src/store_impls/dynamic/write.rs | 7 +- gix-odb/src/store_impls/loose/find.rs | 18 +-- gix-odb/src/store_impls/loose/verify.rs | 8 +- gix-odb/src/store_impls/loose/write.rs | 36 +++--- gix-odb/src/traits.rs | 104 ++++++------------ gix-odb/tests/odb/alternate/mod.rs | 6 +- gix-odb/tests/odb/find/mod.rs | 2 +- gix-odb/tests/odb/header/mod.rs | 2 +- gix-odb/tests/odb/mod.rs | 2 +- gix-odb/tests/odb/regression/mod.rs | 2 +- gix-odb/tests/odb/sink/mod.rs | 2 +- gix-odb/tests/odb/store/compound.rs | 2 +- gix-odb/tests/odb/store/dynamic.rs | 95 ++++++++-------- gix-odb/tests/odb/store/linked.rs | 12 +- gix-odb/tests/odb/store/loose.rs | 40 +++---- gix-pack/src/bundle/find.rs | 8 +- gix-pack/src/bundle/mod.rs | 14 +-- gix-pack/src/bundle/write/mod.rs | 51 ++++----- gix-pack/src/cache/delta/from_offsets.rs | 8 +- gix-pack/src/cache/delta/mod.rs | 8 +- gix-pack/src/cache/delta/traverse/mod.rs | 22 ++-- gix-pack/src/cache/delta/traverse/resolve.rs | 22 ++-- gix-pack/src/data/entry/decode.rs | 8 +- gix-pack/src/data/entry/header.rs | 4 +- gix-pack/src/data/file/decode/entry.rs | 8 +- gix-pack/src/data/file/decode/header.rs | 2 +- gix-pack/src/data/file/verify.rs | 2 +- gix-pack/src/data/input/bytes_to_entries.rs | 2 +- gix-pack/src/data/input/entry.rs | 2 +- .../data/input/lookup_ref_delta_objects.rs | 12 +- gix-pack/src/data/output/count/mod.rs | 2 +- gix-pack/src/data/output/count/objects/mod.rs | 71 +++++------- .../src/data/output/count/objects/types.rs | 10 +- .../src/data/output/entry/iter_from_counts.rs | 27 ++--- gix-pack/src/data/output/entry/mod.rs | 9 +- gix-pack/src/find.rs | 21 ++-- gix-pack/src/find_traits.rs | 82 ++++++-------- gix-pack/src/index/access.rs | 11 +- gix-pack/src/index/traverse/mod.rs | 19 ++-- gix-pack/src/index/traverse/with_index.rs | 37 ++++--- gix-pack/src/index/traverse/with_lookup.rs | 24 ++-- gix-pack/src/index/util.rs | 2 +- gix-pack/src/index/verify.rs | 20 ++-- gix-pack/src/index/write/encode.rs | 20 ++-- gix-pack/src/index/write/mod.rs | 28 +++-- gix-pack/src/multi_index/access.rs | 4 +- gix-pack/src/multi_index/chunk.rs | 12 +- gix-pack/src/multi_index/verify.rs | 46 ++++---- gix-pack/src/multi_index/write.rs | 33 +++--- gix-pack/src/verify.rs | 4 +- gix-pack/tests/pack/bundle.rs | 10 +- gix-pack/tests/pack/data/file.rs | 6 +- .../pack/data/output/count_and_entries.rs | 40 +++---- gix-pack/tests/pack/data/output/mod.rs | 2 +- gix-pack/tests/pack/index.rs | 12 +- gix-pack/tests/pack/mod.rs | 2 +- gix-pack/tests/pack/multi_index/access.rs | 6 +- gix-pack/tests/pack/multi_index/verify.rs | 4 +- gix-pack/tests/pack/multi_index/write.rs | 8 +- gix-path/src/convert.rs | 4 +- gix-path/src/realpath.rs | 7 +- gix-path/tests/convert/normalize.rs | 49 ++++++--- gix-path/tests/realpath/mod.rs | 23 ++-- gix-pathspec/src/defaults.rs | 2 +- gix-pathspec/src/pattern.rs | 4 +- gix-pathspec/src/search/init.rs | 64 ++++++----- gix-pathspec/src/search/matching.rs | 7 +- gix-pathspec/tests/defaults.rs | 12 +- gix-pathspec/tests/search/mod.rs | 16 ++- gix-protocol/src/fetch/delegate.rs | 12 +- gix-protocol/src/fetch_fn.rs | 2 +- gix-ref/src/fullname.rs | 2 +- gix-ref/src/name.rs | 8 +- gix-ref/src/namespace.rs | 5 +- gix-ref/src/peel.rs | 3 +- gix-ref/src/store/file/find.rs | 2 +- gix-ref/src/store/file/log/line.rs | 4 +- gix-ref/src/store/file/loose/iter.rs | 7 +- gix-ref/src/store/file/loose/mod.rs | 12 +- gix-ref/src/store/file/loose/reflog.rs | 2 +- .../loose/reflog/create_or_update/tests.rs | 2 +- gix-ref/src/store/file/overlay_iter.rs | 13 +-- gix-ref/src/store/file/raw_ext.rs | 32 +++--- gix-ref/src/store/file/transaction/prepare.rs | 24 +++- gix-ref/src/store/general/init.rs | 7 +- gix-ref/src/store/packed/buffer.rs | 3 +- gix-ref/src/store/packed/iter.rs | 3 +- gix-ref/src/store/packed/transaction.rs | 6 +- gix-ref/src/transaction/ext.rs | 12 +- gix-ref/tests/file/reference.rs | 14 +-- gix-ref/tests/file/store/find.rs | 8 +- gix-ref/tests/file/store/iter.rs | 14 +-- gix-ref/tests/file/transaction/mod.rs | 6 +- .../create_or_update/mod.rs | 6 +- gix-ref/tests/file/worktree.rs | 21 ++-- gix-ref/tests/namespace/mod.rs | 2 +- gix-ref/tests/packed/iter.rs | 10 +- gix-ref/tests/refs.rs | 2 +- gix-ref/tests/transaction/mod.rs | 24 ++-- gix-refspec/src/write.rs | 4 +- gix-revision/src/describe.rs | 4 +- gix-revision/tests/describe/mod.rs | 2 +- gix-revwalk/src/graph/mod.rs | 20 ++-- gix-sec/src/identity.rs | 9 +- gix-sec/src/trust.rs | 4 +- gix-sec/tests/identity/mod.rs | 4 +- gix-status/tests/status/index_as_worktree.rs | 2 +- gix-submodule/src/access.rs | 18 +-- gix-submodule/src/is_active_platform.rs | 2 +- gix-submodule/src/lib.rs | 2 +- gix-tempfile/src/forksafe.rs | 6 +- gix-tempfile/src/handle.rs | 18 +-- gix-tempfile/src/lib.rs | 2 +- .../client/blocking_io/http/curl/remote.rs | 2 +- gix-traverse/tests/traverse.rs | 2 +- gix-traverse/tests/tree/mod.rs | 12 +- gix-url/src/lib.rs | 7 +- gix-url/tests/access/mod.rs | 9 +- gix-worktree-state/src/checkout/entry.rs | 2 +- gix-worktree-state/tests/state/checkout.rs | 6 +- gix-worktree-stream/src/from_tree/traverse.rs | 2 +- gix-worktree/src/stack/delegate.rs | 18 +-- gix-worktree/src/stack/mod.rs | 7 +- gix-worktree/src/stack/state/attributes.rs | 13 +-- gix-worktree/src/stack/state/ignore.rs | 11 +- gix-worktree/tests/worktree/mod.rs | 2 +- gix-worktree/tests/worktree/stack/ignore.rs | 2 +- gix-worktree/tests/worktree/stack/mod.rs | 2 +- gix/src/clone/checkout.rs | 9 +- gix/src/clone/fetch/util.rs | 9 +- gix/src/commit.rs | 2 +- gix/src/config/cache/access.rs | 2 +- gix/src/config/cache/init.rs | 4 +- gix/src/config/overrides.rs | 8 +- gix/src/config/snapshot/access.rs | 5 +- gix/src/create.rs | 2 +- gix/src/discover.rs | 2 +- gix/src/filter.rs | 8 +- gix/src/object/errors.rs | 10 +- gix/src/object/tree/mod.rs | 4 +- gix/src/open/repository.rs | 12 +- gix/src/pathspec.rs | 9 +- gix/src/reference/iter.rs | 12 +- gix/src/reference/mod.rs | 4 +- gix/src/remote/connect.rs | 6 +- .../remote/connection/fetch/receive_pack.rs | 36 +++--- .../connection/fetch/update_refs/mod.rs | 3 +- .../connection/fetch/update_refs/tests.rs | 2 +- gix/src/repository/object.rs | 18 +-- gix/src/revision/walk.rs | 2 +- gix/src/submodule/mod.rs | 2 +- gix/tests/clone/mod.rs | 5 +- gix/tests/remote/fetch.rs | 1 + gix/tests/remote/save.rs | 7 +- gix/tests/repository/object.rs | 2 +- gix/tests/repository/shallow.rs | 3 +- gix/tests/repository/worktree.rs | 5 +- gix/tests/revision/spec/from_bytes/util.rs | 1 + gix/tests/util/mod.rs | 2 +- src/shared.rs | 2 +- tests/tools/src/lib.rs | 2 +- 289 files changed, 1694 insertions(+), 1641 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index bcf595ff7d9..6458d8165e5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1137,7 +1137,7 @@ dependencies = [ "is-terminal", "once_cell", "owo-colors", - "prodash 26.2.0", + "prodash 26.2.1", "serde_derive", "tabled", "time", @@ -1237,7 +1237,7 @@ dependencies = [ "log", "once_cell", "parking_lot", - "prodash 26.2.0", + "prodash 26.2.1", "regex", "reqwest", "serde", @@ -1570,7 +1570,7 @@ dependencies = [ "libc", "once_cell", "parking_lot", - "prodash 26.2.0", + "prodash 26.2.1", "sha1", "sha1_smol", "thiserror", @@ -3503,9 +3503,9 @@ checksum = "9516b775656bc3e8985e19cd4b8c0c0de045095074e453d2c0a513b5f978392d" [[package]] name = "prodash" -version = "26.2.0" +version = "26.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fdc60e4df7c418baa9fbfc62b5054b06745dfc3a2aee40294ad390b701f6351" +checksum = "50bcc40e3e88402f12b15f94d43a2c7673365e9601cc52795e119b95a266100c" dependencies = [ "async-io", "bytesize", diff --git a/gitoxide-core/src/commitgraph/verify.rs b/gitoxide-core/src/commitgraph/verify.rs index 3a4623a1c21..8d601a762d3 100644 --- a/gitoxide-core/src/commitgraph/verify.rs +++ b/gitoxide-core/src/commitgraph/verify.rs @@ -39,7 +39,7 @@ pub(crate) mod function { W1: io::Write, W2: io::Write, { - let g = Graph::at(path).with_context(|| "Could not open commit graph")?; + let g = Graph::at(path.as_ref()).with_context(|| "Could not open commit graph")?; #[allow(clippy::unnecessary_wraps, unknown_lints)] fn noop_processor(_commit: &gix::commitgraph::file::Commit<'_>) -> std::result::Result<(), std::fmt::Error> { diff --git a/gitoxide-core/src/corpus/run.rs b/gitoxide-core/src/corpus/run.rs index fb924fc1d05..1cabea65115 100644 --- a/gitoxide-core/src/corpus/run.rs +++ b/gitoxide-core/src/corpus/run.rs @@ -1,3 +1,4 @@ +use gix::progress::DynNestedProgress; use std::{path::Path, sync::atomic::AtomicBool}; use crate::{ @@ -141,7 +142,7 @@ impl Execute for VerifyOdb { crate::repository::verify::integrity( repo, std::io::sink(), - progress, + progress.add_child("integrity".into()), should_interrupt, crate::repository::verify::Context { output_statistics: None, diff --git a/gitoxide-core/src/index/checkout.rs b/gitoxide-core/src/index/checkout.rs index 5ecb3688860..f7f31432c7d 100644 --- a/gitoxide-core/src/index/checkout.rs +++ b/gitoxide-core/src/index/checkout.rs @@ -104,8 +104,8 @@ pub fn checkout_exclusive( } } }, - &mut files, - &mut bytes, + &files, + &bytes, should_interrupt, opts, ), @@ -116,8 +116,8 @@ pub fn checkout_exclusive( buf.clear(); Ok(gix::objs::BlobRef { data: buf }) }, - &mut files, - &mut bytes, + &files, + &bytes, should_interrupt, opts, ), diff --git a/gitoxide-core/src/organize.rs b/gitoxide-core/src/organize.rs index 1feed705a18..04764c2df5d 100644 --- a/gitoxide-core/src/organize.rs +++ b/gitoxide-core/src/organize.rs @@ -92,8 +92,8 @@ pub fn find_git_repository_workdirs( fn find_origin_remote(repo: &Path) -> anyhow::Result> { let non_bare = repo.join(".git").join("config"); let local = gix::config::Source::Local; - let config = gix::config::File::from_path_no_includes(non_bare.as_path(), local) - .or_else(|_| gix::config::File::from_path_no_includes(repo.join("config").as_path(), local))?; + let config = gix::config::File::from_path_no_includes(non_bare.as_path().into(), local) + .or_else(|_| gix::config::File::from_path_no_includes(repo.join("config"), local))?; Ok(config .string_by_key("remote.origin.url") .map(|url| gix_url::Url::from_bytes(url.as_ref())) diff --git a/gitoxide-core/src/pack/create.rs b/gitoxide-core/src/pack/create.rs index 7501e22a27f..6b3d3d65d8c 100644 --- a/gitoxide-core/src/pack/create.rs +++ b/gitoxide-core/src/pack/create.rs @@ -112,14 +112,13 @@ where P: NestedProgress, P::SubProgress: 'static, { + type ObjectIdIter = dyn Iterator>> + Send; + let repo = gix::discover(repository_path)?.into_sync(); progress.init(Some(2), progress::steps()); let tips = tips.into_iter(); let make_cancellation_err = || anyhow!("Cancelled by user"); - let (mut handle, input): ( - _, - Box> + Send>, - ) = match input { + let (mut handle, mut input): (_, Box) = match input { None => { let mut progress = progress.add_child("traversing"); progress.init(None, progress::count("commits")); @@ -141,7 +140,7 @@ where let handle = handle.clone(); move |oid, buf| handle.find_commit_iter(oid, buf).map(|t| t.0) }) - .map(|res| res.map_err(Into::into).map(|c| c.id)) + .map(|res| res.map_err(|err| Box::new(err) as Box<_>).map(|c| c.id)) .inspect(move |_| progress.inc()), ); (handle, iter) @@ -157,7 +156,7 @@ where .lines() .map(|hex_id| { hex_id - .map_err(Into::into) + .map_err(|err| Box::new(err) as Box<_>) .and_then(|hex_id| ObjectId::from_hex(hex_id.as_bytes()).map_err(Into::into)) }) .inspect(move |_| progress.inc()), @@ -207,7 +206,7 @@ where pack::data::output::count::objects( handle.clone(), input, - progress, + &progress, &interrupt::IS_INTERRUPTED, pack::data::output::count::objects::Options { thread_limit, @@ -217,9 +216,9 @@ where )? } else { pack::data::output::count::objects_unthreaded( - handle.clone(), - input, - progress, + &handle, + &mut input, + &progress, &interrupt::IS_INTERRUPTED, input_object_expansion, )? @@ -236,7 +235,7 @@ where InOrderIter::from(pack::data::output::entry::iter_from_counts( counts, handle, - progress, + Box::new(progress), pack::data::output::entry::iter_from_counts::Options { thread_limit, mode: pack::data::output::entry::iter_from_counts::Mode::PackCopyAndBaseObjects, diff --git a/gitoxide-core/src/pack/explode.rs b/gitoxide-core/src/pack/explode.rs index 5b00f29da0c..f73a54533ad 100644 --- a/gitoxide-core/src/pack/explode.rs +++ b/gitoxide-core/src/pack/explode.rs @@ -97,19 +97,22 @@ enum OutputWriter { } impl gix::odb::Write for OutputWriter { - type Error = Error; - - fn write_buf(&self, kind: object::Kind, from: &[u8]) -> Result { + fn write_buf(&self, kind: object::Kind, from: &[u8]) -> Result { match self { - OutputWriter::Loose(db) => db.write_buf(kind, from).map_err(Into::into), - OutputWriter::Sink(db) => db.write_buf(kind, from).map_err(Into::into), + OutputWriter::Loose(db) => db.write_buf(kind, from), + OutputWriter::Sink(db) => db.write_buf(kind, from), } } - fn write_stream(&self, kind: object::Kind, size: u64, from: impl Read) -> Result { + fn write_stream( + &self, + kind: object::Kind, + size: u64, + from: &mut dyn Read, + ) -> Result { match self { - OutputWriter::Loose(db) => db.write_stream(kind, size, from).map_err(Into::into), - OutputWriter::Sink(db) => db.write_stream(kind, size, from).map_err(Into::into), + OutputWriter::Loose(db) => db.write_stream(kind, size, from), + OutputWriter::Sink(db) => db.write_stream(kind, size, from), } } } @@ -137,7 +140,7 @@ pub fn pack_or_pack_index( pack_path: impl AsRef, object_path: Option>, check: SafetyCheck, - progress: impl NestedProgress, + mut progress: impl NestedProgress + 'static, Context { thread_limit, delete_pack, @@ -178,11 +181,11 @@ pub fn pack_or_pack_index( |_| pack::index::traverse::Algorithm::Lookup, ); - let pack::index::traverse::Outcome { progress, .. } = bundle + let pack::index::traverse::Outcome { .. } = bundle .index .traverse( &bundle.pack, - progress, + &mut progress, &should_interrupt, { let object_path = object_path.map(|p| p.as_ref().to_owned()); @@ -193,7 +196,7 @@ pub fn pack_or_pack_index( let mut read_buf = Vec::new(); move |object_kind, buf, index_entry, progress| { let written_id = out.write_buf(object_kind, buf).map_err(|err| Error::Write { - source: Box::new(err) as Box, + source: err, kind: object_kind, id: index_entry.oid, })?; @@ -213,13 +216,13 @@ pub fn pack_or_pack_index( } if let Some(verifier) = loose_odb.as_ref() { let obj = verifier - .try_find(written_id, &mut read_buf) + .try_find(&written_id, &mut read_buf) .map_err(|err| Error::WrittenFileCorrupt { source: err, id: written_id, })? .ok_or(Error::WrittenFileMissing { id: written_id })?; - obj.verify_checksum(written_id)?; + obj.verify_checksum(&written_id)?; } Ok(()) } diff --git a/gitoxide-core/src/pack/index.rs b/gitoxide-core/src/pack/index.rs index 36a69258497..814f43d0697 100644 --- a/gitoxide-core/src/pack/index.rs +++ b/gitoxide-core/src/pack/index.rs @@ -70,16 +70,12 @@ pub enum PathOrRead { Read(Box), } -pub fn from_pack

( +pub fn from_pack( pack: PathOrRead, directory: Option, - progress: P, + mut progress: impl NestedProgress + 'static, ctx: Context<'static, impl io::Write>, -) -> anyhow::Result<()> -where - P: NestedProgress, - P::SubProgress: 'static, -{ +) -> anyhow::Result<()> { use anyhow::Context; let options = pack::bundle::write::Options { thread_limit: ctx.thread_limit, @@ -94,10 +90,10 @@ where let pack_len = pack.metadata()?.len(); let pack_file = fs::File::open(pack)?; pack::Bundle::write_to_directory_eagerly( - pack_file, + Box::new(pack_file), Some(pack_len), directory, - progress, + &mut progress, ctx.should_interrupt, None, options, @@ -107,7 +103,7 @@ where input, None, directory, - progress, + &mut progress, ctx.should_interrupt, None, options, diff --git a/gitoxide-core/src/pack/multi_index.rs b/gitoxide-core/src/pack/multi_index.rs index b8e0603f480..c49b2723b1f 100644 --- a/gitoxide-core/src/pack/multi_index.rs +++ b/gitoxide-core/src/pack/multi_index.rs @@ -9,17 +9,17 @@ pub const PROGRESS_RANGE: std::ops::RangeInclusive = 1..=3; pub fn verify( multi_index_path: PathBuf, - progress: impl NestedProgress, + mut progress: impl NestedProgress + 'static, should_interrupt: &AtomicBool, ) -> anyhow::Result<()> { - gix::odb::pack::multi_index::File::at(multi_index_path)?.verify_integrity_fast(progress, should_interrupt)?; + gix::odb::pack::multi_index::File::at(multi_index_path)?.verify_integrity_fast(&mut progress, should_interrupt)?; Ok(()) } pub fn create( index_paths: Vec, output_path: PathBuf, - progress: impl NestedProgress, + mut progress: impl NestedProgress + 'static, should_interrupt: &AtomicBool, object_hash: gix::hash::Kind, ) -> anyhow::Result<()> { @@ -31,7 +31,7 @@ pub fn create( gix::odb::pack::multi_index::File::write_from_index_paths( index_paths, &mut out, - progress, + &mut progress, should_interrupt, gix::odb::pack::multi_index::write::Options { object_hash }, )?; diff --git a/gitoxide-core/src/pack/receive.rs b/gitoxide-core/src/pack/receive.rs index 9e4c009bb54..fe6de13e697 100644 --- a/gitoxide-core/src/pack/receive.rs +++ b/gitoxide-core/src/pack/receive.rs @@ -130,7 +130,7 @@ mod blocking_io { fn receive_pack( &mut self, input: impl BufRead, - progress: impl NestedProgress, + progress: impl NestedProgress + 'static, refs: &[Ref], _previous_response: &Response, ) -> io::Result<()> { @@ -156,7 +156,7 @@ mod blocking_io { ) -> anyhow::Result<()> where W: std::io::Write, - P: NestedProgress, + P: NestedProgress + 'static, P::SubProgress: 'static, { let transport = net::connect( @@ -212,7 +212,7 @@ mod async_io { async fn receive_pack( &mut self, input: impl AsyncBufRead + Unpin + 'async_trait, - progress: impl gix::NestedProgress, + progress: impl gix::NestedProgress + 'static, refs: &[Ref], _previous_response: &Response, ) -> io::Result<()> { @@ -367,8 +367,8 @@ fn receive_pack_blocking( mut directory: Option, mut refs_directory: Option, ctx: &mut Context, - input: impl io::BufRead, - progress: impl NestedProgress, + mut input: impl io::BufRead, + mut progress: impl NestedProgress + 'static, refs: &[Ref], ) -> io::Result<()> { let options = pack::bundle::write::Options { @@ -377,9 +377,15 @@ fn receive_pack_blocking( iteration_mode: pack::data::input::Mode::Verify, object_hash: ctx.object_hash, }; - let outcome = - pack::Bundle::write_to_directory(input, directory.take(), progress, &ctx.should_interrupt, None, options) - .map_err(|err| io::Error::new(io::ErrorKind::Other, err))?; + let outcome = pack::Bundle::write_to_directory( + &mut input, + directory.take().as_deref(), + &mut progress, + &ctx.should_interrupt, + None, + options, + ) + .map_err(|err| io::Error::new(io::ErrorKind::Other, err))?; if let Some(directory) = refs_directory.take() { write_raw_refs(refs, directory)?; diff --git a/gitoxide-core/src/pack/verify.rs b/gitoxide-core/src/pack/verify.rs index 3b40a13858a..6c9eed25328 100644 --- a/gitoxide-core/src/pack/verify.rs +++ b/gitoxide-core/src/pack/verify.rs @@ -87,7 +87,7 @@ impl pack::cache::DecodeEntry for EitherCache { pub fn pack_or_pack_index( path: impl AsRef, - mut progress: impl NestedProgress, + mut progress: impl NestedProgress + 'static, Context { mut out, mut err, @@ -121,7 +121,7 @@ where let res = match ext { "pack" => { let pack = odb::pack::data::File::at(path, object_hash).with_context(|| "Could not open pack file")?; - pack.verify_checksum(progress.add_child("Sha1 of pack"), should_interrupt) + pack.verify_checksum(&mut progress.add_child("Sha1 of pack"), should_interrupt) .map(|id| (id, None))? } "idx" => { @@ -151,7 +151,7 @@ where thread_limit } }), - progress, + &mut progress, should_interrupt, ) .map(|o| (o.actual_index_checksum, o.pack_traverse_statistics)) @@ -161,7 +161,7 @@ where match path.file_name() { Some(file_name) if file_name == "multi-pack-index" => { let multi_index = gix::odb::pack::multi_index::File::at(path)?; - let res = multi_index.verify_integrity(progress, should_interrupt, gix::odb::pack::index::verify::integrity::Options{ + let res = multi_index.verify_integrity(&mut progress, should_interrupt, gix::odb::pack::index::verify::integrity::Options{ verify_mode: mode, traversal: algorithm.into(), thread_limit, diff --git a/gitoxide-core/src/repository/archive.rs b/gitoxide-core/src/repository/archive.rs index 7ef715638fa..9fdf6fbeace 100644 --- a/gitoxide-core/src/repository/archive.rs +++ b/gitoxide-core/src/repository/archive.rs @@ -34,7 +34,7 @@ pub fn stream( .ok_or_else(|| anyhow!("Adding files requires a worktree directory that contains them"))?, )?; for path in add_paths { - stream.add_entry_from_path(&root, &gix::path::realpath(path)?)?; + stream.add_entry_from_path(&root, &gix::path::realpath(&path)?)?; } } for (path, content) in files { diff --git a/gitoxide-core/src/repository/attributes/query.rs b/gitoxide-core/src/repository/attributes/query.rs index 223edb64462..b2d57563f5f 100644 --- a/gitoxide-core/src/repository/attributes/query.rs +++ b/gitoxide-core/src/repository/attributes/query.rs @@ -8,6 +8,7 @@ pub struct Options { } pub(crate) mod function { + use std::borrow::Cow; use std::{io, path::Path}; use anyhow::{anyhow, bail}; @@ -38,7 +39,10 @@ pub(crate) mod function { match input { PathsOrPatterns::Paths(paths) => { for path in paths { - let is_dir = gix::path::from_bstr(path.as_ref()).metadata().ok().map(|m| m.is_dir()); + let is_dir = gix::path::from_bstr(Cow::Borrowed(path.as_ref())) + .metadata() + .ok() + .map(|m| m.is_dir()); let entry = cache.at_entry(path.as_slice(), is_dir)?; if !entry.matching_attributes(&mut matches) { diff --git a/gitoxide-core/src/repository/clone.rs b/gitoxide-core/src/repository/clone.rs index 96640c69537..fdb2878776b 100644 --- a/gitoxide-core/src/repository/clone.rs +++ b/gitoxide-core/src/repository/clone.rs @@ -11,6 +11,7 @@ pub struct Options { pub const PROGRESS_RANGE: std::ops::RangeInclusive = 1..=3; pub(crate) mod function { + use std::borrow::Cow; use std::ffi::OsStr; use anyhow::{bail, Context}; @@ -45,7 +46,7 @@ pub(crate) mod function { let url: gix::Url = url.as_ref().try_into()?; let directory = directory.map_or_else( || { - gix::path::from_bstr(url.path.as_ref()) + gix::path::from_bstr(Cow::Borrowed(url.path.as_ref())) .as_ref() .file_stem() .map(Into::into) diff --git a/gitoxide-core/src/repository/exclude.rs b/gitoxide-core/src/repository/exclude.rs index d42e9fcade4..f3ed2e3595a 100644 --- a/gitoxide-core/src/repository/exclude.rs +++ b/gitoxide-core/src/repository/exclude.rs @@ -1,3 +1,4 @@ +use std::borrow::Cow; use std::io; use anyhow::{anyhow, bail}; @@ -37,14 +38,17 @@ pub fn query( let index = repo.index()?; let mut cache = repo.excludes( &index, - Some(gix::ignore::Search::from_overrides(overrides)), + Some(gix::ignore::Search::from_overrides(&mut overrides.into_iter())), Default::default(), )?; match input { PathsOrPatterns::Paths(paths) => { for path in paths { - let is_dir = gix::path::from_bstr(path.as_ref()).metadata().ok().map(|m| m.is_dir()); + let is_dir = gix::path::from_bstr(Cow::Borrowed(path.as_ref())) + .metadata() + .ok() + .map(|m| m.is_dir()); let entry = cache.at_entry(path.as_slice(), is_dir, |oid, buf| repo.objects.find_blob(oid, buf))?; let match_ = entry .matching_exclude_pattern() diff --git a/gitoxide-core/src/repository/index/entries.rs b/gitoxide-core/src/repository/index/entries.rs index f5f988660f1..893f89dda3c 100644 --- a/gitoxide-core/src/repository/index/entries.rs +++ b/gitoxide-core/src/repository/index/entries.rs @@ -158,26 +158,30 @@ pub(crate) mod function { // Note that we intentionally ignore `_case` so that we act like git does, attribute matching case is determined // by the repository, not the pathspec. let entry_is_excluded = pathspec - .pattern_matching_relative_path(entry.path(&index), Some(false), |rela_path, _case, is_dir, out| { - cache - .as_mut() - .map(|(attrs, cache)| { - match last_match { - // The user wants the attributes for display, so the match happened already. - Some(matched) => { - attrs.copy_into(cache.attributes_collection(), out); - matched + .pattern_matching_relative_path( + entry.path(&index), + Some(false), + &mut |rela_path, _case, is_dir, out| { + cache + .as_mut() + .map(|(attrs, cache)| { + match last_match { + // The user wants the attributes for display, so the match happened already. + Some(matched) => { + attrs.copy_into(cache.attributes_collection(), out); + matched + } + // The user doesn't want attributes, so we set the cache position on demand only + None => cache + .at_entry(rela_path, Some(is_dir)) + .ok() + .map(|platform| platform.matching_attributes(out)) + .unwrap_or_default(), } - // The user doesn't want attributes, so we set the cache position on demand only - None => cache - .at_entry(rela_path, Some(is_dir)) - .ok() - .map(|platform| platform.matching_attributes(out)) - .unwrap_or_default(), - } - }) - .unwrap_or_default() - }) + }) + .unwrap_or_default() + }, + ) .map_or(true, |m| m.is_excluded()); let entry_is_submodule = entry.mode.is_submodule(); diff --git a/gitoxide-core/src/repository/verify.rs b/gitoxide-core/src/repository/verify.rs index df5a74c5192..3f033fae5e4 100644 --- a/gitoxide-core/src/repository/verify.rs +++ b/gitoxide-core/src/repository/verify.rs @@ -19,7 +19,7 @@ pub const PROGRESS_RANGE: std::ops::RangeInclusive = 1..=3; pub fn integrity( repo: gix::Repository, mut out: impl std::io::Write, - progress: impl gix::NestedProgress, + mut progress: impl gix::NestedProgress + 'static, should_interrupt: &AtomicBool, Context { output_statistics, @@ -30,7 +30,7 @@ pub fn integrity( ) -> anyhow::Result<()> { #[cfg_attr(not(feature = "serde"), allow(unused))] let outcome = repo.objects.store_ref().verify_integrity( - progress, + &mut progress, should_interrupt, gix::odb::pack::index::verify::integrity::Options { verify_mode, @@ -48,9 +48,7 @@ pub fn integrity( let objects = repo.objects; move |oid, buf: &mut Vec| objects.find_tree_iter(oid, buf).ok() })?; - outcome - .progress - .info(format!("Index at '{}' OK", index.path().display())); + progress.info(format!("Index at '{}' OK", index.path().display())); } match output_statistics { Some(OutputFormat::Human) => writeln!(out, "Human output is currently unsupported, use JSON instead")?, diff --git a/gix-actor/src/identity.rs b/gix-actor/src/identity.rs index 9507afdc297..e6d8fcb520f 100644 --- a/gix-actor/src/identity.rs +++ b/gix-actor/src/identity.rs @@ -35,14 +35,14 @@ mod write { /// Output impl Identity { /// Serialize this instance to `out` in the git serialization format for signatures (but without timestamp). - pub fn write_to(&self, out: impl std::io::Write) -> std::io::Result<()> { + pub fn write_to(&self, out: &mut dyn std::io::Write) -> std::io::Result<()> { self.to_ref().write_to(out) } } impl<'a> IdentityRef<'a> { /// Serialize this instance to `out` in the git serialization format for signatures (but without timestamp). - pub fn write_to(&self, mut out: impl std::io::Write) -> std::io::Result<()> { + pub fn write_to(&self, out: &mut dyn std::io::Write) -> std::io::Result<()> { out.write_all(validated_token(self.name)?)?; out.write_all(b" ")?; out.write_all(b"<")?; diff --git a/gix-actor/src/signature/mod.rs b/gix-actor/src/signature/mod.rs index cb91bd8eb9f..057d4293e7d 100644 --- a/gix-actor/src/signature/mod.rs +++ b/gix-actor/src/signature/mod.rs @@ -95,7 +95,7 @@ pub(crate) mod write { /// Output impl Signature { /// Serialize this instance to `out` in the git serialization format for actors. - pub fn write_to(&self, out: impl std::io::Write) -> std::io::Result<()> { + pub fn write_to(&self, out: &mut dyn std::io::Write) -> std::io::Result<()> { self.to_ref().write_to(out) } /// Computes the number of bytes necessary to serialize this signature @@ -106,7 +106,7 @@ pub(crate) mod write { impl<'a> SignatureRef<'a> { /// Serialize this instance to `out` in the git serialization format for actors. - pub fn write_to(&self, mut out: impl std::io::Write) -> std::io::Result<()> { + pub fn write_to(&self, out: &mut dyn std::io::Write) -> std::io::Result<()> { out.write_all(validated_token(self.name)?)?; out.write_all(b" ")?; out.write_all(b"<")?; diff --git a/gix-actor/tests/signature/mod.rs b/gix-actor/tests/signature/mod.rs index e0c7e663d2e..496fb54ae54 100644 --- a/gix-actor/tests/signature/mod.rs +++ b/gix-actor/tests/signature/mod.rs @@ -11,7 +11,7 @@ mod write_to { time: default_time(), }; assert_eq!( - format!("{:?}", signature.write_to(Vec::new())), + format!("{:?}", signature.write_to(&mut Vec::new())), "Err(Custom { kind: Other, error: IllegalCharacter })" ); } @@ -24,7 +24,7 @@ mod write_to { time: default_time(), }; assert_eq!( - format!("{:?}", signature.write_to(Vec::new())), + format!("{:?}", signature.write_to(&mut Vec::new())), "Err(Custom { kind: Other, error: IllegalCharacter })" ); } @@ -37,7 +37,7 @@ mod write_to { time: default_time(), }; assert_eq!( - format!("{:?}", signature.write_to(Vec::new())), + format!("{:?}", signature.write_to(&mut Vec::new())), "Err(Custom { kind: Other, error: IllegalCharacter })" ); } diff --git a/gix-attributes/src/search/attributes.rs b/gix-attributes/src/search/attributes.rs index 8eb66621366..2b48d1ed3be 100644 --- a/gix-attributes/src/search/attributes.rs +++ b/gix-attributes/src/search/attributes.rs @@ -27,14 +27,14 @@ impl Search { let mut group = Self::default(); group.add_patterns_buffer( b"[attr]binary -diff -merge -text", - "[builtin]", + "[builtin]".into(), None, collection, true, /* allow macros */ ); for path in files.into_iter() { - group.add_patterns_file(path, true, None, buf, collection, true /* allow macros */)?; + group.add_patterns_file(path.into(), true, None, buf, collection, true /* allow macros */)?; } Ok(group) } @@ -49,7 +49,7 @@ impl Search { /// Returns `true` if the file was added, or `false` if it didn't exist. pub fn add_patterns_file( &mut self, - source: impl Into, + source: PathBuf, follow_symlinks: bool, root: Option<&Path>, buf: &mut Vec, @@ -75,7 +75,7 @@ impl Search { pub fn add_patterns_buffer( &mut self, bytes: &[u8], - source: impl Into, + source: PathBuf, root: Option<&Path>, collection: &mut MetadataCollection, allow_macros: bool, @@ -99,14 +99,13 @@ impl Search { impl Search { /// Match `relative_path`, a path relative to the repository, while respective `case`-sensitivity and write them to `out` /// Return `true` if at least one pattern matched. - pub fn pattern_matching_relative_path<'a, 'b>( - &'a self, - relative_path: impl Into<&'b BStr>, + pub fn pattern_matching_relative_path( + &self, + relative_path: &BStr, case: gix_glob::pattern::Case, is_dir: Option, out: &mut Outcome, ) -> bool { - let relative_path = relative_path.into(); let basename_pos = relative_path.rfind(b"/").map(|p| p + 1); let mut has_match = false; self.patterns.iter().rev().any(|pl| { diff --git a/gix-attributes/src/search/outcome.rs b/gix-attributes/src/search/outcome.rs index 409be393833..6f724a407ff 100644 --- a/gix-attributes/src/search/outcome.rs +++ b/gix-attributes/src/search/outcome.rs @@ -45,12 +45,19 @@ impl Outcome { &mut self, collection: &MetadataCollection, attribute_names: impl IntoIterator>>, + ) { + self.initialize_with_selection_inner(collection, &mut attribute_names.into_iter().map(Into::into)) + } + + fn initialize_with_selection_inner( + &mut self, + collection: &MetadataCollection, + attribute_names: &mut dyn Iterator>, ) { self.initialize(collection); self.selected.clear(); - self.selected.extend(attribute_names.into_iter().map(|name| { - let name = name.into(); + self.selected.extend(attribute_names.map(|name| { ( name.to_owned(), collection.name_to_meta.get(name.as_str()).map(|meta| meta.id), diff --git a/gix-attributes/tests/search/mod.rs b/gix-attributes/tests/search/mod.rs index b8fbaf83072..36e6286c8ed 100644 --- a/gix-attributes/tests/search/mod.rs +++ b/gix-attributes/tests/search/mod.rs @@ -50,7 +50,7 @@ mod specials { ); let mut out = Outcome::default(); out.initialize(&collection); - search.pattern_matching_relative_path(path, case, None, &mut out) + search.pattern_matching_relative_path(path.into(), case, None, &mut out) } fn searchi(pattern: &str, path: &str, rela_containing_dir: Option<&str>) -> bool { @@ -66,7 +66,7 @@ fn baseline() -> crate::Result { let mut buf = Vec::new(); // Due to the way our setup differs from gits dynamic stack (which involves trying to read files from disk // by path) we can only test one case baseline, so we require multiple platforms (or filesystems) to run this. - let case = if gix_fs::Capabilities::probe("../.git").ignore_case { + let case = if gix_fs::Capabilities::probe("../.git".as_ref()).ignore_case { Case::Fold } else { Case::Sensitive @@ -307,7 +307,11 @@ mod baseline { let mut buf = Vec::new(); let mut collection = MetadataCollection::default(); - let group = gix_attributes::Search::new_globals([base.join("user.attributes")], &mut buf, &mut collection)?; + let group = gix_attributes::Search::new_globals( + &mut [base.join("user.attributes")].into_iter(), + &mut buf, + &mut collection, + )?; Ok((group, collection, base, input)) } diff --git a/gix-commitgraph/src/file/access.rs b/gix-commitgraph/src/file/access.rs index d3c32d8bb0e..79a40d75dbf 100644 --- a/gix-commitgraph/src/file/access.rs +++ b/gix-commitgraph/src/file/access.rs @@ -74,7 +74,10 @@ impl File { /// Translate the given object hash to its position within this file, if present. // copied from gix-odb/src/pack/index/ext pub fn lookup(&self, id: impl AsRef) -> Option { - let id = id.as_ref(); + self.lookup_inner(id.as_ref()) + } + + fn lookup_inner(&self, id: &gix_hash::oid) -> Option { let first_byte = usize::from(id.first_byte()); let mut upper_bound = self.fan[first_byte]; let mut lower_bound = if first_byte != 0 { self.fan[first_byte - 1] } else { 0 }; diff --git a/gix-commitgraph/src/file/verify.rs b/gix-commitgraph/src/file/verify.rs index 91da92c635e..c91f6b4d281 100644 --- a/gix-commitgraph/src/file/verify.rs +++ b/gix-commitgraph/src/file/verify.rs @@ -160,8 +160,7 @@ impl File { /// If the given path's filename matches "graph-{hash}.graph", check that `hash` matches the /// expected hash. -fn verify_split_chain_filename_hash(path: impl AsRef, expected: &gix_hash::oid) -> Result<(), String> { - let path = path.as_ref(); +fn verify_split_chain_filename_hash(path: &Path, expected: &gix_hash::oid) -> Result<(), String> { path.file_name() .and_then(std::ffi::OsStr::to_str) .and_then(|filename| filename.strip_suffix(".graph")) diff --git a/gix-commitgraph/src/init.rs b/gix-commitgraph/src/init.rs index f964aade029..0b03ba9462d 100644 --- a/gix-commitgraph/src/init.rs +++ b/gix-commitgraph/src/init.rs @@ -41,13 +41,13 @@ pub enum Error { /// Instantiate a `Graph` from various sources. impl Graph { /// Instantiate a commit graph from `path` which may be a directory containing graph files or the graph file itself. - pub fn at(path: impl AsRef) -> Result { - Self::try_from(path.as_ref()) + pub fn at(path: &Path) -> Result { + Self::try_from(path) } /// Instantiate a commit graph from the directory containing all of its files. - pub fn from_commit_graphs_dir(path: impl AsRef) -> Result { - let commit_graphs_dir = path.as_ref(); + pub fn from_commit_graphs_dir(path: &Path) -> Result { + let commit_graphs_dir = path; let chain_file_path = commit_graphs_dir.join("commit-graph-chain"); let chain_file = std::fs::File::open(&chain_file_path).map_err(|e| Error::Io { err: e, @@ -70,8 +70,7 @@ impl Graph { /// Instantiate a commit graph from a `.git/objects/info/commit-graph` or /// `.git/objects/info/commit-graphs/graph-*.graph` file. - pub fn from_file(path: impl AsRef) -> Result { - let path = path.as_ref(); + pub fn from_file(path: &Path) -> Result { let file = File::at(path).map_err(|e| Error::File { err: e, path: path.to_owned(), @@ -80,9 +79,9 @@ impl Graph { } /// Instantiate a commit graph from an `.git/objects/info` directory. - pub fn from_info_dir(info_dir: impl AsRef) -> Result { - Self::from_file(info_dir.as_ref().join("commit-graph")) - .or_else(|_| Self::from_commit_graphs_dir(info_dir.as_ref().join("commit-graphs"))) + pub fn from_info_dir(info_dir: &Path) -> Result { + Self::from_file(&info_dir.join("commit-graph")) + .or_else(|_| Self::from_commit_graphs_dir(&info_dir.join("commit-graphs"))) } /// Create a new commit graph from a list of `files`. diff --git a/gix-commitgraph/src/lib.rs b/gix-commitgraph/src/lib.rs index 231c11c6fb0..a247ccd87de 100644 --- a/gix-commitgraph/src/lib.rs +++ b/gix-commitgraph/src/lib.rs @@ -45,7 +45,7 @@ pub struct Graph { /// Instantiate a commit graph from an `.git/objects/info` directory, or one of the various commit-graph files. pub fn at(path: impl AsRef) -> Result { - Graph::at(path) + Graph::at(path.as_ref()) } mod access; diff --git a/gix-commitgraph/tests/commitgraph.rs b/gix-commitgraph/tests/commitgraph.rs index 20d20dee1ee..94568fe5cfa 100644 --- a/gix-commitgraph/tests/commitgraph.rs +++ b/gix-commitgraph/tests/commitgraph.rs @@ -80,7 +80,8 @@ pub fn graph_and_expected_named( .expect("script succeeds all the time") .join(name); let expected = inspect_refs(&repo_dir, refs); - let cg = Graph::from_info_dir(repo_dir.join(".git").join("objects").join("info")).expect("graph present and valid"); + let cg = + Graph::from_info_dir(&repo_dir.join(".git").join("objects").join("info")).expect("graph present and valid"); (cg, expected) } diff --git a/gix-config/fuzz/fuzz_targets/parse.rs b/gix-config/fuzz/fuzz_targets/parse.rs index a065ad75950..34a12ceeb02 100644 --- a/gix-config/fuzz/fuzz_targets/parse.rs +++ b/gix-config/fuzz/fuzz_targets/parse.rs @@ -4,5 +4,5 @@ use libfuzzer_sys::fuzz_target; fuzz_target!(|data: &[u8]| { // Don't name this _; Rust may optimize it out. - let _a = gix_config::parse::from_bytes(data, |_e| ()); + let _a = gix_config::parse::from_bytes(data, &mut |_e| ()); }); diff --git a/gix-config/src/file/access/comfort.rs b/gix-config/src/file/access/comfort.rs index 5ad0e6186b7..ed62e779269 100644 --- a/gix-config/src/file/access/comfort.rs +++ b/gix-config/src/file/access/comfort.rs @@ -31,7 +31,8 @@ impl<'event> File<'event> { key: impl AsRef, filter: &mut MetadataFilter, ) -> Option> { - self.raw_value_filter(section_name, subsection_name, key, filter).ok() + self.raw_value_filter(section_name.as_ref(), subsection_name, key.as_ref(), filter) + .ok() } /// Like [`string_filter()`][File::string_filter()], but suitable for statically known `key`s like `remote.origin.url`. @@ -40,7 +41,7 @@ impl<'event> File<'event> { key: impl Into<&'a BStr>, filter: &mut MetadataFilter, ) -> Option> { - let key = crate::parse::key(key)?; + let key = crate::parse::key(key.into())?; self.raw_value_filter(key.section_name, key.subsection_name, key.value_name, filter) .ok() } @@ -78,7 +79,7 @@ impl<'event> File<'event> { key: impl AsRef, filter: &mut MetadataFilter, ) -> Option> { - self.raw_value_filter(section_name, subsection_name, key, filter) + self.raw_value_filter(section_name.as_ref(), subsection_name, key.as_ref(), filter) .ok() .map(crate::Path::from) } @@ -89,7 +90,7 @@ impl<'event> File<'event> { key: impl Into<&'a BStr>, filter: &mut MetadataFilter, ) -> Option> { - let key = crate::parse::key(key)?; + let key = crate::parse::key(key.into())?; self.path_filter(key.section_name, key.subsection_name, key.value_name, filter) } @@ -141,7 +142,7 @@ impl<'event> File<'event> { key: impl Into<&'a BStr>, filter: &mut MetadataFilter, ) -> Option> { - let key = crate::parse::key(key)?; + let key = crate::parse::key(key.into())?; self.boolean_filter(key.section_name, key.subsection_name, key.value_name, filter) } @@ -168,7 +169,9 @@ impl<'event> File<'event> { key: impl AsRef, filter: &mut MetadataFilter, ) -> Option> { - let int = self.raw_value_filter(section_name, subsection_name, key, filter).ok()?; + let int = self + .raw_value_filter(section_name.as_ref(), subsection_name, key.as_ref(), filter) + .ok()?; Some(crate::Integer::try_from(int.as_ref()).and_then(|b| { b.to_decimal() .ok_or_else(|| value::Error::new("Integer overflow", int.into_owned())) @@ -181,7 +184,7 @@ impl<'event> File<'event> { key: impl Into<&'a BStr>, filter: &mut MetadataFilter, ) -> Option> { - let key = crate::parse::key(key)?; + let key = crate::parse::key(key.into())?; self.integer_filter(key.section_name, key.subsection_name, key.value_name, filter) } @@ -192,12 +195,13 @@ impl<'event> File<'event> { subsection_name: Option<&BStr>, key: impl AsRef, ) -> Option>> { - self.raw_values(section_name, subsection_name, key).ok() + self.raw_values(section_name.as_ref(), subsection_name, key.as_ref()) + .ok() } /// Like [`strings()`][File::strings()], but suitable for statically known `key`s like `remote.origin.url`. pub fn strings_by_key<'a>(&self, key: impl Into<&'a BStr>) -> Option>> { - let key = crate::parse::key(key)?; + let key = crate::parse::key(key.into())?; self.strings(key.section_name, key.subsection_name, key.value_name) } @@ -209,7 +213,8 @@ impl<'event> File<'event> { key: impl AsRef, filter: &mut MetadataFilter, ) -> Option>> { - self.raw_values_filter(section_name, subsection_name, key, filter).ok() + self.raw_values_filter(section_name.as_ref(), subsection_name, key.as_ref(), filter) + .ok() } /// Like [`strings_filter()`][File::strings_filter()], but suitable for statically known `key`s like `remote.origin.url`. @@ -218,7 +223,7 @@ impl<'event> File<'event> { key: impl Into<&'a BStr>, filter: &mut MetadataFilter, ) -> Option>> { - let key = crate::parse::key(key)?; + let key = crate::parse::key(key.into())?; self.strings_filter(key.section_name, key.subsection_name, key.value_name, filter) } @@ -247,7 +252,7 @@ impl<'event> File<'event> { key: impl AsRef, filter: &mut MetadataFilter, ) -> Option, value::Error>> { - self.raw_values_filter(section_name, subsection_name, key, filter) + self.raw_values_filter(section_name.as_ref(), subsection_name, key.as_ref(), filter) .ok() .map(|values| { values @@ -268,7 +273,7 @@ impl<'event> File<'event> { key: impl Into<&'a BStr>, filter: &mut MetadataFilter, ) -> Option, value::Error>> { - let key = crate::parse::key(key)?; + let key = crate::parse::key(key.into())?; self.integers_filter(key.section_name, key.subsection_name, key.value_name, filter) } } diff --git a/gix-config/src/file/access/mutate.rs b/gix-config/src/file/access/mutate.rs index 5237b3794bb..4844a34f4d1 100644 --- a/gix-config/src/file/access/mutate.rs +++ b/gix-config/src/file/access/mutate.rs @@ -17,9 +17,17 @@ impl<'event> File<'event> { &'a mut self, name: impl AsRef, subsection_name: Option<&BStr>, + ) -> Result, lookup::existing::Error> { + self.section_mut_inner(name.as_ref(), subsection_name) + } + + fn section_mut_inner<'a>( + &'a mut self, + name: &str, + subsection_name: Option<&BStr>, ) -> Result, lookup::existing::Error> { let id = self - .section_ids_by_name_and_subname(name.as_ref(), subsection_name)? + .section_ids_by_name_and_subname(name, subsection_name)? .next_back() .expect("BUG: Section lookup vec was empty"); let nl = self.detect_newline_style_smallvec(); @@ -64,7 +72,15 @@ impl<'event> File<'event> { subsection_name: Option<&BStr>, filter: &mut MetadataFilter, ) -> Result, section::header::Error> { - let name = name.as_ref(); + self.section_mut_or_create_new_filter_inner(name.as_ref(), subsection_name, filter) + } + + fn section_mut_or_create_new_filter_inner<'a>( + &'a mut self, + name: &str, + subsection_name: Option<&BStr>, + filter: &mut MetadataFilter, + ) -> Result, section::header::Error> { match self .section_ids_by_name_and_subname(name.as_ref(), subsection_name) .ok() @@ -95,9 +111,18 @@ impl<'event> File<'event> { name: impl AsRef, subsection_name: Option<&BStr>, filter: &mut MetadataFilter, + ) -> Result>, lookup::existing::Error> { + self.section_mut_filter_inner(name.as_ref(), subsection_name, filter) + } + + fn section_mut_filter_inner<'a>( + &'a mut self, + name: &str, + subsection_name: Option<&BStr>, + filter: &mut MetadataFilter, ) -> Result>, lookup::existing::Error> { let id = self - .section_ids_by_name_and_subname(name.as_ref(), subsection_name)? + .section_ids_by_name_and_subname(name, subsection_name)? .rev() .find(|id| { let s = &self.sections[id]; @@ -158,6 +183,14 @@ impl<'event> File<'event> { &mut self, name: impl Into>, subsection: impl Into>>, + ) -> Result, section::header::Error> { + self.new_section_inner(name.into(), subsection.into()) + } + + fn new_section_inner( + &mut self, + name: Cow<'event, str>, + subsection: Option>, ) -> Result, section::header::Error> { let id = self.push_section_internal(file::Section::new(name, subsection, OwnShared::clone(&self.meta))?); let nl = self.detect_newline_style_smallvec(); @@ -205,11 +238,11 @@ impl<'event> File<'event> { /// ``` pub fn remove_section<'a>( &mut self, - name: &str, + name: impl AsRef, subsection_name: impl Into>, ) -> Option> { let id = self - .section_ids_by_name_and_subname(name, subsection_name.into()) + .section_ids_by_name_and_subname(name.as_ref(), subsection_name.into()) .ok()? .next_back()?; self.remove_section_by_id(id) @@ -254,12 +287,21 @@ impl<'event> File<'event> { /// later sections with the same name have precedent over earlier ones. pub fn remove_section_filter<'a>( &mut self, - name: &str, + name: impl AsRef, subsection_name: impl Into>, filter: &mut MetadataFilter, + ) -> Option> { + self.remove_section_filter_inner(name.as_ref(), subsection_name.into(), filter) + } + + fn remove_section_filter_inner( + &mut self, + name: &str, + subsection_name: Option<&BStr>, + filter: &mut MetadataFilter, ) -> Option> { let id = self - .section_ids_by_name_and_subname(name, subsection_name.into()) + .section_ids_by_name_and_subname(name, subsection_name) .ok()? .rev() .find(|id| filter(self.sections.get(id).expect("each id has a section").meta()))?; diff --git a/gix-config/src/file/access/raw.rs b/gix-config/src/file/access/raw.rs index 6fef6c9ed40..3736bf3a286 100644 --- a/gix-config/src/file/access/raw.rs +++ b/gix-config/src/file/access/raw.rs @@ -40,8 +40,17 @@ impl<'event> File<'event> { key: impl AsRef, filter: &mut MetadataFilter, ) -> Result, lookup::existing::Error> { - let section_ids = self.section_ids_by_name_and_subname(section_name.as_ref(), subsection_name)?; - let key = key.as_ref(); + self.raw_value_filter_inner(section_name.as_ref(), subsection_name, key.as_ref(), filter) + } + + fn raw_value_filter_inner( + &self, + section_name: &str, + subsection_name: Option<&BStr>, + key: &str, + filter: &mut MetadataFilter, + ) -> Result, lookup::existing::Error> { + let section_ids = self.section_ids_by_name_and_subname(section_name, subsection_name)?; for section_id in section_ids.rev() { let section = self.sections.get(§ion_id).expect("known section id"); if !filter(section.meta()) { @@ -80,9 +89,19 @@ impl<'event> File<'event> { subsection_name: Option<&'lookup BStr>, key: &'lookup str, filter: &mut MetadataFilter, + ) -> Result, lookup::existing::Error> { + self.raw_value_mut_filter_inner(section_name.as_ref(), subsection_name, key, filter) + } + + fn raw_value_mut_filter_inner<'lookup>( + &mut self, + section_name: &str, + subsection_name: Option<&'lookup BStr>, + key: &'lookup str, + filter: &mut MetadataFilter, ) -> Result, lookup::existing::Error> { let mut section_ids = self - .section_ids_by_name_and_subname(section_name.as_ref(), subsection_name)? + .section_ids_by_name_and_subname(section_name, subsection_name)? .rev(); let key = section::Key(Cow::::Borrowed(key.into())); @@ -190,10 +209,19 @@ impl<'event> File<'event> { subsection_name: Option<&BStr>, key: impl AsRef, filter: &mut MetadataFilter, + ) -> Result>, lookup::existing::Error> { + self.raw_values_filter_inner(section_name.as_ref(), subsection_name, key.as_ref(), filter) + } + + fn raw_values_filter_inner( + &self, + section_name: &str, + subsection_name: Option<&BStr>, + key: &str, + filter: &mut MetadataFilter, ) -> Result>, lookup::existing::Error> { let mut values = Vec::new(); - let section_ids = self.section_ids_by_name_and_subname(section_name.as_ref(), subsection_name)?; - let key = key.as_ref(); + let section_ids = self.section_ids_by_name_and_subname(section_name, subsection_name)?; for section_id in section_ids { let section = self.sections.get(§ion_id).expect("known section id"); if !filter(section.meta()) { @@ -277,7 +305,17 @@ impl<'event> File<'event> { key: &'lookup str, filter: &mut MetadataFilter, ) -> Result, lookup::existing::Error> { - let section_ids = self.section_ids_by_name_and_subname(section_name.as_ref(), subsection_name)?; + self.raw_values_mut_filter_inner(section_name.as_ref(), subsection_name, key, filter) + } + + fn raw_values_mut_filter_inner<'lookup>( + &mut self, + section_name: &str, + subsection_name: Option<&'lookup BStr>, + key: &'lookup str, + filter: &mut MetadataFilter, + ) -> Result, lookup::existing::Error> { + let section_ids = self.section_ids_by_name_and_subname(section_name, subsection_name)?; let key = section::Key(Cow::::Borrowed(key.into())); let mut offsets = HashMap::new(); @@ -432,7 +470,7 @@ impl<'event> File<'event> { section::key::Error: From, { let mut section = self.section_mut_or_create_new_filter(section_name, subsection_name, filter)?; - Ok(section.set(key.try_into().map_err(section::key::Error::from)?, new_value)) + Ok(section.set(key.try_into().map_err(section::key::Error::from)?, new_value.into())) } /// Sets a multivar in a given section, optional subsection, and key value. diff --git a/gix-config/src/file/access/read_only.rs b/gix-config/src/file/access/read_only.rs index d5fd192bb7b..eb1071fe2e1 100644 --- a/gix-config/src/file/access/read_only.rs +++ b/gix-config/src/file/access/read_only.rs @@ -131,7 +131,7 @@ impl<'event> File<'event> { /// Returns the last found immutable section with a given `name` and optional `subsection_name`. pub fn section( &self, - name: impl AsRef, + name: &str, subsection_name: Option<&BStr>, ) -> Result<&file::Section<'event>, lookup::existing::Error> { self.section_filter(name, subsection_name, &mut |_| true)? @@ -140,10 +140,7 @@ impl<'event> File<'event> { /// Returns the last found immutable section with a given `key`, identifying the name and subsection name like `core` /// or `remote.origin`. - pub fn section_by_key<'a>( - &self, - key: impl Into<&'a BStr>, - ) -> Result<&file::Section<'event>, lookup::existing::Error> { + pub fn section_by_key(&self, key: &BStr) -> Result<&file::Section<'event>, lookup::existing::Error> { let key = crate::parse::section::unvalidated::Key::parse(key).ok_or(lookup::existing::Error::KeyMissing)?; self.section(key.section_name, key.subsection_name) } @@ -154,7 +151,7 @@ impl<'event> File<'event> { /// is returned. pub fn section_filter<'a>( &'a self, - name: impl AsRef, + name: &str, subsection_name: Option<&BStr>, filter: &mut MetadataFilter, ) -> Result>, lookup::existing::Error> { @@ -171,9 +168,9 @@ impl<'event> File<'event> { } /// Like [`section_filter()`][File::section_filter()], but identifies the section with `key` like `core` or `remote.origin`. - pub fn section_filter_by_key<'a, 'b>( + pub fn section_filter_by_key<'a>( &'a self, - key: impl Into<&'b BStr>, + key: &BStr, filter: &mut MetadataFilter, ) -> Result>, lookup::existing::Error> { let key = crate::parse::section::unvalidated::Key::parse(key).ok_or(lookup::existing::Error::KeyMissing)?; diff --git a/gix-config/src/file/init/comfort.rs b/gix-config/src/file/init/comfort.rs index f8e624c731b..4a5a1c68b25 100644 --- a/gix-config/src/file/init/comfort.rs +++ b/gix-config/src/file/init/comfort.rs @@ -82,16 +82,16 @@ impl File<'static> { /// /// Includes will be resolved within limits as some information like the git installation directory is missing to interpolate /// paths with as well as git repository information like the branch name. - pub fn from_git_dir(dir: impl Into) -> Result, from_git_dir::Error> { + pub fn from_git_dir(dir: std::path::PathBuf) -> Result, from_git_dir::Error> { let (mut local, git_dir) = { let source = Source::Local; - let mut path = dir.into(); + let mut path = dir; path.push( source .storage_location(&mut gix_path::env::var) .expect("location available for local"), ); - let local = Self::from_path_no_includes(&path, source)?; + let local = Self::from_path_no_includes(path.clone(), source)?; path.pop(); (local, path) }; diff --git a/gix-config/src/file/init/from_paths.rs b/gix-config/src/file/init/from_paths.rs index ea209cefc4c..5d092f88a7c 100644 --- a/gix-config/src/file/init/from_paths.rs +++ b/gix-config/src/file/init/from_paths.rs @@ -23,8 +23,7 @@ impl File<'static> { /// Load the single file at `path` with `source` without following include directives. /// /// Note that the path will be checked for ownership to derive trust. - pub fn from_path_no_includes(path: impl Into, source: crate::Source) -> Result { - let path = path.into(); + pub fn from_path_no_includes(path: std::path::PathBuf, source: crate::Source) -> Result { let trust = match gix_sec::Trust::from_path_ownership(&path) { Ok(t) => t, Err(err) => return Err(Error::Io { source: err, path }), @@ -60,7 +59,12 @@ impl File<'static> { ) -> Result, Error> { let mut buf = Vec::with_capacity(512); let err_on_nonexisting_paths = true; - Self::from_paths_metadata_buf(path_meta, &mut buf, err_on_nonexisting_paths, options) + Self::from_paths_metadata_buf( + &mut path_meta.into_iter().map(Into::into), + &mut buf, + err_on_nonexisting_paths, + options, + ) } /// Like [`from_paths_metadata()`][Self::from_paths_metadata()], but will use `buf` to temporarily store the config file @@ -68,17 +72,14 @@ impl File<'static> { /// /// If `err_on_nonexisting_paths` is false, instead of aborting with error, we will continue to the next path instead. pub fn from_paths_metadata_buf( - path_meta: impl IntoIterator>, + path_meta: &mut dyn Iterator, buf: &mut Vec, err_on_non_existing_paths: bool, options: Options<'_>, ) -> Result, Error> { let mut target = None; let mut seen = BTreeSet::default(); - for (path, mut meta) in path_meta.into_iter().filter_map(|meta| { - let mut meta = meta.into(); - meta.path.take().map(|p| (p, meta)) - }) { + for (path, mut meta) in path_meta.filter_map(|mut meta| meta.path.take().map(|p| (p, meta))) { if !seen.insert(path.clone()) { continue; } diff --git a/gix-config/src/file/mutable/section.rs b/gix-config/src/file/mutable/section.rs index f13b87e483a..336ccad2d7e 100644 --- a/gix-config/src/file/mutable/section.rs +++ b/gix-config/src/file/mutable/section.rs @@ -123,10 +123,10 @@ impl<'a, 'event> SectionMut<'a, 'event> { /// Sets the last key value pair if it exists, or adds the new value. /// Returns the previous value if it replaced a value, or None if it adds /// the value. - pub fn set<'b>(&mut self, key: Key<'event>, value: impl Into<&'b BStr>) -> Option> { + pub fn set(&mut self, key: Key<'event>, value: &BStr) -> Option> { match self.key_and_value_range_by(&key) { None => { - self.push(key, Some(value.into())); + self.push(key, Some(value)); None } Some((key_range, value_range)) => { @@ -136,15 +136,15 @@ impl<'a, 'event> SectionMut<'a, 'event> { self.section .body .0 - .insert(range_start, Event::Value(escape_value(value.into()).into())); + .insert(range_start, Event::Value(escape_value(value).into())); Some(ret) } } } /// Removes the latest value by key and returns it, if it exists. - pub fn remove(&mut self, key: impl AsRef) -> Option> { - let key = Key::from_str_unchecked(key.as_ref()); + pub fn remove(&mut self, key: &str) -> Option> { + let key = Key::from_str_unchecked(key); let (key_range, _value_range) = self.key_and_value_range_by(&key)?; Some(self.remove_internal(key_range, true)) } diff --git a/gix-config/src/file/section/body.rs b/gix-config/src/file/section/body.rs index 694de18bd91..1bc12725c6b 100644 --- a/gix-config/src/file/section/body.rs +++ b/gix-config/src/file/section/body.rs @@ -18,14 +18,14 @@ impl<'event> Body<'event> { /// Note that we consider values without key separator `=` non-existing. #[must_use] pub fn value(&self, key: impl AsRef) -> Option> { - self.value_implicit(key).flatten() + self.value_implicit(key.as_ref()).flatten() } /// Retrieves the last matching value in a section with the given key, if present, and indicates an implicit value with `Some(None)`, /// and a non-existing one as `None` #[must_use] - pub fn value_implicit(&self, key: impl AsRef) -> Option>> { - let key = Key::from_str_unchecked(key.as_ref()); + pub fn value_implicit(&self, key: &str) -> Option>> { + let key = Key::from_str_unchecked(key); let (_key_range, range) = self.key_and_value_range_by(&key)?; let range = match range { None => return Some(None), @@ -54,8 +54,8 @@ impl<'event> Body<'event> { /// Retrieves all values that have the provided key name. This may return /// an empty vec, which implies there were no values with the provided key. #[must_use] - pub fn values(&self, key: impl AsRef) -> Vec> { - let key = &Key::from_str_unchecked(key.as_ref()); + pub fn values(&self, key: &str) -> Vec> { + let key = &Key::from_str_unchecked(key); let mut values = Vec::new(); let mut expect_value = false; let mut concatenated_value = BString::default(); @@ -92,8 +92,8 @@ impl<'event> Body<'event> { /// Returns true if the section contains the provided key. #[must_use] - pub fn contains_key(&self, key: impl AsRef) -> bool { - let key = &Key::from_str_unchecked(key.as_ref()); + pub fn contains_key(&self, key: &str) -> bool { + let key = &Key::from_str_unchecked(key); self.0.iter().any(|e| { matches!(e, Event::SectionKey(k) if k == key diff --git a/gix-config/src/file/section/mod.rs b/gix-config/src/file/section/mod.rs index f73405960d0..f07a145e3d4 100644 --- a/gix-config/src/file/section/mod.rs +++ b/gix-config/src/file/section/mod.rs @@ -74,7 +74,7 @@ impl<'a> Section<'a> { /// Stream ourselves to the given `out`, in order to reproduce this section mostly losslessly /// as it was parsed. - pub fn write_to(&self, mut out: impl std::io::Write) -> std::io::Result<()> { + pub fn write_to(&self, mut out: &mut dyn std::io::Write) -> std::io::Result<()> { self.header.write_to(&mut out)?; if self.body.0.is_empty() { diff --git a/gix-config/src/file/write.rs b/gix-config/src/file/write.rs index b4cd9c48fc6..772054f9529 100644 --- a/gix-config/src/file/write.rs +++ b/gix-config/src/file/write.rs @@ -17,8 +17,8 @@ impl File<'_> { /// as it was parsed, while writing only sections for which `filter` returns true. pub fn write_to_filter( &self, - mut out: impl std::io::Write, - mut filter: impl FnMut(&Section<'_>) -> bool, + mut out: &mut dyn std::io::Write, + mut filter: &mut dyn FnMut(&Section<'_>) -> bool, ) -> std::io::Result<()> { let nl = self.detect_newline_style(); @@ -65,8 +65,8 @@ impl File<'_> { /// Stream ourselves to the given `out`, in order to reproduce this file mostly losslessly /// as it was parsed. - pub fn write_to(&self, out: impl std::io::Write) -> std::io::Result<()> { - self.write_to_filter(out, |_| true) + pub fn write_to(&self, out: &mut dyn std::io::Write) -> std::io::Result<()> { + self.write_to_filter(out, &mut |_| true) } } diff --git a/gix-config/src/parse/event.rs b/gix-config/src/parse/event.rs index b7b96934d04..f528e2077d6 100644 --- a/gix-config/src/parse/event.rs +++ b/gix-config/src/parse/event.rs @@ -33,7 +33,7 @@ impl Event<'_> { /// Stream ourselves to the given `out`, in order to reproduce this event mostly losslessly /// as it was parsed. - pub fn write_to(&self, mut out: impl std::io::Write) -> std::io::Result<()> { + pub fn write_to(&self, mut out: &mut dyn std::io::Write) -> std::io::Result<()> { match self { Self::ValueNotDone(e) => { out.write_all(e.as_ref())?; diff --git a/gix-config/src/parse/events.rs b/gix-config/src/parse/events.rs index 1a1287d642b..f3f5275005a 100644 --- a/gix-config/src/parse/events.rs +++ b/gix-config/src/parse/events.rs @@ -229,7 +229,7 @@ impl Events<'static> { input: &'a [u8], filter: Option) -> bool>, ) -> Result, parse::Error> { - from_bytes(input, |e| e.to_owned(), filter) + from_bytes(input, &|e| e.to_owned(), filter) } } @@ -241,7 +241,7 @@ impl<'a> Events<'a> { /// /// Use `filter` to only include those events for which it returns true. pub fn from_bytes(input: &'a [u8], filter: Option) -> bool>) -> Result, parse::Error> { - from_bytes(input, std::convert::identity, filter) + from_bytes(input, &std::convert::identity, filter) } /// Attempt to zero-copy parse the provided `input` string. @@ -288,14 +288,14 @@ impl<'a> TryFrom<&'a [u8]> for Events<'a> { fn from_bytes<'a, 'b>( input: &'a [u8], - convert: impl Fn(Event<'a>) -> Event<'b>, + convert: &dyn Fn(Event<'a>) -> Event<'b>, filter: Option) -> bool>, ) -> Result, parse::Error> { let mut header = None; let mut events = section::Events::default(); let mut frontmatter = FrontMatterEvents::default(); let mut sections = Vec::new(); - parse::from_bytes(input, |e: Event<'_>| match e { + parse::from_bytes(input, &mut |e: Event<'_>| match e { Event::SectionHeader(next_header) => { match header.take() { None => { diff --git a/gix-config/src/parse/key.rs b/gix-config/src/parse/key.rs index b0e0376be2a..0ebb09e5f51 100644 --- a/gix-config/src/parse/key.rs +++ b/gix-config/src/parse/key.rs @@ -14,8 +14,7 @@ pub struct Key<'a> { /// Parse `input` like `core.bare` or `remote.origin.url` as a `Key` to make its fields available, /// or `None` if there were not at least 2 tokens separated by `.`. /// Note that `input` isn't validated, and is `str` as ascii is a subset of UTF-8 which is required for any valid keys. -pub fn parse_unvalidated<'a>(input: impl Into<&'a BStr>) -> Option> { - let input = input.into(); +pub fn parse_unvalidated(input: &BStr) -> Option> { let mut tokens = input.splitn(2, |b| *b == b'.'); let section_name = tokens.next()?; let subsection_or_key = tokens.next()?; diff --git a/gix-config/src/parse/nom/mod.rs b/gix-config/src/parse/nom/mod.rs index 1ae2f8593d1..3ae45618dc2 100644 --- a/gix-config/src/parse/nom/mod.rs +++ b/gix-config/src/parse/nom/mod.rs @@ -12,7 +12,7 @@ use winnow::{ use crate::parse::{error::ParseNode, section, Comment, Error, Event}; /// Attempt to zero-copy parse the provided bytes, passing results to `dispatch`. -pub fn from_bytes<'i>(mut input: &'i [u8], mut dispatch: impl FnMut(Event<'i>)) -> Result<(), Error> { +pub fn from_bytes<'i>(mut input: &'i [u8], dispatch: &mut dyn FnMut(Event<'i>)) -> Result<(), Error> { let start = input.checkpoint(); let bom = unicode_bom::Bom::from(input); @@ -46,7 +46,7 @@ pub fn from_bytes<'i>(mut input: &'i [u8], mut dispatch: impl FnMut(Event<'i>)) let mut node = ParseNode::SectionHeader; - let res = repeat(1.., |i: &mut &'i [u8]| section(i, &mut node, &mut dispatch)) + let res = repeat(1.., |i: &mut &'i [u8]| section(i, &mut node, dispatch)) .map(|()| ()) .parse_next(&mut input); res.map_err(|_| { @@ -94,7 +94,7 @@ mod tests; fn section<'i>( i: &mut &'i [u8], node: &mut ParseNode, - dispatch: &mut impl FnMut(Event<'i>), + dispatch: &mut dyn FnMut(Event<'i>), ) -> PResult<(), NomError<&'i [u8]>> { let start = i.checkpoint(); let header = section_header(i).map_err(|e| { @@ -205,7 +205,7 @@ fn is_subsection_unescaped_char(c: u8) -> bool { fn key_value_pair<'i>( i: &mut &'i [u8], node: &mut ParseNode, - dispatch: &mut impl FnMut(Event<'i>), + dispatch: &mut dyn FnMut(Event<'i>), ) -> PResult<(), NomError<&'i [u8]>> { *node = ParseNode::Name; if let Some(name) = opt(config_name).parse_next(i)? { @@ -234,7 +234,7 @@ fn config_name<'i>(i: &mut &'i [u8]) -> PResult<&'i BStr, NomError<&'i [u8]>> { .parse_next(i) } -fn config_value<'i>(i: &mut &'i [u8], dispatch: &mut impl FnMut(Event<'i>)) -> PResult<(), NomError<&'i [u8]>> { +fn config_value<'i>(i: &mut &'i [u8], dispatch: &mut dyn FnMut(Event<'i>)) -> PResult<(), NomError<&'i [u8]>> { if opt('=').parse_next(i)?.is_some() { dispatch(Event::KeyValueSeparator); if let Some(whitespace) = opt(take_spaces1).parse_next(i)? { @@ -252,7 +252,7 @@ fn config_value<'i>(i: &mut &'i [u8], dispatch: &mut impl FnMut(Event<'i>)) -> P /// Handles parsing of known-to-be values. This function handles both single /// line values as well as values that are continuations. -fn value_impl<'i>(i: &mut &'i [u8], dispatch: &mut impl FnMut(Event<'i>)) -> PResult<(), NomError<&'i [u8]>> { +fn value_impl<'i>(i: &mut &'i [u8], dispatch: &mut dyn FnMut(Event<'i>)) -> PResult<(), NomError<&'i [u8]>> { let start_checkpoint = i.checkpoint(); let mut value_start_checkpoint = i.checkpoint(); let mut value_end = None; diff --git a/gix-config/tests/config.rs b/gix-config/tests/config.rs index 874365a2d06..7107bca8bad 100644 --- a/gix-config/tests/config.rs +++ b/gix-config/tests/config.rs @@ -1,4 +1,4 @@ -type Result = std::result::Result>; +pub use gix_testtools::Result; mod file; mod parse; diff --git a/gix-config/tests/file/init/from_env.rs b/gix-config/tests/file/init/from_env.rs index 4987c60603d..198a25575c9 100644 --- a/gix-config/tests/file/init/from_env.rs +++ b/gix-config/tests/file/init/from_env.rs @@ -44,7 +44,7 @@ fn single_key_value_pair() -> crate::Result { let config = File::from_env(Default::default())?.unwrap(); assert_eq!(config.raw_value("core", None, "key")?, Cow::<[u8]>::Borrowed(b"value")); assert_eq!( - config.section_by_key("core")?.meta(), + config.section_by_key("core".into())?.meta(), &gix_config::file::Metadata::from(gix_config::Source::Env), "source if configured correctly" ); diff --git a/gix-config/tests/file/mod.rs b/gix-config/tests/file/mod.rs index 3a2bc92ab03..2cf50210db7 100644 --- a/gix-config/tests/file/mod.rs +++ b/gix-config/tests/file/mod.rs @@ -21,7 +21,7 @@ mod open { #[test] fn parse_config_with_windows_line_endings_successfully() { - File::from_path_no_includes(&fixture_path_standalone("repo-config.crlf"), gix_config::Source::Local).unwrap(); + File::from_path_no_includes(fixture_path_standalone("repo-config.crlf"), gix_config::Source::Local).unwrap(); } } diff --git a/gix-config/tests/file/mutable/section.rs b/gix-config/tests/file/mutable/section.rs index ea17ce7a401..17ef1df586b 100644 --- a/gix-config/tests/file/mutable/section.rs +++ b/gix-config/tests/file/mutable/section.rs @@ -51,7 +51,7 @@ mod remove { let prev_values = vec!["v", "", "", "", "a b c"]; let mut num_values = section.num_values(); for (key, expected_prev_value) in ('a'..='e').zip(prev_values) { - let prev_value = section.remove(key.to_string()); + let prev_value = section.remove(&key.to_string()); num_values -= 1; assert_eq!(prev_value.expect("present").as_ref(), expected_prev_value); assert_eq!(section.num_values(), num_values); @@ -104,7 +104,7 @@ mod set { for (key, (new_value, expected_prev_value)) in (b'a'..=b'e').zip(values.into_iter().zip(prev_values)) { let key = std::str::from_utf8(std::slice::from_ref(&key))?.to_owned(); - let prev_value = section.set(key.try_into()?, new_value); + let prev_value = section.set(key.try_into()?, new_value.as_ref()); assert_eq!(prev_value.as_deref().expect("prev value set"), expected_prev_value); } @@ -112,7 +112,7 @@ mod set { assert_eq!( config .section_mut("a", None)? - .set("new-one".to_owned().try_into()?, "value"), + .set("new-one".to_owned().try_into()?, "value".into()), None, "new values don't replace an existing one" ); diff --git a/gix-config/tests/file/write.rs b/gix-config/tests/file/write.rs index 3ae71d313ff..26c72c7f72b 100644 --- a/gix-config/tests/file/write.rs +++ b/gix-config/tests/file/write.rs @@ -137,7 +137,7 @@ mod to_filter { .push("c".try_into()?, Some("d".into())); let mut buf = Vec::::new(); - config.write_to_filter(&mut buf, |s| s.meta().source == gix_config::Source::Local)?; + config.write_to_filter(&mut buf, &mut |s| s.meta().source == gix_config::Source::Local)?; let nl = config.detect_newline_style(); assert_eq!(buf.to_str_lossy(), format!("[a \"local\"]{nl}\tb = c{nl}\tc = d{nl}")); diff --git a/gix-config/tests/parse/key.rs b/gix-config/tests/parse/key.rs index 6342429f6e4..40de5ae4269 100644 --- a/gix-config/tests/parse/key.rs +++ b/gix-config/tests/parse/key.rs @@ -2,13 +2,13 @@ use gix_config::parse; #[test] fn missing_dot_is_invalid() { - assert_eq!(parse::key("hello"), None); + assert_eq!(parse::key("hello".into()), None); } #[test] fn section_name_and_key() { assert_eq!( - parse::key("core.bare"), + parse::key("core.bare".into()), Some(parse::Key { section_name: "core", subsection_name: None, @@ -20,7 +20,7 @@ fn section_name_and_key() { #[test] fn section_name_subsection_and_key() { assert_eq!( - parse::key("remote.origin.url"), + parse::key("remote.origin.url".into()), Some(parse::Key { section_name: "remote", subsection_name: Some("origin".into()), @@ -29,7 +29,7 @@ fn section_name_subsection_and_key() { ); assert_eq!( - parse::key("includeIf.gitdir/i:C:\\bare.git.path"), + parse::key("includeIf.gitdir/i:C:\\bare.git.path".into()), Some(parse::Key { section_name: "includeIf", subsection_name: Some("gitdir/i:C:\\bare.git".into()), diff --git a/gix-credentials/src/helper/invoke.rs b/gix-credentials/src/helper/invoke.rs index 563f3b2ffc8..e5662f4ca4e 100644 --- a/gix-credentials/src/helper/invoke.rs +++ b/gix-credentials/src/helper/invoke.rs @@ -4,7 +4,7 @@ use crate::helper::{Action, Context, Error, NextAction, Outcome, Result}; impl Action { /// Send ourselves to the given `write` which is expected to be credentials-helper compatible - pub fn send(&self, mut write: impl std::io::Write) -> std::io::Result<()> { + pub fn send(&self, write: &mut dyn std::io::Write) -> std::io::Result<()> { match self { Action::Get(ctx) => ctx.write_to(write), Action::Store(last) | Action::Erase(last) => { @@ -40,11 +40,12 @@ pub fn invoke(helper: &mut crate::Program, action: &Action) -> Result { } pub(crate) fn raw(helper: &mut crate::Program, action: &Action) -> std::result::Result>, Error> { - let (stdin, stdout) = helper.start(action)?; + let (mut stdin, stdout) = helper.start(action)?; if let (Action::Get(_), None) = (&action, &stdout) { panic!("BUG: `Helper` impls must return an output handle to read output from if Action::Get is provided") } - action.send(stdin)?; + action.send(&mut stdin)?; + drop(stdin); let stdout = stdout .map(|mut stdout| { let mut buf = Vec::new(); diff --git a/gix-credentials/src/program/mod.rs b/gix-credentials/src/program/mod.rs index e13e0a5ecfa..80146601856 100644 --- a/gix-credentials/src/program/mod.rs +++ b/gix-credentials/src/program/mod.rs @@ -39,29 +39,31 @@ impl Program { /// Parse the given input as per the custom helper definition, supporting `!