Skip to main content

cargo/ops/
cargo_fetch.rs

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