Skip to main content

cargo/core/
manifest.rs

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