diff --git a/examples/flatpack.yaml b/examples/flatpack.yaml index 10aa2f5..c9c5862 100644 --- a/examples/flatpack.yaml +++ b/examples/flatpack.yaml @@ -1,17 +1,9 @@ packages: - name: Flatpack - fetch: - - exe: flatpak - params: - - update - - --no-deploy - - --assumeyes - - --noninteractive install: exe: flatpak params: - update - - --no-pull - --assumeyes - --noninteractive post-install: diff --git a/src/command.rs b/src/command.rs index 9372d3b..7e6b564 100644 --- a/src/command.rs +++ b/src/command.rs @@ -1,6 +1,6 @@ use crate::*; use serde::{Deserialize, Serialize}; -use std::collections::HashMap; +use std::collections::BTreeMap; use std::io::Write; use std::path::PathBuf; use std::process::{Command, ExitStatus, Stdio}; @@ -14,17 +14,25 @@ enum UpdateSteps { PostInstall, } +// TODO: change the struct’s names for the `topgrade`’s one. They are much better. + +/// Root of the machine’s dependency graph #[derive(Debug, Serialize, Deserialize)] pub struct Updater { - pub systems: Vec, + pub systems: BTreeMap, } +/// A list of equivalent executors that will update a given component +/// +/// Example: the `system` one will try to do update the system for as if it is Debian with `apt update`, if it fails it will try for openSUSE with `zypper refresh`, … +/// The step will be considered a succes if **any** executor succeed and will skip all the other ones. #[derive(Debug, Serialize, Deserialize)] pub struct System { packages: Vec, // TODO: => make a system dependend on another? This will allow to give a "Rust" config which update "rustup", and a custom "git helix" could then be executed after (with the updated toolchain, and NOT concurrently) } +/// All the infos for an executor to proceed until completion #[derive(Debug, Serialize, Deserialize)] pub struct Package { pub name: String, @@ -36,20 +44,22 @@ pub struct Package { // exclusive_with : List } +/// A command to execute on the system as part of an executor #[derive(Debug, Clone, Serialize, Deserialize)] struct Cmd { exe: String, params: Option>, current_dir: Option, - env: Option>, + env: Option>, } +/// The actual (cleaned) command that will be executed on the system as part of an executor #[derive(Debug, Clone, Serialize, Deserialize)] pub(crate) struct ActualCmd { exe: String, params: Vec, current_dir: Option, - env: HashMap, + env: BTreeMap, } // QUESTION: Would String be less awkward? @@ -94,10 +104,12 @@ pub fn get_packages_folder(opt: &Opt) -> io::Result { impl Updater { fn new() -> Updater { - Updater { systems: vec![] } + Updater { + systems: BTreeMap::from([(String::new(), System { packages: vec![] })]), + } } - // /// To create a sample config from code + /// To create a sample config from code #[doc(hidden)] fn write_config(&self, opt: &Opt) { use std::fs::OpenOptions; @@ -123,9 +135,15 @@ impl Updater { // Example to generate a config file if false { - updater.systems.push(System { packages: vec![] }); + updater + .systems + .insert("Test".to_owned(), System { packages: vec![] }); + let sys = updater + .systems + .get_mut("Test") + .expect("We just created the key"); - updater.systems[0].packages.push(Package { + sys.packages.push(Package { name: "Rustup".to_owned(), fetch: None, compile: None, @@ -138,7 +156,7 @@ impl Updater { post_install: None, }); - updater.systems[0].packages.push(Package { + sys.packages.push(Package { name: "Cargo".to_owned(), fetch: None, compile: None, @@ -171,7 +189,16 @@ impl Updater { Err(e) => return Err(e), } - for file in packages_folder.read_dir()? { + for file in packages_folder.read_dir()?.filter(|name| match name { + Ok(n) => { + if n.file_name().into_string().unwrap().ends_with(".yaml") { + true + } else { + false + } + } + Err(..) => false, + }) { let file = packages_folder.join(file?.path()); // "default.yaml"); let sys = std::fs::read_to_string(&file).unwrap(); let sys = serde_yaml::from_str(&sys).map_err(|err| { @@ -184,7 +211,9 @@ impl Updater { ), ) })?; - updater.systems.push(sys); + updater + .systems + .insert(file.file_stem().unwrap().to_str().unwrap().to_owned(), sys); } // eprintln!("{:#?}", updater); @@ -196,7 +225,7 @@ impl Updater { let mut status: Vec<_> = vec![]; // XXX: We may parallelise (iter_par from rayon?) this loop. But the UI will be problematic to handle - for sys in &self.systems { + for (_sys_name, sys) in &self.systems { for pkg in &sys.packages { status.push((pkg.name.clone(), self.update(&pkg, opt).into())); } @@ -328,7 +357,7 @@ impl Cmd { // This means I need to know how to know which values to pass for (at least) rustup & cargo let env = match self.env { Some(env) => env, - None => HashMap::from([("PATH".to_owned(), std::env!("PATH").to_owned())]), + None => BTreeMap::default(), }; ActualCmd { @@ -350,7 +379,9 @@ impl ActualCmd { cmd.current_dir(std::fs::canonicalize(cdir)?); } - print!("Executing: {}", self); + println!(); + println!("*** Executing: {} ***", self); + // eprintln!("{:?}", self.params); if opt.quiet { // FIXME: stdin does not work with sudo? @@ -370,7 +401,7 @@ impl fmt::Display for ActualCmd { } else { self.exe.clone() }; - write!(f, "`{}`", command)?; + write!(f, "{}", command)?; if let Some(cdir) = &self.current_dir { write!(f, " in {:?}", cdir)?; diff --git a/src/lib.rs b/src/lib.rs index fb03103..1f2e34a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -55,7 +55,8 @@ pub struct Summary { impl Display for Summary { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - writeln!(f, "Summary:")?; + writeln!(f, "")?; + writeln!(f, "*** Summary: ***")?; for (name, status) in &self.status { // TODO: also print version before/after, update time