cargo_subcommand/
manifest.rs1use serde::Deserialize;
2use std::{
3 collections::HashMap,
4 path::{Path, PathBuf},
5};
6
7use crate::error::{Error, Result};
8use crate::utils;
9
10#[derive(Clone, Debug, Deserialize)]
11pub struct Manifest {
12 pub workspace: Option<Workspace>,
13 pub package: Option<Package>,
14 pub lib: Option<Lib>,
15 #[serde(default, rename = "bin")]
16 pub bins: Vec<Bin>,
17 #[serde(default, rename = "example")]
18 pub examples: Vec<Example>,
19}
20
21impl Manifest {
22 pub fn parse_from_toml(path: &Path) -> Result<Self> {
23 let contents = std::fs::read_to_string(path).map_err(|e| Error::Io(path.to_owned(), e))?;
24 toml::from_str(&contents).map_err(|e| Error::Toml(path.to_owned(), e))
25 }
26
27 pub fn members(&self, workspace_root: &Path) -> Result<HashMap<PathBuf, (PathBuf, Manifest)>> {
29 let workspace = self
30 .workspace
31 .as_ref()
32 .ok_or(Error::ManifestNotAWorkspace)?;
33 let workspace_root = utils::canonicalize(workspace_root)?;
34
35 let mut all_members = HashMap::new();
37
38 for member in &workspace.members {
39 for manifest_dir in glob::glob(workspace_root.join(member).to_str().unwrap())? {
40 let manifest_dir = manifest_dir?;
41 let manifest_path = manifest_dir.join("Cargo.toml");
42 let manifest = Manifest::parse_from_toml(&manifest_path)?;
43
44 if manifest.workspace.is_some() {
46 return Err(Error::UnexpectedWorkspace(manifest_path));
47 }
48
49 if manifest.package.is_none() {
52 return Err(Error::NoPackageInManifest(manifest_path));
53 }
54
55 all_members.insert(manifest_dir, (manifest_path, manifest));
56 }
57 }
58
59 Ok(all_members)
60 }
61
62 pub fn map_nonvirtual_package(
65 self,
66 manifest_path: PathBuf,
67 name: Option<&str>,
68 ) -> Result<(PathBuf, Self)> {
69 if self.workspace.is_some() {
70 return Err(Error::UnexpectedWorkspace(manifest_path));
71 }
72
73 if let Some(package) = &self.package {
74 if let Some(name) = name {
75 if package.name == name {
76 Ok((manifest_path, self))
77 } else {
78 Err(Error::PackageNotFound(manifest_path, name.into()))
79 }
80 } else {
81 Ok((manifest_path, self))
82 }
83 } else {
84 Err(Error::NoPackageInManifest(manifest_path))
85 }
86 }
87}
88
89#[derive(Clone, Debug, Deserialize)]
90#[serde(rename_all = "kebab-case")]
91pub struct Workspace {
92 #[serde(default)]
93 pub default_members: Vec<String>,
94 #[serde(default)]
95 pub members: Vec<String>,
96}
97
98const fn default_true() -> bool {
99 true
100}
101
102#[derive(Clone, Debug, Deserialize)]
103pub struct Package {
104 pub name: String,
105
106 #[serde(default = "default_true")]
108 pub autobins: bool,
109 #[serde(default = "default_true")]
110 pub autoexamples: bool,
111 }
116
117#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, Deserialize)]
118pub enum CrateType {
119 Bin,
120 Lib,
121 Staticlib,
122 Cdylib,
123}
124
125#[derive(Clone, Debug, Deserialize)]
126pub struct Lib {
127 pub name: Option<String>,
128 pub path: Option<PathBuf>,
129 }
131
132#[derive(Clone, Debug, Deserialize)]
133pub struct Bin {
134 pub name: String,
135 pub path: Option<PathBuf>,
136 }
138
139#[derive(Clone, Debug, Deserialize)]
140pub struct Example {
141 pub name: String,
142 pub path: Option<PathBuf>,
143 }