diff options
-rw-r--r-- | src/packages.rs | 9 | ||||
-rw-r--r-- | src/packages/dnf.rs | 62 | ||||
-rw-r--r-- | src/pathinfo.rs | 23 |
3 files changed, 85 insertions, 9 deletions
diff --git a/src/packages.rs b/src/packages.rs index 41b9478..5fb08d0 100644 --- a/src/packages.rs +++ b/src/packages.rs | |||
@@ -1,11 +1,13 @@ | |||
1 | use std::{fs::File, io::Read}; | 1 | use std::{fs::File, io::Read}; |
2 | 2 | ||
3 | use dnf::Dnf; | ||
3 | use pacman::Pacman; | 4 | use pacman::Pacman; |
4 | use portage::Portage; | 5 | use portage::Portage; |
5 | use serde::{Deserialize, Serialize}; | 6 | use serde::{Deserialize, Serialize}; |
6 | 7 | ||
7 | use crate::error::{Error, Result}; | 8 | use crate::error::{Error, Result}; |
8 | 9 | ||
10 | mod dnf; | ||
9 | mod pacman; | 11 | mod pacman; |
10 | mod portage; | 12 | mod portage; |
11 | 13 | ||
@@ -32,6 +34,7 @@ pub struct Package { | |||
32 | 34 | ||
33 | #[derive(Debug, Clone, clap::ValueEnum, Serialize, Deserialize)] | 35 | #[derive(Debug, Clone, clap::ValueEnum, Serialize, Deserialize)] |
34 | pub enum Manager { | 36 | pub enum Manager { |
37 | Dnf, | ||
35 | Pacman, | 38 | Pacman, |
36 | Portage, | 39 | Portage, |
37 | } | 40 | } |
@@ -62,14 +65,16 @@ impl Manager { | |||
62 | 65 | ||
63 | fn from_str(value: &str) -> Result<Self> { | 66 | fn from_str(value: &str) -> Result<Self> { |
64 | Ok(match value { | 67 | Ok(match value { |
65 | "arch" => Self::Pacman, | 68 | "fedora" => Box::new(Dnf), |
66 | "gentoo" => Self::Portage, | 69 | "arch" => Box::new(Pacman), |
70 | "gentoo" => Box::new(Portage), | ||
67 | _ => return Err(Error::Unsupported), | 71 | _ => return Err(Error::Unsupported), |
68 | }) | 72 | }) |
69 | } | 73 | } |
70 | 74 | ||
71 | pub fn to_package_manager(&self) -> Box<dyn PackageManager> { | 75 | pub fn to_package_manager(&self) -> Box<dyn PackageManager> { |
72 | match self { | 76 | match self { |
77 | Self::Dnf => Box::new(Dnf), | ||
73 | Self::Pacman => Box::new(Pacman), | 78 | Self::Pacman => Box::new(Pacman), |
74 | Self::Portage => Box::new(Portage), | 79 | Self::Portage => Box::new(Portage), |
75 | } | 80 | } |
diff --git a/src/packages/dnf.rs b/src/packages/dnf.rs new file mode 100644 index 0000000..6f451ee --- /dev/null +++ b/src/packages/dnf.rs | |||
@@ -0,0 +1,62 @@ | |||
1 | use std::process::{Command, Stdio}; | ||
2 | |||
3 | use super::{Package, PackageList, PackageManager}; | ||
4 | |||
5 | use crate::error::{Error, Result}; | ||
6 | |||
7 | pub struct Dnf; | ||
8 | |||
9 | impl PackageManager for Dnf { | ||
10 | fn get_installed(&self) -> Result<PackageList> { | ||
11 | let list = Command::new("dnf").args(["list", "installed"]).output().unwrap(); | ||
12 | let explicit_list = Command::new("dnf").args(["repoquery", "--userinstalled"]).output().unwrap(); | ||
13 | |||
14 | let list_str = String::from_utf8(list.stdout).unwrap(); | ||
15 | let ex_list_str = String::from_utf8(explicit_list.stdout).unwrap(); | ||
16 | |||
17 | |||
18 | let mut pkgs: Vec<Package> = Vec::new(); | ||
19 | let list_lines: Vec<&str> = list_str.split('\n').collect(); | ||
20 | // Pop first info line | ||
21 | let list_lines = &list_lines[1..list_lines.len()]; | ||
22 | for pkg in list_lines { | ||
23 | if pkg.is_empty() { | ||
24 | continue; | ||
25 | }; | ||
26 | let split: Vec<&str> = pkg.split_whitespace().collect(); | ||
27 | if split.len() != 3 { | ||
28 | return Err(Error::UnknownOutput); | ||
29 | }; | ||
30 | |||
31 | let explicit = ex_list_str.contains(pkg); | ||
32 | |||
33 | let Some(pkg_id) = split[0].split_once('.') else { | ||
34 | return Err(Error::UnknownOutput); | ||
35 | }; | ||
36 | pkgs.push(Package { | ||
37 | id: pkg_id.0.to_string(), | ||
38 | version: split[1].to_string(), | ||
39 | explicit, | ||
40 | }); | ||
41 | } | ||
42 | |||
43 | Ok(PackageList { | ||
44 | packages: pkgs, | ||
45 | manager: super::Manager::Dnf, | ||
46 | }) | ||
47 | } | ||
48 | |||
49 | fn install(&self, pkgs: Vec<super::Package>) -> Result<()> { | ||
50 | let mut args = vec!["dnf".to_string(), "install".to_string(), "--assumeyes".to_string()]; | ||
51 | |||
52 | for pkg in pkgs { | ||
53 | args.push(pkg.id); | ||
54 | } | ||
55 | Command::new("sudo") | ||
56 | .stdout(Stdio::inherit()) | ||
57 | .args(args) | ||
58 | .spawn()? | ||
59 | .wait_with_output()?; | ||
60 | Ok(()) | ||
61 | } | ||
62 | } | ||
diff --git a/src/pathinfo.rs b/src/pathinfo.rs index 009f46a..80614cd 100644 --- a/src/pathinfo.rs +++ b/src/pathinfo.rs | |||
@@ -392,11 +392,16 @@ mod tests { | |||
392 | } | 392 | } |
393 | 393 | ||
394 | #[test] | 394 | #[test] |
395 | fn compare_to_last_modified() -> Result<()> { | 395 | fn compare_to_last_modified() -> color_eyre::Result<()> { |
396 | let mut config = Config { root: "./backup-test".to_string(), ..Default::default() }; | 396 | |
397 | let cwd = std::env::current_dir()?; | ||
398 | let test_dir = format!("{}/backup-test-dir", cwd.display()); | ||
399 | |||
400 | let mut config = Config::default(); | ||
401 | config.root = "./backup-test".to_string(); | ||
397 | config | 402 | config |
398 | .directories | 403 | .directories |
399 | .push("u:fx/code/proj/arbs/backup-test-dir".to_string()); | 404 | .push(format!("r:{test_dir}")); |
400 | 405 | ||
401 | create_dir_all("./backup-test-dir")?; | 406 | create_dir_all("./backup-test-dir")?; |
402 | let mut f = File::create("./backup-test-dir/size.txt")?; | 407 | let mut f = File::create("./backup-test-dir/size.txt")?; |
@@ -414,17 +419,21 @@ mod tests { | |||
414 | let mut f = File::create("./backup-test-dir/content.txt")?; | 419 | let mut f = File::create("./backup-test-dir/content.txt")?; |
415 | f.write_all("unmodefied".as_bytes())?; | 420 | f.write_all("unmodefied".as_bytes())?; |
416 | 421 | ||
417 | let pi = PathInfo::from_path(&config, "u:fx/code/proj/arbs/backup-test-dir")?; | 422 | let pi = PathInfo::from_path(&config, format!("r:{test_dir}").as_str())?; |
423 | |||
424 | let nothing_full = format!("{test_dir}/nothing.txt"); | ||
425 | let nothing = ¬hing_full[1..nothing_full.len()]; | ||
418 | 426 | ||
419 | let last_backup = Backup::get_last(&config)?.unwrap(); | 427 | let last_backup = Backup::get_last(&config)?.unwrap(); |
420 | for file in pi.children { | 428 | for file in pi.children { |
421 | println!("test rel: {}", file.rel_location); | 429 | println!("test rel: {}", file.rel_location); |
422 | let res = if file.rel_location == "code/proj/arbs/backup-test-dir/nothing.txt" { | 430 | println!("nothing: {}", nothing); |
431 | let res = if file.rel_location == nothing { | ||
423 | Some(last_backup.id.clone()) | 432 | Some(last_backup.id.clone()) |
424 | } else { | 433 | } else { |
425 | None | 434 | None |
426 | }; | 435 | }; |
427 | println!("Testing {file:?}"); | 436 | // println!("Testing {file:?}"); |
428 | assert_eq!( | 437 | assert_eq!( |
429 | PathInfo::compare_to_last_modified( | 438 | PathInfo::compare_to_last_modified( |
430 | &config, | 439 | &config, |
@@ -433,7 +442,7 @@ mod tests { | |||
433 | )?, | 442 | )?, |
434 | res | 443 | res |
435 | ); | 444 | ); |
436 | println!("\x1B[FTesting {file:?} ✓"); | 445 | // println!("\x1B[FTesting {file:?} ✓"); |
437 | } | 446 | } |
438 | 447 | ||
439 | remove_dir_all("./backup-test-dir")?; | 448 | remove_dir_all("./backup-test-dir")?; |