From 946f01d2db7135f940b0d82a92f91624486269c7 Mon Sep 17 00:00:00 2001 From: Rain Date: Tue, 27 Sep 2022 12:44:55 -0700 Subject: [PATCH] [WIP] support multiple --target arguments This isn't done yet, and I'd love if someone else picked up this work. --- nextest-metadata/src/test_list.rs | 71 ++++++++++++++++++++-- nextest-runner/src/cargo_config.rs | 8 +-- nextest-runner/src/list/binary_list.rs | 63 +++++++++++-------- nextest-runner/src/list/rust_build_meta.rs | 20 +++--- 4 files changed, 120 insertions(+), 42 deletions(-) diff --git a/nextest-metadata/src/test_list.rs b/nextest-metadata/src/test_list.rs index 77f62c475bf..0a1087a2296 100644 --- a/nextest-metadata/src/test_list.rs +++ b/nextest-metadata/src/test_list.rs @@ -3,7 +3,7 @@ use crate::CommandError; use camino::{Utf8Path, Utf8PathBuf}; -use serde::{Deserialize, Serialize}; +use serde::{de::Visitor, Deserialize, Deserializer, Serialize}; use std::{ borrow::Cow, collections::{BTreeMap, BTreeSet}, @@ -272,9 +272,44 @@ pub struct RustBuildMetaSummary { /// Linked paths, relative to the target directory. pub linked_paths: BTreeSet, - /// The target platform used while compiling the Rust artifacts - #[serde(default)] - pub target_platform: Option, + /// The target platforms used while compiling the Rust artifacts + #[serde( + default, + rename = "target-platform", + deserialize_with = "deserialize_target_platforms" + )] + pub target_platforms: Vec, +} + +fn deserialize_target_platforms<'de, D>(deserializer: D) -> Result, D::Error> +where + D: Deserializer<'de>, +{ + struct DeVisitor; + + impl<'de2> Visitor<'de2> for DeVisitor { + type Value = Vec; + + fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "a string or a list of strings") + } + + fn visit_str(self, v: &str) -> Result + where + E: serde::de::Error, + { + Ok(vec![v.to_owned()]) + } + + fn visit_seq(self, seq: A) -> Result + where + A: serde::de::SeqAccess<'de2>, + { + Vec::::deserialize(serde::de::value::SeqAccessDeserializer::new(seq)) + } + } + + deserializer.deserialize_any(DeVisitor) } /// A non-test Rust binary. Used to set the correct environment @@ -484,8 +519,34 @@ mod tests { base_output_directories: BTreeSet::new(), non_test_binaries: BTreeMap::new(), linked_paths: BTreeSet::new(), - target_platform: None, + target_platforms: vec![], }; "no target platform")] + #[test_case(r#"{ + "target-directory": "/foo", + "base-output-directories": [], + "non-test-binaries": {}, + "linked-paths": [], + "target-platform": "x86_64-unknown-linux-gnu" + }"#, RustBuildMetaSummary { + target_directory: "/foo".into(), + base_output_directories: BTreeSet::new(), + non_test_binaries: BTreeMap::new(), + linked_paths: BTreeSet::new(), + target_platforms: vec!["x86_64-unknown-linux-gnu".to_owned()], + }; "target platform as string")] + #[test_case(r#"{ + "target-directory": "/foo", + "base-output-directories": [], + "non-test-binaries": {}, + "linked-paths": [], + "target-platform": ["x86_64-unknown-linux-gnu", "i686-unknown-linux-gnu"], + }"#, RustBuildMetaSummary { + target_directory: "/foo".into(), + base_output_directories: BTreeSet::new(), + non_test_binaries: BTreeMap::new(), + linked_paths: BTreeSet::new(), + target_platforms: vec!["x86_64-unknown-linux-gnu".to_owned(), "i686-unknown-linux-gnu".to_owned()], + }; "target platforms as vec")] fn test_deserialize_old_rust_build_meta(input: &str, expected: RustBuildMetaSummary) { let build_meta: RustBuildMetaSummary = serde_json::from_str(input).expect("input deserialized correctly"); diff --git a/nextest-runner/src/cargo_config.rs b/nextest-runner/src/cargo_config.rs index dfe0e3373af..7ac0e5f6b0d 100644 --- a/nextest-runner/src/cargo_config.rs +++ b/nextest-runner/src/cargo_config.rs @@ -47,11 +47,11 @@ impl TargetTriple { /// Converts a `String` that was output by `TargetTriple::serialize` back to a target triple. /// This target triple is assumed to orginiate from a build-metadata config. - pub fn deserialize(target_triple: Option) -> Option { - Some(TargetTriple { - triple: target_triple?, + pub fn deserialize(target_triple: String) -> Self { + Self { + triple: target_triple, source: TargetTripleSource::Metadata, - }) + } } /// Find the target triple being built. diff --git a/nextest-runner/src/list/binary_list.rs b/nextest-runner/src/list/binary_list.rs index 8929675841d..5f639604d8b 100644 --- a/nextest-runner/src/list/binary_list.rs +++ b/nextest-runner/src/list/binary_list.rs @@ -50,9 +50,9 @@ impl BinaryList { pub fn from_messages( reader: impl io::BufRead, graph: &PackageGraph, - target_triple: Option, + target_platforms: Vec, ) -> Result { - let mut state = BinaryListBuildState::new(graph, target_triple); + let mut state = BinaryListBuildState::new(graph, target_platforms); for message in Message::parse_stream(reader) { let message = message.map_err(FromMessagesError::ReadMessages)?; @@ -161,13 +161,13 @@ struct BinaryListBuildState<'g> { } impl<'g> BinaryListBuildState<'g> { - fn new(graph: &'g PackageGraph, target_triple: Option) -> Self { + fn new(graph: &'g PackageGraph, target_platforms: Vec) -> Self { let rust_target_dir = graph.workspace().target_directory().to_path_buf(); Self { graph, rust_binaries: vec![], - rust_build_meta: RustBuildMeta::new(rust_target_dir, target_triple), + rust_build_meta: RustBuildMeta::new(rust_target_dir, target_platforms), } } @@ -212,24 +212,28 @@ impl<'g> BinaryListBuildState<'g> { }); } - let (computed_kind, platform) = if kind.iter().any(|k| { - // https://doc.rust-lang.org/nightly/cargo/reference/cargo-targets.html#the-crate-type-field - k == "lib" || k == "rlib" || k == "dylib" || k == "cdylib" || k == "staticlib" - }) { - (RustTestBinaryKind::LIB, BuildPlatform::Target) - } else if kind.get(0).map(String::as_str) == Some("proc-macro") { - (RustTestBinaryKind::PROC_MACRO, BuildPlatform::Host) - } else { - // Non-lib kinds should always have just one element. Grab the first one. - ( - RustTestBinaryKind::new( - kind.into_iter() - .next() - .expect("already checked that kind is non-empty"), - ), - BuildPlatform::Target, - ) - }; + let (computed_kind, platform) = + if kind.get(0).map(String::as_str) == Some("proc-macro") { + (RustTestBinaryKind::PROC_MACRO, BuildPlatform::Host) + } else { + let computed_kind = if kind.iter().any(|k| { + // https://doc.rust-lang.org/nightly/cargo/reference/cargo-targets.html#the-crate-type-field + k == "lib" + || k == "rlib" + || k == "dylib" + || k == "cdylib" + || k == "staticlib" + }) { + RustTestBinaryKind::LIB + } else { + // Non-lib kinds should always have just one element. Grab the first one. + RustTestBinaryKind::new( + kind.into_iter() + .next() + .expect("already checked that kind is non-empty"), + ) + }; + }; // To ensure unique binary IDs, we use the following scheme: if computed_kind == RustTestBinaryKind::LIB { @@ -307,7 +311,7 @@ impl<'g> BinaryListBuildState<'g> { /// have a match. /// /// The `Option` in the return value is to let ? work. - fn detect_base_output_dir(&mut self, artifact_path: &Utf8Path) -> Option<()> { + fn detect_base_output_dir(&mut self, artifact_path: &Utf8Path) -> Option<&TargetTriple> { // Artifact paths must be relative to the target directory. let rel_path = artifact_path .strip_prefix(&self.rust_build_meta.target_directory) @@ -320,8 +324,17 @@ impl<'g> BinaryListBuildState<'g> { .base_output_directories .insert(convert_rel_path_to_forward_slash(base)); } + // If the base has a first component, it likely indicates a target. Look over the list + // of targets to see if one of them matches this one. If it does, return that. + if let Some(target) = base.iter().next() { + return self + .rust_build_meta + .target_platforms + .iter() + .find(|t| t.triple == target); + } } - Some(()) + None } fn process_build_script(&mut self, build_script: BuildScript) -> Result<(), FromMessagesError> { @@ -393,7 +406,7 @@ mod tests { triple: "fake-triple".to_owned(), source: TargetTripleSource::CliOption, }; - let mut rust_build_meta = RustBuildMeta::new("/fake/target", Some(fake_triple)); + let mut rust_build_meta = RustBuildMeta::new("/fake/target", vec![fake_triple]); rust_build_meta .base_output_directories .insert("my-profile".into()); diff --git a/nextest-runner/src/list/rust_build_meta.rs b/nextest-runner/src/list/rust_build_meta.rs index 7330816297a..4654d2bc36a 100644 --- a/nextest-runner/src/list/rust_build_meta.rs +++ b/nextest-runner/src/list/rust_build_meta.rs @@ -36,8 +36,8 @@ pub struct RustBuildMeta { /// requested them. We might consider adding a new field with metadata about that. pub linked_paths: BTreeMap>, - /// The target triple used while compiling the artifacts - pub target_triple: Option, + /// The target triples used while compiling the artifacts + pub target_platforms: Vec, state: PhantomData, } @@ -46,7 +46,7 @@ impl RustBuildMeta { /// Creates a new [`RustBuildMeta`]. pub fn new( target_directory: impl Into, - target_triple: Option, + target_platforms: Vec, ) -> Self { Self { target_directory: target_directory.into(), @@ -54,7 +54,7 @@ impl RustBuildMeta { non_test_binaries: BTreeMap::new(), linked_paths: BTreeMap::new(), state: PhantomData, - target_triple, + target_platforms, } } @@ -70,7 +70,7 @@ impl RustBuildMeta { non_test_binaries: self.non_test_binaries.clone(), linked_paths: self.linked_paths.clone(), state: PhantomData, - target_triple: self.target_triple.clone(), + target_platforms: self.target_platforms.clone(), } } } @@ -85,7 +85,7 @@ impl RustBuildMeta { non_test_binaries: BTreeMap::new(), linked_paths: BTreeMap::new(), state: PhantomData, - target_triple: None, + target_platforms: vec![], } } @@ -134,7 +134,11 @@ impl RustBuildMeta { .map(|linked_path| (linked_path, BTreeSet::new())) .collect(), state: PhantomData, - target_triple: TargetTriple::deserialize(summary.target_platform), + target_platforms: summary + .target_platforms + .into_iter() + .map(TargetTriple::deserialize) + .collect(), } } @@ -145,7 +149,7 @@ impl RustBuildMeta { base_output_directories: self.base_output_directories.clone(), non_test_binaries: self.non_test_binaries.clone(), linked_paths: self.linked_paths.keys().cloned().collect(), - target_platform: TargetTriple::serialize(self.target_triple.as_ref()), + target_platforms: TargetTriple::serialize(self.target_triple.as_ref()), } } }