systemprompt_config/paths/
build.rs1use std::path::{Path, PathBuf};
7
8use super::PathError;
9use systemprompt_manifest::profile::PathsConfig;
10
11#[derive(Debug, Clone)]
12pub struct BuildPaths {
13 bin: PathBuf,
14}
15
16impl BuildPaths {
17 pub fn from_profile(paths: &PathsConfig) -> Self {
18 Self {
19 bin: PathBuf::from(&paths.bin),
20 }
21 }
22
23 pub fn resolve_binary(&self, name: &str) -> Result<PathBuf, PathError> {
24 let mut searched = Vec::new();
25
26 let exe_name = format!("{}{}", name, std::env::consts::EXE_SUFFIX);
27 let primary = self.bin.join(&exe_name);
28 searched.push(primary.clone());
29
30 let sibling = self.sibling_bin_path();
31 let alt = sibling.as_ref().map(|s| s.join(&exe_name));
32 if let Some(ref alt_path) = alt {
33 searched.push(alt_path.clone());
34 }
35
36 let alt_exists = alt.as_ref().filter(|p| p.exists());
37
38 match (primary.exists(), alt_exists) {
39 (true, Some(alt_path)) => {
40 let primary_mtime = std::fs::metadata(&primary).and_then(|m| m.modified()).ok();
41 let alt_mtime = std::fs::metadata(alt_path).and_then(|m| m.modified()).ok();
42 match (primary_mtime, alt_mtime) {
43 (Some(p), Some(a)) if a > p => Self::ensure_absolute(alt_path.clone()),
44 _ => Self::ensure_absolute(primary),
45 }
46 },
47 (true, None) => Self::ensure_absolute(primary),
48 (false, Some(alt_path)) => Self::ensure_absolute(alt_path.clone()),
49 (false, None) => {
50 if !std::env::consts::EXE_SUFFIX.is_empty() {
51 let path = self.bin.join(name);
52 searched.push(path.clone());
53 if path.exists() {
54 return Self::ensure_absolute(path);
55 }
56 }
57 Err(PathError::BinaryNotFound {
58 name: name.to_owned(),
59 searched,
60 })
61 },
62 }
63 }
64
65 pub fn resolve_self() -> Result<PathBuf, PathError> {
69 let exe = std::env::current_exe()
70 .map_err(|source| PathError::CurrentExeUnavailable { source })?;
71 Self::ensure_absolute(exe)
72 }
73
74 fn sibling_bin_path(&self) -> Option<PathBuf> {
75 let dir_name = self.bin.file_name()?.to_str()?;
76 let sibling_name = match dir_name {
77 "release" => "debug",
78 "debug" => "release",
79 _ => return None,
80 };
81 Some(self.bin.with_file_name(sibling_name))
82 }
83
84 fn ensure_absolute(path: PathBuf) -> Result<PathBuf, PathError> {
85 if path.is_absolute() {
86 Ok(path)
87 } else {
88 std::fs::canonicalize(&path).map_err(|source| PathError::CanonicalizeFailed {
89 path,
90 field: "binary",
91 source,
92 })
93 }
94 }
95
96 pub fn bin(&self) -> &Path {
97 &self.bin
98 }
99}