flowey_lib_common/
check_needs_relaunch.rs

1// Copyright (c) Microsoft Corporation.
2// Licensed under the MIT License.
3
4//! Check if shell must be relaunched to refresh environment variables
5
6use flowey::node::prelude::*;
7
8new_simple_flow_node!(struct Node);
9
10#[derive(Serialize, Deserialize)]
11pub enum BinOrEnv {
12    Bin(String),
13    Env(String, String),
14}
15
16flowey_request! {
17    pub struct Params {
18        /// Ensure requested binary is available on path or environment variable contains expected value
19        pub check: ReadVar<Option<BinOrEnv>>,
20        pub done: Vec<WriteVar<SideEffect>>,
21    }
22}
23
24impl SimpleFlowNode for Node {
25    type Request = Params;
26
27    fn imports(_dep: &mut ImportCtx<'_>) {
28        // no deps
29    }
30
31    fn process_request(request: Self::Request, ctx: &mut NodeCtx<'_>) -> anyhow::Result<()> {
32        if !matches!(ctx.backend(), FlowBackend::Local) {
33            anyhow::bail!("only supported on the local backend at this time");
34        }
35
36        let Params { check, done } = request;
37
38        // -- end of req processing -- //
39
40        if done.is_empty() {
41            return Ok(());
42        }
43
44        let check_install = {
45            move |_: &mut RustRuntimeServices<'_>, bin: &String| {
46                if which::which(bin).is_err() {
47                    anyhow::bail!(format!("did not find {} on $PATH", bin));
48                }
49
50                anyhow::Ok(())
51            }
52        };
53
54        let check_env = {
55            move |rt: &mut RustRuntimeServices<'_>, env: &String, expected: &String| {
56                let env = rt.sh.var(env)?;
57
58                if !env.contains(expected) {
59                    anyhow::bail!(format!("did not find '{}' in {}", expected, env));
60                }
61
62                anyhow::Ok(())
63            }
64        };
65
66        ctx.emit_rust_step("ensure binaries are available on path", move |ctx| {
67            done.claim(ctx);
68            let check = check.claim(ctx);
69
70            move |rt| {
71                let check = rt.read(check);
72                if check.is_none() {
73                    return Ok(());
74                }
75
76                let check = check.unwrap();
77                if match check {
78                    BinOrEnv::Bin(bin) => {
79                        check_install(rt, &bin)
80                    }
81                    BinOrEnv::Env(env, expected) => {
82                        check_env(rt, &env, &expected)
83                    }
84                }.is_err() {
85                    let args = std::env::args().collect::<Vec<_>>().join(" ");
86                    anyhow::bail!("To ensure installed dependencies are available on your $PATH, please restart your shell, and re-run: `{args}`");
87                }
88                Ok(())
89            }
90        });
91
92        Ok(())
93    }
94}