diff --git a/src/main.rs b/src/main.rs index 41ffebf..2732bd9 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,7 +1,30 @@ use rustible::Facts; -use rustible::modules::{PlaybookRun, Module, Command}; -fn main() -> Result<(), rustible::modules::command::CommandError> { +use rustible::modules::{ + Module, PlaybookRun, + package::{PackageModule as Package, PackageState, PackageError}, + command::{CommandModule as Command, CommandError}, +}; + +#[derive(Clone, Debug, serde::Serialize)] +pub enum PlaybookError { + Command(CommandError), + Package(PackageError), +} + +impl From for PlaybookError { + fn from(e: CommandError) -> PlaybookError { + PlaybookError::Command(e) + } +} + +impl From for PlaybookError { + fn from(e: PackageError) -> PlaybookError { + PlaybookError::Package(e) + } +} + +fn main() -> Result<(), PlaybookError> { let facts = Facts::new(); println!("Hello, world! Running system {}", facts.os.family().as_str()); @@ -20,7 +43,12 @@ fn main() -> Result<(), rustible::modules::command::CommandError> { .arg("/tmp/lol") .build(); playbook.run(cmd)?; - //let res = cmd.run + + let pkg = Package::new() + .name("hello") + .state(PackageState::Absent) + .build(); + playbook.run(pkg)?; playbook.print_json_pretty(); diff --git a/src/modules/mod.rs b/src/modules/mod.rs index 0be72f4..9d68e5c 100644 --- a/src/modules/mod.rs +++ b/src/modules/mod.rs @@ -129,4 +129,4 @@ pub trait Module { /// Declare module types pub use command::CommandModule as Command; - +pub use package::{PackageModule as Package, PackageState}; diff --git a/src/modules/package/apt.rs b/src/modules/package/apt.rs index 0fed83f..4a476c9 100644 --- a/src/modules/package/apt.rs +++ b/src/modules/package/apt.rs @@ -28,7 +28,12 @@ impl SpecificPackageManager for DebianPackageManager { Ok(()) } - fn remove(&self, _list: PackageList) -> Result<(), PackageError> { - todo!() + fn remove(&self, list: PackageList) -> Result<(), PackageError> { + let res = Cmd::new("apt").arg("remove").args(list.list()).run()?; + + if ! res.success { + return Err(PackageError::CmdFail(res)); + } + Ok(()) } } diff --git a/src/modules/package/builder.rs b/src/modules/package/builder.rs index 8a33a32..4e39fb3 100644 --- a/src/modules/package/builder.rs +++ b/src/modules/package/builder.rs @@ -101,3 +101,17 @@ impl PackageArgsBuilder { + pub fn build(self) -> PackageModule { + let Self { name, state, .. } = self; + + PackageModule { + args: PackageArgs { + name, + state, + }, + manager: NoManager, + } + } +} diff --git a/src/modules/package/mod.rs b/src/modules/package/mod.rs index 202f442..5b769d5 100644 --- a/src/modules/package/mod.rs +++ b/src/modules/package/mod.rs @@ -12,7 +12,7 @@ pub mod apt; use apt::DebianPackageManager; pub mod builder; -pub use builder::PackageArgsBuilder; +pub use builder::{PackageArgsBuilder, NoManager}; pub type PackageStatus = (); @@ -35,10 +35,6 @@ pub struct PackageModule { args: PackageArgs, } - -#[derive(Debug)] -pub struct NoManager; - impl Module for PackageModule> { fn serialize_args(&self) -> serde_json::Value { serde_json::to_value(&self.args).unwrap() @@ -49,7 +45,17 @@ impl Module for PackageModule Result<(), PackageError> { - Ok(()) + let packages = self.args.name; + + match &self.args.state { + PackageState::Present => { + self.manager.install(packages) + }, PackageState::Absent => { + self.manager.remove(packages) + }, PackageState::Latest => { + unimplemented!() + } + } } } @@ -117,15 +123,35 @@ impl PackageList { } } +/// Turn a stringy value or list of values into an actual package list. +/// Only implemented for &str and &str/String slices because apparently +/// there may be a future implementation that turns a slice of stringy values +/// into a stringy value, resulting in conflicting implementations. +/// https://stackoverflow.com/questions/63136970/how-do-i-work-around-the-upstream-crates-may-add-a-new-impl-of-trait-error pub trait IntoPackageList { fn into_package_list(self) -> PackageList; } -impl >> IntoPackageList for T { +impl IntoPackageList for &str { fn into_package_list(self) -> PackageList { PackageList { - list: self.into() + list: vec!(self.to_string()), } } } +impl IntoPackageList for & [ &str ] { + fn into_package_list(self) -> PackageList { + PackageList { + list: self.iter().map(|x| x.to_string()).collect(), + } + } +} + +impl IntoPackageList for & [ String ] { + fn into_package_list(self) -> PackageList { + PackageList { + list: self.to_vec(), + } + } +} diff --git a/src/modules/package/pacman.rs b/src/modules/package/pacman.rs index 20c5986..85651d2 100644 --- a/src/modules/package/pacman.rs +++ b/src/modules/package/pacman.rs @@ -31,6 +31,12 @@ impl SpecificPackageManager for ArchlinuxPackageManager { } fn remove(&self, _list: PackageList) -> Result<(), PackageError> { - todo!() + let res = Cmd::new("pacman").arg("-R").args(list.list()).run()?; + + if ! res.success { + return Err(PackageError::CmdFail(res)); + } + + Ok(()) } }