Skip to content
This repository was archived by the owner on Oct 1, 2025. It is now read-only.

Commit cc0f0a3

Browse files
committed
wip
1 parent 73f250d commit cc0f0a3

File tree

8 files changed

+280
-44
lines changed

8 files changed

+280
-44
lines changed

src/experiments/coreutils.rs

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -18,14 +18,11 @@ impl Experiment for RustCoreutils {
1818
}
1919

2020
fn check_compatible(&self) -> bool {
21-
match self.system.distribution() {
22-
Ok(d) => d.release.as_str() >= FIRST_SUPPORTED_RELEASE,
23-
Err(_) => false,
24-
}
21+
self.system.distribution().release.as_str() >= FIRST_SUPPORTED_RELEASE
2522
}
2623

2724
fn check_installed(&self) -> bool {
28-
self.system.check_installed(PACKAGE).unwrap_or_default()
25+
self.system.check_installed(PACKAGE).unwrap_or(false)
2926
}
3027

3128
fn enable(&self) -> Result<()> {
@@ -38,7 +35,9 @@ impl Experiment for RustCoreutils {
3835

3936
self.system.install_package(PACKAGE)?;
4037

41-
let files = self.system.list_files("/usr/lib/cargo/bin/coreutils")?;
38+
let files = self
39+
.system
40+
.list_files(PathBuf::from("/usr/lib/cargo/bin/coreutils"))?;
4241

4342
for f in files {
4443
let filename = f.file_name().unwrap();
@@ -57,7 +56,9 @@ impl Experiment for RustCoreutils {
5756

5857
info!("Removing {}", PACKAGE);
5958

60-
let files = self.system.list_files("/usr/lib/cargo/bin/coreutils")?;
59+
let files = self
60+
.system
61+
.list_files(PathBuf::from("/usr/lib/cargo/bin/coreutils"))?;
6162

6263
for f in files {
6364
let filename = f.file_name().unwrap();

src/experiments/diffutils.rs

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -17,14 +17,11 @@ impl Experiment for RustDiffutils {
1717
}
1818

1919
fn check_compatible(&self) -> bool {
20-
match self.system.distribution() {
21-
Ok(d) => d.release.as_str() >= FIRST_SUPPORTED_RELEASE,
22-
Err(_) => false,
23-
}
20+
self.system.distribution().release.as_str() >= FIRST_SUPPORTED_RELEASE
2421
}
2522

2623
fn check_installed(&self) -> bool {
27-
self.system.check_installed(PACKAGE).unwrap_or_default()
24+
self.system.check_installed(PACKAGE).unwrap_or(false)
2825
}
2926

3027
fn enable(&self) -> Result<()> {
@@ -37,7 +34,9 @@ impl Experiment for RustDiffutils {
3734

3835
self.system.install_package(PACKAGE)?;
3936

40-
let files = self.system.list_files("/usr/lib/cargo/bin/diffutils")?;
37+
let files = self
38+
.system
39+
.list_files(PathBuf::from("/usr/lib/cargo/bin/diffutils"))?;
4140

4241
for f in files {
4342
let filename = f.file_name().unwrap();
@@ -48,14 +47,16 @@ impl Experiment for RustDiffutils {
4847
}
4948

5049
fn disable(&self) -> Result<()> {
51-
if !self.check_installed() || !self.check_compatible() {
50+
if !self.check_installed() {
5251
warn!("{PACKAGE} not found, skipping restore");
5352
return Ok(());
5453
}
5554

5655
info!("Removing {}", PACKAGE);
5756

58-
let files = self.system.list_files("/usr/lib/cargo/bin/diffutils")?;
57+
let files = self
58+
.system
59+
.list_files(PathBuf::from("/usr/lib/cargo/bin/diffutils"))?;
5960

6061
for f in files {
6162
let filename = f.file_name().unwrap();

src/experiments/findutils.rs

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -18,14 +18,11 @@ impl Experiment for RustFindutils {
1818
}
1919

2020
fn check_compatible(&self) -> bool {
21-
match self.system.distribution() {
22-
Ok(d) => d.release.as_str() >= FIRST_SUPPORTED_RELEASE,
23-
Err(_) => false,
24-
}
21+
self.system.distribution().release.as_str() >= FIRST_SUPPORTED_RELEASE
2522
}
2623

2724
fn check_installed(&self) -> bool {
28-
self.system.check_installed(PACKAGE).unwrap_or_default()
25+
self.system.check_installed(PACKAGE).unwrap_or(false)
2926
}
3027

3128
fn enable(&self) -> Result<()> {
@@ -38,7 +35,9 @@ impl Experiment for RustFindutils {
3835

3936
self.system.install_package(PACKAGE)?;
4037

41-
let files = self.system.list_files("/usr/lib/cargo/bin/findutils")?;
38+
let files = self
39+
.system
40+
.list_files(PathBuf::from("/usr/lib/cargo/bin/findutils"))?;
4241

4342
for f in files {
4443
let filename = f.file_name().unwrap();
@@ -49,14 +48,16 @@ impl Experiment for RustFindutils {
4948
}
5049

5150
fn disable(&self) -> Result<()> {
52-
if !self.check_installed() || !self.check_compatible() {
51+
if !self.check_installed() {
5352
warn!("{PACKAGE} not found, skipping restore");
5453
return Ok(());
5554
}
5655

5756
info!("Removing {}", PACKAGE);
5857

59-
let files = self.system.list_files("/usr/lib/cargo/bin/findutils")?;
58+
let files = self
59+
.system
60+
.list_files(PathBuf::from("/usr/lib/cargo/bin/findutils"))?;
6061

6162
for f in files {
6263
let filename = f.file_name().unwrap();

src/experiments/generic.rs

Lines changed: 204 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,204 @@
1+
use crate::utils::Worker;
2+
use anyhow::Result;
3+
use std::{path::PathBuf, sync::Arc};
4+
use tracing::{info, warn};
5+
6+
use super::NewExperiment;
7+
8+
pub struct UutilsExperiment {
9+
system: Arc<dyn Worker>,
10+
package: String,
11+
first_supported_release: String,
12+
unified_binary: Option<PathBuf>,
13+
bin_directory: PathBuf,
14+
}
15+
16+
impl UutilsExperiment {
17+
pub fn new(
18+
system: Arc<dyn Worker>,
19+
package: &str,
20+
first_supported_release: &str,
21+
unified_binary: Option<PathBuf>,
22+
bin_directory: PathBuf,
23+
) -> Self {
24+
Self {
25+
system,
26+
package: package.to_string(),
27+
first_supported_release: first_supported_release.to_string(),
28+
unified_binary,
29+
bin_directory,
30+
}
31+
}
32+
}
33+
34+
impl NewExperiment for UutilsExperiment {
35+
fn check_compatible(&self) -> bool {
36+
self.system.distribution().release >= self.first_supported_release
37+
}
38+
39+
fn check_installed(&self) -> bool {
40+
self.system.check_installed(&self.package).unwrap_or(false)
41+
}
42+
43+
fn enable(&self) -> Result<()> {
44+
if !self.check_compatible() {
45+
warn!(
46+
"Skipping '{}'. Minimum supported release is {}.",
47+
self.package, self.first_supported_release
48+
);
49+
return Ok(());
50+
}
51+
52+
info!("Installing and configuring {}", self.package);
53+
54+
self.system.install_package(&self.package)?;
55+
56+
let files = self.system.list_files(self.bin_directory.clone())?;
57+
58+
for f in files {
59+
let filename = f.file_name().unwrap();
60+
let existing = PathBuf::from("/usr/bin").join(filename);
61+
62+
if let Some(unified_binary) = &self.unified_binary {
63+
self.system
64+
.replace_file_with_symlink(unified_binary.to_path_buf(), existing.clone())?;
65+
} else {
66+
self.system.replace_file_with_symlink(f, existing)?;
67+
}
68+
}
69+
Ok(())
70+
}
71+
72+
fn disable(&self) -> Result<()> {
73+
if !self.check_installed() {
74+
warn!("{} not found, skipping restore", self.package);
75+
return Ok(());
76+
}
77+
78+
info!("Removing {}", self.package);
79+
80+
let files = self.system.list_files(self.bin_directory.clone())?;
81+
82+
for f in files {
83+
let filename = f.file_name().unwrap();
84+
let existing = PathBuf::from("/usr/bin").join(filename);
85+
self.system.restore_file(existing)?;
86+
}
87+
88+
self.system.remove_package(&self.package)?;
89+
90+
Ok(())
91+
}
92+
}
93+
94+
// #[cfg(test)]
95+
// mod tests {
96+
// use super::*;
97+
// use crate::utils::{Distribution, MockSystem};
98+
99+
// #[test]
100+
// fn test_incompatible_distribution() -> Result<()> {
101+
// let runner = Arc::new(MockSystem::new());
102+
103+
// runner.mock_distribution(Distribution {
104+
// id: "Ubuntu".to_string(),
105+
// release: "20.04".to_string(),
106+
// });
107+
108+
// let coreutils = RustCoreutils::new(runner.clone());
109+
// assert!(!coreutils.check_compatible());
110+
// coreutils.enable()?;
111+
112+
// assert_eq!(runner.commands.clone().into_inner().len(), 0);
113+
// assert_eq!(runner.created_symlinks.clone().into_inner().len(), 0);
114+
// assert_eq!(runner.backed_up_files.clone().into_inner().len(), 0);
115+
// assert_eq!(runner.restored_files.clone().into_inner().len(), 0);
116+
117+
// Ok(())
118+
// }
119+
120+
// #[test]
121+
// fn test_coreutils_install_success() -> Result<()> {
122+
// let runner = Arc::new(MockSystem::new());
123+
// runner.mock_files(vec![
124+
// ("/usr/lib/cargo/bin/coreutils/date", ""),
125+
// ("/usr/lib/cargo/bin/coreutils/sort", ""),
126+
// ("/usr/bin/sort", ""),
127+
// ("/usr/bin/date", ""),
128+
// ]);
129+
130+
// let coreutils = RustCoreutils::new(runner.clone());
131+
// assert!(coreutils.enable().is_ok());
132+
133+
// let commands = runner.commands.clone().into_inner();
134+
// assert_eq!(commands.len(), 1);
135+
// assert!(commands.contains(&"apt-get install -y rust-coreutils".to_string()));
136+
137+
// let backed_up_files = runner.backed_up_files.clone().into_inner();
138+
// let expected = ["/usr/bin/date", "/usr/bin/sort"];
139+
// assert_eq!(backed_up_files.len(), 2);
140+
// backed_up_files
141+
// .iter()
142+
// .for_each(|f| assert!(expected.contains(&f.as_str())));
143+
144+
// let created_symlinks = runner.created_symlinks.clone().into_inner();
145+
// let expected = [
146+
// ("/usr/bin/coreutils", "/usr/bin/sort"),
147+
// ("/usr/bin/coreutils", "/usr/bin/date"),
148+
// ];
149+
// assert!(created_symlinks.len() == 2);
150+
// created_symlinks
151+
// .iter()
152+
// .for_each(|(from, to)| assert!(expected.contains(&(from.as_str(), to.as_str()))));
153+
154+
// assert_eq!(runner.restored_files.clone().into_inner().len(), 0);
155+
156+
// Ok(())
157+
// }
158+
159+
// #[test]
160+
// fn test_restore_not_installed() -> Result<()> {
161+
// let runner = Arc::new(MockSystem::new());
162+
// let coreutils = RustCoreutils::new(runner.clone());
163+
164+
// coreutils.disable()?;
165+
166+
// assert_eq!(runner.commands.clone().into_inner().len(), 0);
167+
// assert_eq!(runner.created_symlinks.clone().into_inner().len(), 0);
168+
// assert_eq!(runner.backed_up_files.clone().into_inner().len(), 0);
169+
// assert_eq!(runner.restored_files.clone().into_inner().len(), 0);
170+
171+
// Ok(())
172+
// }
173+
174+
// #[test]
175+
// fn test_restore_installed() -> Result<()> {
176+
// let runner = Arc::new(MockSystem::new());
177+
// runner.mock_install_package(self.package);
178+
// runner.mock_files(vec![
179+
// ("/usr/lib/cargo/bin/coreutils/date", ""),
180+
// ("/usr/lib/cargo/bin/coreutils/sort", ""),
181+
// ("/usr/bin/sort", ""),
182+
// ("/usr/bin/date", ""),
183+
// ]);
184+
185+
// let coreutils = RustCoreutils::new(runner.clone());
186+
// assert!(coreutils.disable().is_ok());
187+
188+
// assert_eq!(runner.created_symlinks.clone().into_inner().len(), 0);
189+
// assert_eq!(runner.backed_up_files.clone().into_inner().len(), 0);
190+
191+
// let commands = runner.commands.clone().into_inner();
192+
// assert_eq!(commands.len(), 1);
193+
// assert!(commands.contains(&"apt-get remove -y rust-coreutils".to_string()));
194+
195+
// let restored_files = runner.restored_files.clone().into_inner();
196+
// let expected = ["/usr/bin/date", "/usr/bin/sort"];
197+
// assert_eq!(restored_files.len(), 2);
198+
// restored_files
199+
// .iter()
200+
// .for_each(|f| assert!(expected.contains(&f.as_str())));
201+
202+
// Ok(())
203+
// }
204+
// }

src/experiments/mod.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,14 @@
11
mod coreutils;
22
mod diffutils;
33
mod findutils;
4+
mod generic;
45

56
use std::sync::Arc;
67

78
pub use coreutils::RustCoreutils;
89
pub use diffutils::RustDiffutils;
910
pub use findutils::RustFindutils;
11+
pub use generic::UutilsExperiment;
1012

1113
use anyhow::Result;
1214

@@ -22,6 +24,13 @@ pub trait Experiment {
2224
fn check_installed(&self) -> bool;
2325
fn check_compatible(&self) -> bool;
2426
}
27+
pub trait NewExperiment {
28+
fn enable(&self) -> Result<()>;
29+
fn disable(&self) -> Result<()>;
30+
31+
fn check_installed(&self) -> bool;
32+
fn check_compatible(&self) -> bool;
33+
}
2534

2635
pub fn all_experiments(system: Arc<dyn Worker>) -> Vec<(String, Box<dyn Experiment>)> {
2736
vec![

src/main.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -93,11 +93,11 @@ fn main() -> Result<()> {
9393
.with(fmt::layer().compact().with_target(false))
9494
.init();
9595

96-
let system = Arc::new(System {});
96+
let system = Arc::new(System::new()?);
9797
let selected_experiments = enabled_experiments(system.clone(), args.experiments);
9898

9999
anyhow::ensure!(
100-
system.distribution()?.id == "Ubuntu",
100+
system.distribution().id == "Ubuntu",
101101
"This program only supports Ubuntu"
102102
);
103103

0 commit comments

Comments
 (0)