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 |_: &mut RustRuntimeServices<'_>, env: &String, expected: &String| {
56                let sh = xshell::Shell::new()?;
57                let env = sh.var(env)?;
58
59                if !env.contains(expected) {
60                    anyhow::bail!(format!("did not find '{}' in {}", expected, env));
61                }
62
63                anyhow::Ok(())
64            }
65        };
66
67        ctx.emit_rust_step("ensure binaries are available on path", move |ctx| {
68            done.claim(ctx);
69            let check = check.claim(ctx);
70
71            move |rt| {
72                let check = rt.read(check);
73                if check.is_none() {
74                    return Ok(());
75                }
76
77                let check = check.unwrap();
78                if match check {
79                    BinOrEnv::Bin(bin) => {
80                        check_install(rt, &bin)
81                    }
82                    BinOrEnv::Env(env, expected) => {
83                        check_env(rt, &env, &expected)
84                    }
85                }.is_err() {
86                    let args = std::env::args().collect::<Vec<_>>().join(" ");
87                    anyhow::bail!("To ensure installed dependencies are available on your $PATH, please restart your shell, and re-run: `{args}`");
88                }
89                Ok(())
90            }
91        });
92
93        Ok(())
94    }
95}