retch_sysinfo/
packages.rs1pub(crate) fn detect_packages() -> Option<usize> {
10 #[cfg(target_os = "macos")]
11 {
12 let mut count = 0;
13
14 for cellar_path in &["/opt/homebrew/Cellar", "/usr/local/Cellar"] {
15 if let Ok(entries) = std::fs::read_dir(cellar_path) {
16 count += entries.filter_map(|e| e.ok()).count();
17 }
18 }
19
20 for cask_path in &["/opt/homebrew/Caskroom", "/usr/local/Caskroom"] {
21 if let Ok(entries) = std::fs::read_dir(cask_path) {
22 count += entries.filter_map(|e| e.ok()).count();
23 }
24 }
25
26 if let Ok(entries) = std::fs::read_dir("/opt/local/var/macports/software") {
27 count += entries.filter_map(|e| e.ok()).count();
28 }
29
30 if count > 0 {
31 Some(count)
32 } else {
33 None
34 }
35 }
36
37 #[cfg(target_os = "windows")]
38 {
39 let mut count = 0;
40
41 if let Some(home) = dirs::home_dir() {
42 let scoop_dir = std::env::var("SCOOP")
43 .map(std::path::PathBuf::from)
44 .unwrap_or_else(|_| home.join("scoop"));
45 if let Ok(entries) = std::fs::read_dir(scoop_dir.join("apps")) {
46 count += entries.filter_map(|e| e.ok()).count();
47 }
48 }
49
50 let choco_install = std::env::var("ChocolateyInstall")
51 .unwrap_or_else(|_| "C:\\ProgramData\\chocolatey".to_string());
52 if let Ok(entries) = std::fs::read_dir(std::path::Path::new(&choco_install).join("lib")) {
53 count += entries.filter_map(|e| e.ok()).count();
54 }
55
56 if count > 0 {
57 Some(count)
58 } else {
59 None
60 }
61 }
62
63 #[cfg(not(any(target_os = "macos", target_os = "windows")))]
64 {
65 if let Ok(entries) = std::fs::read_dir("/var/lib/pacman/local") {
66 let count = entries.filter_map(|e| e.ok()).count();
67 if count > 0 {
68 return Some(count);
69 }
70 }
71
72 if let Ok(entries) = std::fs::read_dir("/var/lib/dpkg/info") {
73 let count = entries
74 .filter_map(|e| e.ok())
75 .filter(|e| e.path().extension().is_some_and(|ext| ext == "list"))
76 .count();
77 if count > 0 {
78 return Some(count);
79 }
80 }
81
82 if let Ok(entries) = std::fs::read_dir("/var/db/pkg") {
83 let count: usize = entries
84 .filter_map(|e| e.ok())
85 .map(|e| {
86 std::fs::read_dir(e.path())
87 .map(|d| d.filter(|_| true).count())
88 .unwrap_or(0)
89 })
90 .sum();
91 if count > 0 {
92 return Some(count);
93 }
94 }
95
96 if let Ok(entries) = std::fs::read_dir("/var/db/xbps") {
97 let count = entries
98 .filter_map(|e| e.ok())
99 .filter(|e| e.path().extension().is_some_and(|ext| ext == "plist"))
100 .count();
101 if count > 0 {
102 return Some(count);
103 }
104 }
105
106 let rpm_db = "/var/lib/rpm/rpmdb.sqlite";
107 if std::path::Path::new(rpm_db).exists() {
108 match rusqlite::Connection::open(rpm_db) {
109 Ok(conn) => {
110 if let Ok(count) = conn.query_row("SELECT COUNT(*) FROM Packages", [], |row| {
111 row.get::<_, i64>(0)
112 }) {
113 if count > 0 {
114 return Some(count as usize);
115 }
116 }
117 }
118 Err(e) => {
119 eprintln!("warning: failed to open RPM database at {}: {}", rpm_db, e);
120 }
121 }
122 }
123
124 None
125 }
126}