flowey_lib_common/
install_nodejs.rs1use flowey::node::prelude::*;
7
8flowey_config! {
9 pub struct Config {
11 pub version: Option<String>,
13 pub auto_install: Option<bool>,
17 }
18}
19
20flowey_request! {
21 pub enum Request {
22 EnsureInstalled(WriteVar<SideEffect>),
24 }
25}
26
27new_flow_node_with_config!(struct Node);
28
29impl FlowNodeWithConfig for Node {
30 type Request = Request;
31 type Config = Config;
32
33 fn imports(ctx: &mut ImportCtx<'_>) {
34 ctx.import::<crate::ado_task_npm_authenticate::Node>();
35 }
36
37 fn emit(
38 config: Config,
39 requests: Vec<Self::Request>,
40 ctx: &mut NodeCtx<'_>,
41 ) -> anyhow::Result<()> {
42 let mut done = Vec::new();
43
44 for req in requests {
45 match req {
46 Request::EnsureInstalled(v) => done.push(v),
47 }
48 }
49
50 if done.is_empty() {
53 return Ok(());
54 }
55
56 let auto_install = config.auto_install;
57 let version = config
58 .version
59 .ok_or(anyhow::anyhow!("missing config: version"))?;
60 let done = done;
61
62 let is_installed = match ctx.backend() {
65 FlowBackend::Local => {
66 let auto_install = auto_install
67 .ok_or(anyhow::anyhow!("Missing essential request: AutoInstall"))?;
68
69 let check_nodejs_install = {
70 move |_: &mut RustRuntimeServices<'_>| {
71 if which::which("node").is_err() {
72 anyhow::bail!("did not find `node` on $PATH");
73 }
74
75 anyhow::Ok(())
83 }
84 };
85
86 if auto_install {
87 ctx.emit_rust_step("installing nodejs", |_vars| {
88 move |rt| {
89 if check_nodejs_install(rt).is_ok() {
90 return Ok(());
91 }
92
93 log::warn!("automatic nodejs installation is not supported yet!");
94 log::warn!(
95 "follow the guide, and manually ensure you have nodejs installed"
96 );
97 log::warn!(" ensure you have nodejs version {version} installed");
98 log::warn!("press <enter> to continue");
99 let _ = std::io::stdin().read_line(&mut String::new());
100
101 check_nodejs_install(rt)?;
102 Ok(())
103 }
104 })
105 } else {
106 ctx.emit_rust_step("detecting nodejs install", |_vars| {
107 move |rt| {
108 check_nodejs_install(rt)?;
109 Ok(())
110 }
111 })
112 }
113 }
114 FlowBackend::Ado => {
115 if !auto_install.unwrap_or(true) {
116 anyhow::bail!("AutoInstall must be `true` when running on ADO")
117 }
118
119 let auth_done = ctx.reqv(crate::ado_task_npm_authenticate::Request::Done);
120
121 let (did_install, claim_did_install) = ctx.new_var();
122 ctx.emit_ado_step("Install nodejs", |ctx| {
123 auth_done.claim(ctx);
124 claim_did_install.claim(ctx);
125 move |_| {
126 format!(
127 r#"
128 - task: UseNode@1
129 inputs:
130 version: '{version}'
131 "#
132 )
133 }
134 });
135 did_install
136 }
137 FlowBackend::Github => {
138 if !auto_install.unwrap_or(true) {
139 anyhow::bail!("AutoInstall must be `true` when running on Github")
140 }
141
142 ctx.emit_gh_step(
144 "Install nodejs",
145 "actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020",
146 )
147 .with("node-version", version)
148 .finish(ctx)
149 }
150 };
151
152 ctx.emit_side_effect_step([is_installed], done);
153
154 Ok(())
155 }
156}