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