flowey_lib_common/
download_cargo_nextest.rs

1// Copyright (c) Microsoft Corporation.
2// Licensed under the MIT License.
3
4//! Download a copy of `cargo-nextest`.
5
6use crate::cache::CacheHit;
7use flowey::node::prelude::*;
8
9flowey_request! {
10    pub enum Request {
11        /// Version of `cargo nextest` to install (e.g: "0.9.57")
12        Version(String),
13        /// Download `cargo-nextest` as a standalone binary, without requiring Rust
14        /// to be installed.
15        ///
16        /// Useful when running archived nextest tests in a separate job.
17        Get(ReadVar<target_lexicon::Triple>, WriteVar<PathBuf>),
18    }
19}
20
21new_flow_node!(struct Node);
22
23impl FlowNode for Node {
24    type Request = Request;
25
26    fn imports(ctx: &mut ImportCtx<'_>) {
27        ctx.import::<crate::cache::Node>();
28    }
29
30    fn emit(requests: Vec<Self::Request>, ctx: &mut NodeCtx<'_>) -> anyhow::Result<()> {
31        let mut version = None;
32        let mut reqs = Vec::new();
33
34        for req in requests {
35            match req {
36                Request::Version(v) => same_across_all_reqs("Version", &mut version, v)?,
37                Request::Get(target, path) => reqs.push((target, path)),
38            }
39        }
40
41        let version = version.ok_or(anyhow::anyhow!("Missing essential request: Version"))?;
42        let reqs = reqs;
43
44        // -- end of req processing -- //
45
46        if reqs.is_empty() {
47            return Ok(());
48        }
49
50        let cache_dir = ctx.emit_rust_stepv("create cargo-nextest cache dir", |_| {
51            |_| Ok(std::env::current_dir()?.absolute()?)
52        });
53
54        for (target, path) in reqs {
55            let (cache_key, cache_dir) = {
56                let version = version.clone();
57                let cache_key = target.map(ctx, move |target| {
58                    format!("cargo-nextest-{version}-{target}")
59                });
60                let cache_dir = cache_dir
61                    .zip(ctx, cache_key.clone())
62                    .map(ctx, |(p, k)| p.join(k));
63                (cache_key, cache_dir)
64            };
65
66            let hitvar = ctx.reqv(|v| {
67                crate::cache::Request {
68                    label: "cargo-nextest".into(),
69                    dir: cache_dir.clone(),
70                    key: cache_key,
71                    restore_keys: None, // we want an exact hit
72                    hitvar: v,
73                }
74            });
75
76            let version = version.clone();
77            ctx.emit_rust_step("downloading cargo-nextest", |ctx| {
78                let path = path.claim(ctx);
79                let cache_dir = cache_dir.claim(ctx);
80                let hitvar = hitvar.claim(ctx);
81                let target = target.claim(ctx);
82
83                move |rt| {
84                    let cache_dir = rt.read(cache_dir);
85                    let target = rt.read(target);
86
87                    let cargo_nextest_bin = match target.operating_system {
88                        target_lexicon::OperatingSystem::Windows => "cargo-nextest.exe",
89                        _ => "cargo-nextest",
90                    };
91                    let cached_bin_path = cache_dir.join(cargo_nextest_bin);
92                    let target = target.to_string();
93
94                    if !matches!(rt.read(hitvar), CacheHit::Hit) {
95                        let sh = xshell::Shell::new()?;
96
97                        let nextest_archive = "nextest.tar.gz";
98                        xshell::cmd!(sh, "curl --fail -L https://get.nexte.st/{version}/{target}.tar.gz -o {nextest_archive}").run()?;
99                        xshell::cmd!(sh, "tar -xf {nextest_archive}").run()?;
100
101                        // move the downloaded bin into the cache dir
102                        fs_err::create_dir_all(&cache_dir)?;
103                        fs_err::rename(cargo_nextest_bin, &cached_bin_path)?;
104                    }
105
106                    let cached_bin_path = cached_bin_path.absolute()?;
107                    log::info!("downloaded to {}", cached_bin_path.to_string_lossy());
108                    assert!(cached_bin_path.exists());
109                    rt.write(path, &cached_bin_path);
110
111                    Ok(())
112                }
113            });
114        }
115
116        Ok(())
117    }
118}