@@ -8,6 +8,8 @@ use std::process::Command;
88pub 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) ]
140236mod 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