Skip to content

Commit 49433a8

Browse files
committed
Auto merge of #13361 - weihanglo:fingerprint, r=epage
refactor: remove unnecessary Option in `Freshness::Dirty` ### What does this PR try to resolve? This avoids reading and parsing JSON fingerprint files if the detailed rebuild reason is not requested. This also encodes `Freshness::Dirty(None)` better with a new variant `DirtyReason::FreshBuild`.
2 parents cf8d1ae + a04f2b2 commit 49433a8

File tree

7 files changed

+67
-64
lines changed

7 files changed

+67
-64
lines changed

src/cargo/core/compiler/custom_build.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
use super::{fingerprint, Context, Job, Unit, Work};
3535
use crate::core::compiler::artifact;
3636
use crate::core::compiler::context::Metadata;
37+
use crate::core::compiler::fingerprint::DirtyReason;
3738
use crate::core::compiler::job_queue::JobState;
3839
use crate::core::{profiles::ProfileRoot, PackageId, Target};
3940
use crate::util::errors::CargoResult;
@@ -608,7 +609,7 @@ fn build_work(cx: &mut Context<'_, '_>, unit: &Unit) -> CargoResult<Job> {
608609
});
609610

610611
let mut job = if cx.bcx.build_config.build_plan {
611-
Job::new_dirty(Work::noop(), None)
612+
Job::new_dirty(Work::noop(), DirtyReason::FreshBuild)
612613
} else {
613614
fingerprint::prepare_target(cx, unit, false)?
614615
};

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

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,8 @@ pub enum DirtyReason {
7777
FsStatusOutdated(FsStatus),
7878
NothingObvious,
7979
Forced,
80+
/// First time to build something.
81+
FreshBuild,
8082
}
8183

8284
trait ShellExt {
@@ -131,6 +133,11 @@ impl fmt::Display for After {
131133
}
132134

133135
impl DirtyReason {
136+
/// Whether a build is dirty because it is a fresh build being kicked off.
137+
pub fn is_fresh_build(&self) -> bool {
138+
matches!(self, DirtyReason::FreshBuild)
139+
}
140+
134141
fn after(old_time: FileTime, new_time: FileTime, what: &'static str) -> After {
135142
After {
136143
old_time,
@@ -257,6 +264,7 @@ impl DirtyReason {
257264
s.dirty_because(unit, "the fingerprint comparison turned up nothing obvious")
258265
}
259266
DirtyReason::Forced => s.dirty_because(unit, "forced"),
267+
DirtyReason::FreshBuild => s.dirty_because(unit, "fresh build"),
260268
}
261269
}
262270
}

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

Lines changed: 49 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -415,43 +415,27 @@ pub fn prepare_target(cx: &mut Context<'_, '_>, unit: &Unit, force: bool) -> Car
415415
// information about failed comparisons to aid in debugging.
416416
let fingerprint = calculate(cx, unit)?;
417417
let mtime_on_use = cx.bcx.config.cli_unstable().mtime_on_use;
418-
let compare = compare_old_fingerprint(&loc, &*fingerprint, mtime_on_use);
419-
log_compare(unit, &compare);
418+
let dirty_reason = compare_old_fingerprint(unit, &loc, &*fingerprint, mtime_on_use, force);
420419

421-
// If our comparison failed or reported dirty (e.g., we're going to trigger
422-
// a rebuild of this crate), then we also ensure the source of the crate
423-
// passes all verification checks before we build it.
420+
let Some(dirty_reason) = dirty_reason else {
421+
return Ok(Job::new_fresh());
422+
};
423+
424+
// We're going to rebuild, so ensure the source of the crate passes all
425+
// verification checks before we build it.
424426
//
425427
// The `Source::verify` method is intended to allow sources to execute
426428
// pre-build checks to ensure that the relevant source code is all
427429
// up-to-date and as expected. This is currently used primarily for
428430
// directory sources which will use this hook to perform an integrity check
429431
// on all files in the source to ensure they haven't changed. If they have
430432
// changed then an error is issued.
431-
if compare
432-
.as_ref()
433-
.map(|dirty| dirty.is_some())
434-
.unwrap_or(true)
435-
{
436-
let source_id = unit.pkg.package_id().source_id();
437-
let sources = bcx.packages.sources();
438-
let source = sources
439-
.get(source_id)
440-
.ok_or_else(|| internal("missing package source"))?;
441-
source.verify(unit.pkg.package_id())?;
442-
}
443-
444-
let dirty_reason = match compare {
445-
Ok(None) => {
446-
if force {
447-
Some(DirtyReason::Forced)
448-
} else {
449-
return Ok(Job::new_fresh());
450-
}
451-
}
452-
Ok(reason) => reason,
453-
Err(_) => None,
454-
};
433+
let source_id = unit.pkg.package_id().source_id();
434+
let sources = bcx.packages.sources();
435+
let source = sources
436+
.get(source_id)
437+
.ok_or_else(|| internal("missing package source"))?;
438+
source.verify(unit.pkg.package_id())?;
455439

456440
// Clear out the old fingerprint file if it exists. This protects when
457441
// compilation is interrupted leaving a corrupt file. For example, a
@@ -1752,19 +1736,52 @@ fn target_root(cx: &Context<'_, '_>) -> PathBuf {
17521736
/// If dirty, it then restores the detailed information
17531737
/// from the fingerprint JSON file, and provides an rich dirty reason.
17541738
fn compare_old_fingerprint(
1739+
unit: &Unit,
17551740
old_hash_path: &Path,
17561741
new_fingerprint: &Fingerprint,
17571742
mtime_on_use: bool,
1758-
) -> CargoResult<Option<DirtyReason>> {
1759-
let old_fingerprint_short = paths::read(old_hash_path)?;
1760-
1743+
forced: bool,
1744+
) -> Option<DirtyReason> {
17611745
if mtime_on_use {
17621746
// update the mtime so other cleaners know we used it
17631747
let t = FileTime::from_system_time(SystemTime::now());
17641748
debug!("mtime-on-use forcing {:?} to {}", old_hash_path, t);
17651749
paths::set_file_time_no_err(old_hash_path, t);
17661750
}
17671751

1752+
let compare = _compare_old_fingerprint(old_hash_path, new_fingerprint);
1753+
1754+
match compare.as_ref() {
1755+
Ok(None) => {}
1756+
Ok(Some(reason)) => {
1757+
info!(
1758+
"fingerprint dirty for {}/{:?}/{:?}",
1759+
unit.pkg, unit.mode, unit.target,
1760+
);
1761+
info!(" dirty: {reason:?}");
1762+
}
1763+
Err(e) => {
1764+
info!(
1765+
"fingerprint error for {}/{:?}/{:?}",
1766+
unit.pkg, unit.mode, unit.target,
1767+
);
1768+
info!(" err: {e:?}");
1769+
}
1770+
}
1771+
1772+
match compare {
1773+
Ok(None) if forced => Some(DirtyReason::Forced),
1774+
Ok(reason) => reason,
1775+
Err(_) => Some(DirtyReason::FreshBuild),
1776+
}
1777+
}
1778+
1779+
fn _compare_old_fingerprint(
1780+
old_hash_path: &Path,
1781+
new_fingerprint: &Fingerprint,
1782+
) -> CargoResult<Option<DirtyReason>> {
1783+
let old_fingerprint_short = paths::read(old_hash_path)?;
1784+
17681785
let new_hash = new_fingerprint.hash_u64();
17691786

17701787
if util::to_hex(new_hash) == old_fingerprint_short && new_fingerprint.fs_status.up_to_date() {
@@ -1785,29 +1802,6 @@ fn compare_old_fingerprint(
17851802
Ok(Some(new_fingerprint.compare(&old_fingerprint)))
17861803
}
17871804

1788-
/// Logs the result of fingerprint comparison.
1789-
///
1790-
/// TODO: Obsolete and mostly superseded by [`DirtyReason`]. Could be removed.
1791-
fn log_compare(unit: &Unit, compare: &CargoResult<Option<DirtyReason>>) {
1792-
match compare {
1793-
Ok(None) => {}
1794-
Ok(Some(reason)) => {
1795-
info!(
1796-
"fingerprint dirty for {}/{:?}/{:?}",
1797-
unit.pkg, unit.mode, unit.target,
1798-
);
1799-
info!(" dirty: {reason:?}");
1800-
}
1801-
Err(e) => {
1802-
info!(
1803-
"fingerprint error for {}/{:?}/{:?}",
1804-
unit.pkg, unit.mode, unit.target,
1805-
);
1806-
info!(" err: {e:?}");
1807-
}
1808-
}
1809-
}
1810-
18111805
/// Parses Cargo's internal [`EncodedDepInfo`] structure that was previously
18121806
/// serialized to disk.
18131807
///

src/cargo/core/compiler/job_queue/job.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ impl Job {
6060
}
6161

6262
/// Creates a new job representing a unit of work.
63-
pub fn new_dirty(work: Work, dirty_reason: Option<DirtyReason>) -> Job {
63+
pub fn new_dirty(work: Work, dirty_reason: DirtyReason) -> Job {
6464
Job {
6565
work,
6666
fresh: Freshness::Dirty(dirty_reason),
@@ -100,7 +100,7 @@ impl fmt::Debug for Job {
100100
#[derive(Debug, Clone)]
101101
pub enum Freshness {
102102
Fresh,
103-
Dirty(Option<DirtyReason>),
103+
Dirty(DirtyReason),
104104
}
105105

106106
impl Freshness {

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1110,10 +1110,10 @@ impl<'cfg> DrainState<'cfg> {
11101110
// Any dirty stage which runs at least one command gets printed as
11111111
// being a compiled package.
11121112
Dirty(dirty_reason) => {
1113-
if let Some(reason) = dirty_reason {
1113+
if !dirty_reason.is_fresh_build() {
11141114
config
11151115
.shell()
1116-
.verbose(|shell| reason.present_to(shell, unit, ws_root))?;
1116+
.verbose(|shell| dirty_reason.present_to(shell, unit, ws_root))?;
11171117
}
11181118

11191119
if unit.mode.is_doc() {

src/cargo/core/compiler/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -183,7 +183,7 @@ fn compile<'cfg>(
183183
// We run these targets later, so this is just a no-op for now.
184184
Job::new_fresh()
185185
} else if build_plan {
186-
Job::new_dirty(rustc(cx, unit, &exec.clone())?, None)
186+
Job::new_dirty(rustc(cx, unit, &exec.clone())?, DirtyReason::FreshBuild)
187187
} else {
188188
let force = exec.force_rebuild(unit) || force_rebuild;
189189
let mut job = fingerprint::prepare_target(cx, unit, force)?;

src/cargo/ops/common_for_install_and_uninstall.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -175,7 +175,7 @@ impl InstallTracker {
175175
// Check if any tracked exe's are already installed.
176176
let duplicates = self.find_duplicates(dst, &exes);
177177
if force || duplicates.is_empty() {
178-
return Ok((Freshness::Dirty(Some(DirtyReason::Forced)), duplicates));
178+
return Ok((Freshness::Dirty(DirtyReason::Forced), duplicates));
179179
}
180180
// Check if all duplicates come from packages of the same name. If
181181
// there are duplicates from other packages, then --force will be
@@ -205,7 +205,7 @@ impl InstallTracker {
205205
let source_id = pkg.package_id().source_id();
206206
if source_id.is_path() {
207207
// `cargo install --path ...` is always rebuilt.
208-
return Ok((Freshness::Dirty(Some(DirtyReason::Forced)), duplicates));
208+
return Ok((Freshness::Dirty(DirtyReason::Forced), duplicates));
209209
}
210210
let is_up_to_date = |dupe_pkg_id| {
211211
let info = self
@@ -229,7 +229,7 @@ impl InstallTracker {
229229
if matching_duplicates.iter().all(is_up_to_date) {
230230
Ok((Freshness::Fresh, duplicates))
231231
} else {
232-
Ok((Freshness::Dirty(Some(DirtyReason::Forced)), duplicates))
232+
Ok((Freshness::Dirty(DirtyReason::Forced), duplicates))
233233
}
234234
} else {
235235
// Format the error message.

0 commit comments

Comments
 (0)