flowey_lib_common/
install_nodejs.rs1use flowey::node::prelude::*;
7
8flowey_request! {
9 pub enum Request {
10 AutoInstall(bool),
14 Version(String),
16 EnsureInstalled(WriteVar<SideEffect>),
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::ado_task_npm_authenticate::Node>();
28 }
29
30 fn emit(requests: Vec<Self::Request>, ctx: &mut NodeCtx<'_>) -> anyhow::Result<()> {
31 let mut auto_install = None;
32 let mut version = None;
33 let mut done = Vec::new();
34
35 for req in requests {
36 match req {
37 Request::AutoInstall(v) => {
38 same_across_all_reqs("AutoInstall", &mut auto_install, v)?
39 }
40 Request::Version(v) => same_across_all_reqs("Version", &mut version, v)?,
41 Request::EnsureInstalled(v) => done.push(v),
42 }
43 }
44
45 if done.is_empty() {
48 return Ok(());
49 }
50
51 let auto_install = auto_install;
52 let version = version.ok_or(anyhow::anyhow!("Missing essential request: NodeVersion"))?;
53 let done = done;
54
55 let is_installed = match ctx.backend() {
58 FlowBackend::Local => {
59 let auto_install = auto_install
60 .ok_or(anyhow::anyhow!("Missing essential request: AutoInstall"))?;
61
62 let check_nodejs_install = {
63 move |_: &mut RustRuntimeServices<'_>| {
64 if which::which("node").is_err() {
65 anyhow::bail!("did not find `node` on $PATH");
66 }
67
68 anyhow::Ok(())
76 }
77 };
78
79 if auto_install {
80 ctx.emit_rust_step("installing nodejs", |_vars| {
81 move |rt| {
82 if check_nodejs_install(rt).is_ok() {
83 return Ok(());
84 }
85
86 log::warn!("automatic nodejs installation is not supported yet!");
87 log::warn!(
88 "follow the guide, and manually ensure you have nodejs installed"
89 );
90 log::warn!(" ensure you have nodejs version {version} installed");
91 log::warn!("press <enter> to continue");
92 let _ = std::io::stdin().read_line(&mut String::new());
93
94 check_nodejs_install(rt)?;
95 Ok(())
96 }
97 })
98 } else {
99 ctx.emit_rust_step("detecting nodejs install", |_vars| {
100 move |rt| {
101 check_nodejs_install(rt)?;
102 Ok(())
103 }
104 })
105 }
106 }
107 FlowBackend::Ado => {
108 if !auto_install.unwrap_or(true) {
109 anyhow::bail!("AutoInstall must be `true` when running on ADO")
110 }
111
112 let auth_done = ctx.reqv(crate::ado_task_npm_authenticate::Request::Done);
113
114 let (did_install, claim_did_install) = ctx.new_var();
115 ctx.emit_ado_step("Install nodejs", |ctx| {
116 auth_done.claim(ctx);
117 claim_did_install.claim(ctx);
118 move |_| {
119 format!(
120 r#"
121 - task: UseNode@1
122 inputs:
123 version: '{version}'
124 "#
125 )
126 }
127 });
128 did_install
129 }
130 FlowBackend::Github => {
131 if !auto_install.unwrap_or(true) {
132 anyhow::bail!("AutoInstall must be `true` when running on Github")
133 }
134
135 ctx.emit_gh_step("Install nodejs", "actions/setup-node@v4")
136 .with("node-version", version)
137 .finish(ctx)
138 }
139 };
140
141 ctx.emit_side_effect_step([is_installed], done);
142
143 Ok(())
144 }
145}