1 use std::collections::{BTreeMap, BTreeSet, HashMap, HashSet};
2 use std::fmt;
3 use std::marker::PhantomData;
4 use std::path::{Path, PathBuf};
5 use std::rc::Rc;
6 use std::str;
7 
8 use anyhow::{anyhow, bail, Context as _};
9 use cargo_platform::Platform;
10 use cargo_util::paths;
11 use log::{debug, trace};
12 use semver::{self, VersionReq};
13 use serde::de;
14 use serde::ser;
15 use serde::{Deserialize, Serialize};
16 use url::Url;
17 
18 use crate::core::compiler::{CompileKind, CompileTarget};
19 use crate::core::dependency::DepKind;
20 use crate::core::manifest::{ManifestMetadata, TargetSourcePath, Warnings};
21 use crate::core::resolver::ResolveBehavior;
22 use crate::core::{Dependency, Manifest, PackageId, Summary, Target};
23 use crate::core::{Edition, EitherManifest, Feature, Features, VirtualManifest, Workspace};
24 use crate::core::{GitReference, PackageIdSpec, SourceId, WorkspaceConfig, WorkspaceRootConfig};
25 use crate::sources::{CRATES_IO_INDEX, CRATES_IO_REGISTRY};
26 use crate::util::errors::{CargoResult, ManifestError};
27 use crate::util::interning::InternedString;
28 use crate::util::{
29     self, config::ConfigRelativePath, validate_package_name, Config, IntoUrl, VersionReqExt,
30 };
31 
32 mod targets;
33 use self::targets::targets;
34 
35 /// Loads a `Cargo.toml` from a file on disk.
36 ///
37 /// This could result in a real or virtual manifest being returned.
38 ///
39 /// A list of nested paths is also returned, one for each path dependency
40 /// within the manfiest. For virtual manifests, these paths can only
41 /// come from patched or replaced dependencies. These paths are not
42 /// canonicalized.
read_manifest( path: &Path, source_id: SourceId, config: &Config, ) -> Result<(EitherManifest, Vec<PathBuf>), ManifestError>43 pub fn read_manifest(
44     path: &Path,
45     source_id: SourceId,
46     config: &Config,
47 ) -> Result<(EitherManifest, Vec<PathBuf>), ManifestError> {
48     trace!(
49         "read_manifest; path={}; source-id={}",
50         path.display(),
51         source_id
52     );
53     let contents = paths::read(path).map_err(|err| ManifestError::new(err, path.into()))?;
54 
55     do_read_manifest(&contents, path, source_id, config)
56         .with_context(|| format!("failed to parse manifest at `{}`", path.display()))
57         .map_err(|err| ManifestError::new(err, path.into()))
58 }
59 
do_read_manifest( contents: &str, manifest_file: &Path, source_id: SourceId, config: &Config, ) -> CargoResult<(EitherManifest, Vec<PathBuf>)>60 fn do_read_manifest(
61     contents: &str,
62     manifest_file: &Path,
63     source_id: SourceId,
64     config: &Config,
65 ) -> CargoResult<(EitherManifest, Vec<PathBuf>)> {
66     let package_root = manifest_file.parent().unwrap();
67 
68     let toml = {
69         let pretty_filename = manifest_file
70             .strip_prefix(config.cwd())
71             .unwrap_or(manifest_file);
72         parse(contents, pretty_filename, config)?
73     };
74 
75     // Provide a helpful error message for a common user error.
76     if let Some(package) = toml.get("package").or_else(|| toml.get("project")) {
77         if let Some(feats) = package.get("cargo-features") {
78             bail!(
79                 "cargo-features = {} was found in the wrong location, it \
80                  should be set at the top of Cargo.toml before any tables",
81                 toml::to_string(feats).unwrap()
82             );
83         }
84     }
85 
86     let mut unused = BTreeSet::new();
87     let manifest: TomlManifest = serde_ignored::deserialize(toml, |path| {
88         let mut key = String::new();
89         stringify(&mut key, &path);
90         unused.insert(key);
91     })?;
92     let add_unused = |warnings: &mut Warnings| {
93         for key in unused {
94             warnings.add_warning(format!("unused manifest key: {}", key));
95             if key == "profiles.debug" {
96                 warnings.add_warning("use `[profile.dev]` to configure debug builds".to_string());
97             }
98         }
99     };
100 
101     let manifest = Rc::new(manifest);
102     return if manifest.project.is_some() || manifest.package.is_some() {
103         let (mut manifest, paths) =
104             TomlManifest::to_real_manifest(&manifest, source_id, package_root, config)?;
105         add_unused(manifest.warnings_mut());
106         if manifest.targets().iter().all(|t| t.is_custom_build()) {
107             bail!(
108                 "no targets specified in the manifest\n\
109                  either src/lib.rs, src/main.rs, a [lib] section, or \
110                  [[bin]] section must be present"
111             )
112         }
113         Ok((EitherManifest::Real(manifest), paths))
114     } else {
115         let (mut m, paths) =
116             TomlManifest::to_virtual_manifest(&manifest, source_id, package_root, config)?;
117         add_unused(m.warnings_mut());
118         Ok((EitherManifest::Virtual(m), paths))
119     };
120 
121     fn stringify(dst: &mut String, path: &serde_ignored::Path<'_>) {
122         use serde_ignored::Path;
123 
124         match *path {
125             Path::Root => {}
126             Path::Seq { parent, index } => {
127                 stringify(dst, parent);
128                 if !dst.is_empty() {
129                     dst.push('.');
130                 }
131                 dst.push_str(&index.to_string());
132             }
133             Path::Map { parent, ref key } => {
134                 stringify(dst, parent);
135                 if !dst.is_empty() {
136                     dst.push('.');
137                 }
138                 dst.push_str(key);
139             }
140             Path::Some { parent }
141             | Path::NewtypeVariant { parent }
142             | Path::NewtypeStruct { parent } => stringify(dst, parent),
143         }
144     }
145 }
146 
147 /// Attempts to parse a string into a [`toml::Value`]. This is not specific to any
148 /// particular kind of TOML file.
149 ///
150 /// The purpose of this wrapper is to detect invalid TOML which was previously
151 /// accepted and display a warning to the user in that case. The `file` and `config`
152 /// parameters are only used by this fallback path.
parse(toml: &str, file: &Path, config: &Config) -> CargoResult<toml::Value>153 pub fn parse(toml: &str, file: &Path, config: &Config) -> CargoResult<toml::Value> {
154     let first_error = match toml.parse() {
155         Ok(ret) => return Ok(ret),
156         Err(e) => e,
157     };
158 
159     let mut second_parser = toml::de::Deserializer::new(toml);
160     second_parser.set_require_newline_after_table(false);
161     if let Ok(ret) = toml::Value::deserialize(&mut second_parser) {
162         let msg = format!(
163             "\
164 TOML file found which contains invalid syntax and will soon not parse
165 at `{}`.
166 
167 The TOML spec requires newlines after table definitions (e.g., `[a] b = 1` is
168 invalid), but this file has a table header which does not have a newline after
169 it. A newline needs to be added and this warning will soon become a hard error
170 in the future.",
171             file.display()
172         );
173         config.shell().warn(&msg)?;
174         return Ok(ret);
175     }
176 
177     let mut third_parser = toml::de::Deserializer::new(toml);
178     third_parser.set_allow_duplicate_after_longer_table(true);
179     if let Ok(ret) = toml::Value::deserialize(&mut third_parser) {
180         let msg = format!(
181             "\
182 TOML file found which contains invalid syntax and will soon not parse
183 at `{}`.
184 
185 The TOML spec requires that each table header is defined at most once, but
186 historical versions of Cargo have erroneously accepted this file. The table
187 definitions will need to be merged together with one table header to proceed,
188 and this will become a hard error in the future.",
189             file.display()
190         );
191         config.shell().warn(&msg)?;
192         return Ok(ret);
193     }
194 
195     let first_error = anyhow::Error::from(first_error);
196     Err(first_error.context("could not parse input as TOML"))
197 }
198 
199 type TomlLibTarget = TomlTarget;
200 type TomlBinTarget = TomlTarget;
201 type TomlExampleTarget = TomlTarget;
202 type TomlTestTarget = TomlTarget;
203 type TomlBenchTarget = TomlTarget;
204 
205 #[derive(Clone, Debug, Serialize)]
206 #[serde(untagged)]
207 pub enum TomlDependency<P = String> {
208     /// In the simple format, only a version is specified, eg.
209     /// `package = "<version>"`
210     Simple(String),
211     /// The simple format is equivalent to a detailed dependency
212     /// specifying only a version, eg.
213     /// `package = { version = "<version>" }`
214     Detailed(DetailedTomlDependency<P>),
215 }
216 
217 impl<'de, P: Deserialize<'de>> de::Deserialize<'de> for TomlDependency<P> {
deserialize<D>(deserializer: D) -> Result<Self, D::Error> where D: de::Deserializer<'de>,218     fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
219     where
220         D: de::Deserializer<'de>,
221     {
222         struct TomlDependencyVisitor<P>(PhantomData<P>);
223 
224         impl<'de, P: Deserialize<'de>> de::Visitor<'de> for TomlDependencyVisitor<P> {
225             type Value = TomlDependency<P>;
226 
227             fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
228                 formatter.write_str(
229                     "a version string like \"0.9.8\" or a \
230                      detailed dependency like { version = \"0.9.8\" }",
231                 )
232             }
233 
234             fn visit_str<E>(self, s: &str) -> Result<Self::Value, E>
235             where
236                 E: de::Error,
237             {
238                 Ok(TomlDependency::Simple(s.to_owned()))
239             }
240 
241             fn visit_map<V>(self, map: V) -> Result<Self::Value, V::Error>
242             where
243                 V: de::MapAccess<'de>,
244             {
245                 let mvd = de::value::MapAccessDeserializer::new(map);
246                 DetailedTomlDependency::deserialize(mvd).map(TomlDependency::Detailed)
247             }
248         }
249 
250         deserializer.deserialize_any(TomlDependencyVisitor(PhantomData))
251     }
252 }
253 
254 pub trait ResolveToPath {
resolve(&self, config: &Config) -> PathBuf255     fn resolve(&self, config: &Config) -> PathBuf;
256 }
257 
258 impl ResolveToPath for String {
resolve(&self, _: &Config) -> PathBuf259     fn resolve(&self, _: &Config) -> PathBuf {
260         self.into()
261     }
262 }
263 
264 impl ResolveToPath for ConfigRelativePath {
resolve(&self, c: &Config) -> PathBuf265     fn resolve(&self, c: &Config) -> PathBuf {
266         self.resolve_path(c)
267     }
268 }
269 
270 #[derive(Deserialize, Serialize, Clone, Debug)]
271 #[serde(rename_all = "kebab-case")]
272 pub struct DetailedTomlDependency<P = String> {
273     version: Option<String>,
274     registry: Option<String>,
275     /// The URL of the `registry` field.
276     /// This is an internal implementation detail. When Cargo creates a
277     /// package, it replaces `registry` with `registry-index` so that the
278     /// manifest contains the correct URL. All users won't have the same
279     /// registry names configured, so Cargo can't rely on just the name for
280     /// crates published by other users.
281     registry_index: Option<String>,
282     // `path` is relative to the file it appears in. If that's a `Cargo.toml`, it'll be relative to
283     // that TOML file, and if it's a `.cargo/config` file, it'll be relative to that file.
284     path: Option<P>,
285     git: Option<String>,
286     branch: Option<String>,
287     tag: Option<String>,
288     rev: Option<String>,
289     features: Option<Vec<String>>,
290     optional: Option<bool>,
291     default_features: Option<bool>,
292     #[serde(rename = "default_features")]
293     default_features2: Option<bool>,
294     package: Option<String>,
295     public: Option<bool>,
296 }
297 
298 // Explicit implementation so we avoid pulling in P: Default
299 impl<P> Default for DetailedTomlDependency<P> {
default() -> Self300     fn default() -> Self {
301         Self {
302             version: Default::default(),
303             registry: Default::default(),
304             registry_index: Default::default(),
305             path: Default::default(),
306             git: Default::default(),
307             branch: Default::default(),
308             tag: Default::default(),
309             rev: Default::default(),
310             features: Default::default(),
311             optional: Default::default(),
312             default_features: Default::default(),
313             default_features2: Default::default(),
314             package: Default::default(),
315             public: Default::default(),
316         }
317     }
318 }
319 
320 /// This type is used to deserialize `Cargo.toml` files.
321 #[derive(Debug, Deserialize, Serialize)]
322 #[serde(rename_all = "kebab-case")]
323 pub struct TomlManifest {
324     cargo_features: Option<Vec<String>>,
325     package: Option<Box<TomlProject>>,
326     project: Option<Box<TomlProject>>,
327     profile: Option<TomlProfiles>,
328     lib: Option<TomlLibTarget>,
329     bin: Option<Vec<TomlBinTarget>>,
330     example: Option<Vec<TomlExampleTarget>>,
331     test: Option<Vec<TomlTestTarget>>,
332     bench: Option<Vec<TomlTestTarget>>,
333     dependencies: Option<BTreeMap<String, TomlDependency>>,
334     dev_dependencies: Option<BTreeMap<String, TomlDependency>>,
335     #[serde(rename = "dev_dependencies")]
336     dev_dependencies2: Option<BTreeMap<String, TomlDependency>>,
337     build_dependencies: Option<BTreeMap<String, TomlDependency>>,
338     #[serde(rename = "build_dependencies")]
339     build_dependencies2: Option<BTreeMap<String, TomlDependency>>,
340     features: Option<BTreeMap<InternedString, Vec<InternedString>>>,
341     target: Option<BTreeMap<String, TomlPlatform>>,
342     replace: Option<BTreeMap<String, TomlDependency>>,
343     patch: Option<BTreeMap<String, BTreeMap<String, TomlDependency>>>,
344     workspace: Option<TomlWorkspace>,
345     badges: Option<BTreeMap<String, BTreeMap<String, String>>>,
346 }
347 
348 #[derive(Deserialize, Serialize, Clone, Debug, Default)]
349 pub struct TomlProfiles(BTreeMap<InternedString, TomlProfile>);
350 
351 impl TomlProfiles {
get_all(&self) -> &BTreeMap<InternedString, TomlProfile>352     pub fn get_all(&self) -> &BTreeMap<InternedString, TomlProfile> {
353         &self.0
354     }
355 
get(&self, name: &str) -> Option<&TomlProfile>356     pub fn get(&self, name: &str) -> Option<&TomlProfile> {
357         self.0.get(name)
358     }
359 
validate(&self, features: &Features, warnings: &mut Vec<String>) -> CargoResult<()>360     pub fn validate(&self, features: &Features, warnings: &mut Vec<String>) -> CargoResult<()> {
361         for (name, profile) in &self.0 {
362             profile.validate(name, features, warnings)?;
363         }
364         Ok(())
365     }
366 }
367 
368 #[derive(Clone, Debug, Eq, PartialEq)]
369 pub struct TomlOptLevel(pub String);
370 
371 impl<'de> de::Deserialize<'de> for TomlOptLevel {
deserialize<D>(d: D) -> Result<TomlOptLevel, D::Error> where D: de::Deserializer<'de>,372     fn deserialize<D>(d: D) -> Result<TomlOptLevel, D::Error>
373     where
374         D: de::Deserializer<'de>,
375     {
376         struct Visitor;
377 
378         impl<'de> de::Visitor<'de> for Visitor {
379             type Value = TomlOptLevel;
380 
381             fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
382                 formatter.write_str("an optimization level")
383             }
384 
385             fn visit_i64<E>(self, value: i64) -> Result<TomlOptLevel, E>
386             where
387                 E: de::Error,
388             {
389                 Ok(TomlOptLevel(value.to_string()))
390             }
391 
392             fn visit_str<E>(self, value: &str) -> Result<TomlOptLevel, E>
393             where
394                 E: de::Error,
395             {
396                 if value == "s" || value == "z" {
397                     Ok(TomlOptLevel(value.to_string()))
398                 } else {
399                     Err(E::custom(format!(
400                         "must be `0`, `1`, `2`, `3`, `s` or `z`, \
401                          but found the string: \"{}\"",
402                         value
403                     )))
404                 }
405             }
406         }
407 
408         d.deserialize_any(Visitor)
409     }
410 }
411 
412 impl ser::Serialize for TomlOptLevel {
serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> where S: ser::Serializer,413     fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
414     where
415         S: ser::Serializer,
416     {
417         match self.0.parse::<u32>() {
418             Ok(n) => n.serialize(serializer),
419             Err(_) => self.0.serialize(serializer),
420         }
421     }
422 }
423 
424 #[derive(Clone, Debug, Deserialize, Serialize, Eq, PartialEq)]
425 #[serde(untagged, expecting = "expected a boolean or an integer")]
426 pub enum U32OrBool {
427     U32(u32),
428     Bool(bool),
429 }
430 
431 #[derive(Deserialize, Serialize, Clone, Debug, Default, Eq, PartialEq)]
432 #[serde(default, rename_all = "kebab-case")]
433 pub struct TomlProfile {
434     pub opt_level: Option<TomlOptLevel>,
435     pub lto: Option<StringOrBool>,
436     pub codegen_units: Option<u32>,
437     pub debug: Option<U32OrBool>,
438     pub split_debuginfo: Option<String>,
439     pub debug_assertions: Option<bool>,
440     pub rpath: Option<bool>,
441     pub panic: Option<String>,
442     pub overflow_checks: Option<bool>,
443     pub incremental: Option<bool>,
444     pub package: Option<BTreeMap<ProfilePackageSpec, TomlProfile>>,
445     pub build_override: Option<Box<TomlProfile>>,
446     pub dir_name: Option<InternedString>,
447     pub inherits: Option<InternedString>,
448     pub strip: Option<StringOrBool>,
449 }
450 
451 #[derive(Clone, Debug, PartialEq, Eq, Ord, PartialOrd, Hash)]
452 pub enum ProfilePackageSpec {
453     Spec(PackageIdSpec),
454     All,
455 }
456 
457 impl ser::Serialize for ProfilePackageSpec {
serialize<S>(&self, s: S) -> Result<S::Ok, S::Error> where S: ser::Serializer,458     fn serialize<S>(&self, s: S) -> Result<S::Ok, S::Error>
459     where
460         S: ser::Serializer,
461     {
462         match *self {
463             ProfilePackageSpec::Spec(ref spec) => spec.serialize(s),
464             ProfilePackageSpec::All => "*".serialize(s),
465         }
466     }
467 }
468 
469 impl<'de> de::Deserialize<'de> for ProfilePackageSpec {
deserialize<D>(d: D) -> Result<ProfilePackageSpec, D::Error> where D: de::Deserializer<'de>,470     fn deserialize<D>(d: D) -> Result<ProfilePackageSpec, D::Error>
471     where
472         D: de::Deserializer<'de>,
473     {
474         let string = String::deserialize(d)?;
475         if string == "*" {
476             Ok(ProfilePackageSpec::All)
477         } else {
478             PackageIdSpec::parse(&string)
479                 .map_err(de::Error::custom)
480                 .map(ProfilePackageSpec::Spec)
481         }
482     }
483 }
484 
485 impl TomlProfile {
validate( &self, name: &str, features: &Features, warnings: &mut Vec<String>, ) -> CargoResult<()>486     pub fn validate(
487         &self,
488         name: &str,
489         features: &Features,
490         warnings: &mut Vec<String>,
491     ) -> CargoResult<()> {
492         if name == "debug" {
493             warnings.push("use `[profile.dev]` to configure debug builds".to_string());
494         }
495 
496         if let Some(ref profile) = self.build_override {
497             features.require(Feature::profile_overrides())?;
498             profile.validate_override("build-override")?;
499         }
500         if let Some(ref packages) = self.package {
501             features.require(Feature::profile_overrides())?;
502             for profile in packages.values() {
503                 profile.validate_override("package")?;
504             }
505         }
506 
507         // Feature gate definition of named profiles
508         match name {
509             "dev" | "release" | "bench" | "test" | "doc" => {}
510             _ => {
511                 features.require(Feature::named_profiles())?;
512             }
513         }
514 
515         // Profile name validation
516         Self::validate_name(name, "profile name")?;
517 
518         // Feature gate on uses of keys related to named profiles
519         if self.inherits.is_some() {
520             features.require(Feature::named_profiles())?;
521         }
522 
523         if self.dir_name.is_some() {
524             features.require(Feature::named_profiles())?;
525         }
526 
527         // `dir-name` validation
528         match &self.dir_name {
529             None => {}
530             Some(dir_name) => {
531                 Self::validate_name(dir_name, "dir-name")?;
532             }
533         }
534 
535         // `inherits` validation
536         match &self.inherits {
537             None => {}
538             Some(inherits) => {
539                 Self::validate_name(inherits, "inherits")?;
540             }
541         }
542 
543         match name {
544             "doc" => {
545                 warnings.push("profile `doc` is deprecated and has no effect".to_string());
546             }
547             "test" | "bench" => {
548                 if self.panic.is_some() {
549                     warnings.push(format!("`panic` setting is ignored for `{}` profile", name))
550                 }
551             }
552             _ => {}
553         }
554 
555         if let Some(panic) = &self.panic {
556             if panic != "unwind" && panic != "abort" {
557                 bail!(
558                     "`panic` setting of `{}` is not a valid setting, \
559                      must be `unwind` or `abort`",
560                     panic
561                 );
562             }
563         }
564 
565         if self.strip.is_some() {
566             features.require(Feature::strip())?;
567         }
568         Ok(())
569     }
570 
571     /// Validate dir-names and profile names according to RFC 2678.
validate_name(name: &str, what: &str) -> CargoResult<()>572     pub fn validate_name(name: &str, what: &str) -> CargoResult<()> {
573         if let Some(ch) = name
574             .chars()
575             .find(|ch| !ch.is_alphanumeric() && *ch != '_' && *ch != '-')
576         {
577             bail!("Invalid character `{}` in {}: `{}`", ch, what, name);
578         }
579 
580         match name {
581             "package" | "build" => {
582                 bail!("Invalid {}: `{}`", what, name);
583             }
584             "debug" if what == "profile" => {
585                 if what == "profile name" {
586                     // Allowed, but will emit warnings
587                 } else {
588                     bail!("Invalid {}: `{}`", what, name);
589                 }
590             }
591             "doc" if what == "dir-name" => {
592                 bail!("Invalid {}: `{}`", what, name);
593             }
594             _ => {}
595         }
596 
597         Ok(())
598     }
599 
validate_override(&self, which: &str) -> CargoResult<()>600     fn validate_override(&self, which: &str) -> CargoResult<()> {
601         if self.package.is_some() {
602             bail!("package-specific profiles cannot be nested");
603         }
604         if self.build_override.is_some() {
605             bail!("build-override profiles cannot be nested");
606         }
607         if self.panic.is_some() {
608             bail!("`panic` may not be specified in a `{}` profile", which)
609         }
610         if self.lto.is_some() {
611             bail!("`lto` may not be specified in a `{}` profile", which)
612         }
613         if self.rpath.is_some() {
614             bail!("`rpath` may not be specified in a `{}` profile", which)
615         }
616         Ok(())
617     }
618 
619     /// Overwrite self's values with the given profile.
merge(&mut self, profile: &TomlProfile)620     pub fn merge(&mut self, profile: &TomlProfile) {
621         if let Some(v) = &profile.opt_level {
622             self.opt_level = Some(v.clone());
623         }
624 
625         if let Some(v) = &profile.lto {
626             self.lto = Some(v.clone());
627         }
628 
629         if let Some(v) = profile.codegen_units {
630             self.codegen_units = Some(v);
631         }
632 
633         if let Some(v) = &profile.debug {
634             self.debug = Some(v.clone());
635         }
636 
637         if let Some(v) = profile.debug_assertions {
638             self.debug_assertions = Some(v);
639         }
640 
641         if let Some(v) = &profile.split_debuginfo {
642             self.split_debuginfo = Some(v.clone());
643         }
644 
645         if let Some(v) = profile.rpath {
646             self.rpath = Some(v);
647         }
648 
649         if let Some(v) = &profile.panic {
650             self.panic = Some(v.clone());
651         }
652 
653         if let Some(v) = profile.overflow_checks {
654             self.overflow_checks = Some(v);
655         }
656 
657         if let Some(v) = profile.incremental {
658             self.incremental = Some(v);
659         }
660 
661         if let Some(other_package) = &profile.package {
662             match &mut self.package {
663                 Some(self_package) => {
664                     for (spec, other_pkg_profile) in other_package {
665                         match self_package.get_mut(spec) {
666                             Some(p) => p.merge(other_pkg_profile),
667                             None => {
668                                 self_package.insert(spec.clone(), other_pkg_profile.clone());
669                             }
670                         }
671                     }
672                 }
673                 None => self.package = Some(other_package.clone()),
674             }
675         }
676 
677         if let Some(other_bo) = &profile.build_override {
678             match &mut self.build_override {
679                 Some(self_bo) => self_bo.merge(other_bo),
680                 None => self.build_override = Some(other_bo.clone()),
681             }
682         }
683 
684         if let Some(v) = &profile.inherits {
685             self.inherits = Some(*v);
686         }
687 
688         if let Some(v) = &profile.dir_name {
689             self.dir_name = Some(*v);
690         }
691 
692         if let Some(v) = &profile.strip {
693             self.strip = Some(v.clone());
694         }
695     }
696 }
697 
698 #[derive(Clone, Debug, Serialize, Eq, PartialEq)]
699 pub struct StringOrVec(Vec<String>);
700 
701 impl<'de> de::Deserialize<'de> for StringOrVec {
deserialize<D>(deserializer: D) -> Result<Self, D::Error> where D: de::Deserializer<'de>,702     fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
703     where
704         D: de::Deserializer<'de>,
705     {
706         struct Visitor;
707 
708         impl<'de> de::Visitor<'de> for Visitor {
709             type Value = StringOrVec;
710 
711             fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
712                 formatter.write_str("string or list of strings")
713             }
714 
715             fn visit_str<E>(self, s: &str) -> Result<Self::Value, E>
716             where
717                 E: de::Error,
718             {
719                 Ok(StringOrVec(vec![s.to_string()]))
720             }
721 
722             fn visit_seq<V>(self, v: V) -> Result<Self::Value, V::Error>
723             where
724                 V: de::SeqAccess<'de>,
725             {
726                 let seq = de::value::SeqAccessDeserializer::new(v);
727                 Vec::deserialize(seq).map(StringOrVec)
728             }
729         }
730 
731         deserializer.deserialize_any(Visitor)
732     }
733 }
734 
735 #[derive(Clone, Debug, Deserialize, Serialize, Eq, PartialEq)]
736 #[serde(untagged, expecting = "expected a boolean or a string")]
737 pub enum StringOrBool {
738     String(String),
739     Bool(bool),
740 }
741 
742 #[derive(PartialEq, Clone, Debug, Serialize)]
743 #[serde(untagged)]
744 pub enum VecStringOrBool {
745     VecString(Vec<String>),
746     Bool(bool),
747 }
748 
749 impl<'de> de::Deserialize<'de> for VecStringOrBool {
deserialize<D>(deserializer: D) -> Result<Self, D::Error> where D: de::Deserializer<'de>,750     fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
751     where
752         D: de::Deserializer<'de>,
753     {
754         struct Visitor;
755 
756         impl<'de> de::Visitor<'de> for Visitor {
757             type Value = VecStringOrBool;
758 
759             fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
760                 formatter.write_str("a boolean or vector of strings")
761             }
762 
763             fn visit_seq<V>(self, v: V) -> Result<Self::Value, V::Error>
764             where
765                 V: de::SeqAccess<'de>,
766             {
767                 let seq = de::value::SeqAccessDeserializer::new(v);
768                 Vec::deserialize(seq).map(VecStringOrBool::VecString)
769             }
770 
771             fn visit_bool<E>(self, b: bool) -> Result<Self::Value, E>
772             where
773                 E: de::Error,
774             {
775                 Ok(VecStringOrBool::Bool(b))
776             }
777         }
778 
779         deserializer.deserialize_any(Visitor)
780     }
781 }
782 
version_trim_whitespace<'de, D>(deserializer: D) -> Result<semver::Version, D::Error> where D: de::Deserializer<'de>,783 fn version_trim_whitespace<'de, D>(deserializer: D) -> Result<semver::Version, D::Error>
784 where
785     D: de::Deserializer<'de>,
786 {
787     struct Visitor;
788 
789     impl<'de> de::Visitor<'de> for Visitor {
790         type Value = semver::Version;
791 
792         fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
793             formatter.write_str("SemVer version")
794         }
795 
796         fn visit_str<E>(self, string: &str) -> Result<Self::Value, E>
797         where
798             E: de::Error,
799         {
800             string.trim().parse().map_err(de::Error::custom)
801         }
802     }
803 
804     deserializer.deserialize_str(Visitor)
805 }
806 
807 /// Represents the `package`/`project` sections of a `Cargo.toml`.
808 ///
809 /// Note that the order of the fields matters, since this is the order they
810 /// are serialized to a TOML file. For example, you cannot have values after
811 /// the field `metadata`, since it is a table and values cannot appear after
812 /// tables.
813 #[derive(Deserialize, Serialize, Clone, Debug)]
814 #[serde(rename_all = "kebab-case")]
815 pub struct TomlProject {
816     edition: Option<String>,
817     rust_version: Option<String>,
818     name: InternedString,
819     #[serde(deserialize_with = "version_trim_whitespace")]
820     version: semver::Version,
821     authors: Option<Vec<String>>,
822     build: Option<StringOrBool>,
823     metabuild: Option<StringOrVec>,
824     #[serde(rename = "default-target")]
825     default_target: Option<String>,
826     #[serde(rename = "forced-target")]
827     forced_target: Option<String>,
828     links: Option<String>,
829     exclude: Option<Vec<String>>,
830     include: Option<Vec<String>>,
831     publish: Option<VecStringOrBool>,
832     workspace: Option<String>,
833     im_a_teapot: Option<bool>,
834     autobins: Option<bool>,
835     autoexamples: Option<bool>,
836     autotests: Option<bool>,
837     autobenches: Option<bool>,
838     default_run: Option<String>,
839 
840     // Package metadata.
841     description: Option<String>,
842     homepage: Option<String>,
843     documentation: Option<String>,
844     readme: Option<StringOrBool>,
845     keywords: Option<Vec<String>>,
846     categories: Option<Vec<String>>,
847     license: Option<String>,
848     license_file: Option<String>,
849     repository: Option<String>,
850     resolver: Option<String>,
851 
852     // Note that this field must come last due to the way toml serialization
853     // works which requires tables to be emitted after all values.
854     metadata: Option<toml::Value>,
855 }
856 
857 #[derive(Debug, Deserialize, Serialize)]
858 pub struct TomlWorkspace {
859     members: Option<Vec<String>>,
860     #[serde(rename = "default-members")]
861     default_members: Option<Vec<String>>,
862     exclude: Option<Vec<String>>,
863     resolver: Option<String>,
864 
865     // Note that this field must come last due to the way toml serialization
866     // works which requires tables to be emitted after all values.
867     metadata: Option<toml::Value>,
868 }
869 
870 impl TomlProject {
to_package_id(&self, source_id: SourceId) -> CargoResult<PackageId>871     pub fn to_package_id(&self, source_id: SourceId) -> CargoResult<PackageId> {
872         PackageId::new(self.name, self.version.clone(), source_id)
873     }
874 }
875 
876 struct Context<'a, 'b> {
877     deps: &'a mut Vec<Dependency>,
878     source_id: SourceId,
879     nested_paths: &'a mut Vec<PathBuf>,
880     config: &'b Config,
881     warnings: &'a mut Vec<String>,
882     platform: Option<Platform>,
883     root: &'a Path,
884     features: &'a Features,
885 }
886 
887 impl TomlManifest {
888     /// Prepares the manifest for publishing.
889     // - Path and git components of dependency specifications are removed.
890     // - License path is updated to point within the package.
prepare_for_publish( &self, ws: &Workspace<'_>, package_root: &Path, ) -> CargoResult<TomlManifest>891     pub fn prepare_for_publish(
892         &self,
893         ws: &Workspace<'_>,
894         package_root: &Path,
895     ) -> CargoResult<TomlManifest> {
896         let config = ws.config();
897         let mut package = self
898             .package
899             .as_ref()
900             .or_else(|| self.project.as_ref())
901             .unwrap()
902             .clone();
903         package.workspace = None;
904         package.resolver = ws.resolve_behavior().to_manifest();
905         if let Some(license_file) = &package.license_file {
906             let license_path = Path::new(&license_file);
907             let abs_license_path = paths::normalize_path(&package_root.join(license_path));
908             if abs_license_path.strip_prefix(package_root).is_err() {
909                 // This path points outside of the package root. `cargo package`
910                 // will copy it into the root, so adjust the path to this location.
911                 package.license_file = Some(
912                     license_path
913                         .file_name()
914                         .unwrap()
915                         .to_str()
916                         .unwrap()
917                         .to_string(),
918                 );
919             }
920         }
921         let all = |_d: &TomlDependency| true;
922         return Ok(TomlManifest {
923             package: Some(package),
924             project: None,
925             profile: self.profile.clone(),
926             lib: self.lib.clone(),
927             bin: self.bin.clone(),
928             example: self.example.clone(),
929             test: self.test.clone(),
930             bench: self.bench.clone(),
931             dependencies: map_deps(config, self.dependencies.as_ref(), all)?,
932             dev_dependencies: map_deps(
933                 config,
934                 self.dev_dependencies
935                     .as_ref()
936                     .or_else(|| self.dev_dependencies2.as_ref()),
937                 TomlDependency::is_version_specified,
938             )?,
939             dev_dependencies2: None,
940             build_dependencies: map_deps(
941                 config,
942                 self.build_dependencies
943                     .as_ref()
944                     .or_else(|| self.build_dependencies2.as_ref()),
945                 all,
946             )?,
947             build_dependencies2: None,
948             features: self.features.clone(),
949             target: match self.target.as_ref().map(|target_map| {
950                 target_map
951                     .iter()
952                     .map(|(k, v)| {
953                         Ok((
954                             k.clone(),
955                             TomlPlatform {
956                                 dependencies: map_deps(config, v.dependencies.as_ref(), all)?,
957                                 dev_dependencies: map_deps(
958                                     config,
959                                     v.dev_dependencies
960                                         .as_ref()
961                                         .or_else(|| v.dev_dependencies2.as_ref()),
962                                     TomlDependency::is_version_specified,
963                                 )?,
964                                 dev_dependencies2: None,
965                                 build_dependencies: map_deps(
966                                     config,
967                                     v.build_dependencies
968                                         .as_ref()
969                                         .or_else(|| v.build_dependencies2.as_ref()),
970                                     all,
971                                 )?,
972                                 build_dependencies2: None,
973                             },
974                         ))
975                     })
976                     .collect()
977             }) {
978                 Some(Ok(v)) => Some(v),
979                 Some(Err(e)) => return Err(e),
980                 None => None,
981             },
982             replace: None,
983             patch: None,
984             workspace: None,
985             badges: self.badges.clone(),
986             cargo_features: self.cargo_features.clone(),
987         });
988 
989         fn map_deps(
990             config: &Config,
991             deps: Option<&BTreeMap<String, TomlDependency>>,
992             filter: impl Fn(&TomlDependency) -> bool,
993         ) -> CargoResult<Option<BTreeMap<String, TomlDependency>>> {
994             let deps = match deps {
995                 Some(deps) => deps,
996                 None => return Ok(None),
997             };
998             let deps = deps
999                 .iter()
1000                 .filter(|(_k, v)| filter(v))
1001                 .map(|(k, v)| Ok((k.clone(), map_dependency(config, v)?)))
1002                 .collect::<CargoResult<BTreeMap<_, _>>>()?;
1003             Ok(Some(deps))
1004         }
1005 
1006         fn map_dependency(config: &Config, dep: &TomlDependency) -> CargoResult<TomlDependency> {
1007             match dep {
1008                 TomlDependency::Detailed(d) => {
1009                     let mut d = d.clone();
1010                     // Path dependencies become crates.io deps.
1011                     d.path.take();
1012                     // Same with git dependencies.
1013                     d.git.take();
1014                     d.branch.take();
1015                     d.tag.take();
1016                     d.rev.take();
1017                     // registry specifications are elaborated to the index URL
1018                     if let Some(registry) = d.registry.take() {
1019                         let src = SourceId::alt_registry(config, &registry)?;
1020                         d.registry_index = Some(src.url().to_string());
1021                     }
1022                     Ok(TomlDependency::Detailed(d))
1023                 }
1024                 TomlDependency::Simple(s) => Ok(TomlDependency::Detailed(DetailedTomlDependency {
1025                     version: Some(s.clone()),
1026                     ..Default::default()
1027                 })),
1028             }
1029         }
1030     }
1031 
to_real_manifest( me: &Rc<TomlManifest>, source_id: SourceId, package_root: &Path, config: &Config, ) -> CargoResult<(Manifest, Vec<PathBuf>)>1032     pub fn to_real_manifest(
1033         me: &Rc<TomlManifest>,
1034         source_id: SourceId,
1035         package_root: &Path,
1036         config: &Config,
1037     ) -> CargoResult<(Manifest, Vec<PathBuf>)> {
1038         let mut nested_paths = vec![];
1039         let mut warnings = vec![];
1040         let mut errors = vec![];
1041 
1042         // Parse features first so they will be available when parsing other parts of the TOML.
1043         let empty = Vec::new();
1044         let cargo_features = me.cargo_features.as_ref().unwrap_or(&empty);
1045         let features = Features::new(cargo_features, config, &mut warnings)?;
1046 
1047         let project = me.project.as_ref().or_else(|| me.package.as_ref());
1048         let project = project.ok_or_else(|| anyhow!("no `package` section found"))?;
1049 
1050         let package_name = project.name.trim();
1051         if package_name.is_empty() {
1052             bail!("package name cannot be an empty string")
1053         }
1054 
1055         validate_package_name(package_name, "package name", "")?;
1056 
1057         let pkgid = project.to_package_id(source_id)?;
1058 
1059         let edition = if let Some(ref edition) = project.edition {
1060             features
1061                 .require(Feature::edition())
1062                 .with_context(|| "editions are unstable")?;
1063             edition
1064                 .parse()
1065                 .with_context(|| "failed to parse the `edition` key")?
1066         } else {
1067             Edition::Edition2015
1068         };
1069         if edition == Edition::Edition2021 {
1070             features.require(Feature::edition2021())?;
1071         } else if !edition.is_stable() {
1072             // Guard in case someone forgets to add .require()
1073             return Err(util::errors::internal(format!(
1074                 "edition {} should be gated",
1075                 edition
1076             )));
1077         }
1078 
1079         let rust_version = if let Some(rust_version) = &project.rust_version {
1080             if features.require(Feature::rust_version()).is_err() {
1081                 let mut msg =
1082                     "`rust-version` is not supported on this version of Cargo and will be ignored"
1083                         .to_string();
1084                 if config.nightly_features_allowed {
1085                     msg.push_str(
1086                         "\n\n\
1087                         consider adding `cargo-features = [\"rust-version\"]` to the manifest",
1088                     );
1089                 } else {
1090                     msg.push_str(
1091                         "\n\n\
1092                         this Cargo does not support nightly features, but if you\n\
1093                         switch to nightly channel you can add\n\
1094                         `cargo-features = [\"rust-version\"]` to enable this feature",
1095                     );
1096                 }
1097                 warnings.push(msg);
1098                 None
1099             } else {
1100                 let req = match semver::VersionReq::parse(rust_version) {
1101                     // Exclude semver operators like `^` and pre-release identifiers
1102                     Ok(req) if rust_version.chars().all(|c| c.is_ascii_digit() || c == '.') => req,
1103                     _ => bail!("`rust-version` must be a value like \"1.32\""),
1104                 };
1105                 if let Some(first_version) = edition.first_version() {
1106                     let unsupported =
1107                         semver::Version::new(first_version.major, first_version.minor - 1, 9999);
1108                     if req.matches(&unsupported) {
1109                         bail!(
1110                             "rust-version {} is older than first version ({}) required by \
1111                                 the specified edition ({})",
1112                             rust_version,
1113                             first_version,
1114                             edition,
1115                         )
1116                     }
1117                 }
1118                 Some(rust_version.clone())
1119             }
1120         } else {
1121             None
1122         };
1123 
1124         if project.metabuild.is_some() {
1125             features.require(Feature::metabuild())?;
1126         }
1127 
1128         if project.resolver.is_some()
1129             || me
1130                 .workspace
1131                 .as_ref()
1132                 .map_or(false, |ws| ws.resolver.is_some())
1133         {
1134             features.require(Feature::resolver())?;
1135         }
1136         let resolve_behavior = match (
1137             project.resolver.as_ref(),
1138             me.workspace.as_ref().and_then(|ws| ws.resolver.as_ref()),
1139         ) {
1140             (None, None) => None,
1141             (Some(s), None) | (None, Some(s)) => Some(ResolveBehavior::from_manifest(s)?),
1142             (Some(_), Some(_)) => {
1143                 bail!("cannot specify `resolver` field in both `[workspace]` and `[package]`")
1144             }
1145         };
1146 
1147         // If we have no lib at all, use the inferred lib, if available.
1148         // If we have a lib with a path, we're done.
1149         // If we have a lib with no path, use the inferred lib or else the package name.
1150         let targets = targets(
1151             &features,
1152             me,
1153             package_name,
1154             package_root,
1155             edition,
1156             &project.build,
1157             &project.metabuild,
1158             &mut warnings,
1159             &mut errors,
1160         )?;
1161 
1162         if targets.is_empty() {
1163             debug!("manifest has no build targets");
1164         }
1165 
1166         if let Err(e) = unique_build_targets(&targets, package_root) {
1167             warnings.push(format!(
1168                 "file found to be present in multiple \
1169                  build targets: {}",
1170                 e
1171             ));
1172         }
1173 
1174         if let Some(links) = &project.links {
1175             if !targets.iter().any(|t| t.is_custom_build()) {
1176                 bail!(
1177                     "package `{}` specifies that it links to `{}` but does not \
1178                      have a custom build script",
1179                     pkgid,
1180                     links
1181                 )
1182             }
1183         }
1184 
1185         let mut deps = Vec::new();
1186         let replace;
1187         let patch;
1188 
1189         {
1190             let mut cx = Context {
1191                 deps: &mut deps,
1192                 source_id,
1193                 nested_paths: &mut nested_paths,
1194                 config,
1195                 warnings: &mut warnings,
1196                 features: &features,
1197                 platform: None,
1198                 root: package_root,
1199             };
1200 
1201             fn process_dependencies(
1202                 cx: &mut Context<'_, '_>,
1203                 new_deps: Option<&BTreeMap<String, TomlDependency>>,
1204                 kind: Option<DepKind>,
1205             ) -> CargoResult<()> {
1206                 let dependencies = match new_deps {
1207                     Some(dependencies) => dependencies,
1208                     None => return Ok(()),
1209                 };
1210                 for (n, v) in dependencies.iter() {
1211                     let dep = v.to_dependency(n, cx, kind)?;
1212                     validate_package_name(dep.name_in_toml().as_str(), "dependency name", "")?;
1213                     cx.deps.push(dep);
1214                 }
1215 
1216                 Ok(())
1217             }
1218 
1219             // Collect the dependencies.
1220             process_dependencies(&mut cx, me.dependencies.as_ref(), None)?;
1221             let dev_deps = me
1222                 .dev_dependencies
1223                 .as_ref()
1224                 .or_else(|| me.dev_dependencies2.as_ref());
1225             process_dependencies(&mut cx, dev_deps, Some(DepKind::Development))?;
1226             let build_deps = me
1227                 .build_dependencies
1228                 .as_ref()
1229                 .or_else(|| me.build_dependencies2.as_ref());
1230             process_dependencies(&mut cx, build_deps, Some(DepKind::Build))?;
1231 
1232             for (name, platform) in me.target.iter().flatten() {
1233                 cx.platform = {
1234                     let platform: Platform = name.parse()?;
1235                     platform.check_cfg_attributes(&mut cx.warnings);
1236                     Some(platform)
1237                 };
1238                 process_dependencies(&mut cx, platform.dependencies.as_ref(), None)?;
1239                 let build_deps = platform
1240                     .build_dependencies
1241                     .as_ref()
1242                     .or_else(|| platform.build_dependencies2.as_ref());
1243                 process_dependencies(&mut cx, build_deps, Some(DepKind::Build))?;
1244                 let dev_deps = platform
1245                     .dev_dependencies
1246                     .as_ref()
1247                     .or_else(|| platform.dev_dependencies2.as_ref());
1248                 process_dependencies(&mut cx, dev_deps, Some(DepKind::Development))?;
1249             }
1250 
1251             replace = me.replace(&mut cx)?;
1252             patch = me.patch(&mut cx)?;
1253         }
1254 
1255         {
1256             let mut names_sources = BTreeMap::new();
1257             for dep in &deps {
1258                 let name = dep.name_in_toml();
1259                 let prev = names_sources.insert(name.to_string(), dep.source_id());
1260                 if prev.is_some() && prev != Some(dep.source_id()) {
1261                     bail!(
1262                         "Dependency '{}' has different source paths depending on the build \
1263                          target. Each dependency must have a single canonical source path \
1264                          irrespective of build target.",
1265                         name
1266                     );
1267                 }
1268             }
1269         }
1270 
1271         let exclude = project.exclude.clone().unwrap_or_default();
1272         let include = project.include.clone().unwrap_or_default();
1273         let empty_features = BTreeMap::new();
1274 
1275         let summary = Summary::new(
1276             config,
1277             pkgid,
1278             deps,
1279             me.features.as_ref().unwrap_or(&empty_features),
1280             project.links.as_deref(),
1281         )?;
1282         let unstable = config.cli_unstable();
1283         summary.unstable_gate(unstable.namespaced_features, unstable.weak_dep_features)?;
1284 
1285         let metadata = ManifestMetadata {
1286             description: project.description.clone(),
1287             homepage: project.homepage.clone(),
1288             documentation: project.documentation.clone(),
1289             readme: readme_for_project(package_root, project),
1290             authors: project.authors.clone().unwrap_or_default(),
1291             license: project.license.clone(),
1292             license_file: project.license_file.clone(),
1293             repository: project.repository.clone(),
1294             keywords: project.keywords.clone().unwrap_or_default(),
1295             categories: project.categories.clone().unwrap_or_default(),
1296             badges: me.badges.clone().unwrap_or_default(),
1297             links: project.links.clone(),
1298         };
1299 
1300         let workspace_config = match (me.workspace.as_ref(), project.workspace.as_ref()) {
1301             (Some(config), None) => WorkspaceConfig::Root(WorkspaceRootConfig::new(
1302                 package_root,
1303                 &config.members,
1304                 &config.default_members,
1305                 &config.exclude,
1306                 &config.metadata,
1307             )),
1308             (None, root) => WorkspaceConfig::Member {
1309                 root: root.cloned(),
1310             },
1311             (Some(..), Some(..)) => bail!(
1312                 "cannot configure both `package.workspace` and \
1313                  `[workspace]`, only one can be specified"
1314             ),
1315         };
1316         let profiles = me.profile.clone();
1317         if let Some(profiles) = &profiles {
1318             profiles.validate(&features, &mut warnings)?;
1319         }
1320         let publish = match project.publish {
1321             Some(VecStringOrBool::VecString(ref vecstring)) => Some(vecstring.clone()),
1322             Some(VecStringOrBool::Bool(false)) => Some(vec![]),
1323             None | Some(VecStringOrBool::Bool(true)) => None,
1324         };
1325 
1326         if summary.features().contains_key("default-features") {
1327             warnings.push(
1328                 "`default-features = [\"..\"]` was found in [features]. \
1329                  Did you mean to use `default = [\"..\"]`?"
1330                     .to_string(),
1331             )
1332         }
1333 
1334         if let Some(run) = &project.default_run {
1335             if !targets
1336                 .iter()
1337                 .filter(|t| t.is_bin())
1338                 .any(|t| t.name() == run)
1339             {
1340                 let suggestion =
1341                     util::closest_msg(run, targets.iter().filter(|t| t.is_bin()), |t| t.name());
1342                 bail!("default-run target `{}` not found{}", run, suggestion);
1343             }
1344         }
1345 
1346         let default_kind = project
1347             .default_target
1348             .as_ref()
1349             .map(|t| CompileTarget::new(&*t))
1350             .transpose()?
1351             .map(CompileKind::Target);
1352         let forced_kind = project
1353             .forced_target
1354             .as_ref()
1355             .map(|t| CompileTarget::new(&*t))
1356             .transpose()?
1357             .map(CompileKind::Target);
1358 
1359         let custom_metadata = project.metadata.clone();
1360         let mut manifest = Manifest::new(
1361             summary,
1362             default_kind,
1363             forced_kind,
1364             targets,
1365             exclude,
1366             include,
1367             project.links.clone(),
1368             metadata,
1369             custom_metadata,
1370             profiles,
1371             publish,
1372             replace,
1373             patch,
1374             workspace_config,
1375             features,
1376             edition,
1377             rust_version,
1378             project.im_a_teapot,
1379             project.default_run.clone(),
1380             Rc::clone(me),
1381             project.metabuild.clone().map(|sov| sov.0),
1382             resolve_behavior,
1383         );
1384         if project.license_file.is_some() && project.license.is_some() {
1385             manifest.warnings_mut().add_warning(
1386                 "only one of `license` or \
1387                  `license-file` is necessary"
1388                     .to_string(),
1389             );
1390         }
1391         for warning in warnings {
1392             manifest.warnings_mut().add_warning(warning);
1393         }
1394         for error in errors {
1395             manifest.warnings_mut().add_critical_warning(error);
1396         }
1397 
1398         manifest.feature_gate()?;
1399 
1400         Ok((manifest, nested_paths))
1401     }
1402 
to_virtual_manifest( me: &Rc<TomlManifest>, source_id: SourceId, root: &Path, config: &Config, ) -> CargoResult<(VirtualManifest, Vec<PathBuf>)>1403     fn to_virtual_manifest(
1404         me: &Rc<TomlManifest>,
1405         source_id: SourceId,
1406         root: &Path,
1407         config: &Config,
1408     ) -> CargoResult<(VirtualManifest, Vec<PathBuf>)> {
1409         if me.project.is_some() {
1410             bail!("this virtual manifest specifies a [project] section, which is not allowed");
1411         }
1412         if me.package.is_some() {
1413             bail!("this virtual manifest specifies a [package] section, which is not allowed");
1414         }
1415         if me.lib.is_some() {
1416             bail!("this virtual manifest specifies a [lib] section, which is not allowed");
1417         }
1418         if me.bin.is_some() {
1419             bail!("this virtual manifest specifies a [[bin]] section, which is not allowed");
1420         }
1421         if me.example.is_some() {
1422             bail!("this virtual manifest specifies a [[example]] section, which is not allowed");
1423         }
1424         if me.test.is_some() {
1425             bail!("this virtual manifest specifies a [[test]] section, which is not allowed");
1426         }
1427         if me.bench.is_some() {
1428             bail!("this virtual manifest specifies a [[bench]] section, which is not allowed");
1429         }
1430         if me.dependencies.is_some() {
1431             bail!("this virtual manifest specifies a [dependencies] section, which is not allowed");
1432         }
1433         if me.dev_dependencies.is_some() || me.dev_dependencies2.is_some() {
1434             bail!("this virtual manifest specifies a [dev-dependencies] section, which is not allowed");
1435         }
1436         if me.build_dependencies.is_some() || me.build_dependencies2.is_some() {
1437             bail!("this virtual manifest specifies a [build-dependencies] section, which is not allowed");
1438         }
1439         if me.features.is_some() {
1440             bail!("this virtual manifest specifies a [features] section, which is not allowed");
1441         }
1442         if me.target.is_some() {
1443             bail!("this virtual manifest specifies a [target] section, which is not allowed");
1444         }
1445         if me.badges.is_some() {
1446             bail!("this virtual manifest specifies a [badges] section, which is not allowed");
1447         }
1448 
1449         let mut nested_paths = Vec::new();
1450         let mut warnings = Vec::new();
1451         let mut deps = Vec::new();
1452         let empty = Vec::new();
1453         let cargo_features = me.cargo_features.as_ref().unwrap_or(&empty);
1454         let features = Features::new(cargo_features, config, &mut warnings)?;
1455 
1456         let (replace, patch) = {
1457             let mut cx = Context {
1458                 deps: &mut deps,
1459                 source_id,
1460                 nested_paths: &mut nested_paths,
1461                 config,
1462                 warnings: &mut warnings,
1463                 platform: None,
1464                 features: &features,
1465                 root,
1466             };
1467             (me.replace(&mut cx)?, me.patch(&mut cx)?)
1468         };
1469         let profiles = me.profile.clone();
1470         if let Some(profiles) = &profiles {
1471             profiles.validate(&features, &mut warnings)?;
1472         }
1473         if me
1474             .workspace
1475             .as_ref()
1476             .map_or(false, |ws| ws.resolver.is_some())
1477         {
1478             features.require(Feature::resolver())?;
1479         }
1480         let resolve_behavior = me
1481             .workspace
1482             .as_ref()
1483             .and_then(|ws| ws.resolver.as_deref())
1484             .map(|r| ResolveBehavior::from_manifest(r))
1485             .transpose()?;
1486         let workspace_config = match me.workspace {
1487             Some(ref config) => WorkspaceConfig::Root(WorkspaceRootConfig::new(
1488                 root,
1489                 &config.members,
1490                 &config.default_members,
1491                 &config.exclude,
1492                 &config.metadata,
1493             )),
1494             None => {
1495                 bail!("virtual manifests must be configured with [workspace]");
1496             }
1497         };
1498         Ok((
1499             VirtualManifest::new(
1500                 replace,
1501                 patch,
1502                 workspace_config,
1503                 profiles,
1504                 features,
1505                 resolve_behavior,
1506             ),
1507             nested_paths,
1508         ))
1509     }
1510 
replace(&self, cx: &mut Context<'_, '_>) -> CargoResult<Vec<(PackageIdSpec, Dependency)>>1511     fn replace(&self, cx: &mut Context<'_, '_>) -> CargoResult<Vec<(PackageIdSpec, Dependency)>> {
1512         if self.patch.is_some() && self.replace.is_some() {
1513             bail!("cannot specify both [replace] and [patch]");
1514         }
1515         let mut replace = Vec::new();
1516         for (spec, replacement) in self.replace.iter().flatten() {
1517             let mut spec = PackageIdSpec::parse(spec).with_context(|| {
1518                 format!(
1519                     "replacements must specify a valid semver \
1520                      version to replace, but `{}` does not",
1521                     spec
1522                 )
1523             })?;
1524             if spec.url().is_none() {
1525                 spec.set_url(CRATES_IO_INDEX.parse().unwrap());
1526             }
1527 
1528             if replacement.is_version_specified() {
1529                 bail!(
1530                     "replacements cannot specify a version \
1531                      requirement, but found one for `{}`",
1532                     spec
1533                 );
1534             }
1535 
1536             let mut dep = replacement.to_dependency(spec.name().as_str(), cx, None)?;
1537             {
1538                 let version = spec.version().ok_or_else(|| {
1539                     anyhow!(
1540                         "replacements must specify a version \
1541                          to replace, but `{}` does not",
1542                         spec
1543                     )
1544                 })?;
1545                 dep.set_version_req(VersionReq::exact(version));
1546             }
1547             replace.push((spec, dep));
1548         }
1549         Ok(replace)
1550     }
1551 
patch(&self, cx: &mut Context<'_, '_>) -> CargoResult<HashMap<Url, Vec<Dependency>>>1552     fn patch(&self, cx: &mut Context<'_, '_>) -> CargoResult<HashMap<Url, Vec<Dependency>>> {
1553         let mut patch = HashMap::new();
1554         for (url, deps) in self.patch.iter().flatten() {
1555             let url = match &url[..] {
1556                 CRATES_IO_REGISTRY => CRATES_IO_INDEX.parse().unwrap(),
1557                 _ => cx
1558                     .config
1559                     .get_registry_index(url)
1560                     .or_else(|_| url.into_url())
1561                     .with_context(|| {
1562                         format!("[patch] entry `{}` should be a URL or registry name", url)
1563                     })?,
1564             };
1565             patch.insert(
1566                 url,
1567                 deps.iter()
1568                     .map(|(name, dep)| dep.to_dependency(name, cx, None))
1569                     .collect::<CargoResult<Vec<_>>>()?,
1570             );
1571         }
1572         Ok(patch)
1573     }
1574 
1575     /// Returns the path to the build script if one exists for this crate.
maybe_custom_build( &self, build: &Option<StringOrBool>, package_root: &Path, ) -> Option<PathBuf>1576     fn maybe_custom_build(
1577         &self,
1578         build: &Option<StringOrBool>,
1579         package_root: &Path,
1580     ) -> Option<PathBuf> {
1581         let build_rs = package_root.join("build.rs");
1582         match *build {
1583             // Explicitly no build script.
1584             Some(StringOrBool::Bool(false)) => None,
1585             Some(StringOrBool::Bool(true)) => Some(build_rs),
1586             Some(StringOrBool::String(ref s)) => Some(PathBuf::from(s)),
1587             None => {
1588                 // If there is a `build.rs` file next to the `Cargo.toml`, assume it is
1589                 // a build script.
1590                 if build_rs.is_file() {
1591                     Some(build_rs)
1592                 } else {
1593                     None
1594                 }
1595             }
1596         }
1597     }
1598 
has_profiles(&self) -> bool1599     pub fn has_profiles(&self) -> bool {
1600         self.profile.is_some()
1601     }
1602 
features(&self) -> Option<&BTreeMap<InternedString, Vec<InternedString>>>1603     pub fn features(&self) -> Option<&BTreeMap<InternedString, Vec<InternedString>>> {
1604         self.features.as_ref()
1605     }
1606 }
1607 
1608 /// Returns the name of the README file for a `TomlProject`.
readme_for_project(package_root: &Path, project: &TomlProject) -> Option<String>1609 fn readme_for_project(package_root: &Path, project: &TomlProject) -> Option<String> {
1610     match &project.readme {
1611         None => default_readme_from_package_root(package_root),
1612         Some(value) => match value {
1613             StringOrBool::Bool(false) => None,
1614             StringOrBool::Bool(true) => Some("README.md".to_string()),
1615             StringOrBool::String(v) => Some(v.clone()),
1616         },
1617     }
1618 }
1619 
1620 const DEFAULT_README_FILES: [&str; 3] = ["README.md", "README.txt", "README"];
1621 
1622 /// Checks if a file with any of the default README file names exists in the package root.
1623 /// If so, returns a `String` representing that name.
default_readme_from_package_root(package_root: &Path) -> Option<String>1624 fn default_readme_from_package_root(package_root: &Path) -> Option<String> {
1625     for &readme_filename in DEFAULT_README_FILES.iter() {
1626         if package_root.join(readme_filename).is_file() {
1627             return Some(readme_filename.to_string());
1628         }
1629     }
1630 
1631     None
1632 }
1633 
1634 /// Checks a list of build targets, and ensures the target names are unique within a vector.
1635 /// If not, the name of the offending build target is returned.
unique_build_targets(targets: &[Target], package_root: &Path) -> Result<(), String>1636 fn unique_build_targets(targets: &[Target], package_root: &Path) -> Result<(), String> {
1637     let mut seen = HashSet::new();
1638     for target in targets {
1639         if let TargetSourcePath::Path(path) = target.src_path() {
1640             let full = package_root.join(path);
1641             if !seen.insert(full.clone()) {
1642                 return Err(full.display().to_string());
1643             }
1644         }
1645     }
1646     Ok(())
1647 }
1648 
1649 impl<P: ResolveToPath> TomlDependency<P> {
to_dependency_split( &self, name: &str, source_id: SourceId, nested_paths: &mut Vec<PathBuf>, config: &Config, warnings: &mut Vec<String>, platform: Option<Platform>, root: &Path, features: &Features, kind: Option<DepKind>, ) -> CargoResult<Dependency>1650     pub(crate) fn to_dependency_split(
1651         &self,
1652         name: &str,
1653         source_id: SourceId,
1654         nested_paths: &mut Vec<PathBuf>,
1655         config: &Config,
1656         warnings: &mut Vec<String>,
1657         platform: Option<Platform>,
1658         root: &Path,
1659         features: &Features,
1660         kind: Option<DepKind>,
1661     ) -> CargoResult<Dependency> {
1662         self.to_dependency(
1663             name,
1664             &mut Context {
1665                 deps: &mut Vec::new(),
1666                 source_id,
1667                 nested_paths,
1668                 config,
1669                 warnings,
1670                 platform,
1671                 root,
1672                 features,
1673             },
1674             kind,
1675         )
1676     }
1677 
to_dependency( &self, name: &str, cx: &mut Context<'_, '_>, kind: Option<DepKind>, ) -> CargoResult<Dependency>1678     fn to_dependency(
1679         &self,
1680         name: &str,
1681         cx: &mut Context<'_, '_>,
1682         kind: Option<DepKind>,
1683     ) -> CargoResult<Dependency> {
1684         match *self {
1685             TomlDependency::Simple(ref version) => DetailedTomlDependency::<P> {
1686                 version: Some(version.clone()),
1687                 ..Default::default()
1688             }
1689             .to_dependency(name, cx, kind),
1690             TomlDependency::Detailed(ref details) => details.to_dependency(name, cx, kind),
1691         }
1692     }
1693 
is_version_specified(&self) -> bool1694     fn is_version_specified(&self) -> bool {
1695         match self {
1696             TomlDependency::Detailed(d) => d.version.is_some(),
1697             TomlDependency::Simple(..) => true,
1698         }
1699     }
1700 }
1701 
1702 impl<P: ResolveToPath> DetailedTomlDependency<P> {
to_dependency( &self, name_in_toml: &str, cx: &mut Context<'_, '_>, kind: Option<DepKind>, ) -> CargoResult<Dependency>1703     fn to_dependency(
1704         &self,
1705         name_in_toml: &str,
1706         cx: &mut Context<'_, '_>,
1707         kind: Option<DepKind>,
1708     ) -> CargoResult<Dependency> {
1709         if self.version.is_none() && self.path.is_none() && self.git.is_none() {
1710             let msg = format!(
1711                 "dependency ({}) specified without \
1712                  providing a local path, Git repository, or \
1713                  version to use. This will be considered an \
1714                  error in future versions",
1715                 name_in_toml
1716             );
1717             cx.warnings.push(msg);
1718         }
1719 
1720         if let Some(version) = &self.version {
1721             if version.contains('+') {
1722                 cx.warnings.push(format!(
1723                     "version requirement `{}` for dependency `{}` \
1724                      includes semver metadata which will be ignored, removing the \
1725                      metadata is recommended to avoid confusion",
1726                     version, name_in_toml
1727                 ));
1728             }
1729         }
1730 
1731         if self.git.is_none() {
1732             let git_only_keys = [
1733                 (&self.branch, "branch"),
1734                 (&self.tag, "tag"),
1735                 (&self.rev, "rev"),
1736             ];
1737 
1738             for &(key, key_name) in &git_only_keys {
1739                 if key.is_some() {
1740                     let msg = format!(
1741                         "key `{}` is ignored for dependency ({}). \
1742                          This will be considered an error in future versions",
1743                         key_name, name_in_toml
1744                     );
1745                     cx.warnings.push(msg)
1746                 }
1747             }
1748         }
1749 
1750         // Early detection of potentially misused feature syntax
1751         // instead of generating a "feature not found" error.
1752         if let Some(features) = &self.features {
1753             for feature in features {
1754                 if feature.contains('/') {
1755                     bail!(
1756                         "feature `{}` in dependency `{}` is not allowed to contain slashes\n\
1757                          If you want to enable features of a transitive dependency, \
1758                          the direct dependency needs to re-export those features from \
1759                          the `[features]` table.",
1760                         feature,
1761                         name_in_toml
1762                     );
1763                 }
1764                 if feature.starts_with("dep:") {
1765                     bail!(
1766                         "feature `{}` in dependency `{}` is not allowed to use explicit \
1767                         `dep:` syntax\n\
1768                          If you want to enable an optional dependency, specify the name \
1769                          of the optional dependency without the `dep:` prefix, or specify \
1770                          a feature from the dependency's `[features]` table that enables \
1771                          the optional dependency.",
1772                         feature,
1773                         name_in_toml
1774                     );
1775                 }
1776             }
1777         }
1778 
1779         let new_source_id = match (
1780             self.git.as_ref(),
1781             self.path.as_ref(),
1782             self.registry.as_ref(),
1783             self.registry_index.as_ref(),
1784         ) {
1785             (Some(_), _, Some(_), _) | (Some(_), _, _, Some(_)) => bail!(
1786                 "dependency ({}) specification is ambiguous. \
1787                  Only one of `git` or `registry` is allowed.",
1788                 name_in_toml
1789             ),
1790             (_, _, Some(_), Some(_)) => bail!(
1791                 "dependency ({}) specification is ambiguous. \
1792                  Only one of `registry` or `registry-index` is allowed.",
1793                 name_in_toml
1794             ),
1795             (Some(git), maybe_path, _, _) => {
1796                 if maybe_path.is_some() {
1797                     let msg = format!(
1798                         "dependency ({}) specification is ambiguous. \
1799                          Only one of `git` or `path` is allowed. \
1800                          This will be considered an error in future versions",
1801                         name_in_toml
1802                     );
1803                     cx.warnings.push(msg)
1804                 }
1805 
1806                 let n_details = [&self.branch, &self.tag, &self.rev]
1807                     .iter()
1808                     .filter(|d| d.is_some())
1809                     .count();
1810 
1811                 if n_details > 1 {
1812                     bail!(
1813                         "dependency ({}) specification is ambiguous. \
1814                          Only one of `branch`, `tag` or `rev` is allowed.",
1815                         name_in_toml
1816                     );
1817                 }
1818 
1819                 let reference = self
1820                     .branch
1821                     .clone()
1822                     .map(GitReference::Branch)
1823                     .or_else(|| self.tag.clone().map(GitReference::Tag))
1824                     .or_else(|| self.rev.clone().map(GitReference::Rev))
1825                     .unwrap_or(GitReference::DefaultBranch);
1826                 let loc = git.into_url()?;
1827 
1828                 if let Some(fragment) = loc.fragment() {
1829                     let msg = format!(
1830                         "URL fragment `#{}` in git URL is ignored for dependency ({}). \
1831                         If you were trying to specify a specific git revision, \
1832                         use `rev = \"{}\"` in the dependency declaration.",
1833                         fragment, name_in_toml, fragment
1834                     );
1835                     cx.warnings.push(msg)
1836                 }
1837 
1838                 SourceId::for_git(&loc, reference)?
1839             }
1840             (None, Some(path), _, _) => {
1841                 let path = path.resolve(cx.config);
1842                 cx.nested_paths.push(path.clone());
1843                 // If the source ID for the package we're parsing is a path
1844                 // source, then we normalize the path here to get rid of
1845                 // components like `..`.
1846                 //
1847                 // The purpose of this is to get a canonical ID for the package
1848                 // that we're depending on to ensure that builds of this package
1849                 // always end up hashing to the same value no matter where it's
1850                 // built from.
1851                 if cx.source_id.is_path() {
1852                     let path = cx.root.join(path);
1853                     let path = paths::normalize_path(&path);
1854                     SourceId::for_path(&path)?
1855                 } else {
1856                     cx.source_id
1857                 }
1858             }
1859             (None, None, Some(registry), None) => SourceId::alt_registry(cx.config, registry)?,
1860             (None, None, None, Some(registry_index)) => {
1861                 let url = registry_index.into_url()?;
1862                 SourceId::for_registry(&url)?
1863             }
1864             (None, None, None, None) => SourceId::crates_io(cx.config)?,
1865         };
1866 
1867         let (pkg_name, explicit_name_in_toml) = match self.package {
1868             Some(ref s) => (&s[..], Some(name_in_toml)),
1869             None => (name_in_toml, None),
1870         };
1871 
1872         let version = self.version.as_deref();
1873         let mut dep = Dependency::parse(pkg_name, version, new_source_id)?;
1874         dep.set_features(self.features.iter().flatten())
1875             .set_default_features(
1876                 self.default_features
1877                     .or(self.default_features2)
1878                     .unwrap_or(true),
1879             )
1880             .set_optional(self.optional.unwrap_or(false))
1881             .set_platform(cx.platform.clone());
1882         if let Some(registry) = &self.registry {
1883             let registry_id = SourceId::alt_registry(cx.config, registry)?;
1884             dep.set_registry_id(registry_id);
1885         }
1886         if let Some(registry_index) = &self.registry_index {
1887             let url = registry_index.into_url()?;
1888             let registry_id = SourceId::for_registry(&url)?;
1889             dep.set_registry_id(registry_id);
1890         }
1891 
1892         if let Some(kind) = kind {
1893             dep.set_kind(kind);
1894         }
1895         if let Some(name_in_toml) = explicit_name_in_toml {
1896             cx.features.require(Feature::rename_dependency())?;
1897             dep.set_explicit_name_in_toml(name_in_toml);
1898         }
1899 
1900         if let Some(p) = self.public {
1901             cx.features.require(Feature::public_dependency())?;
1902 
1903             if dep.kind() != DepKind::Normal {
1904                 bail!("'public' specifier can only be used on regular dependencies, not {:?} dependencies", dep.kind());
1905             }
1906 
1907             dep.set_public(p);
1908         }
1909         Ok(dep)
1910     }
1911 }
1912 
1913 #[derive(Default, Serialize, Deserialize, Debug, Clone)]
1914 struct TomlTarget {
1915     name: Option<String>,
1916 
1917     // The intention was to only accept `crate-type` here but historical
1918     // versions of Cargo also accepted `crate_type`, so look for both.
1919     #[serde(rename = "crate-type")]
1920     crate_type: Option<Vec<String>>,
1921     #[serde(rename = "crate_type")]
1922     crate_type2: Option<Vec<String>>,
1923 
1924     path: Option<PathValue>,
1925     test: Option<bool>,
1926     doctest: Option<bool>,
1927     bench: Option<bool>,
1928     doc: Option<bool>,
1929     plugin: Option<bool>,
1930     #[serde(rename = "proc-macro")]
1931     proc_macro_raw: Option<bool>,
1932     #[serde(rename = "proc_macro")]
1933     proc_macro_raw2: Option<bool>,
1934     harness: Option<bool>,
1935     #[serde(rename = "required-features")]
1936     required_features: Option<Vec<String>>,
1937     edition: Option<String>,
1938 }
1939 
1940 #[derive(Clone)]
1941 struct PathValue(PathBuf);
1942 
1943 impl<'de> de::Deserialize<'de> for PathValue {
deserialize<D>(deserializer: D) -> Result<Self, D::Error> where D: de::Deserializer<'de>,1944     fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
1945     where
1946         D: de::Deserializer<'de>,
1947     {
1948         Ok(PathValue(String::deserialize(deserializer)?.into()))
1949     }
1950 }
1951 
1952 impl ser::Serialize for PathValue {
serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> where S: ser::Serializer,1953     fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
1954     where
1955         S: ser::Serializer,
1956     {
1957         self.0.serialize(serializer)
1958     }
1959 }
1960 
1961 /// Corresponds to a `target` entry, but `TomlTarget` is already used.
1962 #[derive(Serialize, Deserialize, Debug)]
1963 struct TomlPlatform {
1964     dependencies: Option<BTreeMap<String, TomlDependency>>,
1965     #[serde(rename = "build-dependencies")]
1966     build_dependencies: Option<BTreeMap<String, TomlDependency>>,
1967     #[serde(rename = "build_dependencies")]
1968     build_dependencies2: Option<BTreeMap<String, TomlDependency>>,
1969     #[serde(rename = "dev-dependencies")]
1970     dev_dependencies: Option<BTreeMap<String, TomlDependency>>,
1971     #[serde(rename = "dev_dependencies")]
1972     dev_dependencies2: Option<BTreeMap<String, TomlDependency>>,
1973 }
1974 
1975 impl TomlTarget {
new() -> TomlTarget1976     fn new() -> TomlTarget {
1977         TomlTarget::default()
1978     }
1979 
name(&self) -> String1980     fn name(&self) -> String {
1981         match self.name {
1982             Some(ref name) => name.clone(),
1983             None => panic!("target name is required"),
1984         }
1985     }
1986 
proc_macro(&self) -> Option<bool>1987     fn proc_macro(&self) -> Option<bool> {
1988         self.proc_macro_raw.or(self.proc_macro_raw2).or_else(|| {
1989             if let Some(types) = self.crate_types() {
1990                 if types.contains(&"proc-macro".to_string()) {
1991                     return Some(true);
1992                 }
1993             }
1994             None
1995         })
1996     }
1997 
crate_types(&self) -> Option<&Vec<String>>1998     fn crate_types(&self) -> Option<&Vec<String>> {
1999         self.crate_type
2000             .as_ref()
2001             .or_else(|| self.crate_type2.as_ref())
2002     }
2003 }
2004 
2005 impl fmt::Debug for PathValue {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result2006     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2007         self.0.fmt(f)
2008     }
2009 }
2010