Add a yes argument for commands
This commit is contained in:
		
							
								
								
									
										68
									
								
								Cargo.lock
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										68
									
								
								Cargo.lock
									
									
									
										generated
									
									
									
								
							@@ -57,61 +57,6 @@ dependencies = [
 | 
			
		||||
 "os_str_bytes",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "darling"
 | 
			
		||||
version = "0.14.2"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "b0dd3cd20dc6b5a876612a6e5accfe7f3dd883db6d07acfbf14c128f61550dfa"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "darling_core",
 | 
			
		||||
 "darling_macro",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "darling_core"
 | 
			
		||||
version = "0.14.2"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "a784d2ccaf7c98501746bf0be29b2022ba41fd62a2e622af997a03e9f972859f"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "fnv",
 | 
			
		||||
 "ident_case",
 | 
			
		||||
 "proc-macro2",
 | 
			
		||||
 "quote",
 | 
			
		||||
 "syn",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "darling_macro"
 | 
			
		||||
version = "0.14.2"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "7618812407e9402654622dd402b0a89dff9ba93badd6540781526117b92aab7e"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "darling_core",
 | 
			
		||||
 "quote",
 | 
			
		||||
 "syn",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "enumset"
 | 
			
		||||
version = "1.0.12"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "19be8061a06ab6f3a6cf21106c873578bf01bd42ad15e0311a9c76161cb1c753"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "enumset_derive",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "enumset_derive"
 | 
			
		||||
version = "0.6.1"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "03e7b551eba279bf0fa88b83a46330168c1560a52a94f5126f892f0b364ab3e0"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "darling",
 | 
			
		||||
 "proc-macro2",
 | 
			
		||||
 "quote",
 | 
			
		||||
 "syn",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "errno"
 | 
			
		||||
version = "0.2.8"
 | 
			
		||||
@@ -133,12 +78,6 @@ dependencies = [
 | 
			
		||||
 "libc",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "fnv"
 | 
			
		||||
version = "1.0.7"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "hashbrown"
 | 
			
		||||
version = "0.12.3"
 | 
			
		||||
@@ -160,12 +99,6 @@ dependencies = [
 | 
			
		||||
 "libc",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "ident_case"
 | 
			
		||||
version = "1.0.1"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39"
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "indexmap"
 | 
			
		||||
version = "1.9.2"
 | 
			
		||||
@@ -345,7 +278,6 @@ name = "system-updater"
 | 
			
		||||
version = "0.1.0"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "clap",
 | 
			
		||||
 "enumset",
 | 
			
		||||
 "serde",
 | 
			
		||||
 "serde_yaml",
 | 
			
		||||
]
 | 
			
		||||
 
 | 
			
		||||
@@ -11,6 +11,5 @@ name = "sup"
 | 
			
		||||
 | 
			
		||||
[dependencies]
 | 
			
		||||
clap = { version = "4.1", features = ["derive"] }
 | 
			
		||||
enumset = { version = "1.0" , feature = ["serde"] }
 | 
			
		||||
serde = { version = "1.0", features = ["derive"] }
 | 
			
		||||
serde_yaml = "0.9"
 | 
			
		||||
 
 | 
			
		||||
@@ -28,5 +28,4 @@ systems:
 | 
			
		||||
    - -a
 | 
			
		||||
    current_dir: null
 | 
			
		||||
    env: {}
 | 
			
		||||
steps: Install
 | 
			
		||||
nice: null
 | 
			
		||||
 
 | 
			
		||||
@@ -27,4 +27,3 @@ systems:
 | 
			
		||||
    - -a
 | 
			
		||||
    current_dir: null
 | 
			
		||||
    env: {}
 | 
			
		||||
steps: Install
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										135
									
								
								src/command.rs
									
									
									
									
									
								
							
							
						
						
									
										135
									
								
								src/command.rs
									
									
									
									
									
								
							@@ -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 user’s 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. ")
 | 
			
		||||
        }
 | 
			
		||||
 
 | 
			
		||||
@@ -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) {
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user