-
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
cargo-fetch: add option to fetch for a target #5349
Conversation
Thanks for the pull request, and welcome! The Rust team is excited to review your changes, and you should hear from @alexcrichton (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 this! A few thoughts:
|
Yes I realize that working with a |
Sure yeah, so I think ideally this'd basically work with It may need some refactoring to extract out the platform information from rustc (but that should probably happen anyway). Otherwise you'll need to match up an edge to a Does that make sense? |
As some background (since I was looking at similar things this week), the |
Make it possible to construct TargetInfo without Context This should make stuff like #5349 easier.
I've been away for the past week and should have time this week to get back to this. @alexcrichton Yep that makes sense and sounds like a much more efficient way to approach the problem. @djc Thanks for the pointer! That should make my life a lot easier and make it possible to avoid using a Context object. |
This is still a WIP since tests still need to be written, but here's another attempt at implementing this without using a |
That looks pretty nice! Three remarks (unofficial review):
|
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 looks great to me, thanks @bmwill!
src/cargo/ops/cargo_fetch.rs
Outdated
|
||
set.insert(package); | ||
for pkg in pkg_deps.iter() { | ||
if !set.contains(pkg) { |
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 condition be moved to the top of the function? I think you can do:
if !set.insert(package) {
return
}
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 it could. I'm actually going to take @djc's advice and restructure this to eliminate the recursion since that will probably make the function a little easier to read. In doing that I'll hoist this into the calling function.
src/cargo/ops/cargo_fetch.rs
Outdated
packages: &'a PackageSet<'cfg>, | ||
build_config: &BuildConfig, | ||
target_info: &TargetInfo, | ||
) -> CargoResult<Vec<&'a 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.
It looks like the Vec
return value isn't used much here, right?
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.
Nope its not actually used here, but I think it will be used once I restructure the code to not use recursion. Instead we can use a queue to keep track of the packages that still need their dependencies fetched and append the returned list of dependencies from this function to the queue. Something like this:
while let Some(pkg) = deps_to_fetch.pop_front() {
if !fetched_packages.insert(pkg) {
continue;
}
let deps = fetch_dependencies(
pkg,
resolve,
packages,
&build_config,
&target_info,
)?;
deps_to_fetch.extend(deps);
}
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 seems plausiblee to me!
src/cargo/ops/cargo_fetch.rs
Outdated
let target_info = TargetInfo::new(config, &build_config, Kind::Target)?; | ||
let root_pkgs = ws.default_members() | ||
.map(Package::package_id) | ||
.map(PackageIdSpec::from_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 you can skip the PackageIdSpec
step here and go straight to packages.get
after the initial package_id
above, right?
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.
Yep that's right, I'll fix that.
I'd slightly prefer to not prune the |
Can you say more about why? |
@djc |
K here's another revision with the following changes:
|
src/cargo/ops/cargo_fetch.rs
Outdated
let root_pkgs = ws.default_members() | ||
.map(Package::package_id) | ||
.map(|id| { | ||
let p = packages.get(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 you can eschew the ?
here and just use packages.get(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.
Also I wonder, perhaps the list of deps_to_fetch
could be a list of PackageId
and then the packages.get
call here could be deduplicated with fetch_dependencies
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.
Yeah that looks a bit cleaner, I'll go ahead and make this change.
src/cargo/ops/cargo_fetch.rs
Outdated
packages: &'a PackageSet<'cfg>, | ||
) -> CargoResult<HashSet<&'a Package>> { | ||
let mut fetched_packages = HashSet::new(); | ||
let mut deps_to_fetch = VecDeque::new(); |
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 it's fine to avoid a VecDeque
here, a Vec
should work ok in that you can just use pop
and not worry about the actual order that things are downloaded in
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.
Will do.
src/cargo/ops/cargo_fetch.rs
Outdated
Ok(fetched_packages) | ||
} | ||
|
||
fn fetch_dependencies<'a, 'cfg: 'a>( |
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.
Since this is no longer recursive it may be best to inline this above perhaps?
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.
Yep, I'll inline this.
src/cargo/ops/cargo_fetch.rs
Outdated
if let Some(_) = options.target { | ||
fetch_for_target(ws, options.config, &options.target, &resolve, &packages)?; | ||
} else { | ||
for id in resolve.iter() { |
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.
While it's true that this is a nice optimization I think we may actually want to fold these two branches to the same code at this point, that'll keep the fetch_for_target
code well tested as well since they'll share similar code paths.
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.
Mind explaining a bit more about how you would expect to fold the two branches together?
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.
Oh sure yeah, so down below you've got logic for "only follow dependency edges if the target matches", and that'd be updated to "follow dependency edges if no target is listed or if the target matches"
src/cargo/ops/cargo_fetch.rs
Outdated
package | ||
.dependencies() | ||
.iter() | ||
.filter(|d| d.name() == dep.name() && d.version_req().matches(dep.version())) |
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 logic is sort of wonky and unfortunate (but I think it's "mostly correct" as-is), but with #5415 this'll get much nicer!
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, it's "as correct as it can be" as-is, to clarify. No action needed here!
Teach cargo-fetch how to optionally fetch dependencies based on a target platform by specifying the target triple via `--target <TRIPLE>`. Signed-off-by: Brandon Williams <bmwill@google.com>
This latest version has the following changes:
|
@bors: r+ Thanks! |
📌 Commit 1956c5d has been approved by |
cargo-fetch: add option to fetch for a target Teach cargo-fetch how to optionally fetch dependencies based on a target platform by specifying the target triple via `--target <TRIPLE>`. #5216
☀️ Test successful - status-appveyor, status-travis |
Thanks for doing this, @bmwill! |
Teach cargo-fetch how to optionally fetch dependencies based on a target
platform by specifying the target triple via
--target <TRIPLE>
.#5216