mirror of https://github.com/rust-lang/cargo
Auto merge of #11407 - dnbln:reasons-for-rebuilding, r=weihanglo
Reasons for rebuilding
This commit is contained in:
commit
dd9900585a
|
@ -16,6 +16,11 @@
|
|||
//! `[WARNING]`) to match cargo's "status" output and allows you to ignore
|
||||
//! the alignment. See the source of `substitute_macros` for a complete list
|
||||
//! of substitutions.
|
||||
//! - `[DIRTY-MSVC]` (only when the line starts with it) would be replaced by
|
||||
//! `[DIRTY]` when `cfg(target_env = "msvc")` or the line will be ignored otherwise.
|
||||
//! Tests that work around [issue 7358](https://github.com/rust-lang/cargo/issues/7358)
|
||||
//! can use this to avoid duplicating the `with_stderr` call like:
|
||||
//! `if cfg!(target_env = "msvc") {e.with_stderr("...[DIRTY]...");} else {e.with_stderr("...");}`.
|
||||
//!
|
||||
//! # Normalization
|
||||
//!
|
||||
|
@ -108,7 +113,9 @@ fn normalize_actual(actual: &str, cwd: Option<&Path>) -> String {
|
|||
|
||||
/// Normalizes the expected string so that it can be compared against the actual output.
|
||||
fn normalize_expected(expected: &str, cwd: Option<&Path>) -> String {
|
||||
let expected = substitute_macros(expected);
|
||||
let expected = replace_dirty_msvc(expected);
|
||||
let expected = substitute_macros(&expected);
|
||||
|
||||
if cfg!(windows) {
|
||||
normalize_windows(&expected, cwd)
|
||||
} else {
|
||||
|
@ -121,6 +128,29 @@ fn normalize_expected(expected: &str, cwd: Option<&Path>) -> String {
|
|||
}
|
||||
}
|
||||
|
||||
fn replace_dirty_msvc_impl(s: &str, is_msvc: bool) -> String {
|
||||
if is_msvc {
|
||||
s.replace("[DIRTY-MSVC]", "[DIRTY]")
|
||||
} else {
|
||||
use itertools::Itertools;
|
||||
|
||||
let mut new = s
|
||||
.lines()
|
||||
.filter(|it| !it.starts_with("[DIRTY-MSVC]"))
|
||||
.join("\n");
|
||||
|
||||
if s.ends_with("\n") {
|
||||
new.push_str("\n");
|
||||
}
|
||||
|
||||
new
|
||||
}
|
||||
}
|
||||
|
||||
fn replace_dirty_msvc(s: &str) -> String {
|
||||
replace_dirty_msvc_impl(s, cfg!(target_env = "msvc"))
|
||||
}
|
||||
|
||||
/// Normalizes text for both actual and expected strings on Windows.
|
||||
fn normalize_windows(text: &str, cwd: Option<&Path>) -> String {
|
||||
// Let's not deal with / vs \ (windows...)
|
||||
|
@ -170,6 +200,7 @@ fn substitute_macros(input: &str) -> String {
|
|||
("[DOCUMENTING]", " Documenting"),
|
||||
("[SCRAPING]", " Scraping"),
|
||||
("[FRESH]", " Fresh"),
|
||||
("[DIRTY]", " Dirty"),
|
||||
("[UPDATING]", " Updating"),
|
||||
("[ADDING]", " Adding"),
|
||||
("[REMOVING]", " Removing"),
|
||||
|
@ -637,3 +668,114 @@ fn wild_str_cmp() {
|
|||
assert_ne!(WildStr::new(a), WildStr::new(b));
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn dirty_msvc() {
|
||||
let case = |expected: &str, wild: &str, msvc: bool| {
|
||||
assert_eq!(expected, &replace_dirty_msvc_impl(wild, msvc));
|
||||
};
|
||||
|
||||
// no replacements
|
||||
case("aa", "aa", false);
|
||||
case("aa", "aa", true);
|
||||
|
||||
// with replacements
|
||||
case(
|
||||
"\
|
||||
[DIRTY] a",
|
||||
"\
|
||||
[DIRTY-MSVC] a",
|
||||
true,
|
||||
);
|
||||
case(
|
||||
"",
|
||||
"\
|
||||
[DIRTY-MSVC] a",
|
||||
false,
|
||||
);
|
||||
case(
|
||||
"\
|
||||
[DIRTY] a
|
||||
[COMPILING] a",
|
||||
"\
|
||||
[DIRTY-MSVC] a
|
||||
[COMPILING] a",
|
||||
true,
|
||||
);
|
||||
case(
|
||||
"\
|
||||
[COMPILING] a",
|
||||
"\
|
||||
[DIRTY-MSVC] a
|
||||
[COMPILING] a",
|
||||
false,
|
||||
);
|
||||
|
||||
// test trailing newline behavior
|
||||
case(
|
||||
"\
|
||||
A
|
||||
B
|
||||
", "\
|
||||
A
|
||||
B
|
||||
", true,
|
||||
);
|
||||
|
||||
case(
|
||||
"\
|
||||
A
|
||||
B
|
||||
", "\
|
||||
A
|
||||
B
|
||||
", false,
|
||||
);
|
||||
|
||||
case(
|
||||
"\
|
||||
A
|
||||
B", "\
|
||||
A
|
||||
B", true,
|
||||
);
|
||||
|
||||
case(
|
||||
"\
|
||||
A
|
||||
B", "\
|
||||
A
|
||||
B", false,
|
||||
);
|
||||
|
||||
case(
|
||||
"\
|
||||
[DIRTY] a
|
||||
",
|
||||
"\
|
||||
[DIRTY-MSVC] a
|
||||
",
|
||||
true,
|
||||
);
|
||||
case(
|
||||
"\n",
|
||||
"\
|
||||
[DIRTY-MSVC] a
|
||||
",
|
||||
false,
|
||||
);
|
||||
|
||||
case(
|
||||
"\
|
||||
[DIRTY] a",
|
||||
"\
|
||||
[DIRTY-MSVC] a",
|
||||
true,
|
||||
);
|
||||
case(
|
||||
"",
|
||||
"\
|
||||
[DIRTY-MSVC] a",
|
||||
false,
|
||||
);
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use super::job::{Freshness, Job, Work};
|
||||
use super::job::{Job, Work};
|
||||
use super::{fingerprint, Context, LinkType, Unit};
|
||||
use crate::core::compiler::artifact;
|
||||
use crate::core::compiler::context::Metadata;
|
||||
|
@ -484,11 +484,11 @@ fn build_work(cx: &mut Context<'_, '_>, unit: &Unit) -> CargoResult<Job> {
|
|||
});
|
||||
|
||||
let mut job = if cx.bcx.build_config.build_plan {
|
||||
Job::new_dirty(Work::noop())
|
||||
Job::new_dirty(Work::noop(), None)
|
||||
} else {
|
||||
fingerprint::prepare_target(cx, unit, false)?
|
||||
};
|
||||
if job.freshness() == Freshness::Dirty {
|
||||
if job.freshness().is_dirty() {
|
||||
job.before(dirty);
|
||||
} else {
|
||||
job.before(fresh);
|
||||
|
|
|
@ -312,7 +312,10 @@
|
|||
//! See the `A-rebuild-detection` flag on the issue tracker for more:
|
||||
//! <https://github.com/rust-lang/cargo/issues?q=is%3Aissue+is%3Aopen+label%3AA-rebuild-detection>
|
||||
|
||||
mod dirty_reason;
|
||||
|
||||
use std::collections::hash_map::{Entry, HashMap};
|
||||
|
||||
use std::env;
|
||||
use std::hash::{self, Hash, Hasher};
|
||||
use std::io;
|
||||
|
@ -341,6 +344,8 @@ use super::custom_build::BuildDeps;
|
|||
use super::job::{Job, Work};
|
||||
use super::{BuildContext, Context, FileFlavor, Unit};
|
||||
|
||||
pub use dirty_reason::DirtyReason;
|
||||
|
||||
/// Determines if a `unit` is up-to-date, and if not prepares necessary work to
|
||||
/// update the persisted fingerprint.
|
||||
///
|
||||
|
@ -393,9 +398,17 @@ pub fn prepare_target(cx: &mut Context<'_, '_>, unit: &Unit, force: bool) -> Car
|
|||
source.verify(unit.pkg.package_id())?;
|
||||
}
|
||||
|
||||
if compare.is_ok() && !force {
|
||||
return Ok(Job::new_fresh());
|
||||
}
|
||||
let dirty_reason = match compare {
|
||||
Ok(None) => {
|
||||
if force {
|
||||
Some(DirtyReason::Forced)
|
||||
} else {
|
||||
return Ok(Job::new_fresh());
|
||||
}
|
||||
}
|
||||
Ok(reason) => reason,
|
||||
Err(_) => None,
|
||||
};
|
||||
|
||||
// Clear out the old fingerprint file if it exists. This protects when
|
||||
// compilation is interrupted leaving a corrupt file. For example, a
|
||||
|
@ -466,7 +479,7 @@ pub fn prepare_target(cx: &mut Context<'_, '_>, unit: &Unit, force: bool) -> Car
|
|||
Work::new(move |_| write_fingerprint(&loc, &fingerprint))
|
||||
};
|
||||
|
||||
Ok(Job::new_dirty(write_fingerprint))
|
||||
Ok(Job::new_dirty(write_fingerprint, dirty_reason))
|
||||
}
|
||||
|
||||
/// Dependency edge information for fingerprints. This is generated for each
|
||||
|
@ -559,14 +572,28 @@ pub struct Fingerprint {
|
|||
}
|
||||
|
||||
/// Indication of the status on the filesystem for a particular unit.
|
||||
#[derive(Default)]
|
||||
enum FsStatus {
|
||||
#[derive(Clone, Default, Debug)]
|
||||
pub enum FsStatus {
|
||||
/// This unit is to be considered stale, even if hash information all
|
||||
/// matches. The filesystem inputs have changed (or are missing) and the
|
||||
/// unit needs to subsequently be recompiled.
|
||||
/// matches.
|
||||
#[default]
|
||||
Stale,
|
||||
|
||||
/// File system inputs have changed (or are missing), or there were
|
||||
/// changes to the environment variables that affect this unit. See
|
||||
/// the variants of [`StaleItem`] for more information.
|
||||
StaleItem(StaleItem),
|
||||
|
||||
/// A dependency was stale.
|
||||
StaleDependency {
|
||||
name: InternedString,
|
||||
dep_mtime: FileTime,
|
||||
max_mtime: FileTime,
|
||||
},
|
||||
|
||||
/// A dependency was stale.
|
||||
StaleDepFingerprint { name: InternedString },
|
||||
|
||||
/// This unit is up-to-date. All outputs and their corresponding mtime are
|
||||
/// listed in the payload here for other dependencies to compare against.
|
||||
UpToDate { mtimes: HashMap<PathBuf, FileTime> },
|
||||
|
@ -576,7 +603,10 @@ impl FsStatus {
|
|||
fn up_to_date(&self) -> bool {
|
||||
match self {
|
||||
FsStatus::UpToDate { .. } => true,
|
||||
FsStatus::Stale => false,
|
||||
FsStatus::Stale
|
||||
| FsStatus::StaleItem(_)
|
||||
| FsStatus::StaleDependency { .. }
|
||||
| FsStatus::StaleDepFingerprint { .. } => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -677,7 +707,8 @@ enum LocalFingerprint {
|
|||
RerunIfEnvChanged { var: String, val: Option<String> },
|
||||
}
|
||||
|
||||
enum StaleItem {
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum StaleItem {
|
||||
MissingFile(PathBuf),
|
||||
ChangedFile {
|
||||
reference: PathBuf,
|
||||
|
@ -823,56 +854,53 @@ impl Fingerprint {
|
|||
/// The purpose of this is exclusively to produce a diagnostic message
|
||||
/// indicating why we're recompiling something. This function always returns
|
||||
/// an error, it will never return success.
|
||||
fn compare(&self, old: &Fingerprint) -> CargoResult<()> {
|
||||
fn compare(&self, old: &Fingerprint) -> DirtyReason {
|
||||
if self.rustc != old.rustc {
|
||||
bail!("rust compiler has changed")
|
||||
return DirtyReason::RustcChanged;
|
||||
}
|
||||
if self.features != old.features {
|
||||
bail!(
|
||||
"features have changed: previously {}, now {}",
|
||||
old.features,
|
||||
self.features
|
||||
)
|
||||
return DirtyReason::FeaturesChanged {
|
||||
old: old.features.clone(),
|
||||
new: self.features.clone(),
|
||||
};
|
||||
}
|
||||
if self.target != old.target {
|
||||
bail!("target configuration has changed")
|
||||
return DirtyReason::TargetConfigurationChanged;
|
||||
}
|
||||
if self.path != old.path {
|
||||
bail!("path to the source has changed")
|
||||
return DirtyReason::PathToSourceChanged;
|
||||
}
|
||||
if self.profile != old.profile {
|
||||
bail!("profile configuration has changed")
|
||||
return DirtyReason::ProfileConfigurationChanged;
|
||||
}
|
||||
if self.rustflags != old.rustflags {
|
||||
bail!(
|
||||
"RUSTFLAGS has changed: previously {:?}, now {:?}",
|
||||
old.rustflags,
|
||||
self.rustflags
|
||||
)
|
||||
return DirtyReason::RustflagsChanged {
|
||||
old: old.rustflags.clone(),
|
||||
new: self.rustflags.clone(),
|
||||
};
|
||||
}
|
||||
if self.metadata != old.metadata {
|
||||
bail!("metadata changed")
|
||||
return DirtyReason::MetadataChanged;
|
||||
}
|
||||
if self.config != old.config {
|
||||
bail!("configuration settings have changed")
|
||||
return DirtyReason::ConfigSettingsChanged;
|
||||
}
|
||||
if self.compile_kind != old.compile_kind {
|
||||
bail!("compile kind (rustc target) changed")
|
||||
return DirtyReason::CompileKindChanged;
|
||||
}
|
||||
let my_local = self.local.lock().unwrap();
|
||||
let old_local = old.local.lock().unwrap();
|
||||
if my_local.len() != old_local.len() {
|
||||
bail!("local lens changed");
|
||||
return DirtyReason::LocalLengthsChanged;
|
||||
}
|
||||
for (new, old) in my_local.iter().zip(old_local.iter()) {
|
||||
match (new, old) {
|
||||
(LocalFingerprint::Precalculated(a), LocalFingerprint::Precalculated(b)) => {
|
||||
if a != b {
|
||||
bail!(
|
||||
"precalculated components have changed: previously {}, now {}",
|
||||
b,
|
||||
a
|
||||
)
|
||||
return DirtyReason::PrecalculatedComponentsChanged {
|
||||
old: b.to_string(),
|
||||
new: a.to_string(),
|
||||
};
|
||||
}
|
||||
}
|
||||
(
|
||||
|
@ -880,11 +908,10 @@ impl Fingerprint {
|
|||
LocalFingerprint::CheckDepInfo { dep_info: bdep },
|
||||
) => {
|
||||
if adep != bdep {
|
||||
bail!(
|
||||
"dep info output changed: previously {:?}, now {:?}",
|
||||
bdep,
|
||||
adep
|
||||
)
|
||||
return DirtyReason::DepInfoOutputChanged {
|
||||
old: bdep.clone(),
|
||||
new: adep.clone(),
|
||||
};
|
||||
}
|
||||
}
|
||||
(
|
||||
|
@ -898,18 +925,16 @@ impl Fingerprint {
|
|||
},
|
||||
) => {
|
||||
if aout != bout {
|
||||
bail!(
|
||||
"rerun-if-changed output changed: previously {:?}, now {:?}",
|
||||
bout,
|
||||
aout
|
||||
)
|
||||
return DirtyReason::RerunIfChangedOutputFileChanged {
|
||||
old: bout.clone(),
|
||||
new: aout.clone(),
|
||||
};
|
||||
}
|
||||
if apaths != bpaths {
|
||||
bail!(
|
||||
"rerun-if-changed output changed: previously {:?}, now {:?}",
|
||||
bpaths,
|
||||
apaths,
|
||||
)
|
||||
return DirtyReason::RerunIfChangedOutputPathsChanged {
|
||||
old: bpaths.clone(),
|
||||
new: apaths.clone(),
|
||||
};
|
||||
}
|
||||
}
|
||||
(
|
||||
|
@ -923,57 +948,61 @@ impl Fingerprint {
|
|||
},
|
||||
) => {
|
||||
if *akey != *bkey {
|
||||
bail!("env vars changed: previously {}, now {}", bkey, akey);
|
||||
return DirtyReason::EnvVarsChanged {
|
||||
old: bkey.clone(),
|
||||
new: akey.clone(),
|
||||
};
|
||||
}
|
||||
if *avalue != *bvalue {
|
||||
bail!(
|
||||
"env var `{}` changed: previously {:?}, now {:?}",
|
||||
akey,
|
||||
bvalue,
|
||||
avalue
|
||||
)
|
||||
return DirtyReason::EnvVarChanged {
|
||||
name: akey.clone(),
|
||||
old_value: bvalue.clone(),
|
||||
new_value: avalue.clone(),
|
||||
};
|
||||
}
|
||||
}
|
||||
(a, b) => {
|
||||
return DirtyReason::LocalFingerprintTypeChanged {
|
||||
old: b.kind(),
|
||||
new: a.kind(),
|
||||
}
|
||||
}
|
||||
(a, b) => bail!(
|
||||
"local fingerprint type has changed ({} => {})",
|
||||
b.kind(),
|
||||
a.kind()
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
if self.deps.len() != old.deps.len() {
|
||||
bail!("number of dependencies has changed")
|
||||
return DirtyReason::NumberOfDependenciesChanged {
|
||||
old: old.deps.len(),
|
||||
new: self.deps.len(),
|
||||
};
|
||||
}
|
||||
for (a, b) in self.deps.iter().zip(old.deps.iter()) {
|
||||
if a.name != b.name {
|
||||
let e = format_err!("`{}` != `{}`", a.name, b.name)
|
||||
.context("unit dependency name changed");
|
||||
return Err(e);
|
||||
return DirtyReason::UnitDependencyNameChanged {
|
||||
old: b.name.clone(),
|
||||
new: a.name.clone(),
|
||||
};
|
||||
}
|
||||
|
||||
if a.fingerprint.hash_u64() != b.fingerprint.hash_u64() {
|
||||
let e = format_err!(
|
||||
"new ({}/{:x}) != old ({}/{:x})",
|
||||
a.name,
|
||||
a.fingerprint.hash_u64(),
|
||||
b.name,
|
||||
b.fingerprint.hash_u64()
|
||||
)
|
||||
.context("unit dependency information changed");
|
||||
return Err(e);
|
||||
return DirtyReason::UnitDependencyInfoChanged {
|
||||
new_name: a.name.clone(),
|
||||
new_fingerprint: a.fingerprint.hash_u64(),
|
||||
old_name: b.name.clone(),
|
||||
old_fingerprint: b.fingerprint.hash_u64(),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
if !self.fs_status.up_to_date() {
|
||||
bail!("current filesystem status shows we're outdated");
|
||||
return DirtyReason::FsStatusOutdated(self.fs_status.clone());
|
||||
}
|
||||
|
||||
// This typically means some filesystem modifications happened or
|
||||
// something transitive was odd. In general we should strive to provide
|
||||
// a better error message than this, so if you see this message a lot it
|
||||
// likely means this method needs to be updated!
|
||||
bail!("two fingerprint comparison turned up nothing obvious");
|
||||
DirtyReason::NothingObvious
|
||||
}
|
||||
|
||||
/// Dynamically inspect the local filesystem to update the `fs_status` field
|
||||
|
@ -1034,7 +1063,15 @@ impl Fingerprint {
|
|||
let dep_mtimes = match &dep.fingerprint.fs_status {
|
||||
FsStatus::UpToDate { mtimes } => mtimes,
|
||||
// If our dependency is stale, so are we, so bail out.
|
||||
FsStatus::Stale => return Ok(()),
|
||||
FsStatus::Stale
|
||||
| FsStatus::StaleItem(_)
|
||||
| FsStatus::StaleDependency { .. }
|
||||
| FsStatus::StaleDepFingerprint { .. } => {
|
||||
self.fs_status = FsStatus::StaleDepFingerprint {
|
||||
name: dep.name.clone(),
|
||||
};
|
||||
return Ok(());
|
||||
}
|
||||
};
|
||||
|
||||
// If our dependency edge only requires the rmeta file to be present
|
||||
|
@ -1072,6 +1109,13 @@ impl Fingerprint {
|
|||
"dependency on `{}` is newer than we are {} > {} {:?}",
|
||||
dep.name, dep_mtime, max_mtime, pkg_root
|
||||
);
|
||||
|
||||
self.fs_status = FsStatus::StaleDependency {
|
||||
name: dep.name.clone(),
|
||||
dep_mtime: *dep_mtime,
|
||||
max_mtime: *max_mtime,
|
||||
};
|
||||
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
|
@ -1085,6 +1129,7 @@ impl Fingerprint {
|
|||
local.find_stale_item(mtime_cache, pkg_root, target_root, cargo_exe)?
|
||||
{
|
||||
item.log();
|
||||
self.fs_status = FsStatus::StaleItem(item);
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
|
@ -1625,7 +1670,7 @@ fn compare_old_fingerprint(
|
|||
loc: &Path,
|
||||
new_fingerprint: &Fingerprint,
|
||||
mtime_on_use: bool,
|
||||
) -> CargoResult<()> {
|
||||
) -> CargoResult<Option<DirtyReason>> {
|
||||
let old_fingerprint_short = paths::read(loc)?;
|
||||
|
||||
if mtime_on_use {
|
||||
|
@ -1638,7 +1683,7 @@ fn compare_old_fingerprint(
|
|||
let new_hash = new_fingerprint.hash_u64();
|
||||
|
||||
if util::to_hex(new_hash) == old_fingerprint_short && new_fingerprint.fs_status.up_to_date() {
|
||||
return Ok(());
|
||||
return Ok(None);
|
||||
}
|
||||
|
||||
let old_fingerprint_json = paths::read(&loc.with_extension("json"))?;
|
||||
|
@ -1651,21 +1696,28 @@ fn compare_old_fingerprint(
|
|||
old_fingerprint_short
|
||||
);
|
||||
}
|
||||
let result = new_fingerprint.compare(&old_fingerprint);
|
||||
assert!(result.is_err());
|
||||
result
|
||||
|
||||
Ok(Some(new_fingerprint.compare(&old_fingerprint)))
|
||||
}
|
||||
|
||||
fn log_compare(unit: &Unit, compare: &CargoResult<()>) {
|
||||
let ce = match compare {
|
||||
Ok(..) => return,
|
||||
Err(e) => e,
|
||||
};
|
||||
info!(
|
||||
"fingerprint error for {}/{:?}/{:?}",
|
||||
unit.pkg, unit.mode, unit.target,
|
||||
);
|
||||
info!(" err: {:?}", ce);
|
||||
fn log_compare(unit: &Unit, compare: &CargoResult<Option<DirtyReason>>) {
|
||||
match compare {
|
||||
Ok(None) => {}
|
||||
Ok(Some(reason)) => {
|
||||
info!(
|
||||
"fingerprint dirty for {}/{:?}/{:?}",
|
||||
unit.pkg, unit.mode, unit.target,
|
||||
);
|
||||
info!(" dirty: {reason:?}");
|
||||
}
|
||||
Err(e) => {
|
||||
info!(
|
||||
"fingerprint error for {}/{:?}/{:?}",
|
||||
unit.pkg, unit.mode, unit.target,
|
||||
);
|
||||
info!(" err: {e:?}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Parses Cargo's internal `EncodedDepInfo` structure that was previously
|
||||
|
|
|
@ -0,0 +1,251 @@
|
|||
use std::fmt;
|
||||
use std::fmt::Debug;
|
||||
|
||||
use super::*;
|
||||
use crate::core::Shell;
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum DirtyReason {
|
||||
RustcChanged,
|
||||
FeaturesChanged {
|
||||
old: String,
|
||||
new: String,
|
||||
},
|
||||
TargetConfigurationChanged,
|
||||
PathToSourceChanged,
|
||||
ProfileConfigurationChanged,
|
||||
RustflagsChanged {
|
||||
old: Vec<String>,
|
||||
new: Vec<String>,
|
||||
},
|
||||
MetadataChanged,
|
||||
ConfigSettingsChanged,
|
||||
CompileKindChanged,
|
||||
LocalLengthsChanged,
|
||||
PrecalculatedComponentsChanged {
|
||||
old: String,
|
||||
new: String,
|
||||
},
|
||||
DepInfoOutputChanged {
|
||||
old: PathBuf,
|
||||
new: PathBuf,
|
||||
},
|
||||
RerunIfChangedOutputFileChanged {
|
||||
old: PathBuf,
|
||||
new: PathBuf,
|
||||
},
|
||||
RerunIfChangedOutputPathsChanged {
|
||||
old: Vec<PathBuf>,
|
||||
new: Vec<PathBuf>,
|
||||
},
|
||||
EnvVarsChanged {
|
||||
old: String,
|
||||
new: String,
|
||||
},
|
||||
EnvVarChanged {
|
||||
name: String,
|
||||
old_value: Option<String>,
|
||||
new_value: Option<String>,
|
||||
},
|
||||
LocalFingerprintTypeChanged {
|
||||
old: &'static str,
|
||||
new: &'static str,
|
||||
},
|
||||
NumberOfDependenciesChanged {
|
||||
old: usize,
|
||||
new: usize,
|
||||
},
|
||||
UnitDependencyNameChanged {
|
||||
old: InternedString,
|
||||
new: InternedString,
|
||||
},
|
||||
UnitDependencyInfoChanged {
|
||||
old_name: InternedString,
|
||||
old_fingerprint: u64,
|
||||
|
||||
new_name: InternedString,
|
||||
new_fingerprint: u64,
|
||||
},
|
||||
FsStatusOutdated(FsStatus),
|
||||
NothingObvious,
|
||||
Forced,
|
||||
}
|
||||
|
||||
trait ShellExt {
|
||||
fn dirty_because(&mut self, unit: &Unit, s: impl fmt::Display) -> CargoResult<()>;
|
||||
}
|
||||
|
||||
impl ShellExt for Shell {
|
||||
fn dirty_because(&mut self, unit: &Unit, s: impl fmt::Display) -> CargoResult<()> {
|
||||
self.status("Dirty", format_args!("{}: {s}", &unit.pkg))
|
||||
}
|
||||
}
|
||||
|
||||
struct FileTimeDiff {
|
||||
old_time: FileTime,
|
||||
new_time: FileTime,
|
||||
}
|
||||
|
||||
impl fmt::Display for FileTimeDiff {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
let s_diff = self.new_time.seconds() - self.old_time.seconds();
|
||||
if s_diff >= 1 {
|
||||
fmt::Display::fmt(
|
||||
&humantime::Duration::from(std::time::Duration::from_secs(s_diff as u64)),
|
||||
f,
|
||||
)
|
||||
} else {
|
||||
// format nanoseconds as it is, humantime would display ms, us and ns
|
||||
let ns_diff = self.new_time.nanoseconds() - self.old_time.nanoseconds();
|
||||
write!(f, "{ns_diff}ns")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
struct After {
|
||||
old_time: FileTime,
|
||||
new_time: FileTime,
|
||||
what: &'static str,
|
||||
}
|
||||
|
||||
impl fmt::Display for After {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
let Self {
|
||||
old_time,
|
||||
new_time,
|
||||
what,
|
||||
} = *self;
|
||||
let diff = FileTimeDiff { old_time, new_time };
|
||||
|
||||
write!(f, "{new_time}, {diff} after {what} at {old_time}")
|
||||
}
|
||||
}
|
||||
|
||||
impl DirtyReason {
|
||||
fn after(old_time: FileTime, new_time: FileTime, what: &'static str) -> After {
|
||||
After {
|
||||
old_time,
|
||||
new_time,
|
||||
what,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn present_to(&self, s: &mut Shell, unit: &Unit, root: &Path) -> CargoResult<()> {
|
||||
match self {
|
||||
DirtyReason::RustcChanged => s.dirty_because(unit, "the toolchain changed"),
|
||||
DirtyReason::FeaturesChanged { .. } => {
|
||||
s.dirty_because(unit, "the list of features changed")
|
||||
}
|
||||
DirtyReason::TargetConfigurationChanged => {
|
||||
s.dirty_because(unit, "the target configuration changed")
|
||||
}
|
||||
DirtyReason::PathToSourceChanged => {
|
||||
s.dirty_because(unit, "the path to the source changed")
|
||||
}
|
||||
DirtyReason::ProfileConfigurationChanged => {
|
||||
s.dirty_because(unit, "the profile configuration changed")
|
||||
}
|
||||
DirtyReason::RustflagsChanged { .. } => s.dirty_because(unit, "the rustflags changed"),
|
||||
DirtyReason::MetadataChanged => s.dirty_because(unit, "the metadata changed"),
|
||||
DirtyReason::ConfigSettingsChanged => {
|
||||
s.dirty_because(unit, "the config settings changed")
|
||||
}
|
||||
DirtyReason::CompileKindChanged => {
|
||||
s.dirty_because(unit, "the rustc compile kind changed")
|
||||
}
|
||||
DirtyReason::LocalLengthsChanged => {
|
||||
s.dirty_because(unit, "the local lengths changed")?;
|
||||
s.note(
|
||||
"This could happen because of added/removed `cargo:rerun-if` instructions in the build script",
|
||||
)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
DirtyReason::PrecalculatedComponentsChanged { .. } => {
|
||||
s.dirty_because(unit, "the precalculated components changed")
|
||||
}
|
||||
DirtyReason::DepInfoOutputChanged { .. } => {
|
||||
s.dirty_because(unit, "the dependency info output changed")
|
||||
}
|
||||
DirtyReason::RerunIfChangedOutputFileChanged { .. } => {
|
||||
s.dirty_because(unit, "rerun-if-changed output file path changed")
|
||||
}
|
||||
DirtyReason::RerunIfChangedOutputPathsChanged { .. } => {
|
||||
s.dirty_because(unit, "the rerun-if-changed instructions changed")
|
||||
}
|
||||
DirtyReason::EnvVarsChanged { .. } => {
|
||||
s.dirty_because(unit, "the environment variables changed")
|
||||
}
|
||||
DirtyReason::EnvVarChanged { name, .. } => {
|
||||
s.dirty_because(unit, format_args!("the env variable {name} changed"))
|
||||
}
|
||||
DirtyReason::LocalFingerprintTypeChanged { .. } => {
|
||||
s.dirty_because(unit, "the local fingerprint type changed")
|
||||
}
|
||||
DirtyReason::NumberOfDependenciesChanged { old, new } => s.dirty_because(
|
||||
unit,
|
||||
format_args!("number of dependencies changed ({old} => {new})",),
|
||||
),
|
||||
DirtyReason::UnitDependencyNameChanged { old, new } => s.dirty_because(
|
||||
unit,
|
||||
format_args!("name of dependency changed ({old} => {new})"),
|
||||
),
|
||||
DirtyReason::UnitDependencyInfoChanged { .. } => {
|
||||
s.dirty_because(unit, "dependency info changed")
|
||||
}
|
||||
DirtyReason::FsStatusOutdated(status) => match status {
|
||||
FsStatus::Stale => s.dirty_because(unit, "stale, unknown reason"),
|
||||
FsStatus::StaleItem(item) => match item {
|
||||
StaleItem::MissingFile(missing_file) => {
|
||||
let file = missing_file.strip_prefix(root).unwrap_or(&missing_file);
|
||||
s.dirty_because(
|
||||
unit,
|
||||
format_args!("the file `{}` is missing", file.display()),
|
||||
)
|
||||
}
|
||||
StaleItem::ChangedFile {
|
||||
stale,
|
||||
stale_mtime,
|
||||
reference_mtime,
|
||||
..
|
||||
} => {
|
||||
let file = stale.strip_prefix(root).unwrap_or(&stale);
|
||||
let after = Self::after(*reference_mtime, *stale_mtime, "last build");
|
||||
s.dirty_because(
|
||||
unit,
|
||||
format_args!("the file `{}` has changed ({after})", file.display()),
|
||||
)
|
||||
}
|
||||
StaleItem::ChangedEnv { var, .. } => s.dirty_because(
|
||||
unit,
|
||||
format_args!("the environment variable {var} changed"),
|
||||
),
|
||||
},
|
||||
FsStatus::StaleDependency {
|
||||
name,
|
||||
dep_mtime,
|
||||
max_mtime,
|
||||
..
|
||||
} => {
|
||||
let after = Self::after(*max_mtime, *dep_mtime, "last build");
|
||||
s.dirty_because(
|
||||
unit,
|
||||
format_args!("the dependency {name} was rebuilt ({after})"),
|
||||
)
|
||||
}
|
||||
FsStatus::StaleDepFingerprint { name } => {
|
||||
s.dirty_because(unit, format_args!("the dependency {name} was rebuilt"))
|
||||
}
|
||||
FsStatus::UpToDate { .. } => {
|
||||
unreachable!()
|
||||
}
|
||||
},
|
||||
DirtyReason::NothingObvious => {
|
||||
// See comment in fingerprint compare method.
|
||||
s.dirty_because(unit, "the fingerprint comparison turned up nothing obvious")
|
||||
}
|
||||
DirtyReason::Forced => s.dirty_because(unit, "forced"),
|
||||
}
|
||||
}
|
||||
}
|
|
@ -2,6 +2,7 @@ use std::fmt;
|
|||
use std::mem;
|
||||
|
||||
use super::job_queue::JobState;
|
||||
use crate::core::compiler::fingerprint::DirtyReason;
|
||||
use crate::util::CargoResult;
|
||||
|
||||
pub struct Job {
|
||||
|
@ -49,10 +50,10 @@ impl Job {
|
|||
}
|
||||
|
||||
/// Creates a new job representing a unit of work.
|
||||
pub fn new_dirty(work: Work) -> Job {
|
||||
pub fn new_dirty(work: Work, dirty_reason: Option<DirtyReason>) -> Job {
|
||||
Job {
|
||||
work,
|
||||
fresh: Freshness::Dirty,
|
||||
fresh: Freshness::Dirty(dirty_reason),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -65,8 +66,8 @@ impl Job {
|
|||
/// Returns whether this job was fresh/dirty, where "fresh" means we're
|
||||
/// likely to perform just some small bookkeeping where "dirty" means we'll
|
||||
/// probably do something slow like invoke rustc.
|
||||
pub fn freshness(&self) -> Freshness {
|
||||
self.fresh
|
||||
pub fn freshness(&self) -> &Freshness {
|
||||
&self.fresh
|
||||
}
|
||||
|
||||
pub fn before(&mut self, next: Work) {
|
||||
|
@ -85,8 +86,18 @@ impl fmt::Debug for Job {
|
|||
///
|
||||
/// A fresh package does not necessarily need to be rebuilt (unless a dependency
|
||||
/// was also rebuilt), and a dirty package must always be rebuilt.
|
||||
#[derive(PartialEq, Eq, Debug, Clone, Copy)]
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum Freshness {
|
||||
Fresh,
|
||||
Dirty,
|
||||
Dirty(Option<DirtyReason>),
|
||||
}
|
||||
|
||||
impl Freshness {
|
||||
pub fn is_dirty(&self) -> bool {
|
||||
matches!(self, Freshness::Dirty(_))
|
||||
}
|
||||
|
||||
pub fn is_fresh(&self) -> bool {
|
||||
matches!(self, Freshness::Fresh)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -54,7 +54,7 @@ use std::collections::{BTreeMap, HashMap, HashSet};
|
|||
use std::fmt::Write as _;
|
||||
use std::io;
|
||||
use std::marker;
|
||||
use std::path::PathBuf;
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::sync::Arc;
|
||||
use std::thread::{self, Scope};
|
||||
use std::time::Duration;
|
||||
|
@ -676,7 +676,7 @@ impl<'cfg> DrainState<'cfg> {
|
|||
// NOTE: An error here will drop the job without starting it.
|
||||
// That should be OK, since we want to exit as soon as
|
||||
// possible during an error.
|
||||
self.note_working_on(cx.bcx.config, &unit, job.freshness())?;
|
||||
self.note_working_on(cx.bcx.config, cx.bcx.ws.root(), &unit, job.freshness())?;
|
||||
}
|
||||
self.run(&unit, job, cx, scope);
|
||||
}
|
||||
|
@ -1116,7 +1116,7 @@ impl<'cfg> DrainState<'cfg> {
|
|||
assert!(self.active.insert(id, unit.clone()).is_none());
|
||||
|
||||
let messages = self.messages.clone();
|
||||
let fresh = job.freshness();
|
||||
let is_fresh = job.freshness().is_fresh();
|
||||
let rmeta_required = cx.rmeta_required(unit);
|
||||
|
||||
let doit = move |state: JobState<'_, '_>| {
|
||||
|
@ -1167,8 +1167,8 @@ impl<'cfg> DrainState<'cfg> {
|
|||
}
|
||||
};
|
||||
|
||||
match fresh {
|
||||
Freshness::Fresh => {
|
||||
match is_fresh {
|
||||
true => {
|
||||
self.timings.add_fresh();
|
||||
// Running a fresh job on the same thread is often much faster than spawning a new
|
||||
// thread to run the job.
|
||||
|
@ -1180,7 +1180,7 @@ impl<'cfg> DrainState<'cfg> {
|
|||
_marker: marker::PhantomData,
|
||||
});
|
||||
}
|
||||
Freshness::Dirty => {
|
||||
false => {
|
||||
self.timings.add_dirty();
|
||||
scope.spawn(move || {
|
||||
doit(JobState {
|
||||
|
@ -1355,8 +1355,9 @@ impl<'cfg> DrainState<'cfg> {
|
|||
fn note_working_on(
|
||||
&mut self,
|
||||
config: &Config,
|
||||
ws_root: &Path,
|
||||
unit: &Unit,
|
||||
fresh: Freshness,
|
||||
fresh: &Freshness,
|
||||
) -> CargoResult<()> {
|
||||
if (self.compiled.contains(&unit.pkg.package_id())
|
||||
&& !unit.mode.is_doc()
|
||||
|
@ -1370,7 +1371,13 @@ impl<'cfg> DrainState<'cfg> {
|
|||
match fresh {
|
||||
// Any dirty stage which runs at least one command gets printed as
|
||||
// being a compiled package.
|
||||
Dirty => {
|
||||
Dirty(dirty_reason) => {
|
||||
if let Some(reason) = dirty_reason {
|
||||
config
|
||||
.shell()
|
||||
.verbose(|shell| reason.present_to(shell, unit, ws_root))?;
|
||||
}
|
||||
|
||||
if unit.mode.is_doc() {
|
||||
self.documented.insert(unit.pkg.package_id());
|
||||
config.shell().status("Documenting", &unit.pkg)?;
|
||||
|
|
|
@ -45,6 +45,7 @@ pub use self::compile_kind::{CompileKind, CompileTarget};
|
|||
pub use self::context::{Context, Metadata};
|
||||
pub use self::crate_type::CrateType;
|
||||
pub use self::custom_build::{BuildOutput, BuildScriptOutputs, BuildScripts};
|
||||
pub(crate) use self::fingerprint::DirtyReason;
|
||||
pub use self::job::Freshness;
|
||||
use self::job::{Job, Work};
|
||||
use self::job_queue::{JobQueue, JobState};
|
||||
|
@ -164,11 +165,11 @@ fn compile<'cfg>(
|
|||
// We run these targets later, so this is just a no-op for now.
|
||||
Job::new_fresh()
|
||||
} else if build_plan {
|
||||
Job::new_dirty(rustc(cx, unit, &exec.clone())?)
|
||||
Job::new_dirty(rustc(cx, unit, &exec.clone())?, None)
|
||||
} else {
|
||||
let force = exec.force_rebuild(unit) || force_rebuild;
|
||||
let mut job = fingerprint::prepare_target(cx, unit, force)?;
|
||||
job.before(if job.freshness() == Freshness::Dirty {
|
||||
job.before(if job.freshness().is_dirty() {
|
||||
let work = if unit.mode.is_doc() || unit.mode.is_doc_scrape() {
|
||||
rustdoc(cx, unit)?
|
||||
} else {
|
||||
|
|
|
@ -3,7 +3,7 @@ use std::path::{Path, PathBuf};
|
|||
use std::sync::Arc;
|
||||
use std::{env, fs};
|
||||
|
||||
use crate::core::compiler::{CompileKind, DefaultExecutor, Executor, Freshness, UnitOutput};
|
||||
use crate::core::compiler::{CompileKind, DefaultExecutor, Executor, UnitOutput};
|
||||
use crate::core::{Dependency, Edition, Package, PackageId, Source, SourceId, Workspace};
|
||||
use crate::ops::CompileFilter;
|
||||
use crate::ops::{common_for_install_and_uninstall::*, FilterRule};
|
||||
|
@ -683,7 +683,7 @@ fn is_installed(
|
|||
let tracker = InstallTracker::load(config, root)?;
|
||||
let (freshness, _duplicates) =
|
||||
tracker.check_upgrade(dst, pkg, force, opts, target, &rustc.verbose_version)?;
|
||||
Ok(freshness == Freshness::Fresh)
|
||||
Ok(freshness.is_fresh())
|
||||
}
|
||||
|
||||
/// Checks if vers can only be satisfied by exactly one version of a package in a registry, and it's
|
||||
|
|
|
@ -11,7 +11,7 @@ use ops::FilterRule;
|
|||
use serde::{Deserialize, Serialize};
|
||||
use toml_edit::easy as toml;
|
||||
|
||||
use crate::core::compiler::Freshness;
|
||||
use crate::core::compiler::{DirtyReason, Freshness};
|
||||
use crate::core::Target;
|
||||
use crate::core::{Dependency, FeatureValue, Package, PackageId, QueryKind, Source, SourceId};
|
||||
use crate::ops::{self, CompileFilter, CompileOptions};
|
||||
|
@ -170,7 +170,7 @@ impl InstallTracker {
|
|||
// Check if any tracked exe's are already installed.
|
||||
let duplicates = self.find_duplicates(dst, &exes);
|
||||
if force || duplicates.is_empty() {
|
||||
return Ok((Freshness::Dirty, duplicates));
|
||||
return Ok((Freshness::Dirty(Some(DirtyReason::Forced)), duplicates));
|
||||
}
|
||||
// Check if all duplicates come from packages of the same name. If
|
||||
// there are duplicates from other packages, then --force will be
|
||||
|
@ -200,7 +200,7 @@ impl InstallTracker {
|
|||
let source_id = pkg.package_id().source_id();
|
||||
if source_id.is_path() {
|
||||
// `cargo install --path ...` is always rebuilt.
|
||||
return Ok((Freshness::Dirty, duplicates));
|
||||
return Ok((Freshness::Dirty(Some(DirtyReason::Forced)), duplicates));
|
||||
}
|
||||
let is_up_to_date = |dupe_pkg_id| {
|
||||
let info = self
|
||||
|
@ -224,7 +224,7 @@ impl InstallTracker {
|
|||
if matching_duplicates.iter().all(is_up_to_date) {
|
||||
Ok((Freshness::Fresh, duplicates))
|
||||
} else {
|
||||
Ok((Freshness::Dirty, duplicates))
|
||||
Ok((Freshness::Dirty(Some(DirtyReason::Forced)), duplicates))
|
||||
}
|
||||
} else {
|
||||
// Format the error message.
|
||||
|
|
|
@ -2321,8 +2321,10 @@ fn calc_bin_artifact_fingerprint() {
|
|||
.masquerade_as_nightly_cargo(&["bindeps"])
|
||||
.with_stderr(
|
||||
"\
|
||||
[DIRTY] bar v0.5.0 ([CWD]/bar): the file `bar/src/main.rs` has changed ([..])
|
||||
[COMPILING] bar v0.5.0 ([CWD]/bar)
|
||||
[RUNNING] `rustc --crate-name bar [..]`
|
||||
[DIRTY] foo v0.1.0 ([CWD]): the dependency bar was rebuilt
|
||||
[CHECKING] foo v0.1.0 ([CWD])
|
||||
[RUNNING] `rustc --crate-name foo [..]`
|
||||
[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
|
||||
|
|
|
@ -1214,6 +1214,7 @@ fn only_rerun_build_script() {
|
|||
p.cargo("build -v")
|
||||
.with_stderr(
|
||||
"\
|
||||
[DIRTY] foo v0.5.0 ([CWD]): the precalculated components changed
|
||||
[COMPILING] foo v0.5.0 ([CWD])
|
||||
[RUNNING] `[..]/build-script-build`
|
||||
[RUNNING] `rustc --crate-name foo [..]`
|
||||
|
@ -1320,6 +1321,7 @@ fn testing_and_such() {
|
|||
p.cargo("test -vj1")
|
||||
.with_stderr(
|
||||
"\
|
||||
[DIRTY] foo v0.5.0 ([CWD]): the precalculated components changed
|
||||
[COMPILING] foo v0.5.0 ([CWD])
|
||||
[RUNNING] `[..]/build-script-build`
|
||||
[RUNNING] `rustc --crate-name foo [..]`
|
||||
|
@ -1717,6 +1719,7 @@ fn out_dir_is_preserved() {
|
|||
p.cargo("build -v")
|
||||
.with_stderr(
|
||||
"\
|
||||
[DIRTY] foo [..]: the file `build.rs` has changed ([..])
|
||||
[COMPILING] foo [..]
|
||||
[RUNNING] `rustc --crate-name build_script_build [..]
|
||||
[RUNNING] `[..]/build-script-build`
|
||||
|
@ -1741,6 +1744,7 @@ fn out_dir_is_preserved() {
|
|||
p.cargo("build -v")
|
||||
.with_stderr(
|
||||
"\
|
||||
[DIRTY] foo [..]: the precalculated components changed
|
||||
[COMPILING] foo [..]
|
||||
[RUNNING] `[..]build-script-build`
|
||||
[RUNNING] `rustc --crate-name foo [..]
|
||||
|
@ -3005,6 +3009,7 @@ fn changing_an_override_invalidates() {
|
|||
p.cargo("build -v")
|
||||
.with_stderr(
|
||||
"\
|
||||
[DIRTY] foo v0.5.0 ([..]): the precalculated components changed
|
||||
[COMPILING] foo v0.5.0 ([..]
|
||||
[RUNNING] `rustc [..] -L native=bar`
|
||||
[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
|
||||
|
@ -3295,6 +3300,7 @@ fn rebuild_only_on_explicit_paths() {
|
|||
p.cargo("build -v")
|
||||
.with_stderr(
|
||||
"\
|
||||
[DIRTY] foo v0.5.0 ([..]): the file `foo` is missing
|
||||
[COMPILING] foo v0.5.0 ([..])
|
||||
[RUNNING] `[..]/build-script-build`
|
||||
[RUNNING] `rustc [..] src/lib.rs [..]`
|
||||
|
@ -3313,6 +3319,7 @@ fn rebuild_only_on_explicit_paths() {
|
|||
p.cargo("build -v")
|
||||
.with_stderr(
|
||||
"\
|
||||
[DIRTY] foo v0.5.0 ([..]): the file `foo` has changed ([..])
|
||||
[COMPILING] foo v0.5.0 ([..])
|
||||
[RUNNING] `[..]/build-script-build`
|
||||
[RUNNING] `rustc [..] src/lib.rs [..]`
|
||||
|
@ -3351,6 +3358,7 @@ fn rebuild_only_on_explicit_paths() {
|
|||
p.cargo("build -v")
|
||||
.with_stderr(
|
||||
"\
|
||||
[DIRTY] foo v0.5.0 ([..]): the file `foo` has changed ([..])
|
||||
[COMPILING] foo v0.5.0 ([..])
|
||||
[RUNNING] `[..]/build-script-build`
|
||||
[RUNNING] `rustc [..] src/lib.rs [..]`
|
||||
|
@ -3360,11 +3368,12 @@ fn rebuild_only_on_explicit_paths() {
|
|||
.run();
|
||||
|
||||
// .. as does deleting a file
|
||||
println!("run foo delete");
|
||||
println!("run bar delete");
|
||||
fs::remove_file(p.root().join("bar")).unwrap();
|
||||
p.cargo("build -v")
|
||||
.with_stderr(
|
||||
"\
|
||||
[DIRTY] foo v0.5.0 ([..]): the file `bar` is missing
|
||||
[COMPILING] foo v0.5.0 ([..])
|
||||
[RUNNING] `[..]/build-script-build`
|
||||
[RUNNING] `rustc [..] src/lib.rs [..]`
|
||||
|
@ -4692,12 +4701,29 @@ fn rerun_if_directory() {
|
|||
)
|
||||
.build();
|
||||
|
||||
let dirty = || {
|
||||
p.cargo("check")
|
||||
.with_stderr(
|
||||
"[COMPILING] foo [..]\n\
|
||||
[FINISHED] [..]",
|
||||
)
|
||||
let dirty = |dirty_line: &str, compile_build_script: bool| {
|
||||
let mut dirty_line = dirty_line.to_string();
|
||||
|
||||
if !dirty_line.is_empty() {
|
||||
dirty_line.push('\n');
|
||||
}
|
||||
|
||||
let compile_build_script_line = if compile_build_script {
|
||||
"[RUNNING] `rustc --crate-name build_script_build [..]\n"
|
||||
} else {
|
||||
""
|
||||
};
|
||||
|
||||
p.cargo("check -v")
|
||||
.with_stderr(format!(
|
||||
"\
|
||||
{dirty_line}\
|
||||
[COMPILING] foo [..]
|
||||
{compile_build_script_line}\
|
||||
[RUNNING] `[..]build-script-build[..]`
|
||||
[RUNNING] `rustc --crate-name foo [..]
|
||||
[FINISHED] [..]",
|
||||
))
|
||||
.run();
|
||||
};
|
||||
|
||||
|
@ -4706,10 +4732,13 @@ fn rerun_if_directory() {
|
|||
};
|
||||
|
||||
// Start with a missing directory.
|
||||
dirty();
|
||||
dirty("", true);
|
||||
// Because the directory doesn't exist, it will trigger a rebuild every time.
|
||||
// https://github.com/rust-lang/cargo/issues/6003
|
||||
dirty();
|
||||
dirty(
|
||||
"[DIRTY] foo v0.1.0 ([..]): the file `somedir` is missing",
|
||||
false,
|
||||
);
|
||||
|
||||
if is_coarse_mtime() {
|
||||
sleep_ms(1000);
|
||||
|
@ -4717,7 +4746,10 @@ fn rerun_if_directory() {
|
|||
|
||||
// Empty directory.
|
||||
fs::create_dir(p.root().join("somedir")).unwrap();
|
||||
dirty();
|
||||
dirty(
|
||||
"[DIRTY] foo v0.1.0 ([..]): the file `somedir` has changed ([..])",
|
||||
false,
|
||||
);
|
||||
fresh();
|
||||
|
||||
if is_coarse_mtime() {
|
||||
|
@ -4727,7 +4759,10 @@ fn rerun_if_directory() {
|
|||
// Add a file.
|
||||
p.change_file("somedir/foo", "");
|
||||
p.change_file("somedir/bar", "");
|
||||
dirty();
|
||||
dirty(
|
||||
"[DIRTY] foo v0.1.0 ([..]): the file `somedir` has changed ([..])",
|
||||
false,
|
||||
);
|
||||
fresh();
|
||||
|
||||
if is_coarse_mtime() {
|
||||
|
@ -4736,7 +4771,10 @@ fn rerun_if_directory() {
|
|||
|
||||
// Add a symlink.
|
||||
p.symlink("foo", "somedir/link");
|
||||
dirty();
|
||||
dirty(
|
||||
"[DIRTY] foo v0.1.0 ([..]): the file `somedir` has changed ([..])",
|
||||
false,
|
||||
);
|
||||
fresh();
|
||||
|
||||
if is_coarse_mtime() {
|
||||
|
@ -4746,7 +4784,10 @@ fn rerun_if_directory() {
|
|||
// Move the symlink.
|
||||
fs::remove_file(p.root().join("somedir/link")).unwrap();
|
||||
p.symlink("bar", "somedir/link");
|
||||
dirty();
|
||||
dirty(
|
||||
"[DIRTY] foo v0.1.0 ([..]): the file `somedir` has changed ([..])",
|
||||
false,
|
||||
);
|
||||
fresh();
|
||||
|
||||
if is_coarse_mtime() {
|
||||
|
@ -4755,7 +4796,10 @@ fn rerun_if_directory() {
|
|||
|
||||
// Remove a file.
|
||||
fs::remove_file(p.root().join("somedir/foo")).unwrap();
|
||||
dirty();
|
||||
dirty(
|
||||
"[DIRTY] foo v0.1.0 ([..]): the file `somedir` has changed ([..])",
|
||||
false,
|
||||
);
|
||||
fresh();
|
||||
}
|
||||
|
||||
|
|
|
@ -74,6 +74,7 @@ fn works_with_cli() {
|
|||
.masquerade_as_nightly_cargo(&["config-include"])
|
||||
.with_stderr(
|
||||
"\
|
||||
[DIRTY] foo v0.0.1 ([..]): the rustflags changed
|
||||
[COMPILING] foo v0.0.1 [..]
|
||||
[RUNNING] `rustc [..]-W unsafe-code -W unused`
|
||||
[FINISHED] [..]
|
||||
|
|
|
@ -480,11 +480,14 @@ fn no_feature_doesnt_build() {
|
|||
.run();
|
||||
p.process(&p.bin("foo")).with_stdout("").run();
|
||||
|
||||
p.cargo("build --features bar")
|
||||
p.cargo("build --features bar -v")
|
||||
.with_stderr(
|
||||
"\
|
||||
[COMPILING] bar v0.0.1 ([CWD]/bar)
|
||||
[RUNNING] `rustc --crate-name bar [..]
|
||||
[DIRTY-MSVC] foo v0.0.1 ([CWD]): the list of features changed
|
||||
[COMPILING] foo v0.0.1 ([CWD])
|
||||
[RUNNING] `rustc --crate-name foo [..]
|
||||
[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
|
||||
",
|
||||
)
|
||||
|
@ -537,10 +540,12 @@ fn default_feature_pulled_in() {
|
|||
.run();
|
||||
p.process(&p.bin("foo")).with_stdout("bar\n").run();
|
||||
|
||||
p.cargo("build --no-default-features")
|
||||
p.cargo("build --no-default-features -v")
|
||||
.with_stderr(
|
||||
"\
|
||||
[DIRTY-MSVC] foo v0.0.1 ([CWD]): the list of features changed
|
||||
[COMPILING] foo v0.0.1 ([CWD])
|
||||
[RUNNING] `rustc --crate-name foo [..]
|
||||
[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
|
||||
",
|
||||
)
|
||||
|
|
|
@ -38,10 +38,12 @@ fn modifying_and_moving() {
|
|||
p.root().join("target").move_into_the_past();
|
||||
|
||||
p.change_file("src/a.rs", "#[allow(unused)]fn main() {}");
|
||||
p.cargo("build")
|
||||
p.cargo("build -v")
|
||||
.with_stderr(
|
||||
"\
|
||||
[DIRTY] foo v0.0.1 ([CWD]): the file `src/a.rs` has changed ([..])
|
||||
[COMPILING] foo v0.0.1 ([CWD])
|
||||
[RUNNING] `rustc --crate-name foo [..]
|
||||
[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
|
||||
",
|
||||
)
|
||||
|
@ -83,10 +85,12 @@ fn modify_only_some_files() {
|
|||
lib.move_into_the_past();
|
||||
|
||||
// Make sure the binary is rebuilt, not the lib
|
||||
p.cargo("build")
|
||||
p.cargo("build -v")
|
||||
.with_stderr(
|
||||
"\
|
||||
[DIRTY] foo v0.0.1 ([CWD]): the file `src/b.rs` has changed ([..])
|
||||
[COMPILING] foo v0.0.1 ([CWD])
|
||||
[RUNNING] `rustc --crate-name foo [..]
|
||||
[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
|
||||
",
|
||||
)
|
||||
|
@ -147,6 +151,7 @@ fn rebuild_sub_package_then_while_package() {
|
|||
p.cargo("build -pb -v")
|
||||
.with_stderr(
|
||||
"\
|
||||
[DIRTY] b v0.0.1 ([..]): the file `b/src/lib.rs` has changed ([..])
|
||||
[COMPILING] b [..]
|
||||
[RUNNING] `rustc --crate-name b [..]
|
||||
[FINISHED] dev [..]
|
||||
|
@ -163,8 +168,10 @@ fn rebuild_sub_package_then_while_package() {
|
|||
.with_stderr(
|
||||
"\
|
||||
[FRESH] b [..]
|
||||
[DIRTY] a [..]: the dependency b was rebuilt ([..])
|
||||
[COMPILING] a [..]
|
||||
[RUNNING] `rustc --crate-name a [..]
|
||||
[DIRTY] foo [..]: the dependency b was rebuilt ([..])
|
||||
[COMPILING] foo [..]
|
||||
[RUNNING] `rustc --crate-name foo [..]
|
||||
[FINISHED] dev [..]
|
||||
|
@ -492,21 +499,38 @@ fn changing_bin_features_caches_targets() {
|
|||
|
||||
/* Targets should be cached from the first build */
|
||||
|
||||
let mut e = p.cargo("build");
|
||||
let mut e = p.cargo("build -v");
|
||||
|
||||
// MSVC does not include hash in binary filename, so it gets recompiled.
|
||||
if cfg!(target_env = "msvc") {
|
||||
e.with_stderr("[COMPILING] foo[..]\n[FINISHED] dev[..]");
|
||||
e.with_stderr(
|
||||
"\
|
||||
[DIRTY] foo v0.0.1 ([..]): the list of features changed
|
||||
[COMPILING] foo[..]
|
||||
[RUNNING] `rustc [..]
|
||||
[FINISHED] dev[..]",
|
||||
);
|
||||
} else {
|
||||
e.with_stderr("[FINISHED] dev[..]");
|
||||
e.with_stderr("[FRESH] foo v0.0.1 ([..])\n[FINISHED] dev[..]");
|
||||
}
|
||||
e.run();
|
||||
p.rename_run("foo", "off2").with_stdout("feature off").run();
|
||||
|
||||
let mut e = p.cargo("build --features foo");
|
||||
let mut e = p.cargo("build --features foo -v");
|
||||
if cfg!(target_env = "msvc") {
|
||||
e.with_stderr("[COMPILING] foo[..]\n[FINISHED] dev[..]");
|
||||
e.with_stderr(
|
||||
"\
|
||||
[DIRTY] foo v0.0.1 ([..]): the list of features changed
|
||||
[COMPILING] foo[..]
|
||||
[RUNNING] `rustc [..]
|
||||
[FINISHED] dev[..]",
|
||||
);
|
||||
} else {
|
||||
e.with_stderr("[FINISHED] dev[..]");
|
||||
e.with_stderr(
|
||||
"\
|
||||
[FRESH] foo v0.0.1 ([..])
|
||||
[FINISHED] dev[..]",
|
||||
);
|
||||
}
|
||||
e.run();
|
||||
p.rename_run("foo", "on2").with_stdout("feature on").run();
|
||||
|
@ -843,11 +867,13 @@ fn rebuild_if_environment_changes() {
|
|||
"#,
|
||||
);
|
||||
|
||||
p.cargo("run")
|
||||
p.cargo("run -v")
|
||||
.with_stdout("new desc")
|
||||
.with_stderr(
|
||||
"\
|
||||
[DIRTY] foo v0.0.1 ([CWD]): the metadata changed
|
||||
[COMPILING] foo v0.0.1 ([CWD])
|
||||
[RUNNING] `rustc [..]
|
||||
[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
|
||||
[RUNNING] `target/debug/foo[EXE]`
|
||||
",
|
||||
|
@ -1186,23 +1212,43 @@ fn changing_rustflags_is_cached() {
|
|||
let p = project().file("src/lib.rs", "").build();
|
||||
|
||||
// This isn't ever cached, we always have to recompile
|
||||
for _ in 0..2 {
|
||||
p.cargo("build")
|
||||
.with_stderr(
|
||||
"\
|
||||
p.cargo("build")
|
||||
.with_stderr(
|
||||
"\
|
||||
[COMPILING] foo v0.0.1 ([..])
|
||||
[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]",
|
||||
)
|
||||
.run();
|
||||
p.cargo("build")
|
||||
.env("RUSTFLAGS", "-C linker=cc")
|
||||
.with_stderr(
|
||||
"\
|
||||
)
|
||||
.run();
|
||||
p.cargo("build -v")
|
||||
.env("RUSTFLAGS", "-C linker=cc")
|
||||
.with_stderr(
|
||||
"\
|
||||
[DIRTY] foo v0.0.1 ([..]): the rustflags changed
|
||||
[COMPILING] foo v0.0.1 ([..])
|
||||
[RUNNING] `rustc [..]
|
||||
[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]",
|
||||
)
|
||||
.run();
|
||||
}
|
||||
)
|
||||
.run();
|
||||
|
||||
p.cargo("build -v")
|
||||
.with_stderr(
|
||||
"\
|
||||
[DIRTY] foo v0.0.1 ([..]): the rustflags changed
|
||||
[COMPILING] foo v0.0.1 ([..])
|
||||
[RUNNING] `rustc [..]
|
||||
[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]",
|
||||
)
|
||||
.run();
|
||||
p.cargo("build -v")
|
||||
.env("RUSTFLAGS", "-C linker=cc")
|
||||
.with_stderr(
|
||||
"\
|
||||
[DIRTY] foo v0.0.1 ([..]): the rustflags changed
|
||||
[COMPILING] foo v0.0.1 ([..])
|
||||
[RUNNING] `rustc [..]
|
||||
[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]",
|
||||
)
|
||||
.run();
|
||||
}
|
||||
|
||||
#[cargo_test]
|
||||
|
@ -1480,12 +1526,18 @@ fn bust_patched_dep() {
|
|||
sleep_ms(1000);
|
||||
}
|
||||
|
||||
p.cargo("build")
|
||||
p.cargo("build -v")
|
||||
.with_stderr(
|
||||
"\
|
||||
[DIRTY] registry1 v0.1.0 ([..]): the file `reg1new/src/lib.rs` has changed ([..])
|
||||
[COMPILING] registry1 v0.1.0 ([..])
|
||||
[RUNNING] `rustc [..]
|
||||
[DIRTY] registry2 v0.1.0: the dependency registry1 was rebuilt
|
||||
[COMPILING] registry2 v0.1.0
|
||||
[RUNNING] `rustc [..]
|
||||
[DIRTY] foo v0.0.1 ([..]): the dependency registry2 was rebuilt
|
||||
[COMPILING] foo v0.0.1 ([..])
|
||||
[RUNNING] `rustc [..]
|
||||
[FINISHED] [..]
|
||||
",
|
||||
)
|
||||
|
@ -1598,10 +1650,13 @@ fn rebuild_on_mid_build_file_modification() {
|
|||
)
|
||||
.run();
|
||||
|
||||
p.cargo("build")
|
||||
p.cargo("build -v")
|
||||
.with_stderr(
|
||||
"\
|
||||
[FRESH] proc_macro_dep v0.1.0 ([..]/proc_macro_dep)
|
||||
[DIRTY] root v0.1.0 ([..]/root): the file `root/src/lib.rs` has changed ([..])
|
||||
[COMPILING] root v0.1.0 ([..]/root)
|
||||
[RUNNING] `rustc [..]
|
||||
[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
|
||||
",
|
||||
)
|
||||
|
@ -1877,6 +1932,7 @@ fn simulated_docker_deps_stay_cached() {
|
|||
[FRESH] regdep_env [..]
|
||||
[FRESH] regdep_old_style [..]
|
||||
[FRESH] regdep_rerun [..]
|
||||
[DIRTY] foo [..]: the precalculated components changed
|
||||
[COMPILING] foo [..]
|
||||
[RUNNING] [..]/foo-[..]/build-script-build[..]
|
||||
[RUNNING] `rustc --crate-name foo[..]
|
||||
|
@ -2108,6 +2164,7 @@ fn rerun_if_changes() {
|
|||
.env("FOO", "1")
|
||||
.with_stderr(
|
||||
"\
|
||||
[DIRTY] foo [..]: the env variable FOO changed
|
||||
[COMPILING] foo [..]
|
||||
[RUNNING] `[..]build-script-build`
|
||||
[RUNNING] `rustc [..]
|
||||
|
@ -2125,6 +2182,7 @@ fn rerun_if_changes() {
|
|||
.env("BAR", "1")
|
||||
.with_stderr(
|
||||
"\
|
||||
[DIRTY] foo [..]: the env variable BAR changed
|
||||
[COMPILING] foo [..]
|
||||
[RUNNING] `[..]build-script-build`
|
||||
[RUNNING] `rustc [..]
|
||||
|
@ -2142,6 +2200,7 @@ fn rerun_if_changes() {
|
|||
.env("BAR", "2")
|
||||
.with_stderr(
|
||||
"\
|
||||
[DIRTY] foo [..]: the env variable FOO changed
|
||||
[COMPILING] foo [..]
|
||||
[RUNNING] `[..]build-script-build`
|
||||
[RUNNING] `rustc [..]
|
||||
|
@ -2439,12 +2498,15 @@ fn linking_interrupted() {
|
|||
drop(rustc_conn.read_exact(&mut buf));
|
||||
|
||||
// Build again, shouldn't be fresh.
|
||||
p.cargo("test --test t1")
|
||||
p.cargo("test --test t1 -v")
|
||||
.with_stderr(
|
||||
"\
|
||||
[DIRTY] foo v0.0.1 ([..]): the config settings changed
|
||||
[COMPILING] foo [..]
|
||||
[RUNNING] `rustc --crate-name foo [..]
|
||||
[RUNNING] `rustc --crate-name t1 [..]
|
||||
[FINISHED] [..]
|
||||
[RUNNING] tests/t1.rs (target/debug/deps/t1[..])
|
||||
[RUNNING] `[..]target/debug/deps/t1-[..][EXE]`
|
||||
",
|
||||
)
|
||||
.run();
|
||||
|
@ -2513,25 +2575,43 @@ fn env_in_code_causes_rebuild() {
|
|||
.env_remove("FOO")
|
||||
.with_stderr("[FINISHED] [..]")
|
||||
.run();
|
||||
p.cargo("build")
|
||||
p.cargo("build -v")
|
||||
.env("FOO", "bar")
|
||||
.with_stderr("[COMPILING][..]\n[FINISHED][..]")
|
||||
.with_stderr(
|
||||
"\
|
||||
[DIRTY] foo [..]: the environment variable FOO changed
|
||||
[COMPILING][..]
|
||||
[RUNNING] `rustc [..]
|
||||
[FINISHED][..]",
|
||||
)
|
||||
.run();
|
||||
p.cargo("build")
|
||||
.env("FOO", "bar")
|
||||
.with_stderr("[FINISHED][..]")
|
||||
.run();
|
||||
p.cargo("build")
|
||||
p.cargo("build -v")
|
||||
.env("FOO", "baz")
|
||||
.with_stderr("[COMPILING][..]\n[FINISHED][..]")
|
||||
.with_stderr(
|
||||
"\
|
||||
[DIRTY] foo [..]: the environment variable FOO changed
|
||||
[COMPILING][..]
|
||||
[RUNNING] `rustc [..]
|
||||
[FINISHED][..]",
|
||||
)
|
||||
.run();
|
||||
p.cargo("build")
|
||||
.env("FOO", "baz")
|
||||
.with_stderr("[FINISHED][..]")
|
||||
.run();
|
||||
p.cargo("build")
|
||||
p.cargo("build -v")
|
||||
.env_remove("FOO")
|
||||
.with_stderr("[COMPILING][..]\n[FINISHED][..]")
|
||||
.with_stderr(
|
||||
"\
|
||||
[DIRTY] foo [..]: the environment variable FOO changed
|
||||
[COMPILING][..]
|
||||
[RUNNING] `rustc [..]
|
||||
[FINISHED][..]",
|
||||
)
|
||||
.run();
|
||||
p.cargo("build")
|
||||
.env_remove("FOO")
|
||||
|
@ -2616,6 +2696,7 @@ fn cargo_env_changes() {
|
|||
.arg("-v")
|
||||
.with_stderr(
|
||||
"\
|
||||
[DIRTY] foo v1.0.0 ([..]): the environment variable CARGO changed
|
||||
[CHECKING] foo [..]
|
||||
[RUNNING] `rustc [..]
|
||||
[FINISHED] [..]
|
||||
|
|
|
@ -2521,6 +2521,7 @@ fn include_overrides_gitignore() {
|
|||
p.cargo("build -v")
|
||||
.with_stderr(
|
||||
"\
|
||||
[DIRTY] foo v0.5.0 ([..]): the precalculated components changed
|
||||
[COMPILING] foo v0.5.0 ([..])
|
||||
[RUNNING] `[..]build-script-build[..]`
|
||||
[RUNNING] `rustc --crate-name foo src/lib.rs [..]`
|
||||
|
|
|
@ -595,6 +595,7 @@ fn dylib() {
|
|||
[COMPILING] registry-shared v0.0.1
|
||||
[FRESH] registry v0.0.1
|
||||
[RUNNING] `rustc --crate-name registry_shared [..]-C embed-bitcode=no[..]
|
||||
[DIRTY] bar v0.0.0 ([..]): dependency info changed
|
||||
[COMPILING] bar [..]
|
||||
[RUNNING] `rustc --crate-name bar [..]--crate-type dylib [..]-C embed-bitcode=no[..]
|
||||
[FINISHED] [..]
|
||||
|
@ -612,6 +613,7 @@ fn dylib() {
|
|||
[FRESH] registry-shared v0.0.1
|
||||
[COMPILING] registry v0.0.1
|
||||
[RUNNING] `rustc --crate-name registry [..]
|
||||
[DIRTY] bar v0.0.0 ([..]): dependency info changed
|
||||
[COMPILING] bar [..]
|
||||
[RUNNING] `rustc --crate-name bar [..]--crate-type dylib [..]-C embed-bitcode=no[..]
|
||||
[RUNNING] `rustc --crate-name bar [..]-C lto [..]--test[..]
|
||||
|
|
|
@ -639,6 +639,7 @@ fn rustc_fingerprint() {
|
|||
.with_stderr_does_not_contain("-C debug-assertions")
|
||||
.with_stderr(
|
||||
"\
|
||||
[DIRTY] foo [..]: the profile configuration changed
|
||||
[COMPILING] foo [..]
|
||||
[RUNNING] `rustc [..]
|
||||
[FINISHED] [..]
|
||||
|
|
|
@ -2661,6 +2661,7 @@ fn bin_does_not_rebuild_tests() {
|
|||
p.cargo("test -v --no-run")
|
||||
.with_stderr(
|
||||
"\
|
||||
[DIRTY] foo v0.0.1 ([..]): the file `src/main.rs` has changed ([..])
|
||||
[COMPILING] foo v0.0.1 ([..])
|
||||
[RUNNING] `rustc [..] src/main.rs [..]`
|
||||
[RUNNING] `rustc [..] src/main.rs [..]`
|
||||
|
|
Loading…
Reference in New Issue