Skip to main content

cargo/ops/
cargo_fetch.rs

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