| 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 |  | 
|---|