Skip to content

Commit

Permalink
parse metadata via cargo metadata and parse workspace
Browse files Browse the repository at this point in the history
  • Loading branch information
Emilgardis committed Jan 31, 2024
1 parent 3385bfa commit 794f2a4
Show file tree
Hide file tree
Showing 7 changed files with 87 additions and 52 deletions.
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ toml = "0.7.0"
which = { version = "4.4.0", default_features = false }
shell-escape = "0.1.5"
serde = { version = "1.0.152", features = ["derive"] }
serde_json = "1.0.91"
serde_json = { version = "1.0.91", features = ["raw_value"] }
serde_ignored = "0.1.7"
shell-words = "1.1.0"
const-sha1 = "0.2.0"
Expand Down
2 changes: 1 addition & 1 deletion src/bin/commands/run.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ impl Run {
};

let toml = toml(&metadata, msg_info)?;
let config = Config::new(toml);
let config = Config::new(Some(toml));

let image = match docker::get_image(&config, &target, false) {
Ok(i) => i,
Expand Down
2 changes: 2 additions & 0 deletions src/cargo.rs
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ pub struct CargoMetadata {
pub target_directory: PathBuf,
pub packages: Vec<Package>,
pub workspace_members: Vec<String>,
pub metadata: Option<Box<serde_json::value::RawValue>>,
}

impl CargoMetadata {
Expand Down Expand Up @@ -105,6 +106,7 @@ pub struct Package {
pub source: Option<String>,
pub version: String,
pub license: Option<String>,
pub metadata: Option<Box<serde_json::value::RawValue>>,
}

impl Package {
Expand Down
2 changes: 1 addition & 1 deletion src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -603,7 +603,7 @@ mod tests {

fn toml(content: &str) -> Result<crate::CrossToml> {
Ok(
CrossToml::parse_from_cross_str(content, &mut MessageInfo::default())
CrossToml::parse_from_cross_str(content, None, &mut MessageInfo::default())
.wrap_err("couldn't parse toml")?
.0,
)
Expand Down
47 changes: 17 additions & 30 deletions src/cross_toml.rs
Original file line number Diff line number Diff line change
Expand Up @@ -122,33 +122,18 @@ pub struct CrossToml {
}

impl CrossToml {
/// Parses the [`CrossToml`] from all of the config sources
pub fn parse_str(
cargo_toml: &str,
cross_toml: &str,
msg_info: &mut MessageInfo,
) -> Result<(Self, BTreeSet<String>)> {
let (cross_toml, mut unused) = Self::parse_from_cross_str(cross_toml, msg_info)?;

if let Some((cargo_toml, u_cargo)) = Self::parse_from_cargo_str(cargo_toml, msg_info)? {
unused.extend(u_cargo);
Ok((cargo_toml.merge(cross_toml)?, unused))
} else {
Ok((cross_toml, unused))
}
}

/// Parses the [`CrossToml`] from a string
pub fn parse_from_cross_str(
toml_str: &str,
source: Option<&str>,
msg_info: &mut MessageInfo,
) -> Result<(Self, BTreeSet<String>)> {
let tomld = toml::Deserializer::new(toml_str);
Self::parse_from_deserializer(tomld, None, msg_info)
Self::parse_from_deserializer(tomld, source, msg_info)
}

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

/// Parses the [`CrossToml`] from a [`Deserializer`]
fn parse_from_deserializer<'de, D>(
pub fn parse_from_deserializer<'de, D>(
deserializer: D,
source: Option<&str>,
msg_info: &mut MessageInfo,
Expand Down Expand Up @@ -601,7 +586,7 @@ mod tests {
targets: HashMap::new(),
build: CrossBuildConfig::default(),
};
let (parsed_cfg, unused) = CrossToml::parse_from_cross_str("", &mut m!())?;
let (parsed_cfg, unused) = CrossToml::parse_from_cross_str("", None, &mut m!())?;

assert_eq!(parsed_cfg, cfg);
assert!(unused.is_empty());
Expand Down Expand Up @@ -636,7 +621,7 @@ mod tests {
volumes = ["VOL1_ARG", "VOL2_ARG"]
passthrough = ["VAR1", "VAR2"]
"#;
let (parsed_cfg, unused) = CrossToml::parse_from_cross_str(test_str, &mut m!())?;
let (parsed_cfg, unused) = CrossToml::parse_from_cross_str(test_str, None, &mut m!())?;

assert_eq!(parsed_cfg, cfg);
assert!(unused.is_empty());
Expand Down Expand Up @@ -708,7 +693,7 @@ mod tests {
version = "2.17"
image = "zig:local"
"#;
let (parsed_cfg, unused) = CrossToml::parse_from_cross_str(test_str, &mut m!())?;
let (parsed_cfg, unused) = CrossToml::parse_from_cross_str(test_str, None, &mut m!())?;

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

assert_eq!(parsed_cfg, cfg);
assert!(unused.is_empty());
Expand All @@ -813,7 +798,7 @@ mod tests {
cross = "1.2.3"
"#;

let res = CrossToml::parse_from_cargo_str(test_str, &mut m!())?;
let res = CrossToml::parse_from_cargo_package_str(test_str, &mut m!())?;
assert!(res.is_none());

Ok(())
Expand Down Expand Up @@ -849,7 +834,9 @@ mod tests {
xargo = true
"#;

if let Some((parsed_cfg, _unused)) = CrossToml::parse_from_cargo_str(test_str, &mut m!())? {
if let Some((parsed_cfg, _unused)) =
CrossToml::parse_from_cargo_package_str(test_str, &mut m!())?
{
assert_eq!(parsed_cfg, cfg);
} else {
panic!("Parsing result is None");
Expand All @@ -876,7 +863,7 @@ mod tests {
zig = "2.17"
"#;

let (cfg, _) = CrossToml::parse_from_cross(cfg, &mut m!())?;
let (cfg, _) = CrossToml::parse_from_cross_str(cfg, None, &mut m!())?;
serde_json::from_value::<CrossToml>(serde_json::to_value(cfg)?)?;
Ok(())
}
Expand Down Expand Up @@ -980,9 +967,9 @@ mod tests {
"#;

// Parses configs
let (cfg1, _) = CrossToml::parse_from_cross_str(cfg1_str, &mut m!())?;
let (cfg2, _) = CrossToml::parse_from_cross_str(cfg2_str, &mut m!())?;
let (cfg_expected, _) = CrossToml::parse_from_cross_str(cfg_expected_str, &mut m!())?;
let (cfg1, _) = CrossToml::parse_from_cross_str(cfg1_str, None, &mut m!())?;
let (cfg2, _) = CrossToml::parse_from_cross_str(cfg2_str, None, &mut m!())?;
let (cfg_expected, _) = CrossToml::parse_from_cross_str(cfg_expected_str, None, &mut m!())?;

// Merges config and compares
let cfg_merged = cfg1.merge(cfg2)?;
Expand Down Expand Up @@ -1039,7 +1026,7 @@ mod tests {
[build]
pre-build = ["echo Hello World"]
"#;
let (toml, unused) = CrossToml::parse_from_cross_str(toml_str, &mut m!())?;
let (toml, unused) = CrossToml::parse_from_cross_str(toml_str, None, &mut m!())?;
assert!(unused.is_empty());
assert!(matches!(
toml.pre_build(&Target::new_built_in("aarch64-unknown-linux-gnu")),
Expand Down
71 changes: 55 additions & 16 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -752,7 +752,7 @@ pub fn setup(
) -> Result<Option<CrossSetup>, color_eyre::Report> {
let host = host_version_meta.host();
let toml = toml(metadata, msg_info)?;
let config = Config::new(toml);
let config = Config::new(Some(toml));
let target = args
.target
.clone()
Expand Down Expand Up @@ -893,39 +893,78 @@ macro_rules! commit_info {
/// These locations are checked in the following order:
/// 1. If the `CROSS_CONFIG` variable is set, it tries to read the config from its value
/// 2. Otherwise, the `Cross.toml` in the project root is used
/// 3. Package metadata in the Cargo.toml
/// 3. Package and workspace metadata in the Cargo.toml
///
/// The values from `CROSS_CONFIG` or `Cross.toml` are concatenated with the package
/// The values from `CROSS_CONFIG` or `Cross.toml` are concatenated with the
/// metadata in `Cargo.toml`, with `Cross.toml` having the highest priority.
pub fn toml(metadata: &CargoMetadata, msg_info: &mut MessageInfo) -> Result<Option<CrossToml>> {
pub fn toml(metadata: &CargoMetadata, msg_info: &mut MessageInfo) -> Result<CrossToml> {
let root = &metadata.workspace_root;
let cross_config_path = match env::var("CROSS_CONFIG") {
Ok(var) => PathBuf::from(var),
Err(_) => root.join("Cross.toml"),
};

// Attempts to read the cross config from the Cargo.toml
let cargo_toml_str =
file::read(root.join("Cargo.toml")).wrap_err("failed to read Cargo.toml")?;

if cross_config_path.exists() {
let mut config = if cross_config_path.exists() {
let cross_toml_str = file::read(&cross_config_path)
.wrap_err_with(|| format!("could not read file `{cross_config_path:?}`"))?;

let (config, _) = CrossToml::parse_str(&cargo_toml_str, &cross_toml_str, msg_info)
.wrap_err_with(|| format!("failed to parse file `{cross_config_path:?}` as TOML",))?;
let (config, _) = CrossToml::parse_from_cross_str(
&cross_toml_str,
Some(cross_config_path.to_utf8()?),
msg_info,
)
.wrap_err_with(|| format!("failed to parse file `{cross_config_path:?}` as TOML",))?;

Ok(Some(config))
config
} else {
// Checks if there is a lowercase version of this file
if root.join("cross.toml").exists() {
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.")?;
}
CrossToml::default()
};
let mut found: Option<std::borrow::Cow<'_, str>> = None;

if let Some(workspace_metadata) = dbg!(&metadata.metadata) {
let workspace_metadata =
serde_json::de::from_str::<serde_json::Value>(workspace_metadata.get())?;
if let Some(cross) = dbg!(workspace_metadata.get("cross")) {
found = Some(
metadata
.workspace_root
.join("Cargo.toml")
.to_utf8()?
.to_owned()
.into(),
);
let (workspace_config, _) =
CrossToml::parse_from_deserializer(cross, found.as_deref(), msg_info)?;
config = config.merge(workspace_config)?;
}
}

if let Some((cfg, _)) = CrossToml::parse_from_cargo_str(&cargo_toml_str, msg_info)? {
Ok(Some(cfg))
} else {
Ok(None)
for (package, package_metadata) in metadata
.packages
.iter()
.filter_map(|p| Some((p.manifest_path.as_path(), p.metadata.as_deref()?)))
{
let package_metadata =
serde_json::de::from_str::<serde_json::Value>(package_metadata.get())?;

if let Some(cross) = package_metadata.get("cross") {
if let Some(found) = &found {
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))?;
continue;
}
let (workspace_config, _) = CrossToml::parse_from_deserializer(
cross,
Some(metadata.workspace_root.join("Cargo.toml").to_utf8()?),
msg_info,
)?;
config = config.merge(workspace_config)?;
found = Some(package.to_utf8()?.into());
}
}

Ok(config)
}
13 changes: 10 additions & 3 deletions src/tests/toml.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,10 +62,17 @@ fn toml_check() -> Result<(), Box<dyn std::error::Error>> {
);
let mut msg_info = crate::shell::MessageInfo::default();
let toml = if !cargo {
crate::cross_toml::CrossToml::parse_from_cross_str(&fence_content, &mut msg_info)?
crate::cross_toml::CrossToml::parse_from_cross_str(
&fence_content,
None,
&mut msg_info,
)?
} else {
crate::cross_toml::CrossToml::parse_from_cargo_str(&fence_content, &mut msg_info)?
.unwrap_or_default()
crate::cross_toml::CrossToml::parse_from_cargo_package_str(
&fence_content,
&mut msg_info,
)?
.unwrap_or_default()
};
assert!(toml.1.is_empty());

Expand Down

0 comments on commit 794f2a4

Please sign in to comment.