1use crate::directory::Directory;
2use crate::error::Error;
3use crate::inherit::InheritEdition;
4use crate::manifest::Edition;
5use serde::de::value::MapAccessDeserializer;
6use serde::de::value::StrDeserializer;
7use serde::de::{self, Deserialize, Deserializer, Visitor};
8use serde::ser::{Serialize, Serializer};
9use serde_derive::{Deserialize, Serialize};
10use serde_json::Value;
11use std::collections::BTreeMap as Map;
12use std::fmt;
13use std::fs;
14use std::path::PathBuf;
15
16pub fn get_manifest(manifest_dir: &Directory) -> Result<Manifest, Error> {
17 let cargo_toml_path = manifest_dir.join("Cargo.toml");
18 let mut manifest = (|| {
19 let manifest_str = fs::read_to_string(&cargo_toml_path)?;
20 let manifest: Manifest = toml::from_str(&manifest_str)?;
21 Ok(manifest)
22 })()
23 .map_err(|err| Error::GetManifest(cargo_toml_path, Box::new(err)))?;
24
25 fix_dependencies(&mut manifest.dependencies, manifest_dir);
26 fix_dependencies(&mut manifest.dev_dependencies, manifest_dir);
27 for target in manifest.target.values_mut() {
28 fix_dependencies(&mut target.dependencies, manifest_dir);
29 fix_dependencies(&mut target.dev_dependencies, manifest_dir);
30 }
31
32 Ok(manifest)
33}
34
35pub fn get_workspace_manifest(manifest_dir: &Directory) -> WorkspaceManifest {
36 try_get_workspace_manifest(manifest_dir).unwrap_or_default()
37}
38
39pub fn try_get_workspace_manifest(
40 manifest_dir: &Directory,
41) -> Result<WorkspaceManifest, Error> {
42 let cargo_toml_path = manifest_dir.join("Cargo.toml");
43 let manifest_str = fs::read_to_string(cargo_toml_path)?;
44 let mut manifest: WorkspaceManifest = toml::from_str(&manifest_str)?;
45
46 fix_dependencies(&mut manifest.workspace.dependencies, manifest_dir);
47 fix_patches(&mut manifest.patch, manifest_dir);
48 fix_replacements(&mut manifest.replace, manifest_dir);
49
50 Ok(manifest)
51}
52
53fn fix_dependencies(dependencies: &mut Map<String, Dependency>, dir: &Directory) {
54 dependencies.remove("trybuild");
55 for dep in dependencies.values_mut() {
56 dep.path = dep.path.as_ref().map(|path| Directory::new(dir.join(path)));
57 }
58}
59
60fn fix_patches(patches: &mut Map<String, RegistryPatch>, dir: &Directory) {
61 for registry in patches.values_mut() {
62 registry.crates.remove("trybuild");
63 for patch in registry.crates.values_mut() {
64 patch.path = patch.path.as_ref().map(|path| dir.join(path));
65 }
66 }
67}
68
69fn fix_replacements(replacements: &mut Map<String, Patch>, dir: &Directory) {
70 replacements.remove("trybuild");
71 for replacement in replacements.values_mut() {
72 replacement.path = replacement.path.as_ref().map(|path| dir.join(path));
73 }
74}
75
76#[derive(Deserialize, Default, Debug)]
77pub struct WorkspaceManifest {
78 #[serde(default)]
79 pub workspace: WorkspaceWorkspace,
80 #[serde(default)]
81 pub patch: Map<String, RegistryPatch>,
82 #[serde(default)]
83 pub replace: Map<String, Patch>,
84}
85
86#[derive(Deserialize, Default, Debug)]
87pub struct WorkspaceWorkspace {
88 #[serde(default)]
89 pub package: WorkspacePackage,
90 #[serde(default)]
91 pub dependencies: Map<String, Dependency>,
92}
93
94#[derive(Deserialize, Default, Debug)]
95pub struct WorkspacePackage {
96 pub edition: Option<Edition>,
97}
98
99#[derive(Deserialize, Default, Debug)]
100pub struct Manifest {
101 #[serde(rename = "cargo-features", default)]
102 pub cargo_features: Vec<String>,
103 #[serde(default)]
104 pub package: Package,
105 #[serde(default)]
106 pub features: Map<String, Vec<String>>,
107 #[serde(default)]
108 pub dependencies: Map<String, Dependency>,
109 #[serde(default, alias = "dev-dependencies")]
110 pub dev_dependencies: Map<String, Dependency>,
111 #[serde(default)]
112 pub target: Map<String, TargetDependencies>,
113}
114
115#[derive(Deserialize, Default, Debug)]
116pub struct Package {
117 pub name: String,
118 #[serde(default)]
119 pub edition: EditionOrInherit,
120 pub resolver: Option<String>,
121}
122
123#[derive(Debug)]
124pub enum EditionOrInherit {
125 Edition(Edition),
126 Inherit,
127}
128
129#[derive(Serialize, Deserialize, Clone, Debug)]
130#[serde(remote = "Self")]
131pub struct Dependency {
132 #[serde(skip_serializing_if = "Option::is_none")]
133 pub version: Option<String>,
134 #[serde(skip_serializing_if = "Option::is_none")]
135 pub path: Option<Directory>,
136 #[serde(default, skip_serializing_if = "is_false")]
137 pub optional: bool,
138 #[serde(rename = "default-features", skip_serializing_if = "Option::is_none")]
139 pub default_features: Option<bool>,
140 #[serde(default, skip_serializing_if = "Vec::is_empty")]
141 pub features: Vec<String>,
142 #[serde(skip_serializing_if = "Option::is_none")]
143 pub git: Option<String>,
144 #[serde(skip_serializing_if = "Option::is_none")]
145 pub branch: Option<String>,
146 #[serde(skip_serializing_if = "Option::is_none")]
147 pub tag: Option<String>,
148 #[serde(skip_serializing_if = "Option::is_none")]
149 pub rev: Option<String>,
150 #[serde(default, skip_serializing_if = "is_false")]
151 pub workspace: bool,
152 #[serde(flatten)]
153 pub rest: Map<String, Value>,
154}
155
156#[derive(Serialize, Deserialize, Clone, Debug)]
157pub struct TargetDependencies {
158 #[serde(default, skip_serializing_if = "Map::is_empty")]
159 pub dependencies: Map<String, Dependency>,
160 #[serde(
161 default,
162 alias = "dev-dependencies",
163 skip_serializing_if = "Map::is_empty"
164 )]
165 pub dev_dependencies: Map<String, Dependency>,
166}
167
168#[derive(Serialize, Deserialize, Clone, Debug)]
169#[serde(transparent)]
170pub struct RegistryPatch {
171 pub crates: Map<String, Patch>,
172}
173
174#[derive(Serialize, Deserialize, Clone, Debug)]
175pub struct Patch {
176 #[serde(skip_serializing_if = "Option::is_none")]
177 pub path: Option<PathBuf>,
178 #[serde(skip_serializing_if = "Option::is_none")]
179 pub git: Option<String>,
180 #[serde(skip_serializing_if = "Option::is_none")]
181 pub branch: Option<String>,
182 #[serde(skip_serializing_if = "Option::is_none")]
183 pub tag: Option<String>,
184 #[serde(skip_serializing_if = "Option::is_none")]
185 pub rev: Option<String>,
186 #[serde(flatten)]
187 pub rest: Map<String, Value>,
188}
189
190fn is_false(boolean: &bool) -> bool {
191 !*boolean
192}
193
194impl Default for EditionOrInherit {
195 fn default() -> Self {
196 EditionOrInherit::Edition(Edition::default())
197 }
198}
199
200impl<'de> Deserialize<'de> for EditionOrInherit {
201 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
202 where
203 D: Deserializer<'de>,
204 {
205 struct EditionOrInheritVisitor;
206
207 impl<'de> Visitor<'de> for EditionOrInheritVisitor {
208 type Value = EditionOrInherit;
209
210 fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
211 formatter.write_str("edition")
212 }
213
214 fn visit_str<E>(self, s: &str) -> Result<Self::Value, E>
215 where
216 E: de::Error,
217 {
218 Edition::deserialize(StrDeserializer::new(s)).map(EditionOrInherit::Edition)
219 }
220
221 fn visit_map<M>(self, map: M) -> Result<Self::Value, M::Error>
222 where
223 M: de::MapAccess<'de>,
224 {
225 InheritEdition::deserialize(MapAccessDeserializer::new(map))?;
226 Ok(EditionOrInherit::Inherit)
227 }
228 }
229
230 deserializer.deserialize_any(EditionOrInheritVisitor)
231 }
232}
233
234impl Serialize for Dependency {
235 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
236 where
237 S: Serializer,
238 {
239 Dependency::serialize(self, serializer)
240 }
241}
242
243impl<'de> Deserialize<'de> for Dependency {
244 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
245 where
246 D: Deserializer<'de>,
247 {
248 struct DependencyVisitor;
249
250 impl<'de> Visitor<'de> for DependencyVisitor {
251 type Value = Dependency;
252
253 fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
254 formatter.write_str(
255 "a version string like \"0.9.8\" or a \
256 dependency like { version = \"0.9.8\" }",
257 )
258 }
259
260 fn visit_str<E>(self, s: &str) -> Result<Self::Value, E>
261 where
262 E: de::Error,
263 {
264 Ok(Dependency {
265 version: Some(s.to_owned()),
266 path: None,
267 optional: false,
268 default_features: Some(true),
269 features: Vec::new(),
270 git: None,
271 branch: None,
272 tag: None,
273 rev: None,
274 workspace: false,
275 rest: Map::new(),
276 })
277 }
278
279 fn visit_map<M>(self, map: M) -> Result<Self::Value, M::Error>
280 where
281 M: de::MapAccess<'de>,
282 {
283 Dependency::deserialize(MapAccessDeserializer::new(map))
284 }
285 }
286
287 deserializer.deserialize_any(DependencyVisitor)
288 }
289}