rusty_stack/installers/components/
amdgpu_drivers.rs1use crate::installers::common::DistroFacade;
11use crate::platform::detection::DistroFamily;
12
13#[derive(Debug, Clone, PartialEq, Eq)]
19pub struct ShellCommand {
20 pub program: String,
22 pub args: Vec<String>,
24 pub env: Vec<(String, String)>,
26}
27
28impl ShellCommand {
29 pub fn to_command_string(&self) -> String {
31 let env_prefix = self
32 .env
33 .iter()
34 .map(|(k, v)| format!("{k}={v}"))
35 .collect::<Vec<_>>()
36 .join(" ");
37 let cmd = if self.args.is_empty() {
38 self.program.clone()
39 } else {
40 format!("{} {}", self.program, self.args.join(" "))
41 };
42 if env_prefix.is_empty() {
43 cmd
44 } else {
45 format!("{env_prefix} {cmd}")
46 }
47 }
48}
49
50#[derive(Debug, Clone, Default)]
52pub struct AmdgpuConfig {
53 pub dry_run: bool,
55 pub force: bool,
57}
58
59pub struct AmdgpuInstaller {
61 config: AmdgpuConfig,
62}
63
64impl AmdgpuInstaller {
65 pub fn new(config: AmdgpuConfig) -> Self {
67 Self { config }
68 }
69
70 pub fn with_defaults() -> Self {
72 Self::new(AmdgpuConfig::default())
73 }
74
75 pub fn required_packages(&self, distro: &DistroFacade) -> Vec<&str> {
81 match distro.family() {
82 DistroFamily::Debian => vec![
83 "amdgpu-dkms",
84 "linux-headers-$(uname -r)",
85 "linux-modules-extra-$(uname -r)",
86 ],
87 DistroFamily::Rhel => vec!["amdgpu-dkms", "kernel-devel"],
88 DistroFamily::Arch => vec!["amdgpu"],
89 DistroFamily::Suse => vec!["amdgpu-dkms", "kernel-default-devel"],
90 _ => vec!["amdgpu-dkms"],
91 }
92 }
93
94 pub fn rocm_packages(&self, _distro: &DistroFacade) -> Vec<&str> {
96 vec!["rocm-dev", "rocm-libs", "rocprofiler"]
97 }
98
99 pub fn build_package_install_command(
107 &self,
108 distro: &DistroFacade,
109 packages: &[&str],
110 ) -> ShellCommand {
111 let (program, mut base_args) = match distro.family() {
112 DistroFamily::Debian => (
113 "sudo".to_string(),
114 vec![
115 "apt-get".to_string(),
116 "install".to_string(),
117 "-y".to_string(),
118 ],
119 ),
120 DistroFamily::Rhel => (
121 "sudo".to_string(),
122 vec!["dnf".to_string(), "install".to_string(), "-y".to_string()],
123 ),
124 DistroFamily::Arch => (
125 "sudo".to_string(),
126 vec![
127 "pacman".to_string(),
128 "-S".to_string(),
129 "--noconfirm".to_string(),
130 ],
131 ),
132 DistroFamily::Suse => (
133 "sudo".to_string(),
134 vec![
135 "zypper".to_string(),
136 "install".to_string(),
137 "-y".to_string(),
138 ],
139 ),
140 _ => (
141 "sudo".to_string(),
142 vec![
143 "apt-get".to_string(),
144 "install".to_string(),
145 "-y".to_string(),
146 ],
147 ),
148 };
149
150 for pkg in packages {
151 base_args.push(pkg.to_string());
152 }
153
154 if self.config.dry_run {
156 let mut preview = base_args;
157 preview.insert(0, program.clone());
158 return ShellCommand {
159 program: "echo".to_string(),
160 args: preview,
161 env: vec![],
162 };
163 }
164
165 ShellCommand {
166 program,
167 args: base_args,
168 env: vec![],
169 }
170 }
171
172 pub fn build_amdgpu_install_deb_commands(&self, codename: &str) -> Vec<ShellCommand> {
181 let deb_url = format!(
182 "https://repo.radeon.com/amdgpu-install/7.2.4/ubuntu/{}/amdgpu-install_7.2.4.70204-1_all.deb",
183 codename
184 );
185 let deb_file = "amdgpu-install_7.2.4.70204-1_all.deb";
186
187 vec![
188 ShellCommand {
190 program: "wget".to_string(),
191 args: vec!["-q".to_string(), deb_url],
192 env: vec![],
193 },
194 ShellCommand {
196 program: "sudo".to_string(),
197 args: vec![
198 "apt".to_string(),
199 "install".to_string(),
200 "-y".to_string(),
201 format!("./{deb_file}"),
202 ],
203 env: vec![],
204 },
205 ShellCommand {
207 program: "sudo".to_string(),
208 args: vec!["apt".to_string(), "update".to_string()],
209 env: vec![],
210 },
211 ShellCommand {
213 program: "sudo".to_string(),
214 args: vec![
215 "apt".to_string(),
216 "install".to_string(),
217 "-y".to_string(),
218 "linux-headers-$(uname -r)".to_string(),
219 "linux-modules-extra-$(uname -r)".to_string(),
220 ],
221 env: vec![],
222 },
223 ShellCommand {
225 program: "sudo".to_string(),
226 args: vec![
227 "apt".to_string(),
228 "install".to_string(),
229 "-y".to_string(),
230 "amdgpu-dkms".to_string(),
231 ],
232 env: vec![],
233 },
234 ]
235 }
236
237 pub fn build_verify_command(&self) -> ShellCommand {
239 ShellCommand {
240 program: "lsmod".to_string(),
241 args: vec![],
242 env: vec![],
243 }
244 }
245}
246
247#[cfg(test)]
252mod tests {
253 use super::*;
254 use crate::platform::detection::{DistroFamily, DistroInfo, PackageManager};
255
256 fn make_distro(family: DistroFamily) -> DistroFacade {
258 DistroFacade::from_info(DistroInfo {
259 id: match family {
260 DistroFamily::Debian => "ubuntu",
261 DistroFamily::Rhel => "fedora",
262 DistroFamily::Arch => "arch",
263 DistroFamily::Suse => "opensuse",
264 DistroFamily::Unknown => "unknown",
265 }
266 .to_string(),
267 name: "Test Distro".to_string(),
268 version: "1.0".to_string(),
269 codename: "test".to_string(),
270 id_like: String::new(),
271 family,
272 pkg_manager: match family {
273 DistroFamily::Debian => PackageManager::Apt,
274 DistroFamily::Rhel => PackageManager::Dnf,
275 DistroFamily::Arch => PackageManager::Pacman,
276 DistroFamily::Suse => PackageManager::Zypper,
277 DistroFamily::Unknown => PackageManager::Apt,
278 },
279 })
280 }
281
282 #[test]
287 fn test_package_install_command_debian() {
288 let installer = AmdgpuInstaller::with_defaults();
289 let distro = make_distro(DistroFamily::Debian);
290 let cmd = installer.build_package_install_command(&distro, &["amdgpu-dkms"]);
291
292 assert_eq!(cmd.program, "sudo");
293 assert!(cmd.args.contains(&"apt-get".to_string()));
294 assert!(cmd.args.contains(&"install".to_string()));
295 assert!(cmd.args.contains(&"-y".to_string()));
296 assert!(cmd.args.contains(&"amdgpu-dkms".to_string()));
297 }
298
299 #[test]
300 fn test_package_install_command_rhel() {
301 let installer = AmdgpuInstaller::with_defaults();
302 let distro = make_distro(DistroFamily::Rhel);
303 let cmd = installer.build_package_install_command(&distro, &["amdgpu-dkms"]);
304
305 assert_eq!(cmd.program, "sudo");
306 assert!(cmd.args.contains(&"dnf".to_string()));
307 assert!(cmd.args.contains(&"install".to_string()));
308 assert!(cmd.args.contains(&"-y".to_string()));
309 }
310
311 #[test]
312 fn test_package_install_command_arch() {
313 let installer = AmdgpuInstaller::with_defaults();
314 let distro = make_distro(DistroFamily::Arch);
315 let cmd = installer.build_package_install_command(&distro, &["amdgpu"]);
316
317 assert_eq!(cmd.program, "sudo");
318 assert!(cmd.args.contains(&"pacman".to_string()));
319 assert!(cmd.args.contains(&"-S".to_string()));
320 assert!(cmd.args.contains(&"--noconfirm".to_string()));
321 assert!(cmd.args.contains(&"amdgpu".to_string()));
322 }
323
324 #[test]
325 fn test_package_install_command_suse() {
326 let installer = AmdgpuInstaller::with_defaults();
327 let distro = make_distro(DistroFamily::Suse);
328 let cmd = installer.build_package_install_command(&distro, &["amdgpu-dkms"]);
329
330 assert_eq!(cmd.program, "sudo");
331 assert!(cmd.args.contains(&"zypper".to_string()));
332 assert!(cmd.args.contains(&"install".to_string()));
333 assert!(cmd.args.contains(&"-y".to_string()));
334 }
335
336 #[test]
337 fn test_required_packages_debian() {
338 let installer = AmdgpuInstaller::with_defaults();
339 let distro = make_distro(DistroFamily::Debian);
340 let pkgs = installer.required_packages(&distro);
341 assert!(pkgs.contains(&"amdgpu-dkms"));
342 }
343
344 #[test]
345 fn test_required_packages_arch() {
346 let installer = AmdgpuInstaller::with_defaults();
347 let distro = make_distro(DistroFamily::Arch);
348 let pkgs = installer.required_packages(&distro);
349 assert!(pkgs.contains(&"amdgpu"));
350 }
351
352 #[test]
353 fn test_amdgpu_install_deb_commands() {
354 let installer = AmdgpuInstaller::with_defaults();
355 let cmds = installer.build_amdgpu_install_deb_commands("noble");
356 assert_eq!(cmds.len(), 5);
357
358 assert_eq!(cmds[0].program, "wget");
360 assert!(cmds[0].args.iter().any(|a| a.contains("repo.radeon.com")));
361 assert!(cmds[0].args.iter().any(|a| a.contains("noble")));
362
363 assert!(cmds[1].args.iter().any(|a| a.contains("amdgpu-install")));
365
366 assert!(cmds[2].args.contains(&"update".to_string()));
368
369 assert!(cmds[3].args.iter().any(|a| a.contains("linux-headers")));
371
372 assert!(cmds[4].args.contains(&"amdgpu-dkms".to_string()));
374 }
375
376 #[test]
377 fn test_verify_command() {
378 let installer = AmdgpuInstaller::with_defaults();
379 let cmd = installer.build_verify_command();
380 assert_eq!(cmd.program, "lsmod");
381 }
382}