-
Notifications
You must be signed in to change notification settings - Fork 2.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add --all
flag to cargo test
#3221
Conversation
Thanks for the pull request, and welcome! The Rust team is excited to review your changes, and you should hear from @brson (or someone else) soon. If any changes to this PR are deemed necessary, please add them as extra commits. This ensures that the reviewer can see what has changed since they last reviewed the code. Due to the way GitHub handles out-of-date commits, this should also make it reasonably obvious what issues have or haven't been addressed. Large or tricky changes may require several passes of review and changes. Please see the contribution instructions for more information. |
Thanks for the PR! Unfortunately I'll be pretty busy this week so it may take awhile to get back to this, but I haven't forgotten it! |
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.
Ok, looking good! We may need a few cleanups along the way to really land this, but I think this is a great start.
@@ -281,14 +281,15 @@ impl<'a, 'cfg> Encodable for WorkspaceResolve<'a, 'cfg> { | |||
|
|||
let root = self.ws.members().max_by_key(|member| { | |||
member.name() | |||
}).unwrap().package_id(); | |||
}).map(Package::package_id); |
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.
Hm were the changes in this file required to get tests to pass? Or just cleaning things up?
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.
Yes, that panic is triggered when running test
on a virtual manifest. It is currently prevented by the "error: manifest path ...
is a virtual manifest, but this command requires running against an actual package in this workspace" error.
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.
Ok, sounds good to me
Packages::All => ws.members() | ||
.map(|package| { | ||
let package_id = package.package_id(); | ||
PackageIdSpec::from_package_id(package_id).to_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.
Instead of round-tripping through PackageIdSpec
, perhaps the resolution to a list of local packages could be done sooner?
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.
Where would be the right place to do that? I didn't want to place it too high up so that future --all
commands could share this logic.
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 the concept of "all" could be plumbed farther down as an enum?
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.
Plumbed down where? It makes sense to me to pass Packages
down through resolve_dependencies
but don't you still need to get the PackageIdSpec
s of the workspace here to resolve the targets?
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.
Yeah let's pass this down to resolve_dependencies
, and perhaps that can also return a list of specs?
@@ -28,7 +28,7 @@ pub struct Unit<'a> { | |||
pub struct Context<'a, 'cfg: 'a> { | |||
pub config: &'cfg Config, | |||
pub resolve: &'a Resolve, | |||
pub current_package: PackageId, | |||
pub current_package: Option<PackageId>, |
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.
Hm so I think this is a code smell we need to clean up (not your fault, a historical one). The concept of a "current package" is basically no longer valid in today's world of workspaces and such. Could this field get outright removed as part of this change?
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.
I can try that, sure.
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.
I think I need some clarification. What does "current package" mean in this context? Isn't it the package of the directory that we issue the compile in? Why is that not needed?
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.
Yeah the intention is there really is not right question to what the "current package" means. It has different interpretations depending on where you are asking it from, so that's why I figure it'd be best to remove and we can answer that question on a case-by-case basis.
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.
I see. Digging into this more, I'm noticing that the places that use Context
don't have a Workspace
available to pull a root package from (if one exists). So, doesn't making this an Option
essentially handle this (i.e., a workspace either has a current package, or it's virtual, so it doesn't). Thank you for your patience :)
let root_package = try!(ws.current()); | ||
if spec.len() == 0 { | ||
try!(generate_targets(root_package, &profiles, mode, filter, release)); | ||
} |
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.
This kinda sent me spinning for a bit. I think this if
statement isn't necessary, right? It's implied to always be true given the above condition.
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.
Fixed.
doc: Profile::default_doc(), | ||
custom_build: Profile::default_custom_build(), | ||
}, | ||
}; |
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.
Hm this is somewhat worrisome to me. This is where I think we'll want to learn about the profiles from the workspace root crate instead of whatever the current crate happens to be.
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.
Does the workspace have a root crate in a virtual manifest?
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.
Not exactly yet, see #3249 :)
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.
@matklad Awesome! I can rebase on top of your PR.
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.
Ah yeah #3249 is exactly what I had in mind here
☔ The latest upstream changes (presumably #3242) made this pull request unmergeable. Please resolve the merge conflicts. |
Use a single profile set per workspace This aims to close #3206. I have not figured out how to do this 100% backward compatibly, that's why I want to discuss this separately, although a related PR (#3221) is already in flight. The problem is this: suppose that you have a workspace with two members, A and B and that A includes a profiles section and B does not. Now, mentally `cd` inside B and run `cargo build`. Today, Cargo will use a default profile. We want it to use a profile from A. So here the silent behavior switch will inevitably occur :( Looks like we can't detect this situation. So this PR just switches the behavior to always use root profiles, and to print a warning if a non-root package specifies profiles. Feel free to reuse it in any form for #3221 if that's convenient!
Rebased. Hopefully will get a chance to work on this more later this week. |
@@ -92,8 +99,10 @@ pub enum CompileFilter<'a> { | |||
|
|||
pub fn compile<'a>(ws: &Workspace<'a>, options: &CompileOptions<'a>) | |||
-> CargoResult<ops::Compilation<'a>> { | |||
for key in try!(ws.current()).manifest().warnings().iter() { | |||
try!(options.config.shell().warn(key)) | |||
if let Some(root_package) = ws.current_opt() { |
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.
Random drive-by comment, but could this actually iterate over all members of the workspace? That's the intention here, at least
☔ The latest upstream changes (presumably #3280) made this pull request unmergeable. Please resolve the merge conflicts. |
Rebased, and ready for another round of review, @alexcrichton |
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.
Looking great!
} | ||
|
||
Some(encodable_resolve_node(id, self.resolve)) |
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.
Hm ok to sanity check this (changes to resolve are very subtle).
I don't think this change is needed, right? The change above (unwrap
-> map
) is purely for cargo test
against an empty virtual manifest, right? If there exists any crates at all (e.g. ids
is a non-empty list) then I'd hope there's at least one workspace member.
.collect::<CargoResult<Vec<_>>>()?; | ||
|
||
let pair = resolve_dependencies(ws, | ||
let resolve = resolve_dependencies(ws, | ||
source, |
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.
Some indentation to match up here
for p in spec { | ||
pkgids.push(resolve_with_overrides.query(&p)?); | ||
for p in spec.iter() { | ||
pkgids.push(resolve_with_overrides.query(&p.to_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.
I think this can just be:
pkgids.push(p.query(resolve_with_overrides.iter()));
(avoid going through a string)
} | ||
} else { | ||
let root_package = ws.current()?; | ||
generate_targets(root_package, profiles, mode, filter, release)?; |
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.
I think this was special cased above to get these errors before the resolution process happened (which may involve downloads and such). Perhaps that logic could still be special cased?
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.
Putting this logic the old way caused my tests to fail, but I'm not sure why.
self.config.extra_verbose() | ||
self.ws.current_opt().map_or(false, |p| *pkg == *p.package_id()) | ||
|| pkg.source_id().is_path() | ||
|| self.config.extra_verbose() |
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.
I think this can be updated to just the clause:
pkg.source_id().is_path() || self.config.extra_verbose()
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.
Well technically actually, we should show warnings for all workspace members, not not all path dependencies.
@@ -417,7 +416,8 @@ impl<'a, 'cfg> Context<'a, 'cfg> { | |||
// we don't want to link it up. | |||
if src_dir.ends_with("deps") { | |||
// Don't lift up library dependencies | |||
if unit.pkg.package_id() != &self.current_package && !unit.target.is_bin() { | |||
if self.ws.current_opt().map_or(false, |p| unit.pkg.package_id() != p.package_id()) |
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.
I think here we can actually just test:
if !unit.pkg.package_id().source_id().is_path() && !unit.target.is_bin() {
// ...
}
That is, all path dependencies should hit the code path of Some
below
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.
er actually, we should replace the current_package
check with a check if the crate is in the workspace rather than all path dependencies.
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.
What's the correct way to check this?
ws.members().find(|&p| p == unit.pkg).is_some()
causes test failures.
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.
Hm yeah that should work, but is that not working? What do the test failures look like?
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.
Hm, on a second look I think I might have just been reversing the conditional. Pushed a fix.
@@ -273,7 +272,7 @@ impl<'a, 'cfg> Context<'a, 'cfg> { | |||
|
|||
/// Returns the appropriate directory layout for either a plugin or not. | |||
pub fn layout(&self, unit: &Unit) -> LayoutProxy { | |||
let primary = unit.pkg.package_id() == &self.current_package; | |||
let primary = self.ws.current_opt().map_or(false, |p| unit.pkg.package_id() == p.package_id()); |
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.
I think this can be replaced with:
let primary = is_member_of_current_workspace(self, unit);
let profile = cx.lib_profile(&cx.current_package); | ||
let profile = cx.ws.current_opt().map_or_else(Profile::default, |p| { | ||
cx.lib_profile(p.package_id()).to_owned() | ||
}); |
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 package argument here to lib_profile
is actually ignored (long story), so let's just go ahead and remove that argument and then we can avoid the workaround here.
unit.pkg.package_id() != &cx.current_package); | ||
cx.ws.current_opt().map_or(false, |p| { | ||
*p.package_id() != *unit.pkg.package_id() | ||
})); |
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.
Wow I have absolutely no clue what this clause is doing (the old one).
Let's just replace it though with, like above, a test whether the package is in the current workspace.
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.
Same as above.
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.
Ditto.
Still working on this, haven't had much time for open source lately! Hoping to finish up by the weekend. |
Ah no worries, let me know if you need any help getting it over the finish line! |
☔ The latest upstream changes (presumably #3310) made this pull request unmergeable. Please resolve the merge conflicts. |
fc8e469
to
12331db
Compare
@alexcrichton Most comments addressed, I commented on the remaining issues. |
Sorry for taking awhile to get back to this! I just want to dig into the "is a member" issue a bit and then we should be able to land this. |
@alexcrichton, no problem! Everything should be addressed now. There are failing tests, but those are due to #879. |
@bors: r+ Awesome, thanks! |
📌 Commit addbb7e has been approved by |
Add `--all` flag to `cargo test` Work towards #2878. This flag allows a user to test all members of a workspace by using `cargo test --all`. The command is also supported when using a virtual workspace manifest.
☀️ Test successful - status-appveyor, status-travis |
Was it expected that this changed cargo's behavior so that tests of dependent lib crates are no longer dropped in the |
It's still broken on tip (de2919f) |
Woops, I was testing the wrong binary. It is indeed fixed on tip. I'll bisect for a fix cset. |
Ok, thanks for checking! |
It was indeed fixed by 3cbf141. The regression is present in the cargo that ships with rustc 1.15. That's not a big deal for me (I just won't use it) but something you may want to be aware of. |
Sure thing, thanks for the heads up regardless |
Fix logic for determining prefer-dynamic for a dylib. The logic for determining if a dylib should use `prefer-dynamic` used to be something like "do not use prefer-dynamic if it is the current package". The current logic has a strange behavior where it works as intended if there is only one package in the workspace, but a workspace with multiple packages will always use `prefer-dynamic`. Instead of using `current_opt`, which isn't a good concept to use in a workspace, I switched this to be "primary" (a package selected on the command-line). **History** * 9879a0a Initial prefer-dynamic behavior. * #3221 changed to the faulty logic (see comments at #3221 (comment)). I think there was some confusion there. * #3478 fixed the logic for one of the changed conditions, but not the one for prefer-dynamic
Work towards #2878.
This flag allows a user to test all members of a workspace by using
cargo test --all
. The command is also supported when using a virtual workspace manifest.