flowey_lib_common/
download_cargo_nextest.rs1use crate::cache::CacheHit;
7use flowey::node::prelude::*;
8use std::collections::BTreeMap;
9
10flowey_config! {
11 pub struct Config {
13 pub version: Option<String>,
15 }
16}
17
18flowey_request! {
19 pub enum Request {
20 Get(target_lexicon::Triple, WriteVar<PathBuf>),
25 }
26}
27
28new_flow_node_with_config!(struct Node);
29
30impl FlowNodeWithConfig for Node {
31 type Request = Request;
32 type Config = Config;
33
34 fn imports(ctx: &mut ImportCtx<'_>) {
35 ctx.import::<crate::cache::Node>();
36 }
37
38 fn emit(
39 config: Config,
40 requests: Vec<Self::Request>,
41 ctx: &mut NodeCtx<'_>,
42 ) -> anyhow::Result<()> {
43 let mut reqs: BTreeMap<String, Vec<WriteVar<PathBuf>>> = BTreeMap::new();
44
45 for req in requests {
46 match req {
47 Request::Get(target, path) => {
48 reqs.entry(target.to_string()).or_default().push(path)
49 }
50 }
51 }
52
53 let version = config
54 .version
55 .ok_or(anyhow::anyhow!("missing config: version"))?;
56 let reqs = reqs;
57
58 if reqs.is_empty() {
61 return Ok(());
62 }
63
64 let cache_dir = ctx.emit_rust_stepv("create cargo-nextest cache dir", |_| {
65 |_| Ok(std::env::current_dir()?.absolute()?)
66 });
67
68 for (target, paths) in reqs {
69 let (cache_key, cache_dir) = {
70 let version = version.clone();
71 let cache_key = format!("cargo-nextest-{version}-{target}");
72 let cache_dir = cache_dir.map(ctx, {
73 let k = cache_key.clone();
74 |p| p.join(k)
75 });
76 (ReadVar::from_static(cache_key), cache_dir)
77 };
78
79 let hitvar = ctx.reqv(|v| {
80 crate::cache::Request {
81 label: "cargo-nextest".into(),
82 dir: cache_dir.clone(),
83 key: cache_key,
84 restore_keys: None, hitvar: v,
86 }
87 });
88
89 let version = version.clone();
90 ctx.emit_rust_step("downloading cargo-nextest", |ctx| {
91 let paths = paths.claim(ctx);
92 let cache_dir = cache_dir.claim(ctx);
93 let hitvar = hitvar.claim(ctx);
94
95 move |rt| {
96 let cache_dir = rt.read(cache_dir);
97
98 let cargo_nextest_bin = if target.contains("windows") {
99 "cargo-nextest.exe"
100 } else {
101 "cargo-nextest"
102 };
103 let cached_bin_path = cache_dir.join(cargo_nextest_bin);
104
105 if !matches!(rt.read(hitvar), CacheHit::Hit) {
106 download_cargo_nextest(rt, version, target)?;
107
108 fs_err::create_dir_all(&cache_dir)?;
110 fs_err::rename(cargo_nextest_bin, &cached_bin_path)?;
111 }
112
113 let cached_bin_path = cached_bin_path.absolute()?;
114 log::info!("downloaded to {}", cached_bin_path.to_string_lossy());
115 anyhow::ensure!(
116 cached_bin_path.is_file(),
117 "cargo-nextest cache entry is missing {}",
118 cached_bin_path.display()
119 );
120 for path in paths {
121 rt.write(path, &cached_bin_path);
122 }
123
124 Ok(())
125 }
126 });
127 }
128
129 Ok(())
130 }
131}
132
133fn download_cargo_nextest(
136 rt: &mut RustRuntimeServices<'_>,
137 version: String,
138 target: String,
139) -> anyhow::Result<()> {
140 let nextest_archive = "nextest.tar.gz";
141 flowey::shell_cmd!(
142 rt,
143 "curl --fail -L https://get.nexte.st/{version}/{target}.tar.gz -o {nextest_archive}"
144 )
145 .run()?;
146 flowey::shell_cmd!(rt, "tar -xf {nextest_archive}").run()?;
147
148 Ok(())
149}