#
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.contains(&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.contains(&CrateType::Dylib),
    1020            _ => false,
    1021        }
    1022    }
    1023
    1024    pub fn is_cdylib(&self) -> bool {
    1025        match self.kind() {
    1026            TargetKind::Lib(libs) => libs.contains(&CrateType::Cdylib),
    1027            _ => false,
    1028        }
    1029    }
    1030
    1031    pub fn is_staticlib(&self) -> bool {
    1032        match self.kind() {
    1033            TargetKind::Lib(libs) => libs.contains(&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 `true` if it is a compile time depencencies, e.g., build script or proc macro
    1083    pub fn is_compile_time_dependency(&self) -> bool {
    1084        self.is_custom_build() || self.proc_macro()
    1085    }
    1086
    1087    /// Returns the arguments suitable for `--crate-type` to pass to rustc.
    1088    pub fn rustc_crate_types(&self) -> Vec<CrateType> {
    1089        self.kind().rustc_crate_types()
    1090    }
    1091
    1092    pub fn set_tested(&mut self, tested: bool) -> &mut Target {
    1093        Arc::make_mut(&mut self.inner).tested = tested;
    1094        self
    1095    }
    1096    pub fn set_benched(&mut self, benched: bool) -> &mut Target {
    1097        Arc::make_mut(&mut self.inner).benched = benched;
    1098        self
    1099    }
    1100    pub fn set_doctest(&mut self, doctest: bool) -> &mut Target {
    1101        Arc::make_mut(&mut self.inner).doctest = doctest;
    1102        self
    1103    }
    1104    pub fn set_for_host(&mut self, for_host: bool) -> &mut Target {
    1105        Arc::make_mut(&mut self.inner).for_host = for_host;
    1106        self
    1107    }
    1108    pub fn set_proc_macro(&mut self, proc_macro: bool) -> &mut Target {
    1109        Arc::make_mut(&mut self.inner).proc_macro = proc_macro;
    1110        self
    1111    }
    1112    pub fn set_edition(&mut self, edition: Edition) -> &mut Target {
    1113        Arc::make_mut(&mut self.inner).edition = edition;
    1114        self
    1115    }
    1116    pub fn set_doc_scrape_examples(
    1117        &mut self,
    1118        doc_scrape_examples: RustdocScrapeExamples,
    1119    ) -> &mut Target {
    1120        Arc::make_mut(&mut self.inner).doc_scrape_examples = doc_scrape_examples;
    1121        self
    1122    }
    1123    pub fn set_harness(&mut self, harness: bool) -> &mut Target {
    1124        Arc::make_mut(&mut self.inner).harness = harness;
    1125        self
    1126    }
    1127    pub fn set_doc(&mut self, doc: bool) -> &mut Target {
    1128        Arc::make_mut(&mut self.inner).doc = doc;
    1129        self
    1130    }
    1131    pub fn set_kind(&mut self, kind: TargetKind) -> &mut Target {
    1132        Arc::make_mut(&mut self.inner).kind = kind;
    1133        self
    1134    }
    1135    pub fn set_name(&mut self, name: &str) -> &mut Target {
    1136        Arc::make_mut(&mut self.inner).name = name.to_string();
    1137        self
    1138    }
    1139    pub fn set_name_inferred(&mut self, inferred: bool) -> &mut Target {
    1140        Arc::make_mut(&mut self.inner).name_inferred = inferred;
    1141        self
    1142    }
    1143    pub fn set_binary_name(&mut self, bin_name: Option<String>) -> &mut Target {
    1144        Arc::make_mut(&mut self.inner).bin_name = bin_name;
    1145        self
    1146    }
    1147    pub fn set_required_features(&mut self, required_features: Option<Vec<String>>) -> &mut Target {
    1148        Arc::make_mut(&mut self.inner).required_features = required_features;
    1149        self
    1150    }
    1151    pub fn binary_filename(&self) -> Option<String> {
    1152        self.inner.bin_name.clone()
    1153    }
    1154    pub fn description_named(&self) -> String {
    1155        match self.kind() {
    1156            TargetKind::Lib(..) => "lib".to_string(),
    1157            TargetKind::Bin => format!("bin \"{}\"", self.name()),
    1158            TargetKind::Test => format!("test \"{}\"", self.name()),
    1159            TargetKind::Bench => format!("bench \"{}\"", self.name()),
    1160            TargetKind::ExampleLib(..) | TargetKind::ExampleBin => {
    1161                format!("example \"{}\"", self.name())
    1162            }
    1163            TargetKind::CustomBuild => "build script".to_string(),
    1164        }
    1165    }
    1166}
    1167
    1168impl fmt::Display for Target {
    1169    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
    1170        match self.kind() {
    1171            TargetKind::Lib(..) => write!(f, "Target(lib)"),
    1172            TargetKind::Bin => write!(f, "Target(bin: {})", self.name()),
    1173            TargetKind::Test => write!(f, "Target(test: {})", self.name()),
    1174            TargetKind::Bench => write!(f, "Target(bench: {})", self.name()),
    1175            TargetKind::ExampleBin | TargetKind::ExampleLib(..) => {
    1176                write!(f, "Target(example: {})", self.name())
    1177            }
    1178            TargetKind::CustomBuild => write!(f, "Target(script)"),
    1179        }
    1180    }
    1181}
    1182
    1183impl Warnings {
    1184    fn new() -> Warnings {
    1185        Warnings(Vec::new())
    1186    }
    1187
    1188    pub fn add_warning(&mut self, s: String) {
    1189        self.0.push(DelayedWarning {
    1190            message: s,
    1191            is_critical: false,
    1192        })
    1193    }
    1194
    1195    pub fn add_critical_warning(&mut self, s: String) {
    1196        self.0.push(DelayedWarning {
    1197            message: s,
    1198            is_critical: true,
    1199        })
    1200    }
    1201
    1202    pub fn warnings(&self) -> &[DelayedWarning] {
    1203        &self.0
    1204    }
    1205}