Add a yes argument for commands

This commit is contained in:
Zykino
2023-01-15 23:59:30 +01:00
parent 976fd7bd96
commit 10496f75db
6 changed files with 103 additions and 105 deletions

View File

@ -1,5 +1,4 @@
use crate::*;
use enumset::EnumSetType;
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use std::fmt;
@ -7,8 +6,7 @@ use std::io::{stdout, Write};
use std::path::PathBuf;
use std::process::Command;
#[derive(Debug, Serialize, Deserialize, EnumSetType)]
//#[enumset(serialize_as_list)] // TODO: use it or not?
#[derive(Debug, Serialize, Deserialize, PartialEq)]
enum UpdateSteps {
Fetch,
Compile,
@ -18,7 +16,6 @@ enum UpdateSteps {
#[derive(Debug, Serialize, Deserialize)]
pub struct Updater {
systems: Vec<System>,
steps: UpdateSteps,
}
#[derive(Debug, Serialize, Deserialize)]
@ -31,20 +28,52 @@ pub struct System {
// exclusive_with : List
}
#[derive(Debug, Serialize, Deserialize)]
#[derive(Debug, Serialize, Deserialize, Clone)]
struct Cmd {
exe: String,
params: Vec<String>,
yes: Option<String>,
current_dir: Option<PathBuf>,
env: HashMap<String, String>,
}
#[derive(Debug, Serialize, Deserialize)]
struct ActualCmd {
exe: String,
params: Vec<String>,
current_dir: Option<PathBuf>,
env: HashMap<String, String>,
}
// QUESTION: Would String be less awkward?
impl From<&str> for UpdateSteps {
fn from(value: &str) -> Self {
match &*value.to_lowercase() {
"fetch" => UpdateSteps::Fetch,
"compile" => UpdateSteps::Compile,
"install" => UpdateSteps::Install,
_ => panic!("Step {} not recognized", value),
}
}
}
// QUESTION: Would String be less awkward?
impl From<&String> for UpdateSteps {
fn from(value: &String) -> Self {
match &*value.to_lowercase() {
"fetch" => UpdateSteps::Fetch,
"compile" => UpdateSteps::Compile,
"install" => UpdateSteps::Install,
_ => panic!("Step {} not recognized", value),
}
}
}
impl Updater {
fn new() -> Updater {
let mut up = Updater {
systems: vec![],
steps: UpdateSteps::Fetch,
};
let mut up = Updater { systems: vec![] };
up.systems.push(System {
fetch: None,
compile: None,
@ -78,13 +107,18 @@ impl Updater {
}
pub fn update_all(&self, opt: &Opt) -> Result<()> {
let mut errors = vec![];
for sys in &self.systems {
if let Err(err) = self.update(sys, opt) {
eprintln!("Error catched {}", err);
errors.push(err);
}
}
let errors: Vec<_> = self
.systems
.iter()
.filter_map(|sys| {
if let Err(err) = self.update(sys, opt) {
eprintln!("Error catched {}", err);
Some(err)
} else {
None
}
})
.collect();
// TODO:
if errors.len() == 0 {
@ -98,13 +132,22 @@ impl Updater {
}
fn update(&self, sys: &System, opt: &Opt) -> Result<()> {
if self.steps == UpdateSteps::Fetch {
let steps = match &opt.steps {
Some(v) => v.iter().map(|u| u.into()).collect(),
None => vec![
UpdateSteps::Fetch,
UpdateSteps::Compile,
UpdateSteps::Install,
],
};
if steps.contains(&UpdateSteps::Fetch) {
sys.fetch(opt)?;
}
if self.steps == UpdateSteps::Compile {
if steps.contains(&UpdateSteps::Compile) {
sys.compile(opt)?;
}
if self.steps == UpdateSteps::Install {
if steps.contains(&UpdateSteps::Install) {
sys.install(opt)?;
}
@ -115,20 +158,20 @@ impl Updater {
impl System {
pub fn fetch(&self, opt: &Opt) -> Result<()> {
if let Some(fetch) = &self.fetch {
fetch.execute(opt)?;
fetch.clone().prepare(opt).execute(&opt)?;
}
Ok(())
}
pub fn compile(&self, opt: &Opt) -> Result<()> {
if let Some(compile) = &self.compile {
compile.execute(opt)?;
compile.clone().prepare(opt).execute(opt)?;
}
Ok(())
}
pub fn install(&self, opt: &Opt) -> Result<()> {
self.install.execute(opt)?;
self.install.clone().prepare(opt).execute(opt)?;
Ok(())
}
}
@ -138,16 +181,40 @@ impl Cmd {
Cmd {
exe: "".into(),
params: vec![],
yes: None,
current_dir: None,
env: HashMap::new(),
}
}
fn execute(&self, opt: &Opt) -> Result<()> {
fn prepare(self, opt: &Opt) -> ActualCmd {
let mut params = self.params;
if opt.yes {
if let Some(y) = &self.yes {
params.push(y.to_owned());
}
};
let mut env = self.env;
if !env.contains_key("PATH") {
env.insert("PATH".to_owned(), std::env!("PATH").to_owned());
}
ActualCmd {
exe: self.exe,
params,
current_dir: self.current_dir,
env,
}
}
}
impl ActualCmd {
fn execute(&self, opt: &Opt) -> Result<bool> {
let mut cmd = Command::new(&self.exe);
cmd.args(&self.params)
.env_clear()
.env("PATH", std::env!("PATH"))
.envs(&self.env)
// .stdout(cfg)
// .stderr(cfg)
@ -170,20 +237,20 @@ impl Cmd {
.expect("Unable to read users input");
}
if !yes_no.to_lowercase().starts_with('n') {
if cmd.status().unwrap().success() {
eprintln!("Youpi !");
// Other checks?
} else {
eprintln!("Error executing the command")
}
if yes_no.to_lowercase().starts_with('n') {
eprintln!(
"yes_no? {} {}",
yes_no,
yes_no.to_lowercase().starts_with('n')
);
return Ok(false);
}
Ok(())
Ok(cmd.status().unwrap().success())
}
}
impl fmt::Display for Cmd {
impl fmt::Display for ActualCmd {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let command = if !self.params.is_empty() {
format!("{} {}", &self.exe, &self.params.join(" "))
@ -198,7 +265,7 @@ impl fmt::Display for Cmd {
if !self.env.is_empty() {
writeln!(f, " with the following environment variable:")?;
writeln!(f, "{:?}", self.env)
writeln!(f, "{:#?}", self.env)
} else {
write!(f, " without any environment variable. ")
}

View File

@ -26,6 +26,8 @@ pub struct Opt {
#[arg(short)]
pub yes: bool,
//pub quiet: bool, // imply yes
#[arg(short, long)]
pub steps: Option<Vec<String>>,
}
pub fn run(opt: &Opt) {