-
Notifications
You must be signed in to change notification settings - Fork 255
Rebuild necessary packages when reusing build plan #969
Conversation
src/build/plan.rs
Outdated
.map(|(idx, _)| idx + 1) | ||
.and_then(|idx| args.get(idx)) | ||
.map(|x| x.as_os_str()) | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Using ?
should help redability I think
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe FP/Haskell spoiled me recently, I like the chain of simple transformations 😢
Do you mean doing sth like let idx = ...?; args.get(idx).map(|x| x.as_os_str())
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
let idx = args.iter().enumenrate().find(...)?;
args.get(idx + 1)?.as_os_str()
prev_package_arg: Option<PackageArg>, | ||
/// Packages (names) for which this build plan was prepared. | ||
/// Used to detect if the plan can reused when building certain packages. | ||
built_packages: HashSet<String>, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The might be several packages with the same name. Ideally, we should use something like package_id here I think
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OTOH, I'm all for not peeking into Cargo's internals unless absolutely necessary, and I think using strings for know is the best approach.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agreed on packages with same name; came to the conclusion that having packages with same name in the primary workspace will be rare enough and these strings we're passing to Cargo's Packages::from_flags
, so I think these get converted and resolved later to PackageIdSpec
s internally?
Re Cargo internals I'd love to stabilise a small subset of public-facing structures like PackageId but that's a talk for another time 😄
src/build/plan.rs
Outdated
crate fn cache_compiler_job(&mut self, id: &PackageId, target: &Target, cmd: &ProcessBuilder) { | ||
let pkg_key = (id.clone(), target.kind().clone()); | ||
crate fn cache_compiler_job(&mut self, id: &PackageId, target: &Target, mode: CompileMode, cmd: &ProcessBuilder) { | ||
let pkg_key = (id.clone(), target.clone(), mode); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
s/pkg_key/unit_key/
src/build/plan.rs
Outdated
// collect every unit having the longest path prefix. | ||
let max_matching_prefix = other_targets.values() | ||
.map(|src_dir| matching_prefix_components(modified, src_dir)) | ||
.max().unwrap(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's not obvious that this unwrap
will never trip :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice catch, thanks!
src/build/plan.rs
Outdated
let dirty_units = other_targets.iter() | ||
.filter(|(_, src_dir)| max_matching_prefix == | ||
matching_prefix_components(modified, src_dir) | ||
).map(|(unit, _)| unit); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That is an amusing way to lay out a comparison operator over several lines :)
@nrc @matklad 003e437#diff-80398c5faae3c069e4e6aa2ed11b28c0R16 bumped pulled Cargo commit to the most recent one to include required rust-lang/cargo@90a5ba3 commit. Is that a problem? Or do we only need to coordinate that for Rust distributions? |
@Xanewok no, when building as a part of rust-lang/rust, RLS is forced to use the right cargo, rustfmt and clippy: |
Right then, so if this lands it seems we need to be careful to update Cargo before RLS at rust-lang/rust 👍 |
We'll need to update them simultaneously, b/c the new Cargo won't work with old RLS. We can just add an |
Ah right, obviously. Thanks for the info! I'll do that if/when this lands. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good to me, thanks!
A couple of nits inline.
src/build/plan.rs
Outdated
@@ -214,7 +213,7 @@ impl Plan { | |||
match unit { | |||
None => trace!( | |||
"Modified file {:?} doesn't correspond to any package!", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
s/{:?}/{}
src/build/plan.rs
Outdated
@@ -471,6 +471,15 @@ impl PackageMap { | |||
#[derive(Debug)] | |||
crate struct JobQueue(Vec<ProcessBuilder>); | |||
|
|||
fn proc_arg<T: AsRef<OsStr>>(prc: &ProcessBuilder, key: T) -> Option<&std::ffi::OsStr> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could this function have a more descriptive name? And/or a comment.
Apart from pulling in updated Cargo, it also include Rustfmt 0.9.0 for PR purposes
@nrc addressed the feedback and it's green (with the exception of recently busted AppVeyor) so I'm gonna merge this one now. |
Somewhat fixes #876.
Relies on the Cargo fork branch pulling in rust-lang/cargo#5830.Firstly, it fixes the package autodetection logic. Previously it calculated bare
-p
and compared it against previous cached version. Now we try to build default set of packages for Cargo, create a set out of these packages and if we find ourselves modifying a package not included in the cached build plan, we ask Cargo to rebuild the sum of previous packages and the new one. In short, the build plan is additive and if we don't have what we need, we try to rebuild it including the package we just modified.Secondly, we distinguish more unit types in the dep graph. This changes unit distinction from
(PackageId, TargetKind)
to(PackageId, Target, CompileMode)
.Previous key type was not enough a) when compiling different targets of the same kind (e.g. differently named bin targets) b) when compiling exact same crate target in a regular mode and in the unit test/harness mode. The latter distinction is important, because previously we could have assigned a unit test harness invocation to a regular lib on which other units depended - when we invalidated library, the unit test harness was reran, but the lib was not rebuilt, resulting in missing/invalid data across multiple crate targets.
This also somewhat improves test harness in few places - I think it'd be great to focus on it now and provide a nice set of bulletproof regression tests against cases such as this. This would definitely help bring the 1.0 quality!