Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 [..]"),
);
}