summaryrefslogtreecommitdiffstats
path: root/third_party/rust/cargo_metadata/src
diff options
context:
space:
mode:
Diffstat (limited to 'third_party/rust/cargo_metadata/src')
-rw-r--r--third_party/rust/cargo_metadata/src/dependency.rs90
-rw-r--r--third_party/rust/cargo_metadata/src/diagnostic.rs160
-rw-r--r--third_party/rust/cargo_metadata/src/errors.rs110
-rw-r--r--third_party/rust/cargo_metadata/src/lib.rs641
-rw-r--r--third_party/rust/cargo_metadata/src/messages.rs165
5 files changed, 1166 insertions, 0 deletions
diff --git a/third_party/rust/cargo_metadata/src/dependency.rs b/third_party/rust/cargo_metadata/src/dependency.rs
new file mode 100644
index 0000000000..89bcf9f2f1
--- /dev/null
+++ b/third_party/rust/cargo_metadata/src/dependency.rs
@@ -0,0 +1,90 @@
+//! This module contains `Dependency` and the types/functions it uses for deserialization.
+
+use std::fmt;
+
+use camino::Utf8PathBuf;
+#[cfg(feature = "builder")]
+use derive_builder::Builder;
+use semver::VersionReq;
+use serde::{Deserialize, Deserializer, Serialize};
+
+#[derive(Eq, PartialEq, Clone, Debug, Copy, Hash, Serialize, Deserialize)]
+/// Dependencies can come in three kinds
+pub enum DependencyKind {
+ #[serde(rename = "normal")]
+ /// The 'normal' kind
+ Normal,
+ #[serde(rename = "dev")]
+ /// Those used in tests only
+ Development,
+ #[serde(rename = "build")]
+ /// Those used in build scripts only
+ Build,
+ #[doc(hidden)]
+ #[serde(other)]
+ Unknown,
+}
+
+impl Default for DependencyKind {
+ fn default() -> DependencyKind {
+ DependencyKind::Normal
+ }
+}
+
+impl fmt::Display for DependencyKind {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ let s = serde_json::to_string(self).unwrap();
+ // skip opening and closing quotes
+ f.write_str(&s[1..s.len() - 1])
+ }
+}
+
+/// The `kind` can be `null`, which is interpreted as the default - `Normal`.
+pub(super) fn parse_dependency_kind<'de, D>(d: D) -> Result<DependencyKind, D::Error>
+where
+ D: Deserializer<'de>,
+{
+ Deserialize::deserialize(d).map(|x: Option<_>| x.unwrap_or_default())
+}
+
+#[derive(Clone, Serialize, Deserialize, Debug, PartialEq, Eq)]
+#[cfg_attr(feature = "builder", derive(Builder))]
+#[non_exhaustive]
+#[cfg_attr(feature = "builder", builder(pattern = "owned", setter(into)))]
+/// A dependency of the main crate
+pub struct Dependency {
+ /// Name as given in the `Cargo.toml`
+ pub name: String,
+ /// The source of dependency
+ pub source: Option<String>,
+ /// The required version
+ pub req: VersionReq,
+ /// The kind of dependency this is
+ #[serde(deserialize_with = "parse_dependency_kind")]
+ pub kind: DependencyKind,
+ /// Whether this dependency is required or optional
+ pub optional: bool,
+ /// Whether the default features in this dependency are used.
+ pub uses_default_features: bool,
+ /// The list of features enabled for this dependency.
+ pub features: Vec<String>,
+ /// The target this dependency is specific to.
+ ///
+ /// Use the [`Display`] trait to access the contents.
+ ///
+ /// [`Display`]: std::fmt::Display
+ pub target: Option<Platform>,
+ /// If the dependency is renamed, this is the new name for the dependency
+ /// as a string. None if it is not renamed.
+ pub rename: Option<String>,
+ /// The URL of the index of the registry where this dependency is from.
+ ///
+ /// If None, the dependency is from crates.io.
+ pub registry: Option<String>,
+ /// The file system path for a local path dependency.
+ ///
+ /// Only produced on cargo 1.51+
+ pub path: Option<Utf8PathBuf>,
+}
+
+pub use cargo_platform::Platform;
diff --git a/third_party/rust/cargo_metadata/src/diagnostic.rs b/third_party/rust/cargo_metadata/src/diagnostic.rs
new file mode 100644
index 0000000000..dbe21128a0
--- /dev/null
+++ b/third_party/rust/cargo_metadata/src/diagnostic.rs
@@ -0,0 +1,160 @@
+//! This module contains `Diagnostic` and the types/functions it uses for deserialization.
+
+#[cfg(feature = "builder")]
+use derive_builder::Builder;
+use serde::{Deserialize, Serialize};
+use std::fmt;
+
+/// The error code associated to this diagnostic.
+#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Hash)]
+#[cfg_attr(feature = "builder", derive(Builder))]
+#[non_exhaustive]
+#[cfg_attr(feature = "builder", builder(pattern = "owned", setter(into)))]
+pub struct DiagnosticCode {
+ /// The code itself.
+ pub code: String,
+ /// An explanation for the code
+ pub explanation: Option<String>,
+}
+
+/// A line of code associated with the Diagnostic
+#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Hash)]
+#[cfg_attr(feature = "builder", derive(Builder))]
+#[non_exhaustive]
+#[cfg_attr(feature = "builder", builder(pattern = "owned", setter(into)))]
+pub struct DiagnosticSpanLine {
+ /// The line of code associated with the error
+ pub text: String,
+ /// Start of the section of the line to highlight. 1-based, character offset in self.text
+ pub highlight_start: usize,
+ /// End of the section of the line to highlight. 1-based, character offset in self.text
+ pub highlight_end: usize,
+}
+
+/// Macro expansion information associated with a diagnostic.
+#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Hash)]
+#[cfg_attr(feature = "builder", derive(Builder))]
+#[non_exhaustive]
+#[cfg_attr(feature = "builder", builder(pattern = "owned", setter(into)))]
+pub struct DiagnosticSpanMacroExpansion {
+ /// span where macro was applied to generate this code; note that
+ /// this may itself derive from a macro (if
+ /// `span.expansion.is_some()`)
+ pub span: DiagnosticSpan,
+
+ /// name of macro that was applied (e.g., "foo!" or "#[derive(Eq)]")
+ pub macro_decl_name: String,
+
+ /// span where macro was defined (if known)
+ pub def_site_span: Option<DiagnosticSpan>,
+}
+
+/// A section of the source code associated with a Diagnostic
+#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Hash)]
+#[cfg_attr(feature = "builder", derive(Builder))]
+#[non_exhaustive]
+#[cfg_attr(feature = "builder", builder(pattern = "owned", setter(into)))]
+pub struct DiagnosticSpan {
+ /// The file name or the macro name this diagnostic comes from.
+ pub file_name: String,
+ /// The byte offset in the file where this diagnostic starts from.
+ pub byte_start: u32,
+ /// The byte offset in the file where this diagnostic ends.
+ pub byte_end: u32,
+ /// 1-based. The line in the file.
+ pub line_start: usize,
+ /// 1-based. The line in the file.
+ pub line_end: usize,
+ /// 1-based, character offset.
+ pub column_start: usize,
+ /// 1-based, character offset.
+ pub column_end: usize,
+ /// Is this a "primary" span -- meaning the point, or one of the points,
+ /// where the error occurred?
+ ///
+ /// There are rare cases where multiple spans are marked as primary,
+ /// e.g. "immutable borrow occurs here" and "mutable borrow ends here" can
+ /// be two separate spans both "primary". Top (parent) messages should
+ /// always have at least one primary span, unless it has 0 spans. Child
+ /// messages may have 0 or more primary spans.
+ pub is_primary: bool,
+ /// Source text from the start of line_start to the end of line_end.
+ pub text: Vec<DiagnosticSpanLine>,
+ /// Label that should be placed at this location (if any)
+ pub label: Option<String>,
+ /// If we are suggesting a replacement, this will contain text
+ /// that should be sliced in atop this span.
+ pub suggested_replacement: Option<String>,
+ /// If the suggestion is approximate
+ pub suggestion_applicability: Option<Applicability>,
+ /// Macro invocations that created the code at this span, if any.
+ pub expansion: Option<Box<DiagnosticSpanMacroExpansion>>,
+}
+
+/// Whether a suggestion can be safely applied.
+#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Hash)]
+#[non_exhaustive]
+pub enum Applicability {
+ /// The suggested replacement can be applied automatically safely
+ MachineApplicable,
+ /// The suggested replacement has placeholders that will need to be manually
+ /// replaced.
+ HasPlaceholders,
+ /// The suggested replacement may be incorrect in some circumstances. Needs
+ /// human review.
+ MaybeIncorrect,
+ /// The suggested replacement will probably not work.
+ Unspecified,
+}
+
+/// The diagnostic level
+#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq, Hash)]
+#[non_exhaustive]
+#[serde(rename_all = "lowercase")]
+pub enum DiagnosticLevel {
+ /// Internal compiler error
+ #[serde(rename = "error: internal compiler error")]
+ Ice,
+ /// Error
+ Error,
+ /// Warning
+ Warning,
+ /// Failure note
+ #[serde(rename = "failure-note")]
+ FailureNote,
+ /// Note
+ Note,
+ /// Help
+ Help,
+}
+
+/// A diagnostic message generated by rustc
+#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Hash)]
+#[cfg_attr(feature = "builder", derive(Builder))]
+#[non_exhaustive]
+#[cfg_attr(feature = "builder", builder(pattern = "owned", setter(into)))]
+pub struct Diagnostic {
+ /// The error message of this diagnostic.
+ pub message: String,
+ /// The associated error code for this diagnostic
+ pub code: Option<DiagnosticCode>,
+ /// "error: internal compiler error", "error", "warning", "note", "help"
+ pub level: DiagnosticLevel,
+ /// A list of source code spans this diagnostic is associated with.
+ pub spans: Vec<DiagnosticSpan>,
+ /// Associated diagnostic messages.
+ pub children: Vec<Diagnostic>,
+ /// The message as rustc would render it
+ pub rendered: Option<String>,
+}
+
+impl fmt::Display for Diagnostic {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ if let Some(ref rendered) = self.rendered {
+ f.write_str(rendered)?;
+ } else {
+ f.write_str("cargo didn't render this message")?;
+ }
+ Ok(())
+ }
+}
diff --git a/third_party/rust/cargo_metadata/src/errors.rs b/third_party/rust/cargo_metadata/src/errors.rs
new file mode 100644
index 0000000000..7172057e7f
--- /dev/null
+++ b/third_party/rust/cargo_metadata/src/errors.rs
@@ -0,0 +1,110 @@
+use std::fmt;
+use std::io;
+use std::str::Utf8Error;
+use std::string::FromUtf8Error;
+
+/// Custom result type for `cargo_metadata::Error`
+pub type Result<T> = ::std::result::Result<T, Error>;
+
+/// Error returned when executing/parsing `cargo metadata` fails.
+///
+/// # Note about Backtraces
+///
+/// This error type does not contain backtraces, but each error variant
+/// comes from _one_ specific place, so it's not really needed for the
+/// inside of this crate. If you need a backtrace down to, but not inside
+/// of, a failed call of `cargo_metadata` you can do one of multiple thinks:
+///
+/// 1. Convert it to a `failure::Error` (possible using the `?` operator),
+/// which is similar to a `Box<::std::error::Error + 'static + Send + Sync>`.
+/// 2. Have appropriate variants in your own error type. E.g. you could wrap
+/// a `failure::Context<Error>` or add a `failure::Backtrace` field (which
+/// is empty if `RUST_BACKTRACE` is not set, so it's simple to use).
+/// 3. You still can place a failure based error into a `error_chain` if you
+/// really want to. (Either through foreign_links or by making it a field
+/// value of a `ErrorKind` variant).
+///
+#[derive(Debug)]
+pub enum Error {
+ /// Error during execution of `cargo metadata`
+ CargoMetadata {
+ /// stderr returned by the `cargo metadata` command
+ stderr: String,
+ },
+
+ /// IO Error during execution of `cargo metadata`
+ Io(io::Error),
+
+ /// Output of `cargo metadata` was not valid utf8
+ Utf8(Utf8Error),
+
+ /// Error output of `cargo metadata` was not valid utf8
+ ErrUtf8(FromUtf8Error),
+
+ /// Deserialization error (structure of json did not match expected structure)
+ Json(::serde_json::Error),
+
+ /// The output did not contain any json
+ NoJson,
+}
+
+impl From<io::Error> for Error {
+ fn from(v: io::Error) -> Self {
+ Error::Io(v)
+ }
+}
+
+impl From<Utf8Error> for Error {
+ fn from(v: Utf8Error) -> Self {
+ Error::Utf8(v)
+ }
+}
+
+impl From<FromUtf8Error> for Error {
+ fn from(v: FromUtf8Error) -> Self {
+ Error::ErrUtf8(v)
+ }
+}
+
+impl From<::serde_json::Error> for Error {
+ fn from(v: ::serde_json::Error) -> Self {
+ Error::Json(v)
+ }
+}
+
+impl fmt::Display for Error {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ match self {
+ Error::CargoMetadata { stderr } => {
+ write!(
+ f,
+ "`cargo metadata` exited with an error: {}",
+ stderr.trim_end()
+ )
+ }
+ Error::Io(err) => write!(f, "failed to start `cargo metadata`: {}", err),
+ Error::Utf8(err) => write!(f, "cannot convert the stdout of `cargo metadata`: {}", err),
+ Error::ErrUtf8(err) => {
+ write!(f, "cannot convert the stderr of `cargo metadata`: {}", err)
+ }
+ Error::Json(err) => write!(f, "failed to interpret `cargo metadata`'s json: {}", err),
+ Error::NoJson => write!(
+ f,
+ "could not find any json in the output of `cargo metadata`"
+ ),
+ }
+ }
+}
+
+impl ::std::error::Error for Error {
+ fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
+ match self {
+ Error::CargoMetadata { .. } => None,
+ Error::Io(err) => Some(err),
+ Error::Utf8(err) => Some(err),
+ Error::ErrUtf8(err) => Some(err),
+ Error::Json(err) => Some(err),
+ Error::NoJson => None,
+ }
+ }
+}
diff --git a/third_party/rust/cargo_metadata/src/lib.rs b/third_party/rust/cargo_metadata/src/lib.rs
new file mode 100644
index 0000000000..c88d3240dc
--- /dev/null
+++ b/third_party/rust/cargo_metadata/src/lib.rs
@@ -0,0 +1,641 @@
+#![deny(missing_docs)]
+//! Structured access to the output of `cargo metadata` and `cargo --message-format=json`.
+//! Usually used from within a `cargo-*` executable
+//!
+//! See the [cargo book](https://doc.rust-lang.org/cargo/index.html) for
+//! details on cargo itself.
+//!
+//! ## Examples
+//!
+//! ```rust
+//! # extern crate cargo_metadata;
+//! # use std::path::Path;
+//! let mut args = std::env::args().skip_while(|val| !val.starts_with("--manifest-path"));
+//!
+//! let mut cmd = cargo_metadata::MetadataCommand::new();
+//! let manifest_path = match args.next() {
+//! Some(ref p) if p == "--manifest-path" => {
+//! cmd.manifest_path(args.next().unwrap());
+//! }
+//! Some(p) => {
+//! cmd.manifest_path(p.trim_start_matches("--manifest-path="));
+//! }
+//! None => {}
+//! };
+//!
+//! let _metadata = cmd.exec().unwrap();
+//! ```
+//!
+//! Pass features flags
+//!
+//! ```rust
+//! # // This should be kept in sync with the equivalent example in the readme.
+//! # extern crate cargo_metadata;
+//! # use std::path::Path;
+//! # fn main() {
+//! use cargo_metadata::{MetadataCommand, CargoOpt};
+//!
+//! let _metadata = MetadataCommand::new()
+//! .manifest_path("./Cargo.toml")
+//! .features(CargoOpt::AllFeatures)
+//! .exec()
+//! .unwrap();
+//! # }
+//! ```
+//!
+//! Parse message-format output:
+//!
+//! ```
+//! # extern crate cargo_metadata;
+//! use std::process::{Stdio, Command};
+//! use cargo_metadata::Message;
+//!
+//! let mut command = Command::new("cargo")
+//! .args(&["build", "--message-format=json-render-diagnostics"])
+//! .stdout(Stdio::piped())
+//! .spawn()
+//! .unwrap();
+//!
+//! let reader = std::io::BufReader::new(command.stdout.take().unwrap());
+//! for message in cargo_metadata::Message::parse_stream(reader) {
+//! match message.unwrap() {
+//! Message::CompilerMessage(msg) => {
+//! println!("{:?}", msg);
+//! },
+//! Message::CompilerArtifact(artifact) => {
+//! println!("{:?}", artifact);
+//! },
+//! Message::BuildScriptExecuted(script) => {
+//! println!("{:?}", script);
+//! },
+//! Message::BuildFinished(finished) => {
+//! println!("{:?}", finished);
+//! },
+//! _ => () // Unknown message
+//! }
+//! }
+//!
+//! let output = command.wait().expect("Couldn't get cargo's exit status");
+//! ```
+
+use camino::Utf8PathBuf;
+#[cfg(feature = "builder")]
+use derive_builder::Builder;
+use std::collections::HashMap;
+use std::env;
+use std::fmt;
+use std::path::PathBuf;
+use std::process::Command;
+use std::str::from_utf8;
+
+pub use camino;
+pub use semver::{Version, VersionReq};
+
+pub use dependency::{Dependency, DependencyKind};
+use diagnostic::Diagnostic;
+pub use errors::{Error, Result};
+#[allow(deprecated)]
+pub use messages::parse_messages;
+pub use messages::{
+ Artifact, ArtifactProfile, BuildFinished, BuildScript, CompilerMessage, Message, MessageIter,
+};
+use serde::{Deserialize, Serialize};
+
+mod dependency;
+pub mod diagnostic;
+mod errors;
+mod messages;
+
+/// An "opaque" identifier for a package.
+/// It is possible to inspect the `repr` field, if the need arises, but its
+/// precise format is an implementation detail and is subject to change.
+///
+/// `Metadata` can be indexed by `PackageId`.
+#[derive(Clone, Serialize, Deserialize, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
+#[serde(transparent)]
+pub struct PackageId {
+ /// The underlying string representation of id.
+ pub repr: String,
+}
+
+impl std::fmt::Display for PackageId {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ fmt::Display::fmt(&self.repr, f)
+ }
+}
+
+// Helpers for default metadata fields
+fn is_null(value: &serde_json::Value) -> bool {
+ match value {
+ serde_json::Value::Null => true,
+ _ => false,
+ }
+}
+
+#[derive(Clone, Serialize, Deserialize, Debug)]
+#[cfg_attr(feature = "builder", derive(Builder))]
+#[non_exhaustive]
+#[cfg_attr(feature = "builder", builder(pattern = "owned", setter(into)))]
+/// Starting point for metadata returned by `cargo metadata`
+pub struct Metadata {
+ /// A list of all crates referenced by this crate (and the crate itself)
+ pub packages: Vec<Package>,
+ /// A list of all workspace members
+ pub workspace_members: Vec<PackageId>,
+ /// Dependencies graph
+ pub resolve: Option<Resolve>,
+ /// Workspace root
+ pub workspace_root: Utf8PathBuf,
+ /// Build directory
+ pub target_directory: Utf8PathBuf,
+ /// The workspace-level metadata object. Null if non-existent.
+ #[serde(rename = "metadata", default, skip_serializing_if = "is_null")]
+ pub workspace_metadata: serde_json::Value,
+ /// The metadata format version
+ version: usize,
+}
+
+impl Metadata {
+ /// Get the root package of this metadata instance.
+ pub fn root_package(&self) -> Option<&Package> {
+ let root = self.resolve.as_ref()?.root.as_ref()?;
+ self.packages.iter().find(|pkg| &pkg.id == root)
+ }
+}
+
+impl<'a> std::ops::Index<&'a PackageId> for Metadata {
+ type Output = Package;
+
+ fn index(&self, idx: &'a PackageId) -> &Package {
+ self.packages
+ .iter()
+ .find(|p| p.id == *idx)
+ .unwrap_or_else(|| panic!("no package with this id: {:?}", idx))
+ }
+}
+
+#[derive(Clone, Serialize, Deserialize, Debug)]
+#[cfg_attr(feature = "builder", derive(Builder))]
+#[non_exhaustive]
+#[cfg_attr(feature = "builder", builder(pattern = "owned", setter(into)))]
+/// A dependency graph
+pub struct Resolve {
+ /// Nodes in a dependencies graph
+ pub nodes: Vec<Node>,
+
+ /// The crate for which the metadata was read.
+ pub root: Option<PackageId>,
+}
+
+#[derive(Clone, Serialize, Deserialize, Debug)]
+#[cfg_attr(feature = "builder", derive(Builder))]
+#[non_exhaustive]
+#[cfg_attr(feature = "builder", builder(pattern = "owned", setter(into)))]
+/// A node in a dependencies graph
+pub struct Node {
+ /// An opaque identifier for a package
+ pub id: PackageId,
+ /// Dependencies in a structured format.
+ ///
+ /// `deps` handles renamed dependencies whereas `dependencies` does not.
+ #[serde(default)]
+ pub deps: Vec<NodeDep>,
+
+ /// List of opaque identifiers for this node's dependencies.
+ /// It doesn't support renamed dependencies. See `deps`.
+ pub dependencies: Vec<PackageId>,
+
+ /// Features enabled on the crate
+ #[serde(default)]
+ pub features: Vec<String>,
+}
+
+#[derive(Clone, Serialize, Deserialize, Debug)]
+#[cfg_attr(feature = "builder", derive(Builder))]
+#[non_exhaustive]
+#[cfg_attr(feature = "builder", builder(pattern = "owned", setter(into)))]
+/// A dependency in a node
+pub struct NodeDep {
+ /// The name of the dependency's library target.
+ /// If the crate was renamed, it is the new name.
+ pub name: String,
+ /// Package ID (opaque unique identifier)
+ pub pkg: PackageId,
+ /// The kinds of dependencies.
+ ///
+ /// This field was added in Rust 1.41.
+ #[serde(default)]
+ pub dep_kinds: Vec<DepKindInfo>,
+}
+
+#[derive(Clone, Serialize, Deserialize, Debug)]
+#[cfg_attr(feature = "builder", derive(Builder))]
+#[non_exhaustive]
+#[cfg_attr(feature = "builder", builder(pattern = "owned", setter(into)))]
+/// Information about a dependency kind.
+pub struct DepKindInfo {
+ /// The kind of dependency.
+ #[serde(deserialize_with = "dependency::parse_dependency_kind")]
+ pub kind: DependencyKind,
+ /// The target platform for the dependency.
+ ///
+ /// This is `None` if it is not a target dependency.
+ ///
+ /// Use the [`Display`] trait to access the contents.
+ ///
+ /// By default all platform dependencies are included in the resolve
+ /// graph. Use Cargo's `--filter-platform` flag if you only want to
+ /// include dependencies for a specific platform.
+ ///
+ /// [`Display`]: std::fmt::Display
+ pub target: Option<dependency::Platform>,
+}
+
+#[derive(Clone, Serialize, Deserialize, Debug, PartialEq, Eq)]
+#[cfg_attr(feature = "builder", derive(Builder))]
+#[non_exhaustive]
+#[cfg_attr(feature = "builder", builder(pattern = "owned", setter(into)))]
+/// One or more crates described by a single `Cargo.toml`
+///
+/// Each [`target`][Package::targets] of a `Package` will be built as a crate.
+/// For more information, see <https://doc.rust-lang.org/book/ch07-01-packages-and-crates.html>.
+pub struct Package {
+ /// Name as given in the `Cargo.toml`
+ pub name: String,
+ /// Version given in the `Cargo.toml`
+ pub version: Version,
+ /// Authors given in the `Cargo.toml`
+ #[serde(default)]
+ pub authors: Vec<String>,
+ /// An opaque identifier for a package
+ pub id: PackageId,
+ /// The source of the package, e.g.
+ /// crates.io or `None` for local projects.
+ pub source: Option<Source>,
+ /// Description as given in the `Cargo.toml`
+ pub description: Option<String>,
+ /// List of dependencies of this particular package
+ pub dependencies: Vec<Dependency>,
+ /// License as given in the `Cargo.toml`
+ pub license: Option<String>,
+ /// If the package is using a nonstandard license, this key may be specified instead of
+ /// `license`, and must point to a file relative to the manifest.
+ pub license_file: Option<Utf8PathBuf>,
+ /// Targets provided by the crate (lib, bin, example, test, ...)
+ pub targets: Vec<Target>,
+ /// Features provided by the crate, mapped to the features required by that feature.
+ pub features: HashMap<String, Vec<String>>,
+ /// Path containing the `Cargo.toml`
+ pub manifest_path: Utf8PathBuf,
+ /// Categories as given in the `Cargo.toml`
+ #[serde(default)]
+ pub categories: Vec<String>,
+ /// Keywords as given in the `Cargo.toml`
+ #[serde(default)]
+ pub keywords: Vec<String>,
+ /// Readme as given in the `Cargo.toml`
+ pub readme: Option<Utf8PathBuf>,
+ /// Repository as given in the `Cargo.toml`
+ // can't use `url::Url` because that requires a more recent stable compiler
+ pub repository: Option<String>,
+ /// Homepage as given in the `Cargo.toml`
+ ///
+ /// On versions of cargo before 1.49, this will always be [`None`].
+ pub homepage: Option<String>,
+ /// Documentation URL as given in the `Cargo.toml`
+ ///
+ /// On versions of cargo before 1.49, this will always be [`None`].
+ pub documentation: Option<String>,
+ /// Default Rust edition for the package
+ ///
+ /// Beware that individual targets may specify their own edition in
+ /// [`Target::edition`].
+ #[serde(default = "edition_default")]
+ pub edition: String,
+ /// Contents of the free form package.metadata section
+ ///
+ /// This contents can be serialized to a struct using serde:
+ ///
+ /// ```rust
+ /// use serde::Deserialize;
+ /// use serde_json::json;
+ ///
+ /// #[derive(Debug, Deserialize)]
+ /// struct SomePackageMetadata {
+ /// some_value: i32,
+ /// }
+ ///
+ /// fn main() {
+ /// let value = json!({
+ /// "some_value": 42,
+ /// });
+ ///
+ /// let package_metadata: SomePackageMetadata = serde_json::from_value(value).unwrap();
+ /// assert_eq!(package_metadata.some_value, 42);
+ /// }
+ ///
+ /// ```
+ #[serde(default, skip_serializing_if = "is_null")]
+ pub metadata: serde_json::Value,
+ /// The name of a native library the package is linking to.
+ pub links: Option<String>,
+ /// List of registries to which this package may be published.
+ ///
+ /// Publishing is unrestricted if `None`, and forbidden if the `Vec` is empty.
+ ///
+ /// This is always `None` if running with a version of Cargo older than 1.39.
+ pub publish: Option<Vec<String>>,
+ /// The default binary to run by `cargo run`.
+ ///
+ /// This is always `None` if running with a version of Cargo older than 1.55.
+ pub default_run: Option<String>,
+ /// The minimum supported Rust version of this package.
+ ///
+ /// This is always `None` if running with a version of Cargo older than 1.58.
+ pub rust_version: Option<VersionReq>,
+}
+
+impl Package {
+ /// Full path to the license file if one is present in the manifest
+ pub fn license_file(&self) -> Option<Utf8PathBuf> {
+ self.license_file.as_ref().map(|file| {
+ self.manifest_path
+ .parent()
+ .unwrap_or(&self.manifest_path)
+ .join(file)
+ })
+ }
+
+ /// Full path to the readme file if one is present in the manifest
+ pub fn readme(&self) -> Option<Utf8PathBuf> {
+ self.readme
+ .as_ref()
+ .map(|file| self.manifest_path.join(file))
+ }
+}
+
+/// The source of a package such as crates.io.
+#[derive(Clone, Serialize, Deserialize, Debug, PartialEq, Eq)]
+#[serde(transparent)]
+pub struct Source {
+ /// The underlying string representation of a source.
+ pub repr: String,
+}
+
+impl Source {
+ /// Returns true if the source is crates.io.
+ pub fn is_crates_io(&self) -> bool {
+ self.repr == "registry+https://github.com/rust-lang/crates.io-index"
+ }
+}
+
+impl std::fmt::Display for Source {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ fmt::Display::fmt(&self.repr, f)
+ }
+}
+
+#[derive(Clone, Serialize, Deserialize, Debug, PartialEq, Eq, Hash)]
+#[cfg_attr(feature = "builder", derive(Builder))]
+#[cfg_attr(feature = "builder", builder(pattern = "owned", setter(into)))]
+#[non_exhaustive]
+/// A single target (lib, bin, example, ...) provided by a crate
+pub struct Target {
+ /// Name as given in the `Cargo.toml` or generated from the file name
+ pub name: String,
+ /// Kind of target ("bin", "example", "test", "bench", "lib")
+ pub kind: Vec<String>,
+ /// 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)]
+ #[cfg_attr(feature = "builder", builder(default))]
+ pub crate_types: Vec<String>,
+
+ #[serde(default)]
+ #[cfg_attr(feature = "builder", builder(default))]
+ #[serde(rename = "required-features")]
+ /// This target is built only if these features are enabled.
+ /// It doesn't apply to `lib` targets.
+ pub required_features: Vec<String>,
+ /// Path to the main source file of the target
+ pub src_path: Utf8PathBuf,
+ /// Rust edition for this target
+ #[serde(default = "edition_default")]
+ #[cfg_attr(feature = "builder", builder(default = "edition_default()"))]
+ pub edition: String,
+ /// Whether or not this target has doc tests enabled, and the target is
+ /// compatible with doc testing.
+ ///
+ /// This is always `true` if running with a version of Cargo older than 1.37.
+ #[serde(default = "default_true")]
+ #[cfg_attr(feature = "builder", builder(default = "true"))]
+ pub doctest: bool,
+ /// Whether or not this target is tested by default by `cargo test`.
+ ///
+ /// This is always `true` if running with a version of Cargo older than 1.47.
+ #[serde(default = "default_true")]
+ #[cfg_attr(feature = "builder", builder(default = "true"))]
+ pub test: bool,
+ /// Whether or not this target is documented by `cargo doc`.
+ ///
+ /// This is always `true` if running with a version of Cargo older than 1.50.
+ #[serde(default = "default_true")]
+ #[cfg_attr(feature = "builder", builder(default = "true"))]
+ pub doc: bool,
+}
+
+fn default_true() -> bool {
+ true
+}
+
+fn edition_default() -> String {
+ "2015".to_string()
+}
+
+/// Cargo features flags
+#[derive(Debug, Clone)]
+pub enum CargoOpt {
+ /// Run cargo with `--features-all`
+ AllFeatures,
+ /// Run cargo with `--no-default-features`
+ NoDefaultFeatures,
+ /// Run cargo with `--features <FEATURES>`
+ SomeFeatures(Vec<String>),
+}
+
+/// A builder for configurating `cargo metadata` invocation.
+#[derive(Debug, Clone, Default)]
+pub struct MetadataCommand {
+ /// Path to `cargo` executable. If not set, this will use the
+ /// the `$CARGO` environment variable, and if that is not set, will
+ /// simply be `cargo`.
+ cargo_path: Option<PathBuf>,
+ /// Path to `Cargo.toml`
+ manifest_path: Option<PathBuf>,
+ /// Current directory of the `cargo metadata` process.
+ current_dir: Option<PathBuf>,
+ /// Output information only about the root package and don't fetch dependencies.
+ no_deps: bool,
+ /// Collections of `CargoOpt::SomeFeatures(..)`
+ features: Vec<String>,
+ /// Latched `CargoOpt::AllFeatures`
+ all_features: bool,
+ /// Latched `CargoOpt::NoDefaultFeatures`
+ no_default_features: bool,
+ /// Arbitrary command line flags to pass to `cargo`. These will be added
+ /// to the end of the command line invocation.
+ other_options: Vec<String>,
+}
+
+impl MetadataCommand {
+ /// Creates a default `cargo metadata` command, which will look for
+ /// `Cargo.toml` in the ancestors of the current directory.
+ pub fn new() -> MetadataCommand {
+ MetadataCommand::default()
+ }
+ /// Path to `cargo` executable. If not set, this will use the
+ /// the `$CARGO` environment variable, and if that is not set, will
+ /// simply be `cargo`.
+ pub fn cargo_path(&mut self, path: impl Into<PathBuf>) -> &mut MetadataCommand {
+ self.cargo_path = Some(path.into());
+ self
+ }
+ /// Path to `Cargo.toml`
+ pub fn manifest_path(&mut self, path: impl Into<PathBuf>) -> &mut MetadataCommand {
+ self.manifest_path = Some(path.into());
+ self
+ }
+ /// Current directory of the `cargo metadata` process.
+ pub fn current_dir(&mut self, path: impl Into<PathBuf>) -> &mut MetadataCommand {
+ self.current_dir = Some(path.into());
+ self
+ }
+ /// Output information only about the root package and don't fetch dependencies.
+ pub fn no_deps(&mut self) -> &mut MetadataCommand {
+ self.no_deps = true;
+ self
+ }
+ /// Which features to include.
+ ///
+ /// Call this multiple times to specify advanced feature configurations:
+ ///
+ /// ```no_run
+ /// # use cargo_metadata::{CargoOpt, MetadataCommand};
+ /// MetadataCommand::new()
+ /// .features(CargoOpt::NoDefaultFeatures)
+ /// .features(CargoOpt::SomeFeatures(vec!["feat1".into(), "feat2".into()]))
+ /// .features(CargoOpt::SomeFeatures(vec!["feat3".into()]))
+ /// // ...
+ /// # ;
+ /// ```
+ ///
+ /// # Panics
+ ///
+ /// `cargo metadata` rejects multiple `--no-default-features` flags. Similarly, the `features()`
+ /// method panics when specifying multiple `CargoOpt::NoDefaultFeatures`:
+ ///
+ /// ```should_panic
+ /// # use cargo_metadata::{CargoOpt, MetadataCommand};
+ /// MetadataCommand::new()
+ /// .features(CargoOpt::NoDefaultFeatures)
+ /// .features(CargoOpt::NoDefaultFeatures) // <-- panic!
+ /// // ...
+ /// # ;
+ /// ```
+ ///
+ /// The method also panics for multiple `CargoOpt::AllFeatures` arguments:
+ ///
+ /// ```should_panic
+ /// # use cargo_metadata::{CargoOpt, MetadataCommand};
+ /// MetadataCommand::new()
+ /// .features(CargoOpt::AllFeatures)
+ /// .features(CargoOpt::AllFeatures) // <-- panic!
+ /// // ...
+ /// # ;
+ /// ```
+ pub fn features(&mut self, features: CargoOpt) -> &mut MetadataCommand {
+ match features {
+ CargoOpt::SomeFeatures(features) => self.features.extend(features),
+ CargoOpt::NoDefaultFeatures => {
+ assert!(
+ !self.no_default_features,
+ "Do not supply CargoOpt::NoDefaultFeatures more than once!"
+ );
+ self.no_default_features = true;
+ }
+ CargoOpt::AllFeatures => {
+ assert!(
+ !self.all_features,
+ "Do not supply CargoOpt::AllFeatures more than once!"
+ );
+ self.all_features = true;
+ }
+ }
+ self
+ }
+ /// Arbitrary command line flags to pass to `cargo`. These will be added
+ /// to the end of the command line invocation.
+ pub fn other_options(&mut self, options: impl Into<Vec<String>>) -> &mut MetadataCommand {
+ self.other_options = options.into();
+ self
+ }
+
+ /// Builds a command for `cargo metadata`. This is the first
+ /// part of the work of `exec`.
+ pub fn cargo_command(&self) -> Command {
+ let cargo = self
+ .cargo_path
+ .clone()
+ .or_else(|| env::var("CARGO").map(PathBuf::from).ok())
+ .unwrap_or_else(|| PathBuf::from("cargo"));
+ let mut cmd = Command::new(cargo);
+ cmd.args(&["metadata", "--format-version", "1"]);
+
+ if self.no_deps {
+ cmd.arg("--no-deps");
+ }
+
+ if let Some(path) = self.current_dir.as_ref() {
+ cmd.current_dir(path);
+ }
+
+ if !self.features.is_empty() {
+ cmd.arg("--features").arg(self.features.join(","));
+ }
+ if self.all_features {
+ cmd.arg("--all-features");
+ }
+ if self.no_default_features {
+ cmd.arg("--no-default-features");
+ }
+
+ if let Some(manifest_path) = &self.manifest_path {
+ cmd.arg("--manifest-path").arg(manifest_path.as_os_str());
+ }
+ cmd.args(&self.other_options);
+
+ cmd
+ }
+
+ /// Parses `cargo metadata` output. `data` must have been
+ /// produced by a command built with `cargo_command`.
+ pub fn parse<T: AsRef<str>>(data: T) -> Result<Metadata> {
+ let meta = serde_json::from_str(data.as_ref())?;
+ Ok(meta)
+ }
+
+ /// Runs configured `cargo metadata` and returns parsed `Metadata`.
+ pub fn exec(&self) -> Result<Metadata> {
+ let output = self.cargo_command().output()?;
+ if !output.status.success() {
+ return Err(Error::CargoMetadata {
+ stderr: String::from_utf8(output.stderr)?,
+ });
+ }
+ let stdout = from_utf8(&output.stdout)?
+ .lines()
+ .find(|line| line.starts_with('{'))
+ .ok_or_else(|| Error::NoJson)?;
+ Self::parse(stdout)
+ }
+}
diff --git a/third_party/rust/cargo_metadata/src/messages.rs b/third_party/rust/cargo_metadata/src/messages.rs
new file mode 100644
index 0000000000..a52cde1690
--- /dev/null
+++ b/third_party/rust/cargo_metadata/src/messages.rs
@@ -0,0 +1,165 @@
+use super::{Diagnostic, PackageId, Target};
+use camino::Utf8PathBuf;
+#[cfg(feature = "builder")]
+use derive_builder::Builder;
+use serde::{Deserialize, Serialize};
+use std::fmt;
+use std::io::{self, BufRead, Lines, Read};
+
+/// Profile settings used to determine which compiler flags to use for a
+/// target.
+#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Hash)]
+#[cfg_attr(feature = "builder", derive(Builder))]
+#[non_exhaustive]
+#[cfg_attr(feature = "builder", builder(pattern = "owned", setter(into)))]
+pub struct ArtifactProfile {
+ /// Optimization level. Possible values are 0-3, s or z.
+ pub opt_level: String,
+ /// The amount of debug info. 0 for none, 1 for limited, 2 for full
+ pub debuginfo: Option<u32>,
+ /// 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,
+}
+
+/// A compiler-generated file.
+#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Hash)]
+#[cfg_attr(feature = "builder", derive(Builder))]
+#[non_exhaustive]
+#[cfg_attr(feature = "builder", builder(pattern = "owned", setter(into)))]
+pub struct Artifact {
+ /// The package this artifact belongs to
+ pub package_id: PackageId,
+ /// The target this artifact was compiled for
+ pub target: Target,
+ /// The profile this artifact was compiled with
+ pub profile: ArtifactProfile,
+ /// The enabled features for this artifact
+ pub features: Vec<String>,
+ /// The full paths to the generated artifacts
+ /// (e.g. binary file and separate debug info)
+ pub filenames: Vec<Utf8PathBuf>,
+ /// Path to the executable file
+ pub executable: Option<Utf8PathBuf>,
+ /// If true, then the files were already generated
+ pub fresh: bool,
+}
+
+/// Message left by the compiler
+// TODO: Better name. This one comes from machine_message.rs
+#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Hash)]
+#[cfg_attr(feature = "builder", derive(Builder))]
+#[non_exhaustive]
+#[cfg_attr(feature = "builder", builder(pattern = "owned", setter(into)))]
+pub struct CompilerMessage {
+ /// The package this message belongs to
+ pub package_id: PackageId,
+ /// The target this message is aimed at
+ pub target: Target,
+ /// The message the compiler sent.
+ pub message: Diagnostic,
+}
+
+/// Output of a build script execution.
+#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Hash)]
+#[cfg_attr(feature = "builder", derive(Builder))]
+#[non_exhaustive]
+#[cfg_attr(feature = "builder", builder(pattern = "owned", setter(into)))]
+pub struct BuildScript {
+ /// The package this build script execution belongs to
+ pub package_id: PackageId,
+ /// The libs to link
+ pub linked_libs: Vec<Utf8PathBuf>,
+ /// The paths to search when resolving libs
+ pub linked_paths: Vec<Utf8PathBuf>,
+ /// Various `--cfg` flags to pass to the compiler
+ pub cfgs: Vec<String>,
+ /// The environment variables to add to the compilation
+ pub env: Vec<(String, String)>,
+ /// The `OUT_DIR` environment variable where this script places its output
+ ///
+ /// Added in Rust 1.41.
+ #[serde(default)]
+ pub out_dir: Utf8PathBuf,
+}
+
+/// Final result of a build.
+#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Hash)]
+#[cfg_attr(feature = "builder", derive(Builder))]
+#[non_exhaustive]
+#[cfg_attr(feature = "builder", builder(pattern = "owned", setter(into)))]
+pub struct BuildFinished {
+ /// Whether or not the build finished successfully.
+ pub success: bool,
+}
+
+/// A cargo message
+#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Hash)]
+#[non_exhaustive]
+#[serde(tag = "reason", rename_all = "kebab-case")]
+pub enum Message {
+ /// The compiler generated an artifact
+ CompilerArtifact(Artifact),
+ /// The compiler wants to display a message
+ CompilerMessage(CompilerMessage),
+ /// A build script successfully executed.
+ BuildScriptExecuted(BuildScript),
+ /// The build has finished.
+ ///
+ /// This is emitted at the end of the build as the last message.
+ /// Added in Rust 1.44.
+ BuildFinished(BuildFinished),
+ /// A line of text which isn't a cargo or compiler message.
+ /// Line separator is not included
+ #[serde(skip)]
+ TextLine(String),
+}
+
+impl Message {
+ /// Creates an iterator of Message from a Read outputting a stream of JSON
+ /// messages. For usage information, look at the top-level documentation.
+ pub fn parse_stream<R: BufRead>(input: R) -> MessageIter<R> {
+ MessageIter {
+ lines: input.lines(),
+ }
+ }
+}
+
+impl fmt::Display for CompilerMessage {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ write!(f, "{}", self.message)
+ }
+}
+
+/// An iterator of Messages.
+pub struct MessageIter<R> {
+ lines: Lines<R>,
+}
+
+impl<R: BufRead> Iterator for MessageIter<R> {
+ type Item = io::Result<Message>;
+ fn next(&mut self) -> Option<Self::Item> {
+ let line = self.lines.next()?;
+ let message = line.map(|it| {
+ let mut deserializer = serde_json::Deserializer::from_str(&it);
+ deserializer.disable_recursion_limit();
+ Message::deserialize(&mut deserializer).unwrap_or(Message::TextLine(it))
+ });
+ Some(message)
+ }
+}
+
+/// An iterator of Message.
+type MessageIterator<R> =
+ serde_json::StreamDeserializer<'static, serde_json::de::IoRead<R>, Message>;
+
+/// Creates an iterator of Message from a Read outputting a stream of JSON
+/// messages. For usage information, look at the top-level documentation.
+#[deprecated(note = "Use Message::parse_stream instead")]
+pub fn parse_messages<R: Read>(input: R) -> MessageIterator<R> {
+ serde_json::Deserializer::from_reader(input).into_iter::<Message>()
+}