Skip to content

Commit d999267

Browse files
committed
refactored to macro based metadata env vars tracking
1 parent 43c1913 commit d999267

File tree

5 files changed

+97
-138
lines changed

5 files changed

+97
-138
lines changed

src/cargo/core/compiler/compilation.rs

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
//! Type definitions for the result of a compilation.
22
3-
use std::borrow::Cow;
43
use std::collections::{BTreeSet, HashMap};
54
use std::ffi::{OsStr, OsString};
65
use std::path::PathBuf;
@@ -359,11 +358,17 @@ impl<'gctx> Compilation<'gctx> {
359358
// crate properties which might require rebuild upon change
360359
// consider adding the corresponding properties to the hash
361360
// in BuildContext::target_metadata()
362-
for (key, value) in pkg.emitted_env_vars() {
363-
match value {
364-
Cow::Borrowed(value) => cmd.env(key, value),
365-
Cow::Owned(ref value) => cmd.env(key, value.as_str()),
366-
};
361+
cmd.env("CARGO_MANIFEST_DIR", pkg.root())
362+
.env("CARGO_MANIFEST_PATH", pkg.manifest_path())
363+
.env("CARGO_PKG_VERSION_MAJOR", &pkg.version().major.to_string())
364+
.env("CARGO_PKG_VERSION_MINOR", &pkg.version().minor.to_string())
365+
.env("CARGO_PKG_VERSION_PATCH", &pkg.version().patch.to_string())
366+
.env("CARGO_PKG_VERSION_PRE", pkg.version().pre.as_str())
367+
.env("CARGO_PKG_VERSION", &pkg.version().to_string())
368+
.env("CARGO_PKG_NAME", &*pkg.name());
369+
370+
for (key, value) in pkg.manifest().metadata().env_vars() {
371+
cmd.env(key, value.as_ref());
367372
}
368373

369374
cmd.cwd(pkg.root());

src/cargo/core/compiler/fingerprint/dep_info.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ use cargo_util::paths;
1919
use cargo_util::ProcessBuilder;
2020
use cargo_util::Sha256;
2121

22-
use crate::core::package::EmittablePackageMetadata;
22+
use crate::core::manifest::ManifestMetadata;
2323
use crate::CargoResult;
2424
use crate::CARGO_ENV;
2525

@@ -335,7 +335,7 @@ pub fn translate_dep_info(
335335
//
336336
// For cargo#13280, We trace env vars that are defined in the `[env]` config table.
337337
on_disk_info.env.retain(|(key, _)| {
338-
EmittablePackageMetadata::is_emittable_env_var(key)
338+
ManifestMetadata::should_track(key)
339339
|| env_config.contains_key(key)
340340
|| !rustc_cmd.get_envs().contains_key(key)
341341
|| key == CARGO_ENV

src/cargo/core/compiler/fingerprint/mod.rs

Lines changed: 3 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -189,7 +189,7 @@
189189
//! Cargo then later uses this to trigger a recompile if a referenced env var
190190
//! changes (even if the source didn't change).
191191
//! This also includes env vars generated from Cargo metadata like `CARGO_PKG_DESCRIPTION`.
192-
//! (See [`EmittablePackageMetadata`])
192+
//! (See [`crate::core::manifest::ManifestMetadata`]
193193
//!
194194
//! #### dep-info files for build system integration.
195195
//!
@@ -372,15 +372,13 @@
372372
mod dep_info;
373373
mod dirty_reason;
374374

375-
use std::borrow::Cow;
376375
use std::collections::hash_map::{Entry, HashMap};
377376
use std::env;
378377
use std::fs;
379378
use std::fs::File;
380379
use std::hash::{self, Hash, Hasher};
381380
use std::io::{self};
382381
use std::path::{Path, PathBuf};
383-
use std::str::FromStr;
384382
use std::sync::{Arc, Mutex};
385383
use std::time::SystemTime;
386384

@@ -394,7 +392,6 @@ use serde::{Deserialize, Serialize};
394392
use tracing::{debug, info};
395393

396394
use crate::core::compiler::unit_graph::UnitDep;
397-
use crate::core::package::EmittablePackageMetadata;
398395
use crate::core::Package;
399396
use crate::util;
400397
use crate::util::errors::CargoResult;
@@ -850,14 +847,8 @@ impl LocalFingerprint {
850847
return Ok(Some(StaleItem::MissingFile(dep_info)));
851848
};
852849
for (key, previous) in info.env.iter() {
853-
if let Ok(t) = EmittablePackageMetadata::from_str(key.as_str()) {
854-
let value = pkg.emitted_env_var(&t);
855-
let value = match value {
856-
Cow::Borrowed(v) => v,
857-
Cow::Owned(ref v) => v.as_str(),
858-
};
859-
860-
if Some(value) == previous.as_deref() {
850+
if let Some(value) = pkg.manifest().metadata().env_var(key.as_str()) {
851+
if Some(value.as_ref()) == previous.as_deref() {
861852
continue;
862853
}
863854
}

src/cargo/core/manifest.rs

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
use std::borrow::Cow;
12
use std::collections::{BTreeMap, HashMap};
23
use std::fmt;
34
use std::hash::{Hash, Hasher};
@@ -146,6 +147,86 @@ pub struct ManifestMetadata {
146147
pub rust_version: Option<RustVersion>,
147148
}
148149

150+
macro_rules! get_metadata_env {
151+
($meta:ident, $field:ident) => {
152+
$meta.$field.as_deref().unwrap_or_default().into()
153+
};
154+
($meta:ident, $field:ident, $to_var:expr) => {
155+
$to_var($meta).into()
156+
};
157+
}
158+
159+
macro_rules! metadata_envs {
160+
(
161+
$(
162+
($field:ident, $key:literal$(, $to_var:expr)?),
163+
)*
164+
) => {
165+
struct MetadataEnvs;
166+
impl MetadataEnvs {
167+
$(
168+
fn $field(meta: &ManifestMetadata) -> Cow<'_, str> {
169+
get_metadata_env!(meta, $field$(, $to_var)?)
170+
}
171+
)*
172+
173+
pub fn should_track(key: &str) -> bool {
174+
let keys = [$($key),*];
175+
key.strip_prefix("CARGO_PKG_")
176+
.map(|key| keys.iter().any(|k| *k == key))
177+
.unwrap_or_default()
178+
}
179+
180+
pub fn var<'a>(meta: &'a ManifestMetadata, key: &str) -> Option<Cow<'a, str>> {
181+
key.strip_prefix("CARGO_PKG_").and_then(|key| match key {
182+
$($key => Some(Self::$field(meta)),)*
183+
_ => None,
184+
})
185+
}
186+
187+
pub fn vars(meta: &ManifestMetadata) -> impl Iterator<Item = (&'static str, Cow<'_, str>)> {
188+
[
189+
$(
190+
(
191+
concat!("CARGO_PKG_", $key),
192+
Self::$field(meta),
193+
),
194+
)*
195+
].into_iter()
196+
}
197+
}
198+
}
199+
}
200+
201+
// Metadata enviromental variables that are emitted to rustc. Usable by `env!()`
202+
// If these change we need to trigger a rebuild.
203+
// NOTE: The env var name will be prefixed with `CARGO_PKG_`
204+
metadata_envs! {
205+
(description, "DESCRIPTION"),
206+
(homepage, "HOMEPAGE"),
207+
(repository, "REPOSITORY"),
208+
(license, "LICENSE"),
209+
(license_file, "LICENSE_FILE"),
210+
(authors, "AUTHORS", |m: &ManifestMetadata| m.authors.join(":")),
211+
(rust_version, "RUST_VERSION", |m: &ManifestMetadata| m.rust_version.as_ref().map(ToString::to_string).unwrap_or_default()),
212+
(readme, "README"),
213+
}
214+
215+
impl ManifestMetadata {
216+
/// Whether the given env var should be tracked by Cargo's dep-info.
217+
pub fn should_track(env_key: &str) -> bool {
218+
MetadataEnvs::should_track(env_key)
219+
}
220+
221+
pub fn env_var<'a>(&'a self, env_key: &str) -> Option<Cow<'a, str>> {
222+
MetadataEnvs::var(self, env_key)
223+
}
224+
225+
pub fn env_vars(&self) -> impl Iterator<Item = (&'static str, Cow<'_, str>)> {
226+
MetadataEnvs::vars(self)
227+
}
228+
}
229+
149230
#[derive(Clone, Hash, PartialEq, Eq, PartialOrd, Ord)]
150231
pub enum TargetKind {
151232
Lib(Vec<CrateType>),

src/cargo/core/package.rs

Lines changed: 0 additions & 118 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
use std::borrow::Cow;
21
use std::cell::{Cell, Ref, RefCell, RefMut};
32
use std::cmp::Ordering;
43
use std::collections::{BTreeMap, BTreeSet, HashMap, HashSet};
@@ -7,7 +6,6 @@ use std::hash;
76
use std::mem;
87
use std::path::{Path, PathBuf};
98
use std::rc::Rc;
10-
use std::str::FromStr;
119
use std::time::{Duration, Instant};
1210

1311
use anyhow::Context as _;
@@ -254,122 +252,6 @@ impl Package {
254252
}
255253
}
256254

257-
/// "Emittable" here meaning emitted to rustc as enviromental variables. Usable by `env!()`
258-
/// If these change we need to trigger a rebuild
259-
/// NOTE: If you add a new variant also add a mapping entry in [`EMITTED_METADATA_MAPPINGS`]
260-
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
261-
pub enum EmittablePackageMetadata {
262-
ManifestDir,
263-
ManifestPath,
264-
Name,
265-
Version,
266-
VersionMajor,
267-
VersionMinor,
268-
VersionPatch,
269-
VersionPre,
270-
Description,
271-
Homepage,
272-
Repository,
273-
License,
274-
LicenseFile,
275-
Authors,
276-
RustVersion,
277-
Readme,
278-
}
279-
280-
use crate::core::package::EmittablePackageMetadata::*;
281-
const EMITTED_METADATA_MAPPINGS: [(EmittablePackageMetadata, &'static str); 16] = [
282-
(ManifestDir, "CARGO_MANIFEST_DIR"),
283-
(ManifestPath, "CARGO_MANIFEST_PATH"),
284-
(Name, "CARGO_PKG_NAME"),
285-
(Version, "CARGO_PKG_VERSION"),
286-
(VersionMajor, "CARGO_PKG_VERSION_MAJOR"),
287-
(VersionMinor, "CARGO_PKG_VERSION_MINOR"),
288-
(VersionPatch, "CARGO_PKG_VERSION_PATCH"),
289-
(VersionPre, "CARGO_PKG_VERSION_PRE"),
290-
(Description, "CARGO_PKG_DESCRIPTION"),
291-
(Homepage, "CARGO_PKG_HOMEPAGE"),
292-
(Repository, "CARGO_PKG_REPOSITORY"),
293-
(License, "CARGO_PKG_LICENSE"),
294-
(LicenseFile, "CARGO_PKG_LICENSE_FILE"),
295-
(Authors, "CARGO_PKG_AUTHORS"),
296-
(RustVersion, "CARGO_PKG_RUST_VERSION"),
297-
(Readme, "CARGO_PKG_README"),
298-
];
299-
300-
impl FromStr for EmittablePackageMetadata {
301-
type Err = String;
302-
303-
fn from_str(value: &str) -> Result<Self, Self::Err> {
304-
if let Some(v) = EMITTED_METADATA_MAPPINGS.iter().find(|v| v.1 == value) {
305-
return Ok(v.0);
306-
}
307-
308-
return Err(format!("Invalid emittable manifest metadata key {value}"));
309-
}
310-
}
311-
312-
impl From<EmittablePackageMetadata> for &'static str {
313-
fn from(value: EmittablePackageMetadata) -> Self {
314-
if let Some(v) = EMITTED_METADATA_MAPPINGS.iter().find(|v| v.0 == value) {
315-
return v.1;
316-
}
317-
318-
unreachable!("unknown package metadata");
319-
}
320-
}
321-
322-
impl EmittablePackageMetadata {
323-
pub fn is_emittable_env_var(key: &str) -> bool {
324-
EmittablePackageMetadata::from_str(key).is_ok()
325-
}
326-
}
327-
328-
impl Package {
329-
// k/v pairs of the metadata environmental variables emitted to rustc.
330-
pub fn emitted_env_vars(&self) -> Vec<(&'static str, Cow<'_, str>)> {
331-
let mut vars = Vec::with_capacity(EMITTED_METADATA_MAPPINGS.len());
332-
333-
for (key, name) in EMITTED_METADATA_MAPPINGS {
334-
let value = self.emitted_env_var(&key);
335-
vars.push((name, value));
336-
}
337-
338-
return vars;
339-
}
340-
341-
pub fn emitted_env_var<'a>(&'a self, key: &EmittablePackageMetadata) -> Cow<'a, str> {
342-
let metadata = self.manifest().metadata();
343-
let value = match key {
344-
ManifestDir => self.root().as_os_str().to_str().unwrap_or_default(),
345-
ManifestPath => self
346-
.manifest_path()
347-
.as_os_str()
348-
.to_str()
349-
.unwrap_or_default(),
350-
Name => self.name().as_str(),
351-
Version => return Cow::Owned(self.version().to_string()),
352-
VersionMajor => return Cow::Owned(self.version().major.to_string()),
353-
VersionMinor => return Cow::Owned(self.version().minor.to_string()),
354-
VersionPatch => return Cow::Owned(self.version().patch.to_string()),
355-
VersionPre => return Cow::Owned(self.version().pre.to_string()),
356-
Description => metadata.description.as_deref().unwrap_or_default(),
357-
Homepage => metadata.homepage.as_deref().unwrap_or_default(),
358-
Repository => metadata.repository.as_deref().unwrap_or_default(),
359-
License => metadata.license.as_deref().unwrap_or_default(),
360-
LicenseFile => metadata.license_file.as_deref().unwrap_or_default(),
361-
Authors => return Cow::Owned(metadata.authors.join(":")),
362-
RustVersion => {
363-
let rust_version = metadata.rust_version.as_ref().map(ToString::to_string);
364-
return Cow::Owned(rust_version.unwrap_or_default());
365-
}
366-
Readme => metadata.readme.as_deref().unwrap_or_default(),
367-
};
368-
369-
return Cow::Borrowed(value);
370-
}
371-
}
372-
373255
impl fmt::Display for Package {
374256
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
375257
write!(f, "{}", self.summary().package_id())

0 commit comments

Comments
 (0)