1pub use crate::{AppConfig, AppInfo, AppManifest};
2use std::env;
4use std::fs;
5use std::path::{Path, PathBuf};
6
7pub fn get_rew_root() -> PathBuf {
9 if let Ok(rew_root) = env::var("REW_ROOT") {
11 return PathBuf::from(rew_root);
12 }
13
14 #[cfg(target_os = "windows")]
16 {
17 let local_app_data = env::var("LOCALAPPDATA").unwrap_or_else(|_| {
18 let home = env::var("USERPROFILE").unwrap_or_else(|_| ".".to_string());
19 format!("{}\\AppData\\Local", home)
20 });
21 PathBuf::from(format!("{}\\rew", local_app_data))
22 }
23
24 #[cfg(not(target_os = "windows"))]
25 {
26 if std::path::Path::new("/opt/rew").exists() {
27 PathBuf::from("/opt/rew")
28 } else {
29 let home = env::var("HOME").unwrap_or_else(|_| ".".to_string());
30 PathBuf::from(format!("{}/.rew", home))
31 }
32 }
33}
34
35pub fn pimmy_data_path() -> Option<PathBuf> {
36 Some(get_rew_root().join(".pimmy"))
37}
38
39pub fn find_app_by_package(package_name: &str) -> Option<AppInfo> {
41 let rew_root = get_rew_root();
42 let apps_dir = rew_root.join("apps");
43
44 if !apps_dir.exists() {
45 return None;
46 }
47
48 let app_dirs = fs::read_dir(&apps_dir).ok()?;
49
50 for dir_entry in app_dirs.flatten() {
51 let app_dir = dir_entry.path();
52 if !app_dir.is_dir() {
53 continue;
54 }
55
56 let config_path = app_dir.join("app.yaml");
57 if !config_path.exists() {
58 continue;
59 }
60
61 let config_str = fs::read_to_string(&config_path).ok()?;
63 let config: AppConfig = serde_yaml::from_str(&config_str).ok()?;
64
65 if let Some(manifest) = &config.manifest {
67 if let Some(pkg) = &manifest.package {
68 if pkg == package_name {
69 return Some(AppInfo {
70 path: app_dir,
71 config,
72 });
73 }
74 }
75 }
76 }
77
78 None
79}
80
81pub fn find_app_info(file_path: &Path) -> Option<AppInfo> {
83 let mut current = file_path;
84
85 while let Some(parent) = current.parent() {
87 let config_path = parent.join("app.yaml");
88 if config_path.exists() {
89 let config_str = fs::read_to_string(&config_path).ok()?;
91 let config: AppConfig = serde_yaml::from_str(&config_str).ok()?;
92
93 return Some(AppInfo {
94 path: parent.to_path_buf(),
95 config,
96 });
97 }
98 current = parent;
99 }
100
101 None
102}
103
104pub fn resolve_app_entry(package_name: &str, entry_name: Option<&str>) -> Option<PathBuf> {
106 let app_info = find_app_by_package(package_name)?;
107
108 let entries = app_info.config.entries.as_ref()?;
110
111 let entry_key = entry_name.unwrap_or("main");
113 let entry_path = entries.get(entry_key)?;
114
115 Some(app_info.path.join(entry_path))
117}
118
119pub fn find_app_path(dir_path: &Path) -> Option<PathBuf> {
121 let mut current = dir_path;
122
123 while let Some(parent) = current.parent() {
125 let config_path = parent.join("app.yaml");
126 if config_path.exists() {
127 return Some(parent.to_path_buf());
128 }
129 current = parent;
130 }
131
132 None
133}
134
135pub fn is_valid_utf8<P: AsRef<Path>>(path: P) -> std::io::Result<bool> {
136 let bytes = std::fs::read(path)?;
137 Ok(std::str::from_utf8(&bytes).is_ok())
138}