cargo/ops/
cargo_fetch.rs

1use crate::core::compiler::standard_lib;
2use crate::core::compiler::BuildConfig;
3use crate::core::compiler::RustcTargetData;
4use crate::core::compiler::UserIntent;
5use crate::core::{PackageSet, Resolve, Workspace};
6use crate::ops;
7use crate::util::context::JobsConfig;
8use crate::util::CargoResult;
9use crate::util::GlobalContext;
10use std::collections::HashSet;
11
12pub struct FetchOptions<'a> {
13    pub gctx: &'a GlobalContext,
14    /// The target arch triple to fetch dependencies for
15    pub targets: Vec<String>,
16}
17
18/// Executes `cargo fetch`.
19pub fn fetch<'a>(
20    ws: &Workspace<'a>,
21    options: &FetchOptions<'a>,
22) -> CargoResult<(Resolve, PackageSet<'a>)> {
23    ws.emit_warnings()?;
24    let dry_run = false;
25    let (mut packages, resolve) = ops::resolve_ws(ws, dry_run)?;
26
27    let jobs = Some(JobsConfig::Integer(1));
28    let keep_going = false;
29    let gctx = ws.gctx();
30    let build_config =
31        BuildConfig::new(gctx, jobs, keep_going, &options.targets, UserIntent::Build)?;
32    let mut data = RustcTargetData::new(ws, &build_config.requested_kinds)?;
33    let mut fetched_packages = HashSet::new();
34    let mut deps_to_fetch = ws.members().map(|p| p.package_id()).collect::<Vec<_>>();
35    let mut to_download = Vec::new();
36
37    while let Some(id) = deps_to_fetch.pop() {
38        if !fetched_packages.insert(id) {
39            continue;
40        }
41
42        to_download.push(id);
43        let deps = resolve
44            .deps(id)
45            .filter(|&(_id, deps)| {
46                deps.iter().any(|d| {
47                    // If no target was specified then all dependencies are
48                    // fetched.
49                    if options.targets.is_empty() {
50                        return true;
51                    }
52
53                    // Otherwise we only download this dependency if any of the
54                    // requested platforms would match this dependency. Note
55                    // that this is a bit lossy because not all dependencies are
56                    // always compiled for all platforms, but it should be
57                    // "close enough" for now.
58                    build_config
59                        .requested_kinds
60                        .iter()
61                        .any(|kind| data.dep_platform_activated(d, *kind))
62                })
63            })
64            .map(|(id, _deps)| id);
65        deps_to_fetch.extend(deps);
66    }
67
68    // If -Zbuild-std was passed, download dependencies for the standard library.
69    if let Some(crates) = &gctx.cli_unstable().build_std {
70        let (std_package_set, _, _) = standard_lib::resolve_std(
71            ws,
72            &mut data,
73            &build_config,
74            crates,
75            &build_config.requested_kinds,
76        )?;
77        packages.add_set(std_package_set);
78    }
79
80    packages.get_many(to_download)?;
81    crate::core::gc::auto_gc(gctx);
82
83    Ok((resolve, packages))
84}