Add new Package examples to main
Print debug line with module arguments when run starts Make apt package manager non-interactive Move PackageList to dedicated module and make more impls utils::Cmd now can take environment variables
This commit is contained in:
parent
f26f1c1bf2
commit
1245db813b
17
src/main.rs
17
src/main.rs
|
@ -44,12 +44,29 @@ fn main() -> Result<(), PlaybookError> {
|
|||
.build();
|
||||
playbook.run(cmd)?;
|
||||
|
||||
let pkg = Package::new()
|
||||
.name("hello")
|
||||
.state(PackageState::Present)
|
||||
.build();
|
||||
playbook.run(pkg)?;
|
||||
|
||||
let pkg = Package::new()
|
||||
.name("hello")
|
||||
.state(PackageState::Absent)
|
||||
.build();
|
||||
playbook.run(pkg)?;
|
||||
|
||||
let pkg = Package::new()
|
||||
.name(vec!("hello", "sl"))
|
||||
.state(PackageState::Present)
|
||||
.build();
|
||||
playbook.run(pkg)?;
|
||||
|
||||
let pkg = Package::new()
|
||||
.name(&[ "hello", "sl" ])
|
||||
.state(PackageState::Absent)
|
||||
.build();
|
||||
playbook.run(pkg)?;
|
||||
playbook.print_json_pretty();
|
||||
|
||||
Ok(())
|
||||
|
|
|
@ -79,6 +79,7 @@ impl PlaybookRun {
|
|||
|
||||
let module_name = cmd.module_name().to_string();
|
||||
let args = cmd.serialize_args();
|
||||
println!("Running module {} with args:{:#?}\n\n", &module_name, &args);
|
||||
|
||||
let res = cmd.run();
|
||||
|
||||
|
|
|
@ -2,6 +2,10 @@ use crate::utils::cmd::Cmd;
|
|||
|
||||
use super::{PackageError, PackageList, SpecificPackageManager};
|
||||
|
||||
pub fn apt() -> Cmd {
|
||||
Cmd::new("apt").env("DEBIAN_FRONTEND", "noninteractive")
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct DebianPackageManager;
|
||||
|
||||
|
@ -11,7 +15,7 @@ impl SpecificPackageManager for DebianPackageManager {
|
|||
}
|
||||
|
||||
fn update(&self) -> Result<(), PackageError> {
|
||||
let res = Cmd::new("apt").arg("update").run()?;
|
||||
let res = apt().arg("update").run()?;
|
||||
|
||||
if ! res.success {
|
||||
return Err(PackageError::CmdFail(res));
|
||||
|
@ -20,7 +24,7 @@ impl SpecificPackageManager for DebianPackageManager {
|
|||
}
|
||||
|
||||
fn install(&self, list: PackageList) -> Result<(), PackageError> {
|
||||
let res = Cmd::new("apt").arg("install").args(list.list()).run()?;
|
||||
let res = apt().arg("install").args(list.list()).run()?;
|
||||
|
||||
if ! res.success {
|
||||
return Err(PackageError::CmdFail(res));
|
||||
|
@ -29,7 +33,7 @@ impl SpecificPackageManager for DebianPackageManager {
|
|||
}
|
||||
|
||||
fn remove(&self, list: PackageList) -> Result<(), PackageError> {
|
||||
let res = Cmd::new("apt").arg("remove").args(list.list()).run()?;
|
||||
let res = apt().arg("remove").args(list.list()).run()?;
|
||||
|
||||
if ! res.success {
|
||||
return Err(PackageError::CmdFail(res));
|
||||
|
|
|
@ -1,110 +1,80 @@
|
|||
use serde::Serialize;
|
||||
|
||||
use crate::facts::{Facts, os::OsFamily};
|
||||
use crate::utils::cmd::CmdOutput;
|
||||
|
||||
use std::boxed::Box;
|
||||
|
||||
pub mod pacman;
|
||||
use pacman::ArchlinuxPackageManager;
|
||||
pub mod apt;
|
||||
use apt::DebianPackageManager;
|
||||
|
||||
pub mod builder;
|
||||
use builder::{NoPackage, PackageArgsBuilder};
|
||||
|
||||
#[derive(Clone, Debug, Serialize)]
|
||||
pub struct PackageArgs {
|
||||
name: PackageList,
|
||||
state: PackageState,
|
||||
pub struct PackageList {
|
||||
pub list: Vec<String>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize)]
|
||||
pub enum PackageState {
|
||||
Present,
|
||||
Absent,
|
||||
Latest,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct PackageModule<Manager> {
|
||||
manager: Manager,
|
||||
args: PackageArgs,
|
||||
}
|
||||
|
||||
impl<Manager> Module<PackageArgs, (), PackageError> for PackageModule<Manager> {
|
||||
fn clone_args(&self) -> PackageArgs {
|
||||
self.args.clone()
|
||||
impl PackageList {
|
||||
pub fn list(&self) -> & [ String ] {
|
||||
&self.list
|
||||
}
|
||||
|
||||
fn module_name() -> &'static str {
|
||||
"package"
|
||||
}
|
||||
}
|
||||
|
||||
impl Module<PackageArgs, (), PackageError> for PackageModule<Box<dyn SpecificPackageManager>> {
|
||||
fn run(&self) -> Result<(), PackageError> {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
pub fn add<T: IntoPackageList>(self, add: T) -> PackageList {
|
||||
let Self { mut list } = self;
|
||||
|
||||
let extend_with = add.into_package_list();
|
||||
list.extend(extend_with.list);
|
||||
|
||||
impl Module<PackageArgs, (), PackageError> for PackageModule<NoManager> {
|
||||
fn with_facts(self, facts: &Facts) -> PackageModule<Box<dyn SpecificPackageManager>> {
|
||||
let Self { args, .. } = self;
|
||||
|
||||
let manager = match facts.os.family() {
|
||||
OsFamily::Debian => Box::new(DebianPackageManager),
|
||||
OsFamily::Archlinux => Box::new(ArchlinuxPackageManager),
|
||||
};
|
||||
|
||||
PackageModule {
|
||||
args,
|
||||
manager,
|
||||
PackageList {
|
||||
list
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// 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 PackageModule {
|
||||
pub fn new() -> PackageArgsBuilder {
|
||||
PackageArgsBuilder::new()
|
||||
}
|
||||
|
||||
pub fn from_args_with_facts(args: PackageArgs, facts: &Facts) -> PackageModule {
|
||||
let manager = match facts.os.family() {
|
||||
OsFamily::Debian => PackageModule(Box::new(DebianPackageManager)),
|
||||
OsFamily::Archlinux => PackageModule(Box::new(ArchlinuxPackageManager)),
|
||||
};
|
||||
PackageModule {
|
||||
manager,
|
||||
args,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_args_with(args: PackageArgs, manager: SpecificPackageManager) -> PackageManager {
|
||||
PackageModule {
|
||||
manager: Box::new(manager),
|
||||
args,
|
||||
impl IntoPackageList for &str {
|
||||
fn into_package_list(self) -> PackageList {
|
||||
PackageList {
|
||||
list: vec!(self.to_string()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize)]
|
||||
pub enum PackageError {
|
||||
IoError(String),
|
||||
CmdFail(CmdOutput),
|
||||
}
|
||||
|
||||
impl From<std::io::Error> for PackageError {
|
||||
fn from(e: std::io::Error) -> PackageError {
|
||||
PackageError::IoError(e.to_string())
|
||||
impl IntoPackageList for String {
|
||||
fn into_package_list(self) -> PackageList {
|
||||
PackageList {
|
||||
list: vec!(self),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub trait SpecificPackageManager: std::fmt::Debug {
|
||||
fn name(&self) -> &'static str;
|
||||
fn update(&self) -> Result<(), PackageError>;
|
||||
fn install(&self, list: PackageList) -> Result<(), PackageError>;
|
||||
fn remove(&self, list: PackageList) -> Result<(), PackageError>;
|
||||
impl<const C: usize> IntoPackageList for & [ &str; C ] {
|
||||
fn into_package_list(self) -> PackageList {
|
||||
PackageList {
|
||||
list: self.iter().map(|x| x.to_string()).collect(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<const C: usize> IntoPackageList for & [ String; C ] {
|
||||
fn into_package_list(self) -> PackageList {
|
||||
PackageList {
|
||||
list: self.to_vec(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoPackageList for Vec<&str> {
|
||||
fn into_package_list(self) -> PackageList {
|
||||
PackageList {
|
||||
list: self.iter().map(|x| x.to_string()).collect(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoPackageList for Vec<String> {
|
||||
fn into_package_list(self) -> PackageList {
|
||||
PackageList {
|
||||
list: self,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,6 +6,9 @@ use crate::utils::cmd::CmdOutput;
|
|||
|
||||
use std::boxed::Box;
|
||||
|
||||
pub mod list;
|
||||
pub use list::{PackageList, IntoPackageList};
|
||||
|
||||
pub mod pacman;
|
||||
use pacman::ArchlinuxPackageManager;
|
||||
pub mod apt;
|
||||
|
@ -99,59 +102,4 @@ pub trait SpecificPackageManager: std::fmt::Debug {
|
|||
fn update(&self) -> Result<(), PackageError>;
|
||||
fn install(&self, list: PackageList) -> Result<(), PackageError>;
|
||||
fn remove(&self, list: PackageList) -> Result<(), PackageError>;
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize)]
|
||||
pub struct PackageList {
|
||||
pub list: Vec<String>,
|
||||
}
|
||||
|
||||
impl PackageList {
|
||||
pub fn list(&self) -> & [ String ] {
|
||||
&self.list
|
||||
}
|
||||
|
||||
pub fn add<T: IntoPackageList>(self, add: T) -> PackageList {
|
||||
let Self { mut list } = self;
|
||||
|
||||
let extend_with = add.into_package_list();
|
||||
list.extend(extend_with.list);
|
||||
|
||||
PackageList {
|
||||
list
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// 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 &str {
|
||||
fn into_package_list(self) -> PackageList {
|
||||
PackageList {
|
||||
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(),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -30,7 +30,7 @@ impl SpecificPackageManager for ArchlinuxPackageManager {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
fn remove(&self, _list: PackageList) -> Result<(), PackageError> {
|
||||
fn remove(&self, list: PackageList) -> Result<(), PackageError> {
|
||||
let res = Cmd::new("pacman").arg("-R").args(list.list()).run()?;
|
||||
|
||||
if ! res.success {
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
use duct::cmd as duct_cmd;
|
||||
|
||||
use std::collections::HashMap;
|
||||
use std::path::PathBuf;
|
||||
|
||||
#[derive(Clone, Debug, Serialize)]
|
||||
|
@ -8,6 +9,7 @@ pub struct Cmd {
|
|||
args: Vec<String>,
|
||||
stdin: Option<String>,
|
||||
chdir: Option<PathBuf>,
|
||||
env: HashMap<String, String>,
|
||||
}
|
||||
|
||||
impl Cmd {
|
||||
|
@ -17,11 +19,12 @@ impl Cmd {
|
|||
args: Vec::new(),
|
||||
stdin: None,
|
||||
chdir: None,
|
||||
env: HashMap::new(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn arg<T: AsRef<str>>(self, arg: T) -> Cmd {
|
||||
let Self { program, mut args, stdin, chdir, .. } = self;
|
||||
let Self { program, mut args, stdin, chdir, env, .. } = self;
|
||||
|
||||
args.push(arg.as_ref().to_string());
|
||||
|
||||
|
@ -30,12 +33,13 @@ impl Cmd {
|
|||
args,
|
||||
stdin,
|
||||
chdir,
|
||||
env,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn args<T: AsRef<str>>(self, new_args: & [ T ]) -> Cmd {
|
||||
|
||||
let Self { program, mut args, stdin, chdir, .. } = self;
|
||||
let Self { program, mut args, stdin, chdir, env, .. } = self;
|
||||
|
||||
for arg in new_args {
|
||||
args.push(arg.as_ref().to_string());
|
||||
|
@ -46,10 +50,12 @@ impl Cmd {
|
|||
args,
|
||||
stdin,
|
||||
chdir,
|
||||
} }
|
||||
env,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn stdin<T: AsRef<str>>(self, input: T) -> Cmd {
|
||||
let Self { program, args, mut stdin, chdir, .. } = self;
|
||||
let Self { program, args, mut stdin, chdir, env, .. } = self;
|
||||
|
||||
stdin = if let Some(mut s) = stdin {
|
||||
s.push_str(input.as_ref());
|
||||
|
@ -63,25 +69,47 @@ impl Cmd {
|
|||
args,
|
||||
stdin,
|
||||
chdir,
|
||||
env,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn chdir<T: AsRef<str>>(self, dir: T) -> Cmd {
|
||||
let Self { program, args, stdin, .. } = self;
|
||||
let Self { program, args, stdin, env, .. } = self;
|
||||
|
||||
Cmd {
|
||||
program,
|
||||
args,
|
||||
stdin,
|
||||
chdir: Some(PathBuf::from(dir.as_ref())),
|
||||
env,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn env<K: AsRef<str>, V: AsRef<str>>(self, key: K, value: V) -> Cmd {
|
||||
let Self { program, args, stdin, chdir, mut env, .. } = self;
|
||||
|
||||
env.insert(key.as_ref().to_string(), value.as_ref().to_string());
|
||||
|
||||
Cmd {
|
||||
program,
|
||||
args,
|
||||
stdin,
|
||||
chdir,
|
||||
env,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn run(self) -> Result<CmdOutput, std::io::Error> {
|
||||
let Self { program, args, stdin, chdir, .. } = self;
|
||||
let Self { program, args, stdin, chdir, env, .. } = self;
|
||||
|
||||
let mut cmd = duct_cmd(&program, &args);
|
||||
|
||||
if ! env.is_empty() {
|
||||
for (key, value) in env {
|
||||
cmd = cmd.env(key, value);
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(stdin) = &stdin {
|
||||
cmd = cmd.stdin_bytes(stdin.as_bytes());
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user