cargo/core/
manifest.rs

1use std::borrow::Cow;
2use std::collections::{BTreeMap, HashMap};
3use std::fmt;
4use std::hash::{Hash, Hasher};
5use std::path::{Path, PathBuf};
6use std::rc::Rc;
7use std::sync::Arc;
8
9use anyhow::Context as _;
10use cargo_util_schemas::manifest::RustVersion;
11use cargo_util_schemas::manifest::{TomlManifest, TomlProfiles};
12use semver::Version;
13use serde::ser;
14use serde::Serialize;
15use url::Url;
16
17use crate::core::compiler::rustdoc::RustdocScrapeExamples;
18use crate::core::compiler::{CompileKind, CrateType};
19use crate::core::resolver::ResolveBehavior;
20use crate::core::{Dependency, PackageId, PackageIdSpec, SourceId, Summary};
21use crate::core::{Edition, Feature, Features, WorkspaceConfig};
22use crate::util::errors::*;
23use crate::util::interning::InternedString;
24use crate::util::{short_hash, Filesystem, GlobalContext};
25
26pub const MANIFEST_PREAMBLE: &str = "\
27# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO
28#
29# When uploading crates to the registry Cargo will automatically
30# \"normalize\" Cargo.toml files for maximal compatibility
31# with all versions of Cargo and also rewrite `path` dependencies
32# to registry (e.g., crates.io) dependencies.
33#
34# If you are reading this file be aware that the original Cargo.toml
35# will likely look very different (and much more reasonable).
36# See Cargo.toml.orig for the original contents.
37";
38
39pub enum EitherManifest {
40    Real(Manifest),
41    Virtual(VirtualManifest),
42}
43
44impl EitherManifest {
45    pub fn warnings_mut(&mut self) -> &mut Warnings {
46        match self {
47            EitherManifest::Real(r) => r.warnings_mut(),
48            EitherManifest::Virtual(v) => v.warnings_mut(),
49        }
50    }
51    pub(crate) fn workspace_config(&self) -> &WorkspaceConfig {
52        match *self {
53            EitherManifest::Real(ref r) => r.workspace_config(),
54            EitherManifest::Virtual(ref v) => v.workspace_config(),
55        }
56    }
57}
58
59/// Contains all the information about a package, as loaded from a `Cargo.toml`.
60///
61/// This is deserialized using the [`TomlManifest`] type.
62#[derive(Clone, Debug)]
63pub struct Manifest {
64    // alternate forms of manifests:
65    contents: Rc<String>,
66    document: Rc<toml_edit::ImDocument<String>>,
67    original_toml: Rc<TomlManifest>,
68    normalized_toml: Rc<TomlManifest>,
69    summary: Summary,
70
71    // this form of manifest:
72    targets: Vec<Target>,
73    default_kind: Option<CompileKind>,
74    forced_kind: Option<CompileKind>,
75    links: Option<String>,
76    warnings: Warnings,
77    exclude: Vec<String>,
78    include: Vec<String>,
79    metadata: ManifestMetadata,
80    custom_metadata: Option<toml::Value>,
81    publish: Option<Vec<String>>,
82    replace: Vec<(PackageIdSpec, Dependency)>,
83    patch: HashMap<Url, Vec<Dependency>>,
84    workspace: WorkspaceConfig,
85    unstable_features: Features,
86    edition: Edition,
87    rust_version: Option<RustVersion>,
88    im_a_teapot: Option<bool>,
89    default_run: Option<String>,
90    metabuild: Option<Vec<String>>,
91    resolve_behavior: Option<ResolveBehavior>,
92    lint_rustflags: Vec<String>,
93    embedded: bool,
94}
95
96/// When parsing `Cargo.toml`, some warnings should silenced
97/// if the manifest comes from a dependency. `ManifestWarning`
98/// allows this delayed emission of warnings.
99#[derive(Clone, Debug)]
100pub struct DelayedWarning {
101    pub message: String,
102    pub is_critical: bool,
103}
104
105#[derive(Clone, Debug)]
106pub struct Warnings(Vec<DelayedWarning>);
107
108#[derive(Clone, Debug)]
109pub struct VirtualManifest {
110    // alternate forms of manifests:
111    contents: Rc<String>,
112    document: Rc<toml_edit::ImDocument<String>>,
113    original_toml: Rc<TomlManifest>,
114    normalized_toml: Rc<TomlManifest>,
115
116    // this form of manifest:
117    replace: Vec<(PackageIdSpec, Dependency)>,
118    patch: HashMap<Url, Vec<Dependency>>,
119    workspace: WorkspaceConfig,
120    warnings: Warnings,
121    features: Features,
122    resolve_behavior: Option<ResolveBehavior>,
123}
124
125/// General metadata about a package which is just blindly uploaded to the
126/// registry.
127///
128/// Note that many of these fields can contain invalid values such as the
129/// homepage, repository, documentation, or license. These fields are not
130/// validated by cargo itself, but rather it is up to the registry when uploaded
131/// to validate these fields. Cargo will itself accept any valid TOML
132/// specification for these values.
133#[derive(PartialEq, Clone, Debug)]
134pub struct ManifestMetadata {
135    pub authors: Vec<String>,
136    pub keywords: Vec<String>,
137    pub categories: Vec<String>,
138    pub license: Option<String>,
139    pub license_file: Option<String>,
140    pub description: Option<String>,   // Not in Markdown
141    pub readme: Option<String>,        // File, not contents
142    pub homepage: Option<String>,      // URL
143    pub repository: Option<String>,    // URL
144    pub documentation: Option<String>, // URL
145    pub badges: BTreeMap<String, BTreeMap<String, String>>,
146    pub links: Option<String>,
147    pub rust_version: Option<RustVersion>,
148}
149
150impl ManifestMetadata {
151    /// Whether the given env var should be tracked by Cargo's dep-info.
152    pub fn should_track(env_key: &str) -> bool {
153        let keys = MetadataEnvs::keys();
154        keys.iter().any(|k| *k == env_key)
155    }
156
157    pub fn env_var<'a>(&'a self, env_key: &str) -> Option<Cow<'a, str>> {
158        MetadataEnvs::var(self, env_key)
159    }
160
161    pub fn env_vars(&self) -> impl Iterator<Item = (&'static str, Cow<'_, str>)> {
162        MetadataEnvs::keys()
163            .iter()
164            .map(|k| (*k, MetadataEnvs::var(self, k).unwrap()))
165    }
166}
167
168macro_rules! get_metadata_env {
169    ($meta:ident, $field:ident) => {
170        $meta.$field.as_deref().unwrap_or_default().into()
171    };
172    ($meta:ident, $field:ident, $to_var:expr) => {
173        $to_var($meta).into()
174    };
175}
176
177struct MetadataEnvs;
178
179macro_rules! metadata_envs {
180    (
181        $(
182            ($field:ident, $key:literal$(, $to_var:expr)?),
183        )*
184    ) => {
185        impl MetadataEnvs {
186            fn keys() -> &'static [&'static str] {
187                &[$($key),*]
188            }
189
190            fn var<'a>(meta: &'a ManifestMetadata, key: &str) -> Option<Cow<'a, str>> {
191                match key {
192                    $($key => Some(get_metadata_env!(meta, $field$(, $to_var)?)),)*
193                    _ => None,
194                }
195            }
196        }
197    }
198}
199
200// Metadata environmental variables that are emitted to rustc. Usable by `env!()`
201// If these change we need to trigger a rebuild.
202// NOTE: The env var name will be prefixed with `CARGO_PKG_`
203metadata_envs! {
204    (description, "CARGO_PKG_DESCRIPTION"),
205    (homepage, "CARGO_PKG_HOMEPAGE"),
206    (repository, "CARGO_PKG_REPOSITORY"),
207    (license, "CARGO_PKG_LICENSE"),
208    (license_file, "CARGO_PKG_LICENSE_FILE"),
209    (authors, "CARGO_PKG_AUTHORS", |m: &ManifestMetadata| m.authors.join(":")),
210    (rust_version, "CARGO_PKG_RUST_VERSION", |m: &ManifestMetadata| m.rust_version.as_ref().map(ToString::to_string).unwrap_or_default()),
211    (readme, "CARGO_PKG_README"),
212}
213
214#[derive(Clone, Hash, PartialEq, Eq, PartialOrd, Ord)]
215pub enum TargetKind {
216    Lib(Vec<CrateType>),
217    Bin,
218    Test,
219    Bench,
220    ExampleLib(Vec<CrateType>),
221    ExampleBin,
222    CustomBuild,
223}
224
225impl ser::Serialize for TargetKind {
226    fn serialize<S>(&self, s: S) -> Result<S::Ok, S::Error>
227    where
228        S: ser::Serializer,
229    {
230        use self::TargetKind::*;
231        match self {
232            Lib(kinds) => s.collect_seq(kinds.iter().map(|t| t.to_string())),
233            Bin => ["bin"].serialize(s),
234            ExampleBin | ExampleLib(_) => ["example"].serialize(s),
235            Test => ["test"].serialize(s),
236            CustomBuild => ["custom-build"].serialize(s),
237            Bench => ["bench"].serialize(s),
238        }
239    }
240}
241
242impl fmt::Debug for TargetKind {
243    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
244        use self::TargetKind::*;
245        match *self {
246            Lib(ref kinds) => kinds.fmt(f),
247            Bin => "bin".fmt(f),
248            ExampleBin | ExampleLib(_) => "example".fmt(f),
249            Test => "test".fmt(f),
250            CustomBuild => "custom-build".fmt(f),
251            Bench => "bench".fmt(f),
252        }
253    }
254}
255
256impl TargetKind {
257    pub fn description(&self) -> &'static str {
258        match self {
259            TargetKind::Lib(..) => "lib",
260            TargetKind::Bin => "bin",
261            TargetKind::Test => "integration-test",
262            TargetKind::ExampleBin | TargetKind::ExampleLib(..) => "example",
263            TargetKind::Bench => "bench",
264            TargetKind::CustomBuild => "build-script",
265        }
266    }
267
268    /// Returns whether production of this artifact requires the object files
269    /// from dependencies to be available.
270    ///
271    /// This only returns `false` when all we're producing is an rlib, otherwise
272    /// it will return `true`.
273    pub fn requires_upstream_objects(&self) -> bool {
274        match self {
275            TargetKind::Lib(kinds) | TargetKind::ExampleLib(kinds) => {
276                kinds.iter().any(|k| k.requires_upstream_objects())
277            }
278            _ => true,
279        }
280    }
281
282    /// Returns whether production of this artifact could benefit from splitting metadata
283    /// into a .rmeta file.
284    pub fn benefits_from_no_embed_metadata(&self) -> bool {
285        match self {
286            TargetKind::Lib(kinds) | TargetKind::ExampleLib(kinds) => {
287                kinds.iter().any(|k| k.benefits_from_no_embed_metadata())
288            }
289            _ => false,
290        }
291    }
292
293    /// Returns the arguments suitable for `--crate-type` to pass to rustc.
294    pub fn rustc_crate_types(&self) -> Vec<CrateType> {
295        match self {
296            TargetKind::Lib(kinds) | TargetKind::ExampleLib(kinds) => kinds.clone(),
297            TargetKind::CustomBuild
298            | TargetKind::Bench
299            | TargetKind::Test
300            | TargetKind::ExampleBin
301            | TargetKind::Bin => vec![CrateType::Bin],
302        }
303    }
304}
305
306/// Information about a binary, a library, an example, etc. that is part of the
307/// package.
308#[derive(Clone, Hash, PartialEq, Eq, PartialOrd, Ord)]
309pub struct Target {
310    inner: Arc<TargetInner>,
311}
312
313#[derive(Clone, Hash, PartialEq, Eq, PartialOrd, Ord)]
314struct TargetInner {
315    kind: TargetKind,
316    name: String,
317    // Whether the name was inferred by Cargo, or explicitly given.
318    name_inferred: bool,
319    // Note that `bin_name` is used for the cargo-feature `different_binary_name`
320    bin_name: Option<String>,
321    // Note that the `src_path` here is excluded from the `Hash` implementation
322    // as it's absolute currently and is otherwise a little too brittle for
323    // causing rebuilds. Instead the hash for the path that we send to the
324    // compiler is handled elsewhere.
325    src_path: TargetSourcePath,
326    required_features: Option<Vec<String>>,
327    tested: bool,
328    benched: bool,
329    doc: bool,
330    doctest: bool,
331    harness: bool, // whether to use the test harness (--test)
332    for_host: bool,
333    proc_macro: bool,
334    edition: Edition,
335    doc_scrape_examples: RustdocScrapeExamples,
336}
337
338#[derive(Clone, PartialEq, Eq, PartialOrd, Ord)]
339pub enum TargetSourcePath {
340    Path(PathBuf),
341    Metabuild,
342}
343
344impl TargetSourcePath {
345    pub fn path(&self) -> Option<&Path> {
346        match self {
347            TargetSourcePath::Path(path) => Some(path.as_ref()),
348            TargetSourcePath::Metabuild => None,
349        }
350    }
351
352    pub fn is_path(&self) -> bool {
353        matches!(self, TargetSourcePath::Path(_))
354    }
355}
356
357impl Hash for TargetSourcePath {
358    fn hash<H: Hasher>(&self, _: &mut H) {
359        // ...
360    }
361}
362
363impl fmt::Debug for TargetSourcePath {
364    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
365        match self {
366            TargetSourcePath::Path(path) => path.fmt(f),
367            TargetSourcePath::Metabuild => "metabuild".fmt(f),
368        }
369    }
370}
371
372impl From<PathBuf> for TargetSourcePath {
373    fn from(path: PathBuf) -> Self {
374        assert!(path.is_absolute(), "`{}` is not absolute", path.display());
375        TargetSourcePath::Path(path)
376    }
377}
378
379#[derive(Serialize)]
380struct SerializedTarget<'a> {
381    /// Is this a `--bin bin`, `--lib`, `--example ex`?
382    /// Serialized as a list of strings for historical reasons.
383    kind: &'a TargetKind,
384    /// Corresponds to `--crate-type` compiler attribute.
385    /// See <https://doc.rust-lang.org/reference/linkage.html>
386    crate_types: Vec<CrateType>,
387    name: &'a str,
388    src_path: Option<&'a PathBuf>,
389    edition: &'a str,
390    #[serde(rename = "required-features", skip_serializing_if = "Option::is_none")]
391    required_features: Option<Vec<&'a str>>,
392    /// Whether docs should be built for the target via `cargo doc`
393    /// See <https://doc.rust-lang.org/cargo/commands/cargo-doc.html#target-selection>
394    doc: bool,
395    doctest: bool,
396    /// Whether tests should be run for the target (`test` field in `Cargo.toml`)
397    test: bool,
398}
399
400impl ser::Serialize for Target {
401    fn serialize<S: ser::Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
402        let src_path = match self.src_path() {
403            TargetSourcePath::Path(p) => Some(p),
404            // Unfortunately getting the correct path would require access to
405            // target_dir, which is not available here.
406            TargetSourcePath::Metabuild => None,
407        };
408        SerializedTarget {
409            kind: self.kind(),
410            crate_types: self.rustc_crate_types(),
411            name: self.name(),
412            src_path,
413            edition: &self.edition().to_string(),
414            required_features: self
415                .required_features()
416                .map(|rf| rf.iter().map(|s| s.as_str()).collect()),
417            doc: self.documented(),
418            doctest: self.doctested() && self.doctestable(),
419            test: self.tested(),
420        }
421        .serialize(s)
422    }
423}
424
425impl fmt::Debug for Target {
426    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
427        self.inner.fmt(f)
428    }
429}
430
431compact_debug! {
432    impl fmt::Debug for TargetInner {
433        fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
434            let (default, default_name) = {
435                match &self.kind {
436                    TargetKind::Lib(kinds) => {
437                        (
438                            Target::lib_target(
439                                &self.name,
440                                kinds.clone(),
441                                self.src_path.path().unwrap().to_path_buf(),
442                                self.edition,
443                            ).inner,
444                            format!("lib_target({:?}, {:?}, {:?}, {:?})",
445                                    self.name, kinds, self.src_path, self.edition),
446                        )
447                    }
448                    TargetKind::CustomBuild => {
449                        match self.src_path {
450                            TargetSourcePath::Path(ref path) => {
451                                (
452                                    Target::custom_build_target(
453                                        &self.name,
454                                        path.to_path_buf(),
455                                        self.edition,
456                                    ).inner,
457                                    format!("custom_build_target({:?}, {:?}, {:?})",
458                                            self.name, path, self.edition),
459                                )
460                            }
461                            TargetSourcePath::Metabuild => {
462                                (
463                                    Target::metabuild_target(&self.name).inner,
464                                    format!("metabuild_target({:?})", self.name),
465                                )
466                            }
467                        }
468                    }
469                    _ => (
470                        Target::new(self.src_path.clone(), self.edition).inner,
471                        format!("with_path({:?}, {:?})", self.src_path, self.edition),
472                    ),
473                }
474            };
475            [debug_the_fields(
476                kind
477                name
478                name_inferred
479                bin_name
480                src_path
481                required_features
482                tested
483                benched
484                doc
485                doctest
486                harness
487                for_host
488                proc_macro
489                edition
490                doc_scrape_examples
491            )]
492        }
493    }
494}
495
496impl Manifest {
497    pub fn new(
498        contents: Rc<String>,
499        document: Rc<toml_edit::ImDocument<String>>,
500        original_toml: Rc<TomlManifest>,
501        normalized_toml: Rc<TomlManifest>,
502        summary: Summary,
503
504        default_kind: Option<CompileKind>,
505        forced_kind: Option<CompileKind>,
506        targets: Vec<Target>,
507        exclude: Vec<String>,
508        include: Vec<String>,
509        links: Option<String>,
510        metadata: ManifestMetadata,
511        custom_metadata: Option<toml::Value>,
512        publish: Option<Vec<String>>,
513        replace: Vec<(PackageIdSpec, Dependency)>,
514        patch: HashMap<Url, Vec<Dependency>>,
515        workspace: WorkspaceConfig,
516        unstable_features: Features,
517        edition: Edition,
518        rust_version: Option<RustVersion>,
519        im_a_teapot: Option<bool>,
520        default_run: Option<String>,
521        metabuild: Option<Vec<String>>,
522        resolve_behavior: Option<ResolveBehavior>,
523        lint_rustflags: Vec<String>,
524        embedded: bool,
525    ) -> Manifest {
526        Manifest {
527            contents,
528            document,
529            original_toml,
530            normalized_toml,
531            summary,
532
533            default_kind,
534            forced_kind,
535            targets,
536            warnings: Warnings::new(),
537            exclude,
538            include,
539            links,
540            metadata,
541            custom_metadata,
542            publish,
543            replace,
544            patch,
545            workspace,
546            unstable_features,
547            edition,
548            rust_version,
549            im_a_teapot,
550            default_run,
551            metabuild,
552            resolve_behavior,
553            lint_rustflags,
554            embedded,
555        }
556    }
557
558    /// The raw contents of the original TOML
559    pub fn contents(&self) -> &str {
560        self.contents.as_str()
561    }
562    /// See [`Manifest::normalized_toml`] for what "normalized" means
563    pub fn to_normalized_contents(&self) -> CargoResult<String> {
564        let toml = toml::to_string_pretty(self.normalized_toml())?;
565        Ok(format!("{}\n{}", MANIFEST_PREAMBLE, toml))
566    }
567    /// Collection of spans for the original TOML
568    pub fn document(&self) -> &toml_edit::ImDocument<String> {
569        &self.document
570    }
571    /// The [`TomlManifest`] as parsed from [`Manifest::document`]
572    pub fn original_toml(&self) -> &TomlManifest {
573        &self.original_toml
574    }
575    /// The [`TomlManifest`] with all fields expanded
576    ///
577    /// This is the intersection of what fields need resolving for cargo-publish that also are
578    /// useful for the operation of cargo, including
579    /// - workspace inheritance
580    /// - target discovery
581    pub fn normalized_toml(&self) -> &TomlManifest {
582        &self.normalized_toml
583    }
584    pub fn summary(&self) -> &Summary {
585        &self.summary
586    }
587    pub fn summary_mut(&mut self) -> &mut Summary {
588        &mut self.summary
589    }
590
591    pub fn dependencies(&self) -> &[Dependency] {
592        self.summary.dependencies()
593    }
594    pub fn default_kind(&self) -> Option<CompileKind> {
595        self.default_kind
596    }
597    pub fn forced_kind(&self) -> Option<CompileKind> {
598        self.forced_kind
599    }
600    pub fn exclude(&self) -> &[String] {
601        &self.exclude
602    }
603    pub fn include(&self) -> &[String] {
604        &self.include
605    }
606    pub fn metadata(&self) -> &ManifestMetadata {
607        &self.metadata
608    }
609    pub fn name(&self) -> InternedString {
610        self.package_id().name()
611    }
612    pub fn package_id(&self) -> PackageId {
613        self.summary.package_id()
614    }
615    pub fn targets(&self) -> &[Target] {
616        &self.targets
617    }
618    // It is used by cargo-c, please do not remove it
619    pub fn targets_mut(&mut self) -> &mut [Target] {
620        &mut self.targets
621    }
622    pub fn version(&self) -> &Version {
623        self.package_id().version()
624    }
625    pub fn warnings_mut(&mut self) -> &mut Warnings {
626        &mut self.warnings
627    }
628    pub fn warnings(&self) -> &Warnings {
629        &self.warnings
630    }
631    pub fn profiles(&self) -> Option<&TomlProfiles> {
632        self.normalized_toml.profile.as_ref()
633    }
634    pub fn publish(&self) -> &Option<Vec<String>> {
635        &self.publish
636    }
637    pub fn replace(&self) -> &[(PackageIdSpec, Dependency)] {
638        &self.replace
639    }
640    pub fn patch(&self) -> &HashMap<Url, Vec<Dependency>> {
641        &self.patch
642    }
643    pub fn links(&self) -> Option<&str> {
644        self.links.as_deref()
645    }
646    pub fn is_embedded(&self) -> bool {
647        self.embedded
648    }
649
650    pub fn workspace_config(&self) -> &WorkspaceConfig {
651        &self.workspace
652    }
653
654    /// Unstable, nightly features that are enabled in this manifest.
655    pub fn unstable_features(&self) -> &Features {
656        &self.unstable_features
657    }
658
659    /// The style of resolver behavior to use, declared with the `resolver` field.
660    ///
661    /// Returns `None` if it is not specified.
662    pub fn resolve_behavior(&self) -> Option<ResolveBehavior> {
663        self.resolve_behavior
664    }
665
666    /// `RUSTFLAGS` from the `[lints]` table
667    pub fn lint_rustflags(&self) -> &[String] {
668        self.lint_rustflags.as_slice()
669    }
670
671    pub fn map_source(self, to_replace: SourceId, replace_with: SourceId) -> Manifest {
672        Manifest {
673            summary: self.summary.map_source(to_replace, replace_with),
674            ..self
675        }
676    }
677
678    pub fn feature_gate(&self) -> CargoResult<()> {
679        if self.im_a_teapot.is_some() {
680            self.unstable_features
681                .require(Feature::test_dummy_unstable())
682                .with_context(|| {
683                    "the `im-a-teapot` manifest key is unstable and may \
684                     not work properly in England"
685                })?;
686        }
687
688        if self.default_kind.is_some() || self.forced_kind.is_some() {
689            self.unstable_features
690                .require(Feature::per_package_target())
691                .with_context(|| {
692                    "the `package.default-target` and `package.forced-target` \
693                     manifest keys are unstable and may not work properly"
694                })?;
695        }
696
697        Ok(())
698    }
699
700    // Just a helper function to test out `-Z` flags on Cargo
701    pub fn print_teapot(&self, gctx: &GlobalContext) {
702        if let Some(teapot) = self.im_a_teapot {
703            if gctx.cli_unstable().print_im_a_teapot {
704                crate::drop_println!(gctx, "im-a-teapot = {}", teapot);
705            }
706        }
707    }
708
709    pub fn edition(&self) -> Edition {
710        self.edition
711    }
712
713    pub fn rust_version(&self) -> Option<&RustVersion> {
714        self.rust_version.as_ref()
715    }
716
717    pub fn custom_metadata(&self) -> Option<&toml::Value> {
718        self.custom_metadata.as_ref()
719    }
720
721    pub fn default_run(&self) -> Option<&str> {
722        self.default_run.as_deref()
723    }
724
725    pub fn metabuild(&self) -> Option<&Vec<String>> {
726        self.metabuild.as_ref()
727    }
728
729    pub fn metabuild_path(&self, target_dir: Filesystem) -> PathBuf {
730        let hash = short_hash(&self.package_id());
731        target_dir
732            .into_path_unlocked()
733            .join(".metabuild")
734            .join(format!("metabuild-{}-{}.rs", self.name(), hash))
735    }
736}
737
738impl VirtualManifest {
739    pub fn new(
740        contents: Rc<String>,
741        document: Rc<toml_edit::ImDocument<String>>,
742        original_toml: Rc<TomlManifest>,
743        normalized_toml: Rc<TomlManifest>,
744        replace: Vec<(PackageIdSpec, Dependency)>,
745        patch: HashMap<Url, Vec<Dependency>>,
746        workspace: WorkspaceConfig,
747        features: Features,
748        resolve_behavior: Option<ResolveBehavior>,
749    ) -> VirtualManifest {
750        VirtualManifest {
751            contents,
752            document,
753            original_toml,
754            normalized_toml,
755            replace,
756            patch,
757            workspace,
758            warnings: Warnings::new(),
759            features,
760            resolve_behavior,
761        }
762    }
763
764    /// The raw contents of the original TOML
765    pub fn contents(&self) -> &str {
766        self.contents.as_str()
767    }
768    /// Collection of spans for the original TOML
769    pub fn document(&self) -> &toml_edit::ImDocument<String> {
770        &self.document
771    }
772    /// The [`TomlManifest`] as parsed from [`VirtualManifest::document`]
773    pub fn original_toml(&self) -> &TomlManifest {
774        &self.original_toml
775    }
776    /// The [`TomlManifest`] with all fields expanded
777    pub fn normalized_toml(&self) -> &TomlManifest {
778        &self.normalized_toml
779    }
780
781    pub fn replace(&self) -> &[(PackageIdSpec, Dependency)] {
782        &self.replace
783    }
784
785    pub fn patch(&self) -> &HashMap<Url, Vec<Dependency>> {
786        &self.patch
787    }
788
789    pub fn workspace_config(&self) -> &WorkspaceConfig {
790        &self.workspace
791    }
792
793    pub fn profiles(&self) -> Option<&TomlProfiles> {
794        self.normalized_toml.profile.as_ref()
795    }
796
797    pub fn warnings_mut(&mut self) -> &mut Warnings {
798        &mut self.warnings
799    }
800
801    pub fn warnings(&self) -> &Warnings {
802        &self.warnings
803    }
804
805    pub fn unstable_features(&self) -> &Features {
806        &self.features
807    }
808
809    /// The style of resolver behavior to use, declared with the `resolver` field.
810    ///
811    /// Returns `None` if it is not specified.
812    pub fn resolve_behavior(&self) -> Option<ResolveBehavior> {
813        self.resolve_behavior
814    }
815}
816
817impl Target {
818    fn new(src_path: TargetSourcePath, edition: Edition) -> Target {
819        Target {
820            inner: Arc::new(TargetInner {
821                kind: TargetKind::Bin,
822                name: String::new(),
823                name_inferred: false,
824                bin_name: None,
825                src_path,
826                required_features: None,
827                doc: false,
828                doctest: false,
829                harness: true,
830                for_host: false,
831                proc_macro: false,
832                doc_scrape_examples: RustdocScrapeExamples::Unset,
833                edition,
834                tested: true,
835                benched: true,
836            }),
837        }
838    }
839
840    fn with_path(src_path: PathBuf, edition: Edition) -> Target {
841        Target::new(TargetSourcePath::from(src_path), edition)
842    }
843
844    pub fn lib_target(
845        name: &str,
846        crate_targets: Vec<CrateType>,
847        src_path: PathBuf,
848        edition: Edition,
849    ) -> Target {
850        let mut target = Target::with_path(src_path, edition);
851        target
852            .set_kind(TargetKind::Lib(crate_targets))
853            .set_name(name)
854            .set_doctest(true)
855            .set_doc(true);
856        target
857    }
858
859    pub fn bin_target(
860        name: &str,
861        bin_name: Option<String>,
862        src_path: PathBuf,
863        required_features: Option<Vec<String>>,
864        edition: Edition,
865    ) -> Target {
866        let mut target = Target::with_path(src_path, edition);
867        target
868            .set_kind(TargetKind::Bin)
869            .set_name(name)
870            .set_binary_name(bin_name)
871            .set_required_features(required_features)
872            .set_doc(true);
873        target
874    }
875
876    /// Builds a `Target` corresponding to the `build = "build.rs"` entry.
877    pub fn custom_build_target(name: &str, src_path: PathBuf, edition: Edition) -> Target {
878        let mut target = Target::with_path(src_path, edition);
879        target
880            .set_kind(TargetKind::CustomBuild)
881            .set_name(name)
882            .set_for_host(true)
883            .set_benched(false)
884            .set_tested(false)
885            .set_doc_scrape_examples(RustdocScrapeExamples::Disabled);
886        target
887    }
888
889    pub fn metabuild_target(name: &str) -> Target {
890        let mut target = Target::new(TargetSourcePath::Metabuild, Edition::Edition2018);
891        target
892            .set_kind(TargetKind::CustomBuild)
893            .set_name(name)
894            .set_for_host(true)
895            .set_benched(false)
896            .set_tested(false)
897            .set_doc_scrape_examples(RustdocScrapeExamples::Disabled);
898        target
899    }
900
901    pub fn example_target(
902        name: &str,
903        crate_targets: Vec<CrateType>,
904        src_path: PathBuf,
905        required_features: Option<Vec<String>>,
906        edition: Edition,
907    ) -> Target {
908        let kind = if crate_targets.is_empty() || crate_targets.iter().all(|t| *t == CrateType::Bin)
909        {
910            TargetKind::ExampleBin
911        } else {
912            TargetKind::ExampleLib(crate_targets)
913        };
914        let mut target = Target::with_path(src_path, edition);
915        target
916            .set_kind(kind)
917            .set_name(name)
918            .set_required_features(required_features)
919            .set_tested(false)
920            .set_benched(false);
921        target
922    }
923
924    pub fn test_target(
925        name: &str,
926        src_path: PathBuf,
927        required_features: Option<Vec<String>>,
928        edition: Edition,
929    ) -> Target {
930        let mut target = Target::with_path(src_path, edition);
931        target
932            .set_kind(TargetKind::Test)
933            .set_name(name)
934            .set_required_features(required_features)
935            .set_benched(false);
936        target
937    }
938
939    pub fn bench_target(
940        name: &str,
941        src_path: PathBuf,
942        required_features: Option<Vec<String>>,
943        edition: Edition,
944    ) -> Target {
945        let mut target = Target::with_path(src_path, edition);
946        target
947            .set_kind(TargetKind::Bench)
948            .set_name(name)
949            .set_required_features(required_features)
950            .set_tested(false);
951        target
952    }
953
954    pub fn name(&self) -> &str {
955        &self.inner.name
956    }
957    pub fn name_inferred(&self) -> bool {
958        self.inner.name_inferred
959    }
960    pub fn crate_name(&self) -> String {
961        self.name().replace("-", "_")
962    }
963    pub fn src_path(&self) -> &TargetSourcePath {
964        &self.inner.src_path
965    }
966    pub fn set_src_path(&mut self, src_path: TargetSourcePath) {
967        Arc::make_mut(&mut self.inner).src_path = src_path;
968    }
969    pub fn required_features(&self) -> Option<&Vec<String>> {
970        self.inner.required_features.as_ref()
971    }
972    pub fn kind(&self) -> &TargetKind {
973        &self.inner.kind
974    }
975    pub fn tested(&self) -> bool {
976        self.inner.tested
977    }
978    pub fn harness(&self) -> bool {
979        self.inner.harness
980    }
981    pub fn documented(&self) -> bool {
982        self.inner.doc
983    }
984    // A proc-macro or build-script.
985    pub fn for_host(&self) -> bool {
986        self.inner.for_host
987    }
988    pub fn proc_macro(&self) -> bool {
989        self.inner.proc_macro
990    }
991    pub fn edition(&self) -> Edition {
992        self.inner.edition
993    }
994    pub fn doc_scrape_examples(&self) -> RustdocScrapeExamples {
995        self.inner.doc_scrape_examples
996    }
997    pub fn benched(&self) -> bool {
998        self.inner.benched
999    }
1000    pub fn doctested(&self) -> bool {
1001        self.inner.doctest
1002    }
1003
1004    pub fn doctestable(&self) -> bool {
1005        match self.kind() {
1006            TargetKind::Lib(ref kinds) => kinds.iter().any(|k| {
1007                *k == CrateType::Rlib || *k == CrateType::Lib || *k == CrateType::ProcMacro
1008            }),
1009            _ => false,
1010        }
1011    }
1012
1013    pub fn is_lib(&self) -> bool {
1014        matches!(self.kind(), TargetKind::Lib(_))
1015    }
1016
1017    pub fn is_dylib(&self) -> bool {
1018        match self.kind() {
1019            TargetKind::Lib(libs) => libs.iter().any(|l| *l == CrateType::Dylib),
1020            _ => false,
1021        }
1022    }
1023
1024    pub fn is_cdylib(&self) -> bool {
1025        match self.kind() {
1026            TargetKind::Lib(libs) => libs.iter().any(|l| *l == CrateType::Cdylib),
1027            _ => false,
1028        }
1029    }
1030
1031    pub fn is_staticlib(&self) -> bool {
1032        match self.kind() {
1033            TargetKind::Lib(libs) => libs.iter().any(|l| *l == CrateType::Staticlib),
1034            _ => false,
1035        }
1036    }
1037
1038    /// Returns whether this target produces an artifact which can be linked
1039    /// into a Rust crate.
1040    ///
1041    /// This only returns true for certain kinds of libraries.
1042    pub fn is_linkable(&self) -> bool {
1043        match self.kind() {
1044            TargetKind::Lib(kinds) => kinds.iter().any(|k| k.is_linkable()),
1045            _ => false,
1046        }
1047    }
1048
1049    pub fn is_bin(&self) -> bool {
1050        *self.kind() == TargetKind::Bin
1051    }
1052
1053    pub fn is_example(&self) -> bool {
1054        matches!(
1055            self.kind(),
1056            TargetKind::ExampleBin | TargetKind::ExampleLib(..)
1057        )
1058    }
1059
1060    /// Returns `true` if it is a binary or executable example.
1061    /// NOTE: Tests are `false`!
1062    pub fn is_executable(&self) -> bool {
1063        self.is_bin() || self.is_exe_example()
1064    }
1065
1066    /// Returns `true` if it is an executable example.
1067    pub fn is_exe_example(&self) -> bool {
1068        // Needed for --all-examples in contexts where only runnable examples make sense
1069        matches!(self.kind(), TargetKind::ExampleBin)
1070    }
1071
1072    pub fn is_test(&self) -> bool {
1073        *self.kind() == TargetKind::Test
1074    }
1075    pub fn is_bench(&self) -> bool {
1076        *self.kind() == TargetKind::Bench
1077    }
1078    pub fn is_custom_build(&self) -> bool {
1079        *self.kind() == TargetKind::CustomBuild
1080    }
1081
1082    /// Returns the arguments suitable for `--crate-type` to pass to rustc.
1083    pub fn rustc_crate_types(&self) -> Vec<CrateType> {
1084        self.kind().rustc_crate_types()
1085    }
1086
1087    pub fn set_tested(&mut self, tested: bool) -> &mut Target {
1088        Arc::make_mut(&mut self.inner).tested = tested;
1089        self
1090    }
1091    pub fn set_benched(&mut self, benched: bool) -> &mut Target {
1092        Arc::make_mut(&mut self.inner).benched = benched;
1093        self
1094    }
1095    pub fn set_doctest(&mut self, doctest: bool) -> &mut Target {
1096        Arc::make_mut(&mut self.inner).doctest = doctest;
1097        self
1098    }
1099    pub fn set_for_host(&mut self, for_host: bool) -> &mut Target {
1100        Arc::make_mut(&mut self.inner).for_host = for_host;
1101        self
1102    }
1103    pub fn set_proc_macro(&mut self, proc_macro: bool) -> &mut Target {
1104        Arc::make_mut(&mut self.inner).proc_macro = proc_macro;
1105        self
1106    }
1107    pub fn set_edition(&mut self, edition: Edition) -> &mut Target {
1108        Arc::make_mut(&mut self.inner).edition = edition;
1109        self
1110    }
1111    pub fn set_doc_scrape_examples(
1112        &mut self,
1113        doc_scrape_examples: RustdocScrapeExamples,
1114    ) -> &mut Target {
1115        Arc::make_mut(&mut self.inner).doc_scrape_examples = doc_scrape_examples;
1116        self
1117    }
1118    pub fn set_harness(&mut self, harness: bool) -> &mut Target {
1119        Arc::make_mut(&mut self.inner).harness = harness;
1120        self
1121    }
1122    pub fn set_doc(&mut self, doc: bool) -> &mut Target {
1123        Arc::make_mut(&mut self.inner).doc = doc;
1124        self
1125    }
1126    pub fn set_kind(&mut self, kind: TargetKind) -> &mut Target {
1127        Arc::make_mut(&mut self.inner).kind = kind;
1128        self
1129    }
1130    pub fn set_name(&mut self, name: &str) -> &mut Target {
1131        Arc::make_mut(&mut self.inner).name = name.to_string();
1132        self
1133    }
1134    pub fn set_name_inferred(&mut self, inferred: bool) -> &mut Target {
1135        Arc::make_mut(&mut self.inner).name_inferred = inferred;
1136        self
1137    }
1138    pub fn set_binary_name(&mut self, bin_name: Option<String>) -> &mut Target {
1139        Arc::make_mut(&mut self.inner).bin_name = bin_name;
1140        self
1141    }
1142    pub fn set_required_features(&mut self, required_features: Option<Vec<String>>) -> &mut Target {
1143        Arc::make_mut(&mut self.inner).required_features = required_features;
1144        self
1145    }
1146    pub fn binary_filename(&self) -> Option<String> {
1147        self.inner.bin_name.clone()
1148    }
1149    pub fn description_named(&self) -> String {
1150        match self.kind() {
1151            TargetKind::Lib(..) => "lib".to_string(),
1152            TargetKind::Bin => format!("bin \"{}\"", self.name()),
1153            TargetKind::Test => format!("test \"{}\"", self.name()),
1154            TargetKind::Bench => format!("bench \"{}\"", self.name()),
1155            TargetKind::ExampleLib(..) | TargetKind::ExampleBin => {
1156                format!("example \"{}\"", self.name())
1157            }
1158            TargetKind::CustomBuild => "build script".to_string(),
1159        }
1160    }
1161}
1162
1163impl fmt::Display for Target {
1164    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1165        match self.kind() {
1166            TargetKind::Lib(..) => write!(f, "Target(lib)"),
1167            TargetKind::Bin => write!(f, "Target(bin: {})", self.name()),
1168            TargetKind::Test => write!(f, "Target(test: {})", self.name()),
1169            TargetKind::Bench => write!(f, "Target(bench: {})", self.name()),
1170            TargetKind::ExampleBin | TargetKind::ExampleLib(..) => {
1171                write!(f, "Target(example: {})", self.name())
1172            }
1173            TargetKind::CustomBuild => write!(f, "Target(script)"),
1174        }
1175    }
1176}
1177
1178impl Warnings {
1179    fn new() -> Warnings {
1180        Warnings(Vec::new())
1181    }
1182
1183    pub fn add_warning(&mut self, s: String) {
1184        self.0.push(DelayedWarning {
1185            message: s,
1186            is_critical: false,
1187        })
1188    }
1189
1190    pub fn add_critical_warning(&mut self, s: String) {
1191        self.0.push(DelayedWarning {
1192            message: s,
1193            is_critical: true,
1194        })
1195    }
1196
1197    pub fn warnings(&self) -> &[DelayedWarning] {
1198        &self.0
1199    }
1200}