crate_metadata/
lib.rs

1#![cfg(not(doctest))]
2/*!
3	__For usage from build-script.__
4
5	Utility functions that returns current crate metadata
6	as result of call `cargo metadata`.
7*/
8
9use std::env;
10use std::path::{Path, PathBuf};
11use std::io::{Error as IoError, ErrorKind as IoErrorKind};
12use std::process::Command;
13
14pub use model::*;
15mod model;
16
17type Error = Box<dyn std::error::Error>;
18type Result<T = (), E = self::Error> = std::result::Result<T, E>;
19
20const CARGO_MANIFEST: &str = "Cargo.toml";
21const CARGO_MANIFEST_DIR: &str = "CARGO_MANIFEST_DIR";
22const CARGO_PKG_NAME: &str = "CARGO_PKG_NAME";
23
24
25/// Cargo metadata for caller crate.
26/// Without other packages if it's in a workspace.
27/// Caller crate means crate that currently building.
28pub fn crate_metadata<Metadata>() -> Result<CargoMetadata<Metadata>>
29	where for<'de> Metadata: serde::de::Deserialize<'de> {
30	let path =
31		PathBuf::from(env::var_os(CARGO_MANIFEST_DIR).ok_or(IoError::new(IoErrorKind::NotFound, CARGO_MANIFEST_DIR))?).join(CARGO_MANIFEST);
32	let name = env::var(CARGO_PKG_NAME).unwrap();
33	crate_metadata_for(path, &name)
34}
35
36/// Cargo metadata for caller crate with other packages that in workspace.
37/// Caller crate means crate that currently building.
38pub fn cargo_metadata<Metadata>() -> Result<CargoMetadata<Metadata>>
39	where for<'de> Metadata: serde::de::Deserialize<'de> {
40	let path =
41		PathBuf::from(env::var_os(CARGO_MANIFEST_DIR).ok_or(IoError::new(IoErrorKind::NotFound, CARGO_MANIFEST_DIR))?).join(CARGO_MANIFEST);
42	cargo_metadata_for(path)
43}
44
45
46/// Cargo metadata for specified manifest path,
47/// filtered for specified crate name.
48/// That means that there is only one packages should be, with name end path eq specified.
49///
50/// ```
51/// let path = PathBuf::from(env::var_os("CARGO_MANIFEST_DIR").unwrap()).join("Cargo.toml");
52/// let name = env::var("CARGO_PKG_NAME").unwrap();
53/// let metadata = meta::crate_metadata_for::<Metadata, _>(&path, &name)?;
54/// ```
55pub fn crate_metadata_for<Metadata, P: AsRef<Path>>(manifest: P, name: &str) -> Result<CargoMetadata<Metadata>>
56	where for<'de> Metadata: serde::de::Deserialize<'de> {
57	let mut metadata: CargoMetadata<Metadata> = cargo_metadata_for(&manifest)?;
58	metadata.packages = metadata.packages.into_iter().filter(|p| p.name == name).collect();
59
60	Ok(metadata)
61}
62
63
64/// Cargo metadata for specified manifest path.
65///
66/// ```
67/// let path = PathBuf::from(env::var_os("CARGO_MANIFEST_DIR").unwrap()).join("Cargo.toml");
68/// let metadata = meta::cargo_metadata_for::<Metadata, _>(&path)?;
69/// ```
70pub fn cargo_metadata_for<Metadata, P: AsRef<Path>>(manifest: P) -> Result<CargoMetadata<Metadata>>
71	where for<'de> Metadata: serde::de::Deserialize<'de> {
72	let manifest_path_str = manifest.as_ref()
73	                                .to_str()
74	                                .ok_or(IoError::new(IoErrorKind::InvalidInput, CARGO_MANIFEST))?;
75	let args = [
76	            "metadata",
77	            "--offline",
78	            "--locked",
79	            "--frozen",
80	            "--no-deps",
81	            "--format-version=1",
82	            "--manifest-path",
83	            manifest_path_str,
84	];
85
86	let cargo = env::var("CARGO").ok().unwrap_or("cargo".to_string());
87	let metadata_json_raw = Command::new(cargo).args(&args).output()?;
88	let stdout = std::str::from_utf8(&metadata_json_raw.stdout)?;
89
90	serde_json::from_str(stdout).map_err(Into::into)
91}