Skip to content

Commit 794f2a4

Browse files
committed
parse metadata via cargo metadata and parse workspace
1 parent 3385bfa commit 794f2a4

File tree

7 files changed

+87
-52
lines changed

7 files changed

+87
-52
lines changed

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ toml = "0.7.0"
3838
which = { version = "4.4.0", default_features = false }
3939
shell-escape = "0.1.5"
4040
serde = { version = "1.0.152", features = ["derive"] }
41-
serde_json = "1.0.91"
41+
serde_json = { version = "1.0.91", features = ["raw_value"] }
4242
serde_ignored = "0.1.7"
4343
shell-words = "1.1.0"
4444
const-sha1 = "0.2.0"

src/bin/commands/run.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ impl Run {
6161
};
6262

6363
let toml = toml(&metadata, msg_info)?;
64-
let config = Config::new(toml);
64+
let config = Config::new(Some(toml));
6565

6666
let image = match docker::get_image(&config, &target, false) {
6767
Ok(i) => i,

src/cargo.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@ pub struct CargoMetadata {
7676
pub target_directory: PathBuf,
7777
pub packages: Vec<Package>,
7878
pub workspace_members: Vec<String>,
79+
pub metadata: Option<Box<serde_json::value::RawValue>>,
7980
}
8081

8182
impl CargoMetadata {
@@ -105,6 +106,7 @@ pub struct Package {
105106
pub source: Option<String>,
106107
pub version: String,
107108
pub license: Option<String>,
109+
pub metadata: Option<Box<serde_json::value::RawValue>>,
108110
}
109111

110112
impl Package {

src/config.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -603,7 +603,7 @@ mod tests {
603603

604604
fn toml(content: &str) -> Result<crate::CrossToml> {
605605
Ok(
606-
CrossToml::parse_from_cross_str(content, &mut MessageInfo::default())
606+
CrossToml::parse_from_cross_str(content, None, &mut MessageInfo::default())
607607
.wrap_err("couldn't parse toml")?
608608
.0,
609609
)

src/cross_toml.rs

Lines changed: 17 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -122,33 +122,18 @@ pub struct CrossToml {
122122
}
123123

124124
impl CrossToml {
125-
/// Parses the [`CrossToml`] from all of the config sources
126-
pub fn parse_str(
127-
cargo_toml: &str,
128-
cross_toml: &str,
129-
msg_info: &mut MessageInfo,
130-
) -> Result<(Self, BTreeSet<String>)> {
131-
let (cross_toml, mut unused) = Self::parse_from_cross_str(cross_toml, msg_info)?;
132-
133-
if let Some((cargo_toml, u_cargo)) = Self::parse_from_cargo_str(cargo_toml, msg_info)? {
134-
unused.extend(u_cargo);
135-
Ok((cargo_toml.merge(cross_toml)?, unused))
136-
} else {
137-
Ok((cross_toml, unused))
138-
}
139-
}
140-
141125
/// Parses the [`CrossToml`] from a string
142126
pub fn parse_from_cross_str(
143127
toml_str: &str,
128+
source: Option<&str>,
144129
msg_info: &mut MessageInfo,
145130
) -> Result<(Self, BTreeSet<String>)> {
146131
let tomld = toml::Deserializer::new(toml_str);
147-
Self::parse_from_deserializer(tomld, None, msg_info)
132+
Self::parse_from_deserializer(tomld, source, msg_info)
148133
}
149134

150135
/// Parses the [`CrossToml`] from a string containing the Cargo.toml contents
151-
pub fn parse_from_cargo_str(
136+
pub fn parse_from_cargo_package_str(
152137
cargo_toml_str: &str,
153138
msg_info: &mut MessageInfo,
154139
) -> Result<Option<(Self, BTreeSet<String>)>> {
@@ -170,7 +155,7 @@ impl CrossToml {
170155
}
171156

172157
/// Parses the [`CrossToml`] from a [`Deserializer`]
173-
fn parse_from_deserializer<'de, D>(
158+
pub fn parse_from_deserializer<'de, D>(
174159
deserializer: D,
175160
source: Option<&str>,
176161
msg_info: &mut MessageInfo,
@@ -601,7 +586,7 @@ mod tests {
601586
targets: HashMap::new(),
602587
build: CrossBuildConfig::default(),
603588
};
604-
let (parsed_cfg, unused) = CrossToml::parse_from_cross_str("", &mut m!())?;
589+
let (parsed_cfg, unused) = CrossToml::parse_from_cross_str("", None, &mut m!())?;
605590

606591
assert_eq!(parsed_cfg, cfg);
607592
assert!(unused.is_empty());
@@ -636,7 +621,7 @@ mod tests {
636621
volumes = ["VOL1_ARG", "VOL2_ARG"]
637622
passthrough = ["VAR1", "VAR2"]
638623
"#;
639-
let (parsed_cfg, unused) = CrossToml::parse_from_cross_str(test_str, &mut m!())?;
624+
let (parsed_cfg, unused) = CrossToml::parse_from_cross_str(test_str, None, &mut m!())?;
640625

641626
assert_eq!(parsed_cfg, cfg);
642627
assert!(unused.is_empty());
@@ -708,7 +693,7 @@ mod tests {
708693
version = "2.17"
709694
image = "zig:local"
710695
"#;
711-
let (parsed_cfg, unused) = CrossToml::parse_from_cross_str(test_str, &mut m!())?;
696+
let (parsed_cfg, unused) = CrossToml::parse_from_cross_str(test_str, None, &mut m!())?;
712697

713698
assert_eq!(parsed_cfg, cfg);
714699
assert!(unused.is_empty());
@@ -794,7 +779,7 @@ mod tests {
794779
[target.aarch64-unknown-linux-gnu.env]
795780
volumes = ["VOL"]
796781
"#;
797-
let (parsed_cfg, unused) = CrossToml::parse_from_cross_str(test_str, &mut m!())?;
782+
let (parsed_cfg, unused) = CrossToml::parse_from_cross_str(test_str, None, &mut m!())?;
798783

799784
assert_eq!(parsed_cfg, cfg);
800785
assert!(unused.is_empty());
@@ -813,7 +798,7 @@ mod tests {
813798
cross = "1.2.3"
814799
"#;
815800

816-
let res = CrossToml::parse_from_cargo_str(test_str, &mut m!())?;
801+
let res = CrossToml::parse_from_cargo_package_str(test_str, &mut m!())?;
817802
assert!(res.is_none());
818803

819804
Ok(())
@@ -849,7 +834,9 @@ mod tests {
849834
xargo = true
850835
"#;
851836

852-
if let Some((parsed_cfg, _unused)) = CrossToml::parse_from_cargo_str(test_str, &mut m!())? {
837+
if let Some((parsed_cfg, _unused)) =
838+
CrossToml::parse_from_cargo_package_str(test_str, &mut m!())?
839+
{
853840
assert_eq!(parsed_cfg, cfg);
854841
} else {
855842
panic!("Parsing result is None");
@@ -876,7 +863,7 @@ mod tests {
876863
zig = "2.17"
877864
"#;
878865

879-
let (cfg, _) = CrossToml::parse_from_cross(cfg, &mut m!())?;
866+
let (cfg, _) = CrossToml::parse_from_cross_str(cfg, None, &mut m!())?;
880867
serde_json::from_value::<CrossToml>(serde_json::to_value(cfg)?)?;
881868
Ok(())
882869
}
@@ -980,9 +967,9 @@ mod tests {
980967
"#;
981968

982969
// Parses configs
983-
let (cfg1, _) = CrossToml::parse_from_cross_str(cfg1_str, &mut m!())?;
984-
let (cfg2, _) = CrossToml::parse_from_cross_str(cfg2_str, &mut m!())?;
985-
let (cfg_expected, _) = CrossToml::parse_from_cross_str(cfg_expected_str, &mut m!())?;
970+
let (cfg1, _) = CrossToml::parse_from_cross_str(cfg1_str, None, &mut m!())?;
971+
let (cfg2, _) = CrossToml::parse_from_cross_str(cfg2_str, None, &mut m!())?;
972+
let (cfg_expected, _) = CrossToml::parse_from_cross_str(cfg_expected_str, None, &mut m!())?;
986973

987974
// Merges config and compares
988975
let cfg_merged = cfg1.merge(cfg2)?;
@@ -1039,7 +1026,7 @@ mod tests {
10391026
[build]
10401027
pre-build = ["echo Hello World"]
10411028
"#;
1042-
let (toml, unused) = CrossToml::parse_from_cross_str(toml_str, &mut m!())?;
1029+
let (toml, unused) = CrossToml::parse_from_cross_str(toml_str, None, &mut m!())?;
10431030
assert!(unused.is_empty());
10441031
assert!(matches!(
10451032
toml.pre_build(&Target::new_built_in("aarch64-unknown-linux-gnu")),

src/lib.rs

Lines changed: 55 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -752,7 +752,7 @@ pub fn setup(
752752
) -> Result<Option<CrossSetup>, color_eyre::Report> {
753753
let host = host_version_meta.host();
754754
let toml = toml(metadata, msg_info)?;
755-
let config = Config::new(toml);
755+
let config = Config::new(Some(toml));
756756
let target = args
757757
.target
758758
.clone()
@@ -893,39 +893,78 @@ macro_rules! commit_info {
893893
/// These locations are checked in the following order:
894894
/// 1. If the `CROSS_CONFIG` variable is set, it tries to read the config from its value
895895
/// 2. Otherwise, the `Cross.toml` in the project root is used
896-
/// 3. Package metadata in the Cargo.toml
896+
/// 3. Package and workspace metadata in the Cargo.toml
897897
///
898-
/// The values from `CROSS_CONFIG` or `Cross.toml` are concatenated with the package
898+
/// The values from `CROSS_CONFIG` or `Cross.toml` are concatenated with the
899899
/// metadata in `Cargo.toml`, with `Cross.toml` having the highest priority.
900-
pub fn toml(metadata: &CargoMetadata, msg_info: &mut MessageInfo) -> Result<Option<CrossToml>> {
900+
pub fn toml(metadata: &CargoMetadata, msg_info: &mut MessageInfo) -> Result<CrossToml> {
901901
let root = &metadata.workspace_root;
902902
let cross_config_path = match env::var("CROSS_CONFIG") {
903903
Ok(var) => PathBuf::from(var),
904904
Err(_) => root.join("Cross.toml"),
905905
};
906906

907-
// Attempts to read the cross config from the Cargo.toml
908-
let cargo_toml_str =
909-
file::read(root.join("Cargo.toml")).wrap_err("failed to read Cargo.toml")?;
910-
911-
if cross_config_path.exists() {
907+
let mut config = if cross_config_path.exists() {
912908
let cross_toml_str = file::read(&cross_config_path)
913909
.wrap_err_with(|| format!("could not read file `{cross_config_path:?}`"))?;
914910

915-
let (config, _) = CrossToml::parse_str(&cargo_toml_str, &cross_toml_str, msg_info)
916-
.wrap_err_with(|| format!("failed to parse file `{cross_config_path:?}` as TOML",))?;
911+
let (config, _) = CrossToml::parse_from_cross_str(
912+
&cross_toml_str,
913+
Some(cross_config_path.to_utf8()?),
914+
msg_info,
915+
)
916+
.wrap_err_with(|| format!("failed to parse file `{cross_config_path:?}` as TOML",))?;
917917

918-
Ok(Some(config))
918+
config
919919
} else {
920920
// Checks if there is a lowercase version of this file
921921
if root.join("cross.toml").exists() {
922922
msg_info.warn("There's a file named cross.toml, instead of Cross.toml. You may want to rename it, or it won't be considered.")?;
923923
}
924+
CrossToml::default()
925+
};
926+
let mut found: Option<std::borrow::Cow<'_, str>> = None;
927+
928+
if let Some(workspace_metadata) = dbg!(&metadata.metadata) {
929+
let workspace_metadata =
930+
serde_json::de::from_str::<serde_json::Value>(workspace_metadata.get())?;
931+
if let Some(cross) = dbg!(workspace_metadata.get("cross")) {
932+
found = Some(
933+
metadata
934+
.workspace_root
935+
.join("Cargo.toml")
936+
.to_utf8()?
937+
.to_owned()
938+
.into(),
939+
);
940+
let (workspace_config, _) =
941+
CrossToml::parse_from_deserializer(cross, found.as_deref(), msg_info)?;
942+
config = config.merge(workspace_config)?;
943+
}
944+
}
924945

925-
if let Some((cfg, _)) = CrossToml::parse_from_cargo_str(&cargo_toml_str, msg_info)? {
926-
Ok(Some(cfg))
927-
} else {
928-
Ok(None)
946+
for (package, package_metadata) in metadata
947+
.packages
948+
.iter()
949+
.filter_map(|p| Some((p.manifest_path.as_path(), p.metadata.as_deref()?)))
950+
{
951+
let package_metadata =
952+
serde_json::de::from_str::<serde_json::Value>(package_metadata.get())?;
953+
954+
if let Some(cross) = package_metadata.get("cross") {
955+
if let Some(found) = &found {
956+
msg_info.warn(format_args!("Found conflicting cross configuration in `{}`, use `[workspace.metadata.cross]` in the workspace manifest instead.\nCurrently only using configuration from `{}`", package.to_utf8()?, found))?;
957+
continue;
958+
}
959+
let (workspace_config, _) = CrossToml::parse_from_deserializer(
960+
cross,
961+
Some(metadata.workspace_root.join("Cargo.toml").to_utf8()?),
962+
msg_info,
963+
)?;
964+
config = config.merge(workspace_config)?;
965+
found = Some(package.to_utf8()?.into());
929966
}
930967
}
968+
969+
Ok(config)
931970
}

src/tests/toml.rs

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -62,10 +62,17 @@ fn toml_check() -> Result<(), Box<dyn std::error::Error>> {
6262
);
6363
let mut msg_info = crate::shell::MessageInfo::default();
6464
let toml = if !cargo {
65-
crate::cross_toml::CrossToml::parse_from_cross_str(&fence_content, &mut msg_info)?
65+
crate::cross_toml::CrossToml::parse_from_cross_str(
66+
&fence_content,
67+
None,
68+
&mut msg_info,
69+
)?
6670
} else {
67-
crate::cross_toml::CrossToml::parse_from_cargo_str(&fence_content, &mut msg_info)?
68-
.unwrap_or_default()
71+
crate::cross_toml::CrossToml::parse_from_cargo_package_str(
72+
&fence_content,
73+
&mut msg_info,
74+
)?
75+
.unwrap_or_default()
6976
};
7077
assert!(toml.1.is_empty());
7178

0 commit comments

Comments
 (0)