Skip to content

Commit

Permalink
Auto merge of #5349 - bmwill:fetch-by-target, r=alexcrichton
Browse files Browse the repository at this point in the history
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
  • Loading branch information
bors committed Apr 27, 2018
2 parents 9eece36 + 1956c5d commit d998906
Show file tree
Hide file tree
Showing 6 changed files with 209 additions and 11 deletions.
9 changes: 8 additions & 1 deletion src/bin/commands/fetch.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
use command_prelude::*;

use cargo::ops;
use cargo::ops::FetchOptions;

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

pub fn exec(config: &mut Config, args: &ArgMatches) -> CliResult {
let ws = args.workspace(config)?;
ops::fetch(&ws)?;

let opts = FetchOptions {
config,
target: args.target(),
};
ops::fetch(&ws, &opts)?;
Ok(())
}
3 changes: 1 addition & 2 deletions src/cargo/core/compiler/context/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,7 @@ use self::compilation_files::{CompilationFiles, OutputFile};
pub use self::compilation_files::Metadata;

mod target_info;
pub use self::target_info::FileFlavor;
use self::target_info::TargetInfo;
pub use self::target_info::{FileFlavor, TargetInfo};

/// All information needed to define a Unit.
///
Expand Down
2 changes: 1 addition & 1 deletion src/cargo/core/compiler/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ use self::job_queue::JobQueue;
use self::output_depinfo::output_depinfo;

pub use self::compilation::Compilation;
pub use self::context::{Context, FileFlavor, Unit};
pub use self::context::{Context, FileFlavor, TargetInfo, Unit};
pub use self::custom_build::{BuildMap, BuildOutput, BuildScripts};
pub use self::layout::is_bad_artifact_name;

Expand Down
72 changes: 67 additions & 5 deletions src/cargo/ops/cargo_fetch.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,74 @@
use core::{PackageSet, Resolve, Workspace};
use core::compiler::{BuildConfig, Kind, TargetInfo};
use core::{Package, PackageId, PackageSet, Resolve, Workspace};
use ops;
use std::collections::HashSet;
use util::CargoResult;
use util::Config;

pub struct FetchOptions<'a> {
pub config: &'a Config,
/// The target arch triple to fetch dependencies for
pub target: Option<String>,
}

/// Executes `cargo fetch`.
pub fn fetch<'a>(ws: &Workspace<'a>) -> CargoResult<(Resolve, PackageSet<'a>)> {
pub fn fetch<'a>(
ws: &Workspace<'a>,
options: &FetchOptions<'a>,
) -> CargoResult<(Resolve, PackageSet<'a>)> {
let (packages, resolve) = ops::resolve_ws(ws)?;
for id in resolve.iter() {
packages.get(id)?;
}

fetch_for_target(ws, options.config, &options.target, &resolve, &packages)?;

Ok((resolve, packages))
}

fn fetch_for_target<'a, 'cfg: 'a>(
ws: &'a Workspace<'cfg>,
config: &'cfg Config,
target: &Option<String>,
resolve: &'a Resolve,
packages: &'a PackageSet<'cfg>,
) -> CargoResult<HashSet<&'a PackageId>> {
let mut fetched_packages = HashSet::new();
let mut deps_to_fetch = Vec::new();
let jobs = Some(1);
let build_config = BuildConfig::new(config, jobs, target, None)?;
let target_info = TargetInfo::new(config, &build_config, Kind::Target)?;
let root_package_ids = ws.members().map(Package::package_id).collect::<Vec<_>>();

deps_to_fetch.extend(root_package_ids);

while let Some(id) = deps_to_fetch.pop() {
if !fetched_packages.insert(id) {
continue;
}

let package = packages.get(id)?;
let deps = resolve.deps(id);
let dependency_ids = deps.filter(|dep| {
package
.dependencies()
.iter()
.filter(|d| d.name() == dep.name() && d.version_req().matches(dep.version()))
.any(|d| {
// If no target was specified then all dependencies can be fetched.
let target = match *target {
Some(ref t) => t,
None => return true,
};
// If this dependency is only available for certain platforms,
// make sure we're only fetching it for that platform.
let platform = match d.platform() {
Some(p) => p,
None => return true,
};
platform.matches(target, target_info.cfg())
})
}).collect::<Vec<_>>();

deps_to_fetch.extend(dependency_ids);
}

Ok(fetched_packages)
}
2 changes: 1 addition & 1 deletion src/cargo/ops/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ pub use self::registry::{publish, registry_configuration, RegistryConfig};
pub use self::registry::{http_handle, needs_custom_http_transport, registry_login, search};
pub use self::registry::{modify_owners, yank, OwnersOptions, PublishOpts};
pub use self::registry::configure_http_handle;
pub use self::cargo_fetch::fetch;
pub use self::cargo_fetch::{fetch, FetchOptions};
pub use self::cargo_pkgid::pkgid;
pub use self::resolve::{resolve_with_previous, resolve_ws, resolve_ws_precisely,
resolve_ws_with_method};
Expand Down
132 changes: 131 additions & 1 deletion tests/testsuite/fetch.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
use cargotest::support::{execs, project};
use cargotest::rustc_host;
use cargotest::support::registry::Package;
use cargotest::support::{cross_compile, execs, project};
use hamcrest::assert_that;

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

assert_that(p.cargo("fetch"), execs().with_status(0).with_stdout(""));
}

#[test]
fn fetch_all_platform_dependencies_when_no_target_is_given() {
Package::new("d1", "1.2.3")
.file(
"Cargo.toml",
r#"
[project]
name = "d1"
version = "1.2.3"
"#,
)
.file("src/lib.rs", "")
.publish();

Package::new("d2", "0.1.2")
.file(
"Cargo.toml",
r#"
[project]
name = "d2"
version = "0.1.2"
"#,
)
.file("src/lib.rs", "")
.publish();

let target = cross_compile::alternate();
let host = rustc_host();
let p = project("foo")
.file(
"Cargo.toml",
&format!(
r#"
[package]
name = "foo"
version = "0.0.1"
authors = []
[target.{host}.dependencies]
d1 = "1.2.3"
[target.{target}.dependencies]
d2 = "0.1.2"
"#,
host = host,
target = target
),
)
.file("src/lib.rs", "")
.build();

assert_that(
p.cargo("fetch"),
execs()
.with_status(0)
.with_stderr_contains("[..] Downloading d1 v1.2.3 [..]")
.with_stderr_contains("[..] Downloading d2 v0.1.2 [..]"),
);
}

#[test]
fn fetch_platform_specific_dependencies() {
Package::new("d1", "1.2.3")
.file(
"Cargo.toml",
r#"
[project]
name = "d1"
version = "1.2.3"
"#,
)
.file("src/lib.rs", "")
.publish();

Package::new("d2", "0.1.2")
.file(
"Cargo.toml",
r#"
[project]
name = "d2"
version = "0.1.2"
"#,
)
.file("src/lib.rs", "")
.publish();

let target = cross_compile::alternate();
let host = rustc_host();
let p = project("foo")
.file(
"Cargo.toml",
&format!(
r#"
[package]
name = "foo"
version = "0.0.1"
authors = []
[target.{host}.dependencies]
d1 = "1.2.3"
[target.{target}.dependencies]
d2 = "0.1.2"
"#,
host = host,
target = target
),
)
.file("src/lib.rs", "")
.build();

assert_that(
p.cargo("fetch").arg("--target").arg(&host),
execs()
.with_status(0)
.with_stderr_contains("[..] Downloading d1 v1.2.3 [..]")
.with_stderr_does_not_contain("[..] Downloading d2 v0.1.2 [..]"),
);

assert_that(
p.cargo("fetch").arg("--target").arg(&target),
execs()
.with_status(0)
.with_stderr_contains("[..] Downloading d2 v0.1.2[..]")
.with_stderr_does_not_contain("[..] Downloading d1 v1.2.3 [..]"),
);
}

0 comments on commit d998906

Please sign in to comment.