nextest_runner/cargo_config/
custom_platform.rs1use super::TargetTripleSource;
5use crate::errors::TargetTripleError;
6use camino::{Utf8Path, Utf8PathBuf};
7use camino_tempfile::Utf8TempDir;
8
9#[derive(Debug)]
13pub struct ExtractedCustomPlatform {
14 source: TargetTripleSource,
15 dir: Utf8TempDir,
16 path: Utf8PathBuf,
17}
18
19impl ExtractedCustomPlatform {
20 pub fn new(
22 triple_str: &str,
23 json: &str,
24 source: TargetTripleSource,
25 ) -> Result<Self, TargetTripleError> {
26 let temp_dir = camino_tempfile::Builder::new()
29 .prefix("nextest-custom-target-")
30 .rand_bytes(5)
31 .tempdir()
32 .map_err(|error| TargetTripleError::CustomPlatformTempDirError {
33 source: source.clone(),
34 error,
35 })?;
36
37 let path = temp_dir.path().join(format!("{triple_str}.json"));
38
39 std::fs::write(&path, json).map_err(|error| {
40 TargetTripleError::CustomPlatformWriteError {
41 source: source.clone(),
42 path: path.clone(),
43 error,
44 }
45 })?;
46
47 Ok(Self {
48 source,
49 dir: temp_dir,
50 path,
51 })
52 }
53
54 pub fn source(&self) -> &TargetTripleSource {
56 &self.source
57 }
58
59 pub fn dir(&self) -> &Utf8TempDir {
61 &self.dir
62 }
63
64 pub fn path(&self) -> &Utf8Path {
66 &self.path
67 }
68
69 pub fn close(self) -> Result<(), TargetTripleError> {
74 let dir_path = self.dir.path().to_owned();
75 self.dir
76 .close()
77 .map_err(|error| TargetTripleError::CustomPlatformCloseError {
78 source: self.source,
79 dir_path,
80 error,
81 })
82 }
83}
84
85#[cfg(test)]
86mod tests {
87 use super::*;
88 use crate::cargo_config::{
89 CargoTargetArg, TargetDefinitionLocation, TargetTriple, test_helpers::setup_temp_dir,
90 };
91 use color_eyre::eyre::{Context, Result, bail, eyre};
92
93 #[test]
94 fn test_extracted_custom_platform() -> Result<()> {
95 let target = {
101 let temp_dir = setup_temp_dir()?;
104 let platform_path = temp_dir.path().join("custom-target/my-target.json");
105
106 TargetTriple::custom_from_path(
108 &platform_path,
109 TargetTripleSource::CliOption,
110 temp_dir.path(),
111 )?
112 };
113
114 let summary = target.platform.to_summary();
116
117 let target2 = TargetTriple::deserialize(Some(summary))
119 .wrap_err("deserializing target triple")?
120 .ok_or_else(|| eyre!("deserializing target triple resulted in None"))?;
121
122 assert_eq!(target2.source, TargetTripleSource::Metadata);
123 assert!(
124 matches!(
125 target2.location,
126 TargetDefinitionLocation::MetadataCustom(_)
127 ),
128 "triple2.location should be MetadataCustom: {:?}",
129 target2.location
130 );
131
132 let arg = target2
134 .to_cargo_target_arg()
135 .wrap_err("converting to cargo target arg")?;
136 let extracted = match &arg {
137 CargoTargetArg::Extracted(extracted) => extracted,
138 _ => bail!("expected CargoTargetArg::Extracted, found {:?}", arg),
139 };
140
141 assert!(extracted.path().is_absolute(), "path should be absolute");
143 assert!(
144 extracted.path().ends_with("my-target.json"),
145 "extracted path should end with 'my-target.json'"
146 );
147 assert_eq!(
148 arg.to_string(),
149 extracted.path(),
150 "arg matches extracted path"
151 );
152
153 let target3 = TargetTriple::custom_from_path(
155 extracted.path(),
156 TargetTripleSource::CliOption,
157 extracted.dir().path(),
158 )?;
159 assert_eq!(target3.platform, target.platform, "platform roundtrips");
160
161 Ok(())
162 }
163}