Skip to content

Commit 01eef4f

Browse files
jbattistMoonMao42
authored andcommitted
Add pacman/yay support for Arch Linux
1 parent d4e14cf commit 01eef4f

1 file changed

Lines changed: 145 additions & 4 deletions

File tree

src/platform/packages.rs

Lines changed: 145 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ use std::process::Command;
88
pub enum PackageManagerBackend {
99
Homebrew,
1010
Apt,
11+
Yay,
12+
Pacman,
1113
Unsupported,
1214
}
1315

@@ -16,6 +18,8 @@ impl PackageManagerBackend {
1618
match self {
1719
Self::Homebrew => "Homebrew",
1820
Self::Apt => "apt",
21+
Self::Yay => "yay",
22+
Self::Pacman => "pacman",
1923
Self::Unsupported => "unsupported",
2024
}
2125
}
@@ -33,8 +37,17 @@ pub fn detect_backend() -> PackageManagerBackend {
3337
return PackageManagerBackend::Unsupported;
3438
}
3539

36-
if cfg!(target_os = "linux") && detection::command_path("apt-get").is_some() {
37-
return PackageManagerBackend::Apt;
40+
if cfg!(target_os = "linux") {
41+
if detection::command_path("apt-get").is_some() {
42+
return PackageManagerBackend::Apt;
43+
}
44+
// Prefer yay over pacman — yay covers both official repos and AUR.
45+
if detection::command_path("yay").is_some() {
46+
return PackageManagerBackend::Yay;
47+
}
48+
if detection::command_path("pacman").is_some() {
49+
return PackageManagerBackend::Pacman;
50+
}
3851
}
3952

4053
PackageManagerBackend::Unsupported
@@ -44,9 +57,11 @@ fn capability_report_for_backend(backend: PackageManagerBackend) -> CapabilityRe
4457
match backend {
4558
PackageManagerBackend::Homebrew => CapabilityReport::supported("homebrew"),
4659
PackageManagerBackend::Apt => CapabilityReport::supported("apt"),
60+
PackageManagerBackend::Yay => CapabilityReport::supported("yay"),
61+
PackageManagerBackend::Pacman => CapabilityReport::supported("pacman"),
4762
PackageManagerBackend::Unsupported => CapabilityReport::unsupported(
4863
"unsupported",
49-
"No supported package manager was found. Slate currently supports Homebrew on macOS and apt on Linux.",
64+
"No supported package manager was found. Slate currently supports Homebrew on macOS, apt on Debian/Ubuntu, and pacman/yay on Arch Linux.",
5065
),
5166
}
5267
}
@@ -59,8 +74,10 @@ pub fn install_tool_package(tool_id: &str, brew_package: &str, env: &SlateEnv) -
5974
match detect_backend() {
6075
PackageManagerBackend::Homebrew => install_with_homebrew(brew_package),
6176
PackageManagerBackend::Apt => install_with_apt(tool_id, env),
77+
PackageManagerBackend::Yay => install_with_yay(tool_id),
78+
PackageManagerBackend::Pacman => install_with_pacman(tool_id),
6279
PackageManagerBackend::Unsupported => Err(SlateError::Internal(
63-
"No supported package manager was found. Slate currently supports Homebrew on macOS and apt on Linux.".to_string(),
80+
"No supported package manager was found. Slate currently supports Homebrew on macOS, apt on Debian/Ubuntu, and pacman/yay on Arch Linux.".to_string(),
6481
)),
6582
}
6683
}
@@ -136,6 +153,85 @@ fn apt_package_name(tool_id: &str) -> Option<&'static str> {
136153
}
137154
}
138155

156+
fn install_with_yay(tool_id: &str) -> Result<()> {
157+
if tool_id == "starship" {
158+
return Err(SlateError::Internal(
159+
"starship uses Slate's user-local installer path on Linux.".to_string(),
160+
));
161+
}
162+
163+
let package = pacman_package_name(tool_id).ok_or_else(|| {
164+
SlateError::Internal(format!(
165+
"Slate does not have a pacman/yay package mapping for '{}'. Install it manually, then rerun slate setup.",
166+
tool_id
167+
))
168+
})?;
169+
170+
let yay = detection::command_path("yay").ok_or_else(|| {
171+
SlateError::Internal("yay was not found in PATH.".to_string())
172+
})?;
173+
174+
let mut cmd = Command::new(yay);
175+
detection::apply_normalized_path(&mut cmd);
176+
let output = cmd
177+
.args(["--noconfirm", "-S", package])
178+
.output()
179+
.map_err(|e| SlateError::Internal(format!("Failed to execute yay: {}", e)))?;
180+
181+
if output.status.success() {
182+
Ok(())
183+
} else {
184+
let stderr = String::from_utf8_lossy(&output.stderr);
185+
Err(SlateError::Internal(stderr.trim().to_string()))
186+
}
187+
}
188+
189+
fn install_with_pacman(tool_id: &str) -> Result<()> {
190+
if tool_id == "starship" {
191+
return Err(SlateError::Internal(
192+
"starship uses Slate's user-local installer path on Linux.".to_string(),
193+
));
194+
}
195+
196+
let package = pacman_package_name(tool_id).ok_or_else(|| {
197+
SlateError::Internal(format!(
198+
"Slate does not have a pacman package mapping for '{}'. Install it manually, then rerun slate setup.",
199+
tool_id
200+
))
201+
})?;
202+
203+
let pacman = detection::command_path("pacman").ok_or_else(|| {
204+
SlateError::Internal("pacman was not found in PATH.".to_string())
205+
})?;
206+
207+
let mut cmd = Command::new("sudo");
208+
detection::apply_normalized_path(&mut cmd);
209+
let output = cmd
210+
.arg(pacman)
211+
.args(["--noconfirm", "-S", package])
212+
.output()
213+
.map_err(|e| SlateError::Internal(format!("Failed to execute pacman: {}", e)))?;
214+
215+
if output.status.success() {
216+
Ok(())
217+
} else {
218+
let stderr = String::from_utf8_lossy(&output.stderr);
219+
Err(SlateError::Internal(stderr.trim().to_string()))
220+
}
221+
}
222+
223+
fn pacman_package_name(tool_id: &str) -> Option<&'static str> {
224+
match tool_id {
225+
"bat" => Some("bat"),
226+
"delta" => Some("git-delta"),
227+
"eza" => Some("eza"),
228+
"lazygit" => Some("lazygit"),
229+
"fastfetch" => Some("fastfetch"),
230+
"zsh-syntax-highlighting" => Some("zsh-syntax-highlighting"),
231+
_ => None,
232+
}
233+
}
234+
139235
#[cfg(test)]
140236
mod tests {
141237
use super::*;
@@ -144,6 +240,17 @@ mod tests {
144240
fn test_backend_labels() {
145241
assert_eq!(PackageManagerBackend::Homebrew.label(), "Homebrew");
146242
assert_eq!(PackageManagerBackend::Apt.label(), "apt");
243+
assert_eq!(PackageManagerBackend::Yay.label(), "yay");
244+
assert_eq!(PackageManagerBackend::Pacman.label(), "pacman");
245+
assert_eq!(PackageManagerBackend::Unsupported.label(), "unsupported");
246+
}
247+
248+
#[test]
249+
fn test_backend_is_supported() {
250+
assert!(PackageManagerBackend::Apt.is_supported());
251+
assert!(PackageManagerBackend::Yay.is_supported());
252+
assert!(PackageManagerBackend::Pacman.is_supported());
253+
assert!(!PackageManagerBackend::Unsupported.is_supported());
147254
}
148255

149256
#[test]
@@ -152,6 +259,16 @@ mod tests {
152259
assert_eq!(apt_package_name("delta"), Some("git-delta"));
153260
}
154261

262+
#[test]
263+
fn test_pacman_mappings_cover_core_packages() {
264+
assert_eq!(pacman_package_name("bat"), Some("bat"));
265+
assert_eq!(pacman_package_name("delta"), Some("git-delta"));
266+
assert_eq!(pacman_package_name("eza"), Some("eza"));
267+
assert_eq!(pacman_package_name("lazygit"), Some("lazygit"));
268+
assert_eq!(pacman_package_name("fastfetch"), Some("fastfetch"));
269+
assert_eq!(pacman_package_name("unknown-tool"), None);
270+
}
271+
155272
#[test]
156273
fn test_capability_report_for_apt_reports_supported() {
157274
let report = capability_report_for_backend(PackageManagerBackend::Apt);
@@ -163,4 +280,28 @@ mod tests {
163280
assert_eq!(report.backend, "apt");
164281
assert!(report.reason.is_none());
165282
}
283+
284+
#[test]
285+
fn test_capability_report_for_yay_reports_supported() {
286+
let report = capability_report_for_backend(PackageManagerBackend::Yay);
287+
288+
assert_eq!(
289+
report.level,
290+
crate::platform::capabilities::SupportLevel::Supported
291+
);
292+
assert_eq!(report.backend, "yay");
293+
assert!(report.reason.is_none());
294+
}
295+
296+
#[test]
297+
fn test_capability_report_for_pacman_reports_supported() {
298+
let report = capability_report_for_backend(PackageManagerBackend::Pacman);
299+
300+
assert_eq!(
301+
report.level,
302+
crate::platform::capabilities::SupportLevel::Supported
303+
);
304+
assert_eq!(report.backend, "pacman");
305+
assert!(report.reason.is_none());
306+
}
166307
}

0 commit comments

Comments
 (0)