podbox/quadlet_install/
paths.rs1use std::path::PathBuf;
7
8use crate::config;
9
10pub(crate) fn quadlet_dir() -> PathBuf {
12 dirs::config_dir()
13 .unwrap_or_else(|| config::expand_tilde("~/.config"))
14 .join("containers/systemd")
15}
16
17pub(crate) fn flat_container_path(name: &str) -> PathBuf {
19 quadlet_dir().join(format!("{name}.container"))
20}
21
22pub(crate) fn application_container_path(name: &str) -> PathBuf {
25 quadlet_dir().join(name).join(format!("{name}.container"))
26}
27
28pub fn is_installed(name: &str) -> bool {
30 container_unit_path(name).is_some()
31}
32
33pub(crate) fn container_unit_path(name: &str) -> Option<PathBuf> {
35 let flat = flat_container_path(name);
36 if flat.exists() {
37 return Some(flat);
38 }
39 let app = application_container_path(name);
40 if app.exists() {
41 return Some(app);
42 }
43 None
44}
45
46pub fn list_installed_names() -> Vec<String> {
48 let qdir = quadlet_dir();
49 let mut names = Vec::new();
50
51 let Ok(entries) = std::fs::read_dir(&qdir) else {
52 return names;
53 };
54
55 for entry in entries.flatten() {
56 let path = entry.path();
57 if path.extension().is_some_and(|e| e == "container") {
58 if let Some(stem) = path.file_stem().and_then(|s| s.to_str()) {
59 names.push(stem.to_string());
60 }
61 continue;
62 }
63 if path.is_dir() {
65 let Some(dir_name) = path.file_name().and_then(|s| s.to_str()) else {
66 continue;
67 };
68 let nested = path.join(format!("{dir_name}.container"));
69 if nested.exists() {
70 names.push(dir_name.to_string());
71 }
72 }
73 }
74
75 names.sort();
76 names.dedup();
77 names
78}
79
80pub(crate) fn systemd_user_dir() -> PathBuf {
82 dirs::config_dir()
83 .unwrap_or_else(|| config::expand_tilde("~/.config"))
84 .join("systemd/user")
85}