PageRenderTime 25ms CodeModel.GetById 16ms RepoModel.GetById 0ms app.codeStats 0ms

/third_party/rust/cargo_metadata/v0_14/crate/src/lib.rs

https://github.com/chromium/chromium
Rust | 641 lines | 316 code | 39 blank | 286 comment | 13 complexity | 4fc7c7192c7cd7a68cd203dbc9ac73c6 MD5 | raw file
Possible License(s): MPL-2.0-no-copyleft-exception, Apache-2.0, BSD-3-Clause
  1. #![deny(missing_docs)]
  2. //! Structured access to the output of `cargo metadata` and `cargo --message-format=json`.
  3. //! Usually used from within a `cargo-*` executable
  4. //!
  5. //! See the [cargo book](https://doc.rust-lang.org/cargo/index.html) for
  6. //! details on cargo itself.
  7. //!
  8. //! ## Examples
  9. //!
  10. //! ```rust
  11. //! # extern crate cargo_metadata;
  12. //! # use std::path::Path;
  13. //! let mut args = std::env::args().skip_while(|val| !val.starts_with("--manifest-path"));
  14. //!
  15. //! let mut cmd = cargo_metadata::MetadataCommand::new();
  16. //! let manifest_path = match args.next() {
  17. //! Some(ref p) if p == "--manifest-path" => {
  18. //! cmd.manifest_path(args.next().unwrap());
  19. //! }
  20. //! Some(p) => {
  21. //! cmd.manifest_path(p.trim_start_matches("--manifest-path="));
  22. //! }
  23. //! None => {}
  24. //! };
  25. //!
  26. //! let _metadata = cmd.exec().unwrap();
  27. //! ```
  28. //!
  29. //! Pass features flags
  30. //!
  31. //! ```rust
  32. //! # // This should be kept in sync with the equivalent example in the readme.
  33. //! # extern crate cargo_metadata;
  34. //! # use std::path::Path;
  35. //! # fn main() {
  36. //! use cargo_metadata::{MetadataCommand, CargoOpt};
  37. //!
  38. //! let _metadata = MetadataCommand::new()
  39. //! .manifest_path("./Cargo.toml")
  40. //! .features(CargoOpt::AllFeatures)
  41. //! .exec()
  42. //! .unwrap();
  43. //! # }
  44. //! ```
  45. //!
  46. //! Parse message-format output:
  47. //!
  48. //! ```
  49. //! # extern crate cargo_metadata;
  50. //! use std::process::{Stdio, Command};
  51. //! use cargo_metadata::Message;
  52. //!
  53. //! let mut command = Command::new("cargo")
  54. //! .args(&["build", "--message-format=json-render-diagnostics"])
  55. //! .stdout(Stdio::piped())
  56. //! .spawn()
  57. //! .unwrap();
  58. //!
  59. //! let reader = std::io::BufReader::new(command.stdout.take().unwrap());
  60. //! for message in cargo_metadata::Message::parse_stream(reader) {
  61. //! match message.unwrap() {
  62. //! Message::CompilerMessage(msg) => {
  63. //! println!("{:?}", msg);
  64. //! },
  65. //! Message::CompilerArtifact(artifact) => {
  66. //! println!("{:?}", artifact);
  67. //! },
  68. //! Message::BuildScriptExecuted(script) => {
  69. //! println!("{:?}", script);
  70. //! },
  71. //! Message::BuildFinished(finished) => {
  72. //! println!("{:?}", finished);
  73. //! },
  74. //! _ => () // Unknown message
  75. //! }
  76. //! }
  77. //!
  78. //! let output = command.wait().expect("Couldn't get cargo's exit status");
  79. //! ```
  80. use camino::Utf8PathBuf;
  81. #[cfg(feature = "builder")]
  82. use derive_builder::Builder;
  83. use std::collections::HashMap;
  84. use std::env;
  85. use std::fmt;
  86. use std::path::PathBuf;
  87. use std::process::Command;
  88. use std::str::from_utf8;
  89. pub use camino;
  90. pub use semver::{Version, VersionReq};
  91. pub use dependency::{Dependency, DependencyKind};
  92. use diagnostic::Diagnostic;
  93. pub use errors::{Error, Result};
  94. #[allow(deprecated)]
  95. pub use messages::parse_messages;
  96. pub use messages::{
  97. Artifact, ArtifactProfile, BuildFinished, BuildScript, CompilerMessage, Message, MessageIter,
  98. };
  99. use serde::{Deserialize, Serialize};
  100. mod dependency;
  101. pub mod diagnostic;
  102. mod errors;
  103. mod messages;
  104. /// An "opaque" identifier for a package.
  105. /// It is possible to inspect the `repr` field, if the need arises, but its
  106. /// precise format is an implementation detail and is subject to change.
  107. ///
  108. /// `Metadata` can be indexed by `PackageId`.
  109. #[derive(Clone, Serialize, Deserialize, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
  110. #[serde(transparent)]
  111. pub struct PackageId {
  112. /// The underlying string representation of id.
  113. pub repr: String,
  114. }
  115. impl std::fmt::Display for PackageId {
  116. fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
  117. fmt::Display::fmt(&self.repr, f)
  118. }
  119. }
  120. // Helpers for default metadata fields
  121. fn is_null(value: &serde_json::Value) -> bool {
  122. match value {
  123. serde_json::Value::Null => true,
  124. _ => false,
  125. }
  126. }
  127. #[derive(Clone, Serialize, Deserialize, Debug)]
  128. #[cfg_attr(feature = "builder", derive(Builder))]
  129. #[non_exhaustive]
  130. #[cfg_attr(feature = "builder", builder(pattern = "owned", setter(into)))]
  131. /// Starting point for metadata returned by `cargo metadata`
  132. pub struct Metadata {
  133. /// A list of all crates referenced by this crate (and the crate itself)
  134. pub packages: Vec<Package>,
  135. /// A list of all workspace members
  136. pub workspace_members: Vec<PackageId>,
  137. /// Dependencies graph
  138. pub resolve: Option<Resolve>,
  139. /// Workspace root
  140. pub workspace_root: Utf8PathBuf,
  141. /// Build directory
  142. pub target_directory: Utf8PathBuf,
  143. /// The workspace-level metadata object. Null if non-existent.
  144. #[serde(rename = "metadata", default, skip_serializing_if = "is_null")]
  145. pub workspace_metadata: serde_json::Value,
  146. /// The metadata format version
  147. version: usize,
  148. }
  149. impl Metadata {
  150. /// Get the root package of this metadata instance.
  151. pub fn root_package(&self) -> Option<&Package> {
  152. let root = self.resolve.as_ref()?.root.as_ref()?;
  153. self.packages.iter().find(|pkg| &pkg.id == root)
  154. }
  155. }
  156. impl<'a> std::ops::Index<&'a PackageId> for Metadata {
  157. type Output = Package;
  158. fn index(&self, idx: &'a PackageId) -> &Package {
  159. self.packages
  160. .iter()
  161. .find(|p| p.id == *idx)
  162. .unwrap_or_else(|| panic!("no package with this id: {:?}", idx))
  163. }
  164. }
  165. #[derive(Clone, Serialize, Deserialize, Debug)]
  166. #[cfg_attr(feature = "builder", derive(Builder))]
  167. #[non_exhaustive]
  168. #[cfg_attr(feature = "builder", builder(pattern = "owned", setter(into)))]
  169. /// A dependency graph
  170. pub struct Resolve {
  171. /// Nodes in a dependencies graph
  172. pub nodes: Vec<Node>,
  173. /// The crate for which the metadata was read.
  174. pub root: Option<PackageId>,
  175. }
  176. #[derive(Clone, Serialize, Deserialize, Debug)]
  177. #[cfg_attr(feature = "builder", derive(Builder))]
  178. #[non_exhaustive]
  179. #[cfg_attr(feature = "builder", builder(pattern = "owned", setter(into)))]
  180. /// A node in a dependencies graph
  181. pub struct Node {
  182. /// An opaque identifier for a package
  183. pub id: PackageId,
  184. /// Dependencies in a structured format.
  185. ///
  186. /// `deps` handles renamed dependencies whereas `dependencies` does not.
  187. #[serde(default)]
  188. pub deps: Vec<NodeDep>,
  189. /// List of opaque identifiers for this node's dependencies.
  190. /// It doesn't support renamed dependencies. See `deps`.
  191. pub dependencies: Vec<PackageId>,
  192. /// Features enabled on the crate
  193. #[serde(default)]
  194. pub features: Vec<String>,
  195. }
  196. #[derive(Clone, Serialize, Deserialize, Debug)]
  197. #[cfg_attr(feature = "builder", derive(Builder))]
  198. #[non_exhaustive]
  199. #[cfg_attr(feature = "builder", builder(pattern = "owned", setter(into)))]
  200. /// A dependency in a node
  201. pub struct NodeDep {
  202. /// The name of the dependency's library target.
  203. /// If the crate was renamed, it is the new name.
  204. pub name: String,
  205. /// Package ID (opaque unique identifier)
  206. pub pkg: PackageId,
  207. /// The kinds of dependencies.
  208. ///
  209. /// This field was added in Rust 1.41.
  210. #[serde(default)]
  211. pub dep_kinds: Vec<DepKindInfo>,
  212. }
  213. #[derive(Clone, Serialize, Deserialize, Debug)]
  214. #[cfg_attr(feature = "builder", derive(Builder))]
  215. #[non_exhaustive]
  216. #[cfg_attr(feature = "builder", builder(pattern = "owned", setter(into)))]
  217. /// Information about a dependency kind.
  218. pub struct DepKindInfo {
  219. /// The kind of dependency.
  220. #[serde(deserialize_with = "dependency::parse_dependency_kind")]
  221. pub kind: DependencyKind,
  222. /// The target platform for the dependency.
  223. ///
  224. /// This is `None` if it is not a target dependency.
  225. ///
  226. /// Use the [`Display`] trait to access the contents.
  227. ///
  228. /// By default all platform dependencies are included in the resolve
  229. /// graph. Use Cargo's `--filter-platform` flag if you only want to
  230. /// include dependencies for a specific platform.
  231. ///
  232. /// [`Display`]: std::fmt::Display
  233. pub target: Option<dependency::Platform>,
  234. }
  235. #[derive(Clone, Serialize, Deserialize, Debug, PartialEq, Eq)]
  236. #[cfg_attr(feature = "builder", derive(Builder))]
  237. #[non_exhaustive]
  238. #[cfg_attr(feature = "builder", builder(pattern = "owned", setter(into)))]
  239. /// One or more crates described by a single `Cargo.toml`
  240. ///
  241. /// Each [`target`][Package::targets] of a `Package` will be built as a crate.
  242. /// For more information, see <https://doc.rust-lang.org/book/ch07-01-packages-and-crates.html>.
  243. pub struct Package {
  244. /// Name as given in the `Cargo.toml`
  245. pub name: String,
  246. /// Version given in the `Cargo.toml`
  247. pub version: Version,
  248. /// Authors given in the `Cargo.toml`
  249. #[serde(default)]
  250. pub authors: Vec<String>,
  251. /// An opaque identifier for a package
  252. pub id: PackageId,
  253. /// The source of the package, e.g.
  254. /// crates.io or `None` for local projects.
  255. pub source: Option<Source>,
  256. /// Description as given in the `Cargo.toml`
  257. pub description: Option<String>,
  258. /// List of dependencies of this particular package
  259. pub dependencies: Vec<Dependency>,
  260. /// License as given in the `Cargo.toml`
  261. pub license: Option<String>,
  262. /// If the package is using a nonstandard license, this key may be specified instead of
  263. /// `license`, and must point to a file relative to the manifest.
  264. pub license_file: Option<Utf8PathBuf>,
  265. /// Targets provided by the crate (lib, bin, example, test, ...)
  266. pub targets: Vec<Target>,
  267. /// Features provided by the crate, mapped to the features required by that feature.
  268. pub features: HashMap<String, Vec<String>>,
  269. /// Path containing the `Cargo.toml`
  270. pub manifest_path: Utf8PathBuf,
  271. /// Categories as given in the `Cargo.toml`
  272. #[serde(default)]
  273. pub categories: Vec<String>,
  274. /// Keywords as given in the `Cargo.toml`
  275. #[serde(default)]
  276. pub keywords: Vec<String>,
  277. /// Readme as given in the `Cargo.toml`
  278. pub readme: Option<Utf8PathBuf>,
  279. /// Repository as given in the `Cargo.toml`
  280. // can't use `url::Url` because that requires a more recent stable compiler
  281. pub repository: Option<String>,
  282. /// Homepage as given in the `Cargo.toml`
  283. ///
  284. /// On versions of cargo before 1.49, this will always be [`None`].
  285. pub homepage: Option<String>,
  286. /// Documentation URL as given in the `Cargo.toml`
  287. ///
  288. /// On versions of cargo before 1.49, this will always be [`None`].
  289. pub documentation: Option<String>,
  290. /// Default Rust edition for the package
  291. ///
  292. /// Beware that individual targets may specify their own edition in
  293. /// [`Target::edition`].
  294. #[serde(default = "edition_default")]
  295. pub edition: String,
  296. /// Contents of the free form package.metadata section
  297. ///
  298. /// This contents can be serialized to a struct using serde:
  299. ///
  300. /// ```rust
  301. /// use serde::Deserialize;
  302. /// use serde_json::json;
  303. ///
  304. /// #[derive(Debug, Deserialize)]
  305. /// struct SomePackageMetadata {
  306. /// some_value: i32,
  307. /// }
  308. ///
  309. /// fn main() {
  310. /// let value = json!({
  311. /// "some_value": 42,
  312. /// });
  313. ///
  314. /// let package_metadata: SomePackageMetadata = serde_json::from_value(value).unwrap();
  315. /// assert_eq!(package_metadata.some_value, 42);
  316. /// }
  317. ///
  318. /// ```
  319. #[serde(default, skip_serializing_if = "is_null")]
  320. pub metadata: serde_json::Value,
  321. /// The name of a native library the package is linking to.
  322. pub links: Option<String>,
  323. /// List of registries to which this package may be published.
  324. ///
  325. /// Publishing is unrestricted if `None`, and forbidden if the `Vec` is empty.
  326. ///
  327. /// This is always `None` if running with a version of Cargo older than 1.39.
  328. pub publish: Option<Vec<String>>,
  329. /// The default binary to run by `cargo run`.
  330. ///
  331. /// This is always `None` if running with a version of Cargo older than 1.55.
  332. pub default_run: Option<String>,
  333. /// The minimum supported Rust version of this package.
  334. ///
  335. /// This is always `None` if running with a version of Cargo older than 1.58.
  336. pub rust_version: Option<VersionReq>,
  337. }
  338. impl Package {
  339. /// Full path to the license file if one is present in the manifest
  340. pub fn license_file(&self) -> Option<Utf8PathBuf> {
  341. self.license_file.as_ref().map(|file| {
  342. self.manifest_path
  343. .parent()
  344. .unwrap_or(&self.manifest_path)
  345. .join(file)
  346. })
  347. }
  348. /// Full path to the readme file if one is present in the manifest
  349. pub fn readme(&self) -> Option<Utf8PathBuf> {
  350. self.readme
  351. .as_ref()
  352. .map(|file| self.manifest_path.join(file))
  353. }
  354. }
  355. /// The source of a package such as crates.io.
  356. #[derive(Clone, Serialize, Deserialize, Debug, PartialEq, Eq)]
  357. #[serde(transparent)]
  358. pub struct Source {
  359. /// The underlying string representation of a source.
  360. pub repr: String,
  361. }
  362. impl Source {
  363. /// Returns true if the source is crates.io.
  364. pub fn is_crates_io(&self) -> bool {
  365. self.repr == "registry+https://github.com/rust-lang/crates.io-index"
  366. }
  367. }
  368. impl std::fmt::Display for Source {
  369. fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
  370. fmt::Display::fmt(&self.repr, f)
  371. }
  372. }
  373. #[derive(Clone, Serialize, Deserialize, Debug, PartialEq, Eq, Hash)]
  374. #[cfg_attr(feature = "builder", derive(Builder))]
  375. #[cfg_attr(feature = "builder", builder(pattern = "owned", setter(into)))]
  376. #[non_exhaustive]
  377. /// A single target (lib, bin, example, ...) provided by a crate
  378. pub struct Target {
  379. /// Name as given in the `Cargo.toml` or generated from the file name
  380. pub name: String,
  381. /// Kind of target ("bin", "example", "test", "bench", "lib")
  382. pub kind: Vec<String>,
  383. /// Almost the same as `kind`, except when an example is a library instead of an executable.
  384. /// In that case `crate_types` contains things like `rlib` and `dylib` while `kind` is `example`
  385. #[serde(default)]
  386. #[cfg_attr(feature = "builder", builder(default))]
  387. pub crate_types: Vec<String>,
  388. #[serde(default)]
  389. #[cfg_attr(feature = "builder", builder(default))]
  390. #[serde(rename = "required-features")]
  391. /// This target is built only if these features are enabled.
  392. /// It doesn't apply to `lib` targets.
  393. pub required_features: Vec<String>,
  394. /// Path to the main source file of the target
  395. pub src_path: Utf8PathBuf,
  396. /// Rust edition for this target
  397. #[serde(default = "edition_default")]
  398. #[cfg_attr(feature = "builder", builder(default = "edition_default()"))]
  399. pub edition: String,
  400. /// Whether or not this target has doc tests enabled, and the target is
  401. /// compatible with doc testing.
  402. ///
  403. /// This is always `true` if running with a version of Cargo older than 1.37.
  404. #[serde(default = "default_true")]
  405. #[cfg_attr(feature = "builder", builder(default = "true"))]
  406. pub doctest: bool,
  407. /// Whether or not this target is tested by default by `cargo test`.
  408. ///
  409. /// This is always `true` if running with a version of Cargo older than 1.47.
  410. #[serde(default = "default_true")]
  411. #[cfg_attr(feature = "builder", builder(default = "true"))]
  412. pub test: bool,
  413. /// Whether or not this target is documented by `cargo doc`.
  414. ///
  415. /// This is always `true` if running with a version of Cargo older than 1.50.
  416. #[serde(default = "default_true")]
  417. #[cfg_attr(feature = "builder", builder(default = "true"))]
  418. pub doc: bool,
  419. }
  420. fn default_true() -> bool {
  421. true
  422. }
  423. fn edition_default() -> String {
  424. "2015".to_string()
  425. }
  426. /// Cargo features flags
  427. #[derive(Debug, Clone)]
  428. pub enum CargoOpt {
  429. /// Run cargo with `--features-all`
  430. AllFeatures,
  431. /// Run cargo with `--no-default-features`
  432. NoDefaultFeatures,
  433. /// Run cargo with `--features <FEATURES>`
  434. SomeFeatures(Vec<String>),
  435. }
  436. /// A builder for configurating `cargo metadata` invocation.
  437. #[derive(Debug, Clone, Default)]
  438. pub struct MetadataCommand {
  439. /// Path to `cargo` executable. If not set, this will use the
  440. /// the `$CARGO` environment variable, and if that is not set, will
  441. /// simply be `cargo`.
  442. cargo_path: Option<PathBuf>,
  443. /// Path to `Cargo.toml`
  444. manifest_path: Option<PathBuf>,
  445. /// Current directory of the `cargo metadata` process.
  446. current_dir: Option<PathBuf>,
  447. /// Output information only about the root package and don't fetch dependencies.
  448. no_deps: bool,
  449. /// Collections of `CargoOpt::SomeFeatures(..)`
  450. features: Vec<String>,
  451. /// Latched `CargoOpt::AllFeatures`
  452. all_features: bool,
  453. /// Latched `CargoOpt::NoDefaultFeatures`
  454. no_default_features: bool,
  455. /// Arbitrary command line flags to pass to `cargo`. These will be added
  456. /// to the end of the command line invocation.
  457. other_options: Vec<String>,
  458. }
  459. impl MetadataCommand {
  460. /// Creates a default `cargo metadata` command, which will look for
  461. /// `Cargo.toml` in the ancestors of the current directory.
  462. pub fn new() -> MetadataCommand {
  463. MetadataCommand::default()
  464. }
  465. /// Path to `cargo` executable. If not set, this will use the
  466. /// the `$CARGO` environment variable, and if that is not set, will
  467. /// simply be `cargo`.
  468. pub fn cargo_path(&mut self, path: impl Into<PathBuf>) -> &mut MetadataCommand {
  469. self.cargo_path = Some(path.into());
  470. self
  471. }
  472. /// Path to `Cargo.toml`
  473. pub fn manifest_path(&mut self, path: impl Into<PathBuf>) -> &mut MetadataCommand {
  474. self.manifest_path = Some(path.into());
  475. self
  476. }
  477. /// Current directory of the `cargo metadata` process.
  478. pub fn current_dir(&mut self, path: impl Into<PathBuf>) -> &mut MetadataCommand {
  479. self.current_dir = Some(path.into());
  480. self
  481. }
  482. /// Output information only about the root package and don't fetch dependencies.
  483. pub fn no_deps(&mut self) -> &mut MetadataCommand {
  484. self.no_deps = true;
  485. self
  486. }
  487. /// Which features to include.
  488. ///
  489. /// Call this multiple times to specify advanced feature configurations:
  490. ///
  491. /// ```no_run
  492. /// # use cargo_metadata::{CargoOpt, MetadataCommand};
  493. /// MetadataCommand::new()
  494. /// .features(CargoOpt::NoDefaultFeatures)
  495. /// .features(CargoOpt::SomeFeatures(vec!["feat1".into(), "feat2".into()]))
  496. /// .features(CargoOpt::SomeFeatures(vec!["feat3".into()]))
  497. /// // ...
  498. /// # ;
  499. /// ```
  500. ///
  501. /// # Panics
  502. ///
  503. /// `cargo metadata` rejects multiple `--no-default-features` flags. Similarly, the `features()`
  504. /// method panics when specifying multiple `CargoOpt::NoDefaultFeatures`:
  505. ///
  506. /// ```should_panic
  507. /// # use cargo_metadata::{CargoOpt, MetadataCommand};
  508. /// MetadataCommand::new()
  509. /// .features(CargoOpt::NoDefaultFeatures)
  510. /// .features(CargoOpt::NoDefaultFeatures) // <-- panic!
  511. /// // ...
  512. /// # ;
  513. /// ```
  514. ///
  515. /// The method also panics for multiple `CargoOpt::AllFeatures` arguments:
  516. ///
  517. /// ```should_panic
  518. /// # use cargo_metadata::{CargoOpt, MetadataCommand};
  519. /// MetadataCommand::new()
  520. /// .features(CargoOpt::AllFeatures)
  521. /// .features(CargoOpt::AllFeatures) // <-- panic!
  522. /// // ...
  523. /// # ;
  524. /// ```
  525. pub fn features(&mut self, features: CargoOpt) -> &mut MetadataCommand {
  526. match features {
  527. CargoOpt::SomeFeatures(features) => self.features.extend(features),
  528. CargoOpt::NoDefaultFeatures => {
  529. assert!(
  530. !self.no_default_features,
  531. "Do not supply CargoOpt::NoDefaultFeatures more than once!"
  532. );
  533. self.no_default_features = true;
  534. }
  535. CargoOpt::AllFeatures => {
  536. assert!(
  537. !self.all_features,
  538. "Do not supply CargoOpt::AllFeatures more than once!"
  539. );
  540. self.all_features = true;
  541. }
  542. }
  543. self
  544. }
  545. /// Arbitrary command line flags to pass to `cargo`. These will be added
  546. /// to the end of the command line invocation.
  547. pub fn other_options(&mut self, options: impl Into<Vec<String>>) -> &mut MetadataCommand {
  548. self.other_options = options.into();
  549. self
  550. }
  551. /// Builds a command for `cargo metadata`. This is the first
  552. /// part of the work of `exec`.
  553. pub fn cargo_command(&self) -> Command {
  554. let cargo = self
  555. .cargo_path
  556. .clone()
  557. .or_else(|| env::var("CARGO").map(PathBuf::from).ok())
  558. .unwrap_or_else(|| PathBuf::from("cargo"));
  559. let mut cmd = Command::new(cargo);
  560. cmd.args(&["metadata", "--format-version", "1"]);
  561. if self.no_deps {
  562. cmd.arg("--no-deps");
  563. }
  564. if let Some(path) = self.current_dir.as_ref() {
  565. cmd.current_dir(path);
  566. }
  567. if !self.features.is_empty() {
  568. cmd.arg("--features").arg(self.features.join(","));
  569. }
  570. if self.all_features {
  571. cmd.arg("--all-features");
  572. }
  573. if self.no_default_features {
  574. cmd.arg("--no-default-features");
  575. }
  576. if let Some(manifest_path) = &self.manifest_path {
  577. cmd.arg("--manifest-path").arg(manifest_path.as_os_str());
  578. }
  579. cmd.args(&self.other_options);
  580. cmd
  581. }
  582. /// Parses `cargo metadata` output. `data` must have been
  583. /// produced by a command built with `cargo_command`.
  584. pub fn parse<T: AsRef<str>>(data: T) -> Result<Metadata> {
  585. let meta = serde_json::from_str(data.as_ref())?;
  586. Ok(meta)
  587. }
  588. /// Runs configured `cargo metadata` and returns parsed `Metadata`.
  589. pub fn exec(&self) -> Result<Metadata> {
  590. let output = self.cargo_command().output()?;
  591. if !output.status.success() {
  592. return Err(Error::CargoMetadata {
  593. stderr: String::from_utf8(output.stderr)?,
  594. });
  595. }
  596. let stdout = from_utf8(&output.stdout)?
  597. .lines()
  598. .find(|line| line.starts_with('{'))
  599. .ok_or_else(|| Error::NoJson)?;
  600. Self::parse(stdout)
  601. }
  602. }