1use once_cell::sync::Lazy;
2pub use std::env::*;
3use std::path::PathBuf;
4
5pub static PITCHFORK_BIN: Lazy<PathBuf> = Lazy::new(|| {
6 current_exe()
7 .and_then(|p| p.canonicalize())
8 .unwrap_or_else(|e| {
9 eprintln!("Warning: Could not determine pitchfork binary path: {e}");
10 args()
11 .next()
12 .map(PathBuf::from)
13 .unwrap_or_else(|| PathBuf::from("pitchfork"))
14 })
15});
16pub static CWD: Lazy<PathBuf> = Lazy::new(|| current_dir().unwrap_or_else(|_| PathBuf::from(".")));
17
18pub static HOME_DIR: Lazy<PathBuf> = Lazy::new(|| {
19 #[cfg(unix)]
29 if nix::unistd::Uid::effective().is_root() {
30 if let Ok(sudo_user) = std::env::var("SUDO_USER") {
31 if let Some(home) = home_dir_for_user(&sudo_user) {
32 return home;
33 }
34 }
35 }
36 dirs::home_dir().unwrap_or_else(|| {
37 eprintln!("Warning: Could not determine home directory");
38 PathBuf::from("/tmp")
39 })
40});
41pub static PITCHFORK_CONFIG_DIR: Lazy<PathBuf> = Lazy::new(|| {
42 var_path("PITCHFORK_CONFIG_DIR").unwrap_or(HOME_DIR.join(".config").join("pitchfork"))
43});
44pub static PITCHFORK_GLOBAL_CONFIG_USER: Lazy<PathBuf> =
45 Lazy::new(|| PITCHFORK_CONFIG_DIR.join("config.toml"));
46pub static PITCHFORK_GLOBAL_CONFIG_SYSTEM: Lazy<PathBuf> =
47 Lazy::new(|| PathBuf::from("/etc/pitchfork/config.toml"));
48pub static PITCHFORK_STATE_DIR: Lazy<PathBuf> = Lazy::new(|| {
49 if let Some(p) = var_path("PITCHFORK_STATE_DIR") {
50 return p;
51 }
52 #[cfg(unix)]
53 if nix::unistd::Uid::effective().is_root()
54 && let Some(home) = configured_supervisor_user_home_dir()
55 {
56 return home.join(".local").join("state").join("pitchfork");
57 }
58 #[cfg(unix)]
61 if nix::unistd::Uid::effective().is_root() {
62 return HOME_DIR.join(".local").join("state").join("pitchfork");
63 }
64 dirs::state_dir()
65 .unwrap_or_else(|| HOME_DIR.join(".local").join("state"))
66 .join("pitchfork")
67});
68pub static PITCHFORK_STATE_FILE: Lazy<PathBuf> =
69 Lazy::new(|| PITCHFORK_STATE_DIR.join("state.toml"));
70pub static PITCHFORK_LOG: Lazy<log::LevelFilter> =
71 Lazy::new(|| var_log_level("PITCHFORK_LOG").unwrap_or(log::LevelFilter::Info));
72pub static PITCHFORK_LOG_FILE_LEVEL: Lazy<log::LevelFilter> =
73 Lazy::new(|| var_log_level("PITCHFORK_LOG_FILE_LEVEL").unwrap_or(*PITCHFORK_LOG));
74pub static PITCHFORK_LOGS_DIR: Lazy<PathBuf> =
75 Lazy::new(|| var_path("PITCHFORK_LOGS_DIR").unwrap_or(PITCHFORK_STATE_DIR.join("logs")));
76pub static PITCHFORK_LOG_FILE: Lazy<PathBuf> =
77 Lazy::new(|| PITCHFORK_LOGS_DIR.join("pitchfork").join("pitchfork.log"));
78pub static IPC_SOCK_DIR: Lazy<PathBuf> = Lazy::new(|| PITCHFORK_STATE_DIR.join("sock"));
81pub static IPC_SOCK_MAIN: Lazy<PathBuf> = Lazy::new(|| IPC_SOCK_DIR.join("main.sock"));
82
83pub static ORIGINAL_PATH: Lazy<Option<String>> = Lazy::new(|| var("PATH").ok());
85pub static IPC_JSON: Lazy<bool> = Lazy::new(|| !var_false("IPC_JSON"));
86
87fn var_path(name: &str) -> Option<PathBuf> {
88 var(name).map(PathBuf::from).ok()
89}
90
91fn var_log_level(name: &str) -> Option<log::LevelFilter> {
92 var(name).ok().and_then(|level| level.parse().ok())
93}
94
95fn var_false(name: &str) -> bool {
96 var(name)
97 .map(|val| val.to_lowercase())
98 .map(|val| val == "false" || val == "0")
99 .unwrap_or(false)
100}
101
102#[cfg(unix)]
112fn home_dir_for_user(username: &str) -> Option<PathBuf> {
113 nix::unistd::User::from_name(username)
114 .ok()
115 .flatten()
116 .map(|u| u.dir)
117}
118
119#[cfg(unix)]
120fn configured_supervisor_user_home_dir() -> Option<PathBuf> {
121 let user = crate::settings::settings().supervisor.user.trim();
122 if user.is_empty() {
123 return None;
124 }
125
126 if user.chars().all(|c| c.is_ascii_digit()) {
127 let uid = user.parse::<u32>().ok()?;
128 return nix::unistd::User::from_uid(nix::unistd::Uid::from_raw(uid))
129 .ok()
130 .flatten()
131 .map(|u| u.dir);
132 }
133
134 home_dir_for_user(user)
135}