| 1 | use super::{Diagnostic, PackageId, Target}; |
| 2 | use camino::Utf8PathBuf; |
| 3 | #[cfg (feature = "builder" )] |
| 4 | use derive_builder::Builder; |
| 5 | use serde::{de, ser, Deserialize, Serialize}; |
| 6 | use std::fmt::{self, Write}; |
| 7 | use std::io::{self, BufRead, Read}; |
| 8 | |
| 9 | /// Profile settings used to determine which compiler flags to use for a |
| 10 | /// target. |
| 11 | #[derive (Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Hash)] |
| 12 | #[cfg_attr (feature = "builder" , derive(Builder))] |
| 13 | #[non_exhaustive ] |
| 14 | #[cfg_attr (feature = "builder" , builder(pattern = "owned" , setter(into)))] |
| 15 | pub struct ArtifactProfile { |
| 16 | /// Optimization level. Possible values are 0-3, s or z. |
| 17 | pub opt_level: String, |
| 18 | /// The kind of debug information. |
| 19 | #[serde(default)] |
| 20 | pub debuginfo: ArtifactDebuginfo, |
| 21 | /// State of the `cfg(debug_assertions)` directive, enabling macros like |
| 22 | /// `debug_assert!` |
| 23 | pub debug_assertions: bool, |
| 24 | /// State of the overflow checks. |
| 25 | pub overflow_checks: bool, |
| 26 | /// Whether this profile is a test |
| 27 | pub test: bool, |
| 28 | } |
| 29 | |
| 30 | /// The kind of debug information included in the artifact. |
| 31 | #[derive (Debug, Clone, PartialEq, Eq, Hash)] |
| 32 | #[non_exhaustive ] |
| 33 | pub enum ArtifactDebuginfo { |
| 34 | /// No debug information. |
| 35 | None, |
| 36 | /// Line directives only. |
| 37 | LineDirectivesOnly, |
| 38 | /// Line tables only. |
| 39 | LineTablesOnly, |
| 40 | /// Debug information without type or variable-level information. |
| 41 | Limited, |
| 42 | /// Full debug information. |
| 43 | Full, |
| 44 | /// An unknown integer level. |
| 45 | /// |
| 46 | /// This may be produced by a version of rustc in the future that has |
| 47 | /// additional levels represented by an integer that are not known by this |
| 48 | /// version of `cargo_metadata`. |
| 49 | UnknownInt(i64), |
| 50 | /// An unknown string level. |
| 51 | /// |
| 52 | /// This may be produced by a version of rustc in the future that has |
| 53 | /// additional levels represented by a string that are not known by this |
| 54 | /// version of `cargo_metadata`. |
| 55 | UnknownString(String), |
| 56 | } |
| 57 | |
| 58 | impl Default for ArtifactDebuginfo { |
| 59 | fn default() -> Self { |
| 60 | ArtifactDebuginfo::None |
| 61 | } |
| 62 | } |
| 63 | |
| 64 | impl ser::Serialize for ArtifactDebuginfo { |
| 65 | fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> |
| 66 | where |
| 67 | S: ser::Serializer, |
| 68 | { |
| 69 | match self { |
| 70 | Self::None => 0.serialize(serializer), |
| 71 | Self::LineDirectivesOnly => "line-directives-only" .serialize(serializer), |
| 72 | Self::LineTablesOnly => "line-tables-only" .serialize(serializer), |
| 73 | Self::Limited => 1.serialize(serializer), |
| 74 | Self::Full => 2.serialize(serializer), |
| 75 | Self::UnknownInt(n: &i64) => n.serialize(serializer), |
| 76 | Self::UnknownString(s: &String) => s.serialize(serializer), |
| 77 | } |
| 78 | } |
| 79 | } |
| 80 | |
| 81 | impl<'de> de::Deserialize<'de> for ArtifactDebuginfo { |
| 82 | fn deserialize<D>(d: D) -> Result<ArtifactDebuginfo, D::Error> |
| 83 | where |
| 84 | D: de::Deserializer<'de>, |
| 85 | { |
| 86 | struct Visitor; |
| 87 | |
| 88 | impl<'de> de::Visitor<'de> for Visitor { |
| 89 | type Value = ArtifactDebuginfo; |
| 90 | |
| 91 | fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { |
| 92 | formatter.write_str("an integer or string" ) |
| 93 | } |
| 94 | |
| 95 | fn visit_i64<E>(self, value: i64) -> Result<ArtifactDebuginfo, E> |
| 96 | where |
| 97 | E: de::Error, |
| 98 | { |
| 99 | let debuginfo = match value { |
| 100 | 0 => ArtifactDebuginfo::None, |
| 101 | 1 => ArtifactDebuginfo::Limited, |
| 102 | 2 => ArtifactDebuginfo::Full, |
| 103 | n => ArtifactDebuginfo::UnknownInt(n), |
| 104 | }; |
| 105 | Ok(debuginfo) |
| 106 | } |
| 107 | |
| 108 | fn visit_u64<E>(self, value: u64) -> Result<ArtifactDebuginfo, E> |
| 109 | where |
| 110 | E: de::Error, |
| 111 | { |
| 112 | self.visit_i64(value as i64) |
| 113 | } |
| 114 | |
| 115 | fn visit_str<E>(self, value: &str) -> Result<ArtifactDebuginfo, E> |
| 116 | where |
| 117 | E: de::Error, |
| 118 | { |
| 119 | let debuginfo = match value { |
| 120 | "none" => ArtifactDebuginfo::None, |
| 121 | "limited" => ArtifactDebuginfo::Limited, |
| 122 | "full" => ArtifactDebuginfo::Full, |
| 123 | "line-directives-only" => ArtifactDebuginfo::LineDirectivesOnly, |
| 124 | "line-tables-only" => ArtifactDebuginfo::LineTablesOnly, |
| 125 | s => ArtifactDebuginfo::UnknownString(s.to_string()), |
| 126 | }; |
| 127 | Ok(debuginfo) |
| 128 | } |
| 129 | |
| 130 | fn visit_unit<E>(self) -> Result<ArtifactDebuginfo, E> |
| 131 | where |
| 132 | E: de::Error, |
| 133 | { |
| 134 | Ok(ArtifactDebuginfo::None) |
| 135 | } |
| 136 | } |
| 137 | |
| 138 | d.deserialize_any(Visitor) |
| 139 | } |
| 140 | } |
| 141 | |
| 142 | impl fmt::Display for ArtifactDebuginfo { |
| 143 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
| 144 | match self { |
| 145 | ArtifactDebuginfo::None => f.write_char('0' ), |
| 146 | ArtifactDebuginfo::Limited => f.write_char('1' ), |
| 147 | ArtifactDebuginfo::Full => f.write_char('2' ), |
| 148 | ArtifactDebuginfo::LineDirectivesOnly => f.write_str(data:"line-directives-only" ), |
| 149 | ArtifactDebuginfo::LineTablesOnly => f.write_str(data:"line-tables-only" ), |
| 150 | ArtifactDebuginfo::UnknownInt(n: &i64) => write!(f, " {}" , n), |
| 151 | ArtifactDebuginfo::UnknownString(s: &String) => f.write_str(data:s), |
| 152 | } |
| 153 | } |
| 154 | } |
| 155 | |
| 156 | /// A compiler-generated file. |
| 157 | #[derive (Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Hash)] |
| 158 | #[cfg_attr (feature = "builder" , derive(Builder))] |
| 159 | #[non_exhaustive ] |
| 160 | #[cfg_attr (feature = "builder" , builder(pattern = "owned" , setter(into)))] |
| 161 | pub struct Artifact { |
| 162 | /// The package this artifact belongs to |
| 163 | pub package_id: PackageId, |
| 164 | /// Path to the `Cargo.toml` file |
| 165 | #[serde(default)] |
| 166 | pub manifest_path: Utf8PathBuf, |
| 167 | /// The target this artifact was compiled for |
| 168 | pub target: Target, |
| 169 | /// The profile this artifact was compiled with |
| 170 | pub profile: ArtifactProfile, |
| 171 | /// The enabled features for this artifact |
| 172 | pub features: Vec<String>, |
| 173 | /// The full paths to the generated artifacts |
| 174 | /// (e.g. binary file and separate debug info) |
| 175 | pub filenames: Vec<Utf8PathBuf>, |
| 176 | /// Path to the executable file |
| 177 | pub executable: Option<Utf8PathBuf>, |
| 178 | /// If true, then the files were already generated |
| 179 | pub fresh: bool, |
| 180 | } |
| 181 | |
| 182 | /// Message left by the compiler |
| 183 | // TODO: Better name. This one comes from machine_message.rs |
| 184 | #[derive (Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Hash)] |
| 185 | #[cfg_attr (feature = "builder" , derive(Builder))] |
| 186 | #[non_exhaustive ] |
| 187 | #[cfg_attr (feature = "builder" , builder(pattern = "owned" , setter(into)))] |
| 188 | pub struct CompilerMessage { |
| 189 | /// The package this message belongs to |
| 190 | pub package_id: PackageId, |
| 191 | /// The target this message is aimed at |
| 192 | pub target: Target, |
| 193 | /// The message the compiler sent. |
| 194 | pub message: Diagnostic, |
| 195 | } |
| 196 | |
| 197 | /// Output of a build script execution. |
| 198 | #[derive (Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Hash)] |
| 199 | #[cfg_attr (feature = "builder" , derive(Builder))] |
| 200 | #[non_exhaustive ] |
| 201 | #[cfg_attr (feature = "builder" , builder(pattern = "owned" , setter(into)))] |
| 202 | pub struct BuildScript { |
| 203 | /// The package this build script execution belongs to |
| 204 | pub package_id: PackageId, |
| 205 | /// The libs to link |
| 206 | pub linked_libs: Vec<Utf8PathBuf>, |
| 207 | /// The paths to search when resolving libs |
| 208 | pub linked_paths: Vec<Utf8PathBuf>, |
| 209 | /// Various `--cfg` flags to pass to the compiler |
| 210 | pub cfgs: Vec<String>, |
| 211 | /// The environment variables to add to the compilation |
| 212 | pub env: Vec<(String, String)>, |
| 213 | /// The `OUT_DIR` environment variable where this script places its output |
| 214 | /// |
| 215 | /// Added in Rust 1.41. |
| 216 | #[serde(default)] |
| 217 | pub out_dir: Utf8PathBuf, |
| 218 | } |
| 219 | |
| 220 | /// Final result of a build. |
| 221 | #[derive (Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Hash)] |
| 222 | #[cfg_attr (feature = "builder" , derive(Builder))] |
| 223 | #[non_exhaustive ] |
| 224 | #[cfg_attr (feature = "builder" , builder(pattern = "owned" , setter(into)))] |
| 225 | pub struct BuildFinished { |
| 226 | /// Whether or not the build finished successfully. |
| 227 | pub success: bool, |
| 228 | } |
| 229 | |
| 230 | /// A cargo message |
| 231 | #[derive (Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Hash)] |
| 232 | #[non_exhaustive ] |
| 233 | #[serde(tag = "reason" , rename_all = "kebab-case" )] |
| 234 | pub enum Message { |
| 235 | /// The compiler generated an artifact |
| 236 | CompilerArtifact(Artifact), |
| 237 | /// The compiler wants to display a message |
| 238 | CompilerMessage(CompilerMessage), |
| 239 | /// A build script successfully executed. |
| 240 | BuildScriptExecuted(BuildScript), |
| 241 | /// The build has finished. |
| 242 | /// |
| 243 | /// This is emitted at the end of the build as the last message. |
| 244 | /// Added in Rust 1.44. |
| 245 | BuildFinished(BuildFinished), |
| 246 | /// A line of text which isn't a cargo or compiler message. |
| 247 | /// Line separator is not included |
| 248 | #[serde(skip)] |
| 249 | TextLine(String), |
| 250 | } |
| 251 | |
| 252 | impl Message { |
| 253 | /// Creates an iterator of Message from a Read outputting a stream of JSON |
| 254 | /// messages. For usage information, look at the top-level documentation. |
| 255 | pub fn parse_stream<R: Read>(input: R) -> MessageIter<R> { |
| 256 | MessageIter { input } |
| 257 | } |
| 258 | } |
| 259 | |
| 260 | impl fmt::Display for CompilerMessage { |
| 261 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { |
| 262 | write!(f, " {}" , self.message) |
| 263 | } |
| 264 | } |
| 265 | |
| 266 | /// An iterator of Messages. |
| 267 | pub struct MessageIter<R> { |
| 268 | input: R, |
| 269 | } |
| 270 | |
| 271 | impl<R: BufRead> Iterator for MessageIter<R> { |
| 272 | type Item = io::Result<Message>; |
| 273 | fn next(&mut self) -> Option<Self::Item> { |
| 274 | let mut line: String = String::new(); |
| 275 | self.input |
| 276 | .read_line(&mut line) |
| 277 | .map(|n: usize| { |
| 278 | if n == 0 { |
| 279 | None |
| 280 | } else { |
| 281 | if line.ends_with(' \n' ) { |
| 282 | line.truncate(new_len:line.len() - 1); |
| 283 | } |
| 284 | let mut deserializer: Deserializer> = serde_json::Deserializer::from_str(&line); |
| 285 | deserializer.disable_recursion_limit(); |
| 286 | Some(Message::deserialize(&mut deserializer).unwrap_or(Message::TextLine(line))) |
| 287 | } |
| 288 | }) |
| 289 | .transpose() |
| 290 | } |
| 291 | } |
| 292 | |
| 293 | /// An iterator of Message. |
| 294 | type MessageIterator<R> = |
| 295 | serde_json::StreamDeserializer<'static, serde_json::de::IoRead<R>, Message>; |
| 296 | |
| 297 | /// Creates an iterator of Message from a Read outputting a stream of JSON |
| 298 | /// messages. For usage information, look at the top-level documentation. |
| 299 | #[deprecated (note = "Use Message::parse_stream instead" )] |
| 300 | pub fn parse_messages<R: Read>(input: R) -> MessageIterator<R> { |
| 301 | serde_json::Deserializer::from_reader(input).into_iter::<Message>() |
| 302 | } |
| 303 | |