1use crate::PathManager;
4use anyhow::Result;
5use std::path::PathBuf;
6
7#[derive(Debug, Clone)]
9pub struct PathResolver {
10 manager: PathManager,
11}
12
13impl PathResolver {
14 pub fn new(manager: PathManager) -> Self {
16 Self { manager }
17 }
18
19 pub fn find_tool_executables(&self, tool_name: &str) -> Result<Vec<PathBuf>> {
21 let versions = self.manager.list_tool_versions(tool_name)?;
22 let mut executables = Vec::new();
23
24 for version in versions {
25 let exe_path = self.manager.tool_executable_path(tool_name, &version);
26 if exe_path.exists() {
27 executables.push(exe_path);
28 }
29 }
30
31 Ok(executables)
32 }
33
34 pub fn find_latest_executable(&self, tool_name: &str) -> Result<Option<PathBuf>> {
36 if let Some(latest_version) = self.manager.get_latest_tool_version(tool_name)? {
37 let exe_path = self
38 .manager
39 .tool_executable_path(tool_name, &latest_version);
40 if exe_path.exists() {
41 return Ok(Some(exe_path));
42 }
43 }
44 Ok(None)
45 }
46
47 pub fn find_version_executable(&self, tool_name: &str, version: &str) -> Option<PathBuf> {
49 let exe_path = self.manager.tool_executable_path(tool_name, version);
50 if exe_path.exists() {
51 Some(exe_path)
52 } else {
53 None
54 }
55 }
56
57 pub fn is_tool_installed(&self, tool_name: &str) -> Result<bool> {
59 let versions = self.manager.list_tool_versions(tool_name)?;
60 Ok(!versions.is_empty())
61 }
62
63 pub fn get_installed_tools_with_versions(&self) -> Result<Vec<(String, Vec<String>)>> {
65 let tools = self.manager.list_installed_tools()?;
66 let mut result = Vec::new();
67
68 for tool in tools {
69 let versions = self.manager.list_tool_versions(&tool)?;
70 result.push((tool, versions));
71 }
72
73 Ok(result)
74 }
75
76 pub fn resolve_tool_path(
80 &self,
81 tool_name: &str,
82 version: Option<&str>,
83 ) -> Result<Option<PathBuf>> {
84 match version {
85 Some(v) => Ok(self.find_version_executable(tool_name, v)),
86 None => self.find_latest_executable(tool_name),
87 }
88 }
89
90 pub fn manager(&self) -> &PathManager {
92 &self.manager
93 }
94}
95
96impl Default for PathResolver {
97 fn default() -> Self {
98 Self::new(PathManager::default())
99 }
100}
101
102#[cfg(test)]
103mod tests {
104 use super::*;
105 use tempfile::TempDir;
106
107 #[test]
108 fn test_path_resolver() {
109 let temp_dir = TempDir::new().unwrap();
110 let manager = PathManager::with_base_dir(temp_dir.path()).unwrap();
111 let resolver = PathResolver::new(manager);
112
113 assert!(!resolver.is_tool_installed("node").unwrap());
115 assert_eq!(
116 resolver.find_tool_executables("node").unwrap(),
117 Vec::<PathBuf>::new()
118 );
119 assert_eq!(resolver.find_latest_executable("node").unwrap(), None);
120
121 let _version_dir = resolver
123 .manager()
124 .create_tool_version_dir("node", "18.17.0")
125 .unwrap();
126 let exe_path = resolver.manager().tool_executable_path("node", "18.17.0");
127 std::fs::write(&exe_path, "fake executable").unwrap();
128
129 assert!(resolver.is_tool_installed("node").unwrap());
131 assert_eq!(
132 resolver.find_tool_executables("node").unwrap(),
133 vec![exe_path.clone()]
134 );
135 assert_eq!(
136 resolver.find_latest_executable("node").unwrap(),
137 Some(exe_path.clone())
138 );
139 assert_eq!(
140 resolver.find_version_executable("node", "18.17.0"),
141 Some(exe_path.clone())
142 );
143 assert_eq!(
144 resolver.resolve_tool_path("node", None).unwrap(),
145 Some(exe_path.clone())
146 );
147 assert_eq!(
148 resolver.resolve_tool_path("node", Some("18.17.0")).unwrap(),
149 Some(exe_path)
150 );
151 }
152}