matrixcode_core/tools/codegraph/
install.rs1use anyhow::Result;
4use std::path::PathBuf;
5use tokio::process::Command;
6
7#[cfg(windows)]
9fn create_command(program: &str) -> std::process::Command {
10 use std::os::windows::process::CommandExt;
11 const CREATE_NO_WINDOW: u32 = 0x08000000;
12 let mut cmd = std::process::Command::new(program);
13 cmd.creation_flags(CREATE_NO_WINDOW);
14 cmd
15}
16
17#[cfg(not(windows))]
18fn create_command(program: &str) -> std::process::Command {
19 std::process::Command::new(program)
20}
21
22#[cfg(windows)]
24fn create_async_command(program: &str) -> Command {
25 const CREATE_NO_WINDOW: u32 = 0x08000000;
26 let mut cmd = Command::new(program);
27 cmd.creation_flags(CREATE_NO_WINDOW);
28 cmd
29}
30
31#[cfg(not(windows))]
32fn create_async_command(program: &str) -> Command {
33 Command::new(program)
34}
35
36fn get_codegraph_install_dir() -> Option<PathBuf> {
38 dirs::data_local_dir().map(|p| p.join("codegraph").join("current").join("bin"))
39}
40
41fn get_codegraph_exe_name() -> String {
43 if cfg!(windows) {
44 "codegraph.cmd".to_string()
45 } else {
46 "codegraph".to_string()
47 }
48}
49
50pub fn is_codegraph_installed() -> bool {
52 if create_command("codegraph")
54 .arg("--version")
55 .output()
56 .is_ok()
57 {
58 return true;
59 }
60
61 if let Some(install_dir) = get_codegraph_install_dir() {
63 let exe_name = get_codegraph_exe_name();
64 let exe_path = install_dir.join(&exe_name);
65 if exe_path.exists()
66 && create_command(exe_path.to_str().unwrap_or("codegraph"))
67 .arg("--version")
68 .output()
69 .is_ok()
70 {
71 return true;
72 }
73 }
74
75 false
76}
77
78pub fn get_codegraph_path() -> Option<String> {
80 if create_command("codegraph")
82 .arg("--version")
83 .output()
84 .is_ok()
85 {
86 return Some("codegraph".to_string());
87 }
88
89 if let Some(install_dir) = get_codegraph_install_dir() {
91 let exe_name = get_codegraph_exe_name();
92 let exe_path = install_dir.join(&exe_name);
93 if exe_path.exists() {
94 return Some(exe_path.to_string_lossy().to_string());
95 }
96 }
97
98 None
99}
100
101pub async fn install_codegraph() -> Result<()> {
103 log::info!("Installing CodeGraph CLI...");
104
105 let result = create_async_command("powershell")
107 .args([
108 "-NoProfile",
109 "-Command",
110 "irm https://raw.githubusercontent.com/colbymchenry/codegraph/main/install.ps1 | iex",
111 ])
112 .output()
113 .await?;
114
115 if result.status.success() {
116 log::info!("CodeGraph CLI installed successfully");
117 Ok(())
118 } else {
119 let stderr = String::from_utf8_lossy(&result.stderr);
120 Err(anyhow::anyhow!("CodeGraph installation failed: {}", stderr))
121 }
122}
123
124#[derive(Debug, Clone, PartialEq, Eq)]
126#[allow(dead_code)]
127pub enum CodeGraphInstallStatus {
128 Installed(String),
130 NotInstalled,
132}
133
134#[allow(dead_code)]
136pub fn check_codegraph_status() -> CodeGraphInstallStatus {
137 match get_codegraph_path() {
138 Some(path) => CodeGraphInstallStatus::Installed(path),
139 None => CodeGraphInstallStatus::NotInstalled,
140 }
141}
142
143pub async fn ensure_codegraph() -> Result<String> {
145 if let Some(path) = get_codegraph_path() {
146 return Ok(path);
147 }
148
149 install_codegraph().await?;
150 get_codegraph_path().ok_or_else(|| anyhow::anyhow!("CodeGraph not found after installation"))
151}