mecha10_cli/services/process/
resolve.rs1use super::ProcessService;
7use crate::paths;
8use anyhow::Result;
9
10impl ProcessService {
11 pub fn find_global_binary(node_name: &str) -> Option<std::path::PathBuf> {
14 let cargo_bin = paths::user::cargo_bin(node_name);
15 if cargo_bin.exists() && cargo_bin.is_file() {
16 return Some(cargo_bin);
17 }
18
19 let mecha10_bin = paths::user::bin(node_name);
20 if mecha10_bin.exists() && mecha10_bin.is_file() {
21 return Some(mecha10_bin);
22 }
23
24 None
25 }
26
27 pub fn resolve_node_runner_path() -> String {
30 if let Some(global_path) = Self::find_global_binary("mecha10-node-runner") {
31 return global_path.to_string_lossy().to_string();
32 }
33
34 "mecha10-node-runner".to_string()
35 }
36
37 pub(super) fn get_node_version_from_config(&self, node_identifier: &str) -> Option<String> {
39 use crate::types::ProjectConfig;
40
41 let config_path = std::path::Path::new(paths::PROJECT_CONFIG);
42 if !config_path.exists() {
43 return None;
44 }
45
46 let config_content = std::fs::read_to_string(config_path).ok()?;
47 let config: ProjectConfig = serde_json::from_str(&config_content).ok()?;
48
49 config.nodes.get_version(node_identifier).map(|s| s.to_string())
50 }
51
52 pub(super) fn disk_logging_enabled(&self) -> bool {
56 use crate::types::ProjectConfig;
57
58 let config_path = std::path::Path::new(paths::PROJECT_CONFIG);
59 if !config_path.exists() {
60 return true;
61 }
62
63 let config_content = match std::fs::read_to_string(config_path) {
64 Ok(c) => c,
65 Err(_) => return true,
66 };
67
68 let config: ProjectConfig = match serde_json::from_str(&config_content) {
69 Ok(c) => c,
70 Err(_) => return true,
71 };
72
73 config.environments.disk_logging_enabled()
74 }
75
76 pub(super) fn is_local_project_node(&self, node_name: &str) -> bool {
79 mecha10_cli_core::types::is_local_project_node(std::path::Path::new(paths::PROJECT_CONFIG), node_name)
80 }
81
82 pub(super) fn resolve_cli_binary() -> Result<String> {
87 mecha10_binary_naming::try_resolution_tiers!("mecha10 CLI binary", {
88 "global binary" => Self::find_global_binary("mecha10")
89 .map(|path| path.to_string_lossy().to_string())
90 .ok_or_else(|| "not found at ~/.cargo/bin or ~/.mecha10/bin".to_string()),
91
92 "local/cargo bin fallback locations" => {
93 let locations = [paths::user::local_bin("mecha10"), paths::user::cargo_bin("mecha10")];
94 locations
95 .iter()
96 .find(|path| path.exists())
97 .map(|path| path.to_string_lossy().to_string())
98 .ok_or_else(|| "not found at local_bin/cargo_bin fallback locations".to_string())
99 },
100
101 "current executable" => std::env::current_exe()
102 .map(|exe| exe.to_string_lossy().to_string())
103 .map_err(|e| format!("current_exe() failed: {e}")),
104 })
105 .map_err(|e| anyhow::anyhow!("{}. Ensure it's installed and in your PATH.", e))
106 }
107
108 pub fn is_node_runner_available() -> bool {
110 Self::find_global_binary("mecha10-node-runner").is_some()
111 }
112}
113
114#[cfg(test)]
115mod tests {
116 use super::*;
117
118 #[test]
120 fn resolve_cli_binary_falls_back_to_current_exe_when_no_global_or_local_binary_exists() {
121 let resolved = ProcessService::resolve_cli_binary().expect("current_exe() tier must succeed");
122 assert!(!resolved.is_empty());
123 }
124}