Skip to main content

flowey_lib_common/
install_git.rs

1// Copyright (c) Microsoft Corporation.
2// Licensed under the MIT License.
3
4//! Globally install git and ensure it is available on the user's $PATH
5
6use flowey::node::prelude::*;
7
8new_flow_node_with_config!(struct Node);
9
10flowey_config! {
11    /// Config for the install_git node.
12    pub struct Config {
13        /// Automatically install Git
14        pub auto_install: Option<bool>,
15    }
16}
17
18flowey_request! {
19    pub enum Request {
20        /// Ensure that Git was installed and is available on $PATH
21        EnsureInstalled(WriteVar<SideEffect>),
22    }
23}
24
25impl FlowNodeWithConfig for Node {
26    type Request = Request;
27    type Config = Config;
28
29    fn imports(dep: &mut ImportCtx<'_>) {
30        dep.import::<crate::check_needs_relaunch::Node>();
31        dep.import::<crate::install_dist_pkg::Node>();
32    }
33
34    fn emit(
35        config: Config,
36        requests: Vec<Self::Request>,
37        ctx: &mut NodeCtx<'_>,
38    ) -> anyhow::Result<()> {
39        let mut ensure_installed = Vec::new();
40
41        for req in requests {
42            match req {
43                Request::EnsureInstalled(v) => ensure_installed.push(v),
44            }
45        }
46
47        let ensure_installed = ensure_installed;
48        let auto_install = config
49            .auto_install
50            .ok_or(anyhow::anyhow!("missing config: auto_install"))?;
51
52        // -- end of req processing -- //
53
54        if ensure_installed.is_empty() {
55            return Ok(());
56        }
57
58        if auto_install {
59            let (read_bin, write_bin) = ctx.new_var();
60            ctx.req(crate::check_needs_relaunch::Params {
61                check: read_bin,
62                done: ensure_installed,
63            });
64
65            let git_installed = ctx.reqv(|v| crate::install_dist_pkg::Request::Install {
66                package_names: vec!["git".into()],
67                done: v,
68            });
69
70            ctx.emit_rust_step("install git", |ctx| {
71                let write_bin = write_bin.claim(ctx);
72                git_installed.claim(ctx);
73
74                |rt: &mut RustRuntimeServices<'_>| {
75                    match rt.platform() {
76                        FlowPlatform::Linux(_) | FlowPlatform::MacOs => {
77                            rt.write(write_bin, &Some(crate::check_needs_relaunch::BinOrEnv::Bin("git".to_string())));
78                            Ok(())
79                        },
80                        FlowPlatform::Windows => {
81                            if which::which("git.exe").is_err() {
82                                flowey::shell_cmd!(rt, "powershell.exe -NoProfile -NonInteractive -Command winget install --id Microsoft.Git --accept-source-agreements").run()?;
83                            }
84
85                            rt.write(write_bin, &Some(crate::check_needs_relaunch::BinOrEnv::Bin("git".to_string())));
86                            Ok(())
87                        },
88                        platform => anyhow::bail!("unsupported platform {platform}"),
89                    }
90                }
91            });
92        } else {
93            ctx.emit_rust_step("ensure git is installed", |ctx| {
94                ensure_installed.claim(ctx);
95                |_rt| {
96                    if which::which("git").is_err() {
97                        anyhow::bail!("Please install git to continue setup.");
98                    }
99
100                    Ok(())
101                }
102            });
103        }
104
105        Ok(())
106    }
107}