Skip to content

Commit d998906

Browse files
committed
Auto merge of #5349 - bmwill:fetch-by-target, r=alexcrichton
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
2 parents 9eece36 + 1956c5d commit d998906

File tree

6 files changed

+209
-11
lines changed

6 files changed

+209
-11
lines changed

src/bin/commands/fetch.rs

+8-1
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
11
use command_prelude::*;
22

33
use cargo::ops;
4+
use cargo::ops::FetchOptions;
45

56
pub fn cli() -> App {
67
subcommand("fetch")
78
.about("Fetch dependencies of a package from the network")
89
.arg_manifest_path()
10+
.arg_target_triple("Fetch dependencies for the target triple")
911
.after_help(
1012
"\
1113
If a lockfile is available, this command will ensure that all of the git
@@ -22,6 +24,11 @@ all updated.
2224

2325
pub fn exec(config: &mut Config, args: &ArgMatches) -> CliResult {
2426
let ws = args.workspace(config)?;
25-
ops::fetch(&ws)?;
27+
28+
let opts = FetchOptions {
29+
config,
30+
target: args.target(),
31+
};
32+
ops::fetch(&ws, &opts)?;
2633
Ok(())
2734
}

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

+1-2
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,7 @@ use self::compilation_files::{CompilationFiles, OutputFile};
2929
pub use self::compilation_files::Metadata;
3030

3131
mod target_info;
32-
pub use self::target_info::FileFlavor;
33-
use self::target_info::TargetInfo;
32+
pub use self::target_info::{FileFlavor, TargetInfo};
3433

3534
/// All information needed to define a Unit.
3635
///

src/cargo/core/compiler/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ use self::job_queue::JobQueue;
2323
use self::output_depinfo::output_depinfo;
2424

2525
pub use self::compilation::Compilation;
26-
pub use self::context::{Context, FileFlavor, Unit};
26+
pub use self::context::{Context, FileFlavor, TargetInfo, Unit};
2727
pub use self::custom_build::{BuildMap, BuildOutput, BuildScripts};
2828
pub use self::layout::is_bad_artifact_name;
2929

src/cargo/ops/cargo_fetch.rs

+67-5
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,74 @@
1-
use core::{PackageSet, Resolve, Workspace};
1+
use core::compiler::{BuildConfig, Kind, TargetInfo};
2+
use core::{Package, PackageId, PackageSet, Resolve, Workspace};
23
use ops;
4+
use std::collections::HashSet;
35
use util::CargoResult;
6+
use util::Config;
7+
8+
pub struct FetchOptions<'a> {
9+
pub config: &'a Config,
10+
/// The target arch triple to fetch dependencies for
11+
pub target: Option<String>,
12+
}
413

514
/// Executes `cargo fetch`.
6-
pub fn fetch<'a>(ws: &Workspace<'a>) -> CargoResult<(Resolve, PackageSet<'a>)> {
15+
pub fn fetch<'a>(
16+
ws: &Workspace<'a>,
17+
options: &FetchOptions<'a>,
18+
) -> CargoResult<(Resolve, PackageSet<'a>)> {
719
let (packages, resolve) = ops::resolve_ws(ws)?;
8-
for id in resolve.iter() {
9-
packages.get(id)?;
10-
}
20+
21+
fetch_for_target(ws, options.config, &options.target, &resolve, &packages)?;
22+
1123
Ok((resolve, packages))
1224
}
25+
26+
fn fetch_for_target<'a, 'cfg: 'a>(
27+
ws: &'a Workspace<'cfg>,
28+
config: &'cfg Config,
29+
target: &Option<String>,
30+
resolve: &'a Resolve,
31+
packages: &'a PackageSet<'cfg>,
32+
) -> CargoResult<HashSet<&'a PackageId>> {
33+
let mut fetched_packages = HashSet::new();
34+
let mut deps_to_fetch = Vec::new();
35+
let jobs = Some(1);
36+
let build_config = BuildConfig::new(config, jobs, target, None)?;
37+
let target_info = TargetInfo::new(config, &build_config, Kind::Target)?;
38+
let root_package_ids = ws.members().map(Package::package_id).collect::<Vec<_>>();
39+
40+
deps_to_fetch.extend(root_package_ids);
41+
42+
while let Some(id) = deps_to_fetch.pop() {
43+
if !fetched_packages.insert(id) {
44+
continue;
45+
}
46+
47+
let package = packages.get(id)?;
48+
let deps = resolve.deps(id);
49+
let dependency_ids = deps.filter(|dep| {
50+
package
51+
.dependencies()
52+
.iter()
53+
.filter(|d| d.name() == dep.name() && d.version_req().matches(dep.version()))
54+
.any(|d| {
55+
// If no target was specified then all dependencies can be fetched.
56+
let target = match *target {
57+
Some(ref t) => t,
58+
None => return true,
59+
};
60+
// If this dependency is only available for certain platforms,
61+
// make sure we're only fetching it for that platform.
62+
let platform = match d.platform() {
63+
Some(p) => p,
64+
None => return true,
65+
};
66+
platform.matches(target, target_info.cfg())
67+
})
68+
}).collect::<Vec<_>>();
69+
70+
deps_to_fetch.extend(dependency_ids);
71+
}
72+
73+
Ok(fetched_packages)
74+
}

src/cargo/ops/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ pub use self::registry::{publish, registry_configuration, RegistryConfig};
1616
pub use self::registry::{http_handle, needs_custom_http_transport, registry_login, search};
1717
pub use self::registry::{modify_owners, yank, OwnersOptions, PublishOpts};
1818
pub use self::registry::configure_http_handle;
19-
pub use self::cargo_fetch::fetch;
19+
pub use self::cargo_fetch::{fetch, FetchOptions};
2020
pub use self::cargo_pkgid::pkgid;
2121
pub use self::resolve::{resolve_with_previous, resolve_ws, resolve_ws_precisely,
2222
resolve_ws_with_method};

tests/testsuite/fetch.rs

+131-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1-
use cargotest::support::{execs, project};
1+
use cargotest::rustc_host;
2+
use cargotest::support::registry::Package;
3+
use cargotest::support::{cross_compile, execs, project};
24
use hamcrest::assert_that;
35

46
#[test]
@@ -24,3 +26,131 @@ fn no_deps() {
2426

2527
assert_that(p.cargo("fetch"), execs().with_status(0).with_stdout(""));
2628
}
29+
30+
#[test]
31+
fn fetch_all_platform_dependencies_when_no_target_is_given() {
32+
Package::new("d1", "1.2.3")
33+
.file(
34+
"Cargo.toml",
35+
r#"
36+
[project]
37+
name = "d1"
38+
version = "1.2.3"
39+
"#,
40+
)
41+
.file("src/lib.rs", "")
42+
.publish();
43+
44+
Package::new("d2", "0.1.2")
45+
.file(
46+
"Cargo.toml",
47+
r#"
48+
[project]
49+
name = "d2"
50+
version = "0.1.2"
51+
"#,
52+
)
53+
.file("src/lib.rs", "")
54+
.publish();
55+
56+
let target = cross_compile::alternate();
57+
let host = rustc_host();
58+
let p = project("foo")
59+
.file(
60+
"Cargo.toml",
61+
&format!(
62+
r#"
63+
[package]
64+
name = "foo"
65+
version = "0.0.1"
66+
authors = []
67+
68+
[target.{host}.dependencies]
69+
d1 = "1.2.3"
70+
71+
[target.{target}.dependencies]
72+
d2 = "0.1.2"
73+
"#,
74+
host = host,
75+
target = target
76+
),
77+
)
78+
.file("src/lib.rs", "")
79+
.build();
80+
81+
assert_that(
82+
p.cargo("fetch"),
83+
execs()
84+
.with_status(0)
85+
.with_stderr_contains("[..] Downloading d1 v1.2.3 [..]")
86+
.with_stderr_contains("[..] Downloading d2 v0.1.2 [..]"),
87+
);
88+
}
89+
90+
#[test]
91+
fn fetch_platform_specific_dependencies() {
92+
Package::new("d1", "1.2.3")
93+
.file(
94+
"Cargo.toml",
95+
r#"
96+
[project]
97+
name = "d1"
98+
version = "1.2.3"
99+
"#,
100+
)
101+
.file("src/lib.rs", "")
102+
.publish();
103+
104+
Package::new("d2", "0.1.2")
105+
.file(
106+
"Cargo.toml",
107+
r#"
108+
[project]
109+
name = "d2"
110+
version = "0.1.2"
111+
"#,
112+
)
113+
.file("src/lib.rs", "")
114+
.publish();
115+
116+
let target = cross_compile::alternate();
117+
let host = rustc_host();
118+
let p = project("foo")
119+
.file(
120+
"Cargo.toml",
121+
&format!(
122+
r#"
123+
[package]
124+
name = "foo"
125+
version = "0.0.1"
126+
authors = []
127+
128+
[target.{host}.dependencies]
129+
d1 = "1.2.3"
130+
131+
[target.{target}.dependencies]
132+
d2 = "0.1.2"
133+
"#,
134+
host = host,
135+
target = target
136+
),
137+
)
138+
.file("src/lib.rs", "")
139+
.build();
140+
141+
assert_that(
142+
p.cargo("fetch").arg("--target").arg(&host),
143+
execs()
144+
.with_status(0)
145+
.with_stderr_contains("[..] Downloading d1 v1.2.3 [..]")
146+
.with_stderr_does_not_contain("[..] Downloading d2 v0.1.2 [..]"),
147+
);
148+
149+
assert_that(
150+
p.cargo("fetch").arg("--target").arg(&target),
151+
execs()
152+
.with_status(0)
153+
.with_stderr_contains("[..] Downloading d2 v0.1.2[..]")
154+
.with_stderr_does_not_contain("[..] Downloading d1 v1.2.3 [..]"),
155+
);
156+
}

0 commit comments

Comments
 (0)