//! Serialization formats for cargo messages. use std::borrow; use std::path; pub mod diagnostic; #[cfg(feature = "test_unstable")] pub mod test; type CowPath<'a> = borrow::Cow<'a, path::Path>; type CowStr<'a> = borrow::Cow<'a, str>; /// A cargo message #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] #[serde(tag = "reason", rename_all = "kebab-case")] #[allow(clippy::large_enum_variant)] pub enum Message<'a> { /// Build completed, all further output should not be parsed BuildFinished(BuildFinished), /// The compiler generated an artifact #[serde(borrow)] CompilerArtifact(Artifact<'a>), /// The compiler wants to display a message #[serde(borrow)] CompilerMessage(FromCompiler<'a>), /// A build script successfully executed. #[serde(borrow)] BuildScriptExecuted(BuildScript<'a>), #[cfg(not(feature = "strict_unstable"))] #[doc(hidden)] #[serde(other)] Unknown, } /// Build completed, all further output should not be parsed #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] #[cfg_attr(feature = "strict_unstable", serde(deny_unknown_fields))] #[non_exhaustive] pub struct BuildFinished { success: bool, } /// A compiler-generated file. #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] #[cfg_attr(feature = "strict_unstable", serde(deny_unknown_fields))] #[non_exhaustive] pub struct Artifact<'a> { /// The workspace member this artifact belongs to #[serde(borrow)] pub package_id: WorkspaceMember<'a>, /// The full path to the artifact's manifest #[serde(borrow)] pub manifest_path: Option>, /// The target this artifact was compiled for #[serde(borrow)] pub target: Target<'a>, /// The profile this artifact was compiled with #[serde(borrow)] pub profile: ArtifactProfile<'a>, /// The enabled features for this artifact #[serde(borrow)] pub features: Vec>, /// The full paths to the generated artifacts #[serde(borrow)] pub filenames: Vec>, /// The full paths to the generated artifacts #[serde(borrow)] #[serde(default)] pub executable: Option>, /// If true, then the files were already generated pub fresh: bool, } /// A single target (lib, bin, example, ...) provided by a crate #[derive(Clone, PartialEq, Eq, Serialize, Deserialize, Debug)] #[cfg_attr(feature = "strict_unstable", serde(deny_unknown_fields))] #[non_exhaustive] pub struct Target<'a> { /// Name as given in the `Cargo.toml` or generated from the file name #[serde(borrow)] pub name: CowStr<'a>, /// Kind of target ("bin", "example", "test", "bench", "lib") #[serde(borrow)] pub kind: Vec>, /// Almost the same as `kind`, except when an example is a library instead of an executable. /// In that case `crate_types` contains things like `rlib` and `dylib` while `kind` is `example` #[serde(default)] #[serde(borrow)] pub crate_types: Vec>, /// Whether this is a doctest or not #[serde(default)] pub doctest: Option, /// Whether this is documentation or not #[serde(default)] pub doc: Option, /// Whether this is a test file #[serde(default)] pub test: bool, #[serde(default)] #[serde(rename = "required-features")] /// This target is built only if these features are enabled. /// It doesn't apply to `lib` targets. #[serde(borrow)] pub required_features: Vec>, /// Path to the main source file of the target #[serde(borrow)] pub src_path: CowPath<'a>, /// Rust edition for this target #[serde(default = "edition_default")] #[serde(borrow)] pub edition: CowStr<'a>, } fn edition_default() -> CowStr<'static> { "2015".into() } /// A workspace member. This is basically identical to `cargo::core::package_id::PackageId`, except /// that this does not use `Arc` internally. #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)] #[serde(transparent)] #[cfg_attr(feature = "strict_unstable", serde(deny_unknown_fields))] pub struct WorkspaceMember<'a> { /// The raw package id as given by cargo #[serde(borrow)] raw: CowStr<'a>, } /// Profile settings used to determine which compiler flags to use for a /// target. #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] #[cfg_attr(feature = "strict_unstable", serde(deny_unknown_fields))] #[non_exhaustive] pub struct ArtifactProfile<'a> { /// Optimization level. Possible values are 0-3, s or z. #[serde(borrow)] pub opt_level: CowStr<'a>, /// The amount of debug info. 0 for none, 1 for limited, 2 for full pub debuginfo: Option, /// State of the `cfg(debug_assertions)` directive, enabling macros like /// `debug_assert!` pub debug_assertions: bool, /// State of the overflow checks. pub overflow_checks: bool, /// Whether this profile is a test pub test: bool, } /// Message left by the compiler #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] #[cfg_attr(feature = "strict_unstable", serde(deny_unknown_fields))] #[non_exhaustive] pub struct FromCompiler<'a> { /// The workspace member this message belongs to #[serde(borrow)] pub package_id: WorkspaceMember<'a>, /// The full path to the artifact's manifest #[serde(borrow)] pub manifest_path: Option>, /// The target this message is aimed at #[serde(borrow)] pub target: Target<'a>, /// The message the compiler sent. #[serde(borrow)] pub message: diagnostic::Diagnostic<'a>, } /// Output of a Build Script execution. #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] #[cfg_attr(feature = "strict_unstable", serde(deny_unknown_fields))] #[non_exhaustive] pub struct BuildScript<'a> { /// The workspace member this build script execution belongs to #[serde(borrow)] pub package_id: WorkspaceMember<'a>, /// The outdir used. #[serde(borrow)] #[serde(default)] pub out_dir: Option>, /// The libs to link #[serde(borrow)] pub linked_libs: Vec>, /// The paths to search when resolving libs #[serde(borrow)] pub linked_paths: Vec>, /// The paths to search when resolving libs #[serde(borrow)] pub cfgs: Vec>, /// The environment variables to add to the compilation #[serde(borrow)] pub env: Vec<(CowStr<'a>, CowStr<'a>)>, } #[cfg(not(feature = "print"))] pub(crate) fn log_message(msg: &Message<'_>) { match msg { Message::BuildFinished(ref finished) => { log::trace!("Build Finished: {:?}", finished.success); } Message::CompilerArtifact(ref art) => { log::trace!("Building {:#?}", art.package_id,); } Message::CompilerMessage(ref comp) => { let content = comp .message .rendered .as_ref() .map(|s| s.as_ref()) .unwrap_or_else(|| comp.message.message.as_ref()); match comp.message.level { diagnostic::DiagnosticLevel::Ice => log::error!("{}", content), diagnostic::DiagnosticLevel::Error => log::error!("{}", content), diagnostic::DiagnosticLevel::Warning => log::warn!("{}", content), diagnostic::DiagnosticLevel::Note => log::info!("{}", content), diagnostic::DiagnosticLevel::Help => log::info!("{}", content), #[cfg(not(feature = "strict_unstable"))] _ => log::warn!("Unknown message: {:#?}", msg), } } Message::BuildScriptExecuted(ref script) => { log::trace!("Ran script from {:#?}", script.package_id); } #[cfg(not(feature = "strict_unstable"))] _ => { log::warn!("Unknown message: {:#?}", msg); } } } #[cfg(feature = "print")] pub(crate) fn log_message(msg: &Message<'_>) { match msg { Message::BuildFinished(ref finished) => { eprintln!("Build Finished: {:?}", finished.success); } Message::CompilerArtifact(ref art) => { eprintln!("Building {:#?}", art.package_id,); } Message::CompilerMessage(ref comp) => { let content = comp .message .rendered .as_ref() .map(|s| s.as_ref()) .unwrap_or_else(|| comp.message.message.as_ref()); match comp.message.level { diagnostic::DiagnosticLevel::Ice => eprintln!("{}", content), diagnostic::DiagnosticLevel::Error => eprintln!("{}", content), diagnostic::DiagnosticLevel::Warning => eprintln!("{}", content), diagnostic::DiagnosticLevel::Note => eprintln!("{}", content), diagnostic::DiagnosticLevel::Help => eprintln!("{}", content), #[cfg(not(feature = "strict_unstable"))] _ => eprintln!("Unknown message: {:#?}", msg), } } Message::BuildScriptExecuted(ref script) => { eprintln!("Ran script from {:#?}", script.package_id); } #[cfg(not(feature = "strict_unstable"))] _ => { eprintln!("Unknown message: {:#?}", msg); } } }