crane-utils: fix workspace dependency merge when it is not a table (#529)

This commit is contained in:
Ivan Petkov 2024-02-21 16:00:58 -08:00 committed by GitHub
parent 2c653e4478
commit f23ae17543
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 124 additions and 66 deletions

View File

@ -13,6 +13,11 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
dummified sources which might have violated a lint marked as `deny` or
`forbid`
### Fixed
* Fixed an edge case with inheriting workspace dependencies where the workspace
dependency is a string (e.g. `foo = "0.1.2"`) but the crate definition is a
table (e.g. `foo = { workspace = true, optional = true }`)
## [0.16.1] - 2024-01-28
### Changed

View File

@ -4,9 +4,9 @@ version = 3
[[package]]
name = "anyhow"
version = "1.0.79"
version = "1.0.80"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "080e9890a082662b09c1ad45f567faeeb47f22b5fb23895fbe1e651e718e25ca"
checksum = "5ad32ce52e4161730f7098c077cd2ed6229b5804ccf99e5366be1ab72a98b4e1"
[[package]]
name = "crane-utils"
@ -39,9 +39,9 @@ checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604"
[[package]]
name = "indexmap"
version = "2.2.0"
version = "2.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cf2a4f498956c7723dc280afc6a37d0dec50b39a29e232c6187ce4503703e8c2"
checksum = "233cf39063f058ea2caae4091bf4a3ef70a653afbc026f5c4a4135d114e3c177"
dependencies = [
"equivalent",
"hashbrown",
@ -89,24 +89,24 @@ dependencies = [
[[package]]
name = "ryu"
version = "1.0.16"
version = "1.0.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f98d2aa92eebf49b69786be48e4477826b256916e84a57ff2a4f21923b48eb4c"
checksum = "e86697c916019a8588c99b5fac3cead74ec0b4b819707a682fd4d23fa0ce1ba1"
[[package]]
name = "serde"
version = "1.0.196"
version = "1.0.197"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "870026e60fa08c69f064aa766c10f10b1d62db9ccd4d0abb206472bee0ce3b32"
checksum = "3fb1c873e1b9b056a4dc4c0c198b24c3ffa059243875552b2bd0933b1aee4ce2"
dependencies = [
"serde_derive",
]
[[package]]
name = "serde_derive"
version = "1.0.196"
version = "1.0.197"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "33c85360c95e7d137454dc81d9a4ed2b8efd8fbe19cee57357b32b9771fccb67"
checksum = "7eb0b34b42edc17f6b7cac84a52a1c5f0e1bb2227e997ca9011ea3dd34e8610b"
dependencies = [
"proc-macro2",
"quote",
@ -115,9 +115,9 @@ dependencies = [
[[package]]
name = "serde_json"
version = "1.0.112"
version = "1.0.114"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4d1bd37ce2324cf3bf85e5a25f96eb4baf0d5aa6eba43e7ae8958870c4ec48ed"
checksum = "c5f09b1bd632ef549eaa9f60a1f8de742bdbc698e6cee2095fc84dde5f549ae0"
dependencies = [
"itoa",
"ryu",
@ -126,9 +126,9 @@ dependencies = [
[[package]]
name = "syn"
version = "2.0.48"
version = "2.0.50"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0f3531638e407dfc0814761abb7c00a5b54992b849452a0646b7f65c9f770f3f"
checksum = "74f1bdc9872430ce9b75da68329d1c1746faf50ffac5f19e02b71e37ff881ffb"
dependencies = [
"proc-macro2",
"quote",
@ -143,9 +143,9 @@ checksum = "3550f4e9685620ac18a50ed434eb3aec30db8ba93b0287467bca5826ea25baf1"
[[package]]
name = "toml_edit"
version = "0.21.0"
version = "0.22.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d34d383cd00a163b4a5b85053df514d45bc330f6de7737edfe0a93311d1eaa03"
checksum = "2c1b5fd4128cc8d3e0cb74d4ed9a9cc7c7284becd4df68f5f940e1ad123606f6"
dependencies = [
"indexmap",
"toml_datetime",
@ -160,9 +160,9 @@ checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
[[package]]
name = "winnow"
version = "0.5.35"
version = "0.6.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1931d78a9c73861da0134f453bb1f790ce49b2e30eba8410b4b79bac72b46a2d"
checksum = "7a4191c47f15cc3ec71fcb4913cb83d58def65dd3787610213c649283b5ce178"
dependencies = [
"memchr",
]

View File

@ -8,7 +8,7 @@ publish = false
anyhow = "1"
serde_json = "1"
serde = { version = "1", features = ["derive"] }
toml_edit = "0.21.0"
toml_edit = "0.22.6"
[dev-dependencies]
pretty_assertions = "1.3.0"

View File

@ -8,5 +8,5 @@ rustPlatform.buildRustPackage {
src = lib.sourceFilesBySuffices ./. [ ".rs" ".toml" ".lock" ];
cargoSha256 = "sha256-/ybcjLrjLBuL8jYN0thBQtqyrpKDPAltF9sRqc98Yw0=";
cargoSha256 = "sha256-sRVk7OrdIYaNBU6gA1etLTVWQvS+HW5DwJaa2xbNqiA=";
}

View File

@ -9,7 +9,7 @@ use std::{
process::{Command, Stdio},
str::FromStr,
};
use toml_edit::Item;
use toml_edit::{Item, Table};
fn main() {
let mut args = env::args();
@ -90,33 +90,28 @@ fn merge(cargo_toml: &mut toml_edit::Document, root: &toml_edit::Document) {
};
// https://doc.rust-lang.org/cargo/reference/workspaces.html#workspaces
for (key, ws_key, inherit) in [
("package", "package", false),
("dependencies", "dependencies", false),
("dev-dependencies", "dependencies", false),
("build-dependencies", "dependencies", false),
("lints", "lints", true),
] {
if let Some((cargo_toml, root)) = cargo_toml.get_mut(key).zip(w.get(ws_key)) {
if inherit {
try_inherit_cargo_table(cargo_toml, root);
} else {
try_merge_cargo_tables(cargo_toml, root);
}
let w_deps = w.get("dependencies");
for key in ["dependencies", "dev-dependencies", "build-dependencies"] {
if let Some((cargo_toml, root)) = cargo_toml.get_mut(key).zip(w_deps) {
try_merge_dependencies_tables(cargo_toml, root);
};
if let Some(targets) = cargo_toml.get_mut("target").and_then(try_as_table_like_mut) {
for (_, tp) in targets.iter_mut() {
if let Some((cargo_toml, root)) = tp.get_mut(key).zip(w.get(ws_key)) {
if inherit {
try_inherit_cargo_table(cargo_toml, root);
} else {
if let Some((cargo_toml, root)) = tp.get_mut(key).zip(w_deps) {
try_merge_dependencies_tables(cargo_toml, root);
}
}
}
}
if let Some((cargo_toml, root)) = cargo_toml.get_mut("package").zip(w.get("package")) {
try_merge_cargo_tables(cargo_toml, root);
}
}
}
}
}
};
if let Some((cargo_toml, root)) = cargo_toml.get_mut("lints").zip(w.get("lints")) {
try_inherit_cargo_table(cargo_toml, root);
};
}
/// Return a [`toml_edit::TableLike`] representation of the [`Item`] (if any)
@ -186,6 +181,54 @@ where
});
}
/// Merge the specified `cargo_toml` and workspace `root` if both are dependency tables
fn try_merge_dependencies_tables(cargo_toml: &mut Item, root: &Item) {
let cargo_toml = try_as_table_like_mut(cargo_toml);
let root = try_as_table_like(root);
if let Some((cargo_toml, root)) = cargo_toml.zip(root) {
merge_dependencies_tables(cargo_toml, root);
}
}
/// Merge the specified `cargo_toml` and workspace `root` dependencies tables
fn merge_dependencies_tables<T, U>(cargo_toml: &mut T, root: &U)
where
T: toml_edit::TableLike + ?Sized,
U: toml_edit::TableLike + ?Sized,
{
use toml_edit::Value;
cargo_toml.iter_mut().for_each(|(k, v)| {
// Bail if:
// - cargo_toml isn't a table (otherwise `workspace = true` can't show up
// - the workspace root doesn't have this key
let (t, root_val) = match try_as_table_like_mut(&mut *v).zip(root.get(&k)) {
Some((t, root_val)) => (t, root_val),
_ => return,
};
if let Some(Item::Value(toml_edit::Value::Boolean(bool_value))) = t.get("workspace") {
if *bool_value.value() {
t.remove("workspace");
let orig_val = mem::replace(
v,
match root_val.clone() {
s @ Item::Value(Value::String(_)) => {
let mut table = Table::new();
table.insert("version", s);
Item::Table(table)
}
v => v,
},
);
merge_items(v, orig_val);
}
}
});
}
/// Recursively merge the `additional` item into the specified `dest`
fn merge_items(dest: &mut Item, additional: Item) {
use toml_edit::Value;
@ -343,6 +386,8 @@ mod tests {
grault = { version = "grault-vers" }
garply = "garply-vers"
waldo = "waldo-vers"
fred.workspace = true
plugh = { workspace = true, optional = true }
[target.'cfg(unix)'.dependencies]
unix = { workspace = true, features = ["some"] }
@ -407,6 +452,8 @@ mod tests {
garply = "garply-workspace-vers"
waldo = { version = "waldo-workspace-vers" }
unix = { version = "unix-vers" }
fred = "0.1.3"
plugh = "0.2.4"
[workspace.lints.rust]
unused_extern_crates = 'warn'
@ -421,34 +468,40 @@ mod tests {
// in cargo_toml
let expected_toml_str = r#"
[package]
authors= ["first author", "second author"]
categories= ["first category", "second category" ]
description= "some description"
documentation= "some doc url"
edition= "2021"
exclude= ["first exclusion", "second exclusion"]
homepage= "some home page"
include= ["first inclusion", "second inclusion"]
keyword= ["first keyword", "second keyword"]
license= "some license"
license-file= "some license-file"
publish= true
readme= "some readme"
repository= "some repository"
rust-version= "some rust-version"
version= "some version"
authors = ["first author", "second author"]
categories = ["first category", "second category" ]
description = "some description"
documentation = "some doc url"
edition = "2021"
exclude = ["first exclusion", "second exclusion"]
homepage = "some home page"
include = ["first inclusion", "second inclusion"]
keyword = ["first keyword", "second keyword"]
license = "some license"
license-file = "some license-file"
publish = true
readme = "some readme"
repository = "some repository"
rust-version = "some rust-version"
version = "some version"
[dependencies]
# the `foo` dependency is most imporant, so it goes first
foo= { version = "foo-vers" }
bar= { version = "bar-vers", default-features = false }
baz= { version = "baz-vers", features = ["baz-feat", "baz-feat2"] }
foo = { version = "foo-vers" }
bar = { version = "bar-vers", default-features = false }
baz = { version = "baz-vers", features = ["baz-feat", "baz-feat2"] }
qux = { version = "qux-vers", features = ["qux-feat","qux-additional"] }
corge = { version = "corge-vers-override" , features = ["qux-feat"] }
grault = { version = "grault-vers" }
garply = "garply-vers"
waldo = "waldo-vers"
[dependencies.fred]
version = "0.1.3"
[ dependencies.plugh ]
version = "0.2.4"
optional = true
[target.'cfg(unix)'.dependencies]
unix = { version = "unix-vers" , features = ["some"] }
@ -456,9 +509,9 @@ mod tests {
unused_extern_crates = 'warn'
[dev-dependencies]
foo= { version = "foo-vers" }
bar= { version = "bar-vers", default-features = false }
baz= { version = "baz-vers", features = ["baz-feat", "baz-feat2"] }
foo = { version = "foo-vers" }
bar = { version = "bar-vers", default-features = false }
baz = { version = "baz-vers", features = ["baz-feat", "baz-feat2"] }
qux = { version = "qux-vers", features = ["qux-feat","qux-additional"] }
corge = { version = "corge-vers-override" , features = ["qux-feat"] }
grault = { version = "grault-vers" }
@ -469,9 +522,9 @@ mod tests {
all = 'allow'
[build-dependencies]
foo= { version = "foo-vers" }
bar= { version = "bar-vers", default-features = false }
baz= { version = "baz-vers", features = ["baz-feat", "baz-feat2"] }
foo = { version = "foo-vers" }
bar = { version = "bar-vers", default-features = false }
baz = { version = "baz-vers", features = ["baz-feat", "baz-feat2"] }
qux = { version = "qux-vers", features = ["qux-feat","qux-additional"] }
corge = { version = "corge-vers-override" , features = ["qux-feat"] }
grault = { version = "grault-vers" }