Add a visual separation between commands and for the summary
This commit is contained in:
		@@ -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:
 | 
			
		||||
 
 | 
			
		||||
@@ -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<System>,
 | 
			
		||||
    pub systems: BTreeMap<String, System>,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// 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<Package>,
 | 
			
		||||
    // 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<Vec<String>>,
 | 
			
		||||
    current_dir: Option<PathBuf>,
 | 
			
		||||
    env: Option<HashMap<String, String>>,
 | 
			
		||||
    env: Option<BTreeMap<String, String>>,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// 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<String>,
 | 
			
		||||
    current_dir: Option<PathBuf>,
 | 
			
		||||
    env: HashMap<String, String>,
 | 
			
		||||
    env: BTreeMap<String, String>,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// QUESTION: Would String be less awkward?
 | 
			
		||||
@@ -94,10 +104,12 @@ pub fn get_packages_folder(opt: &Opt) -> io::Result<PathBuf> {
 | 
			
		||||
 | 
			
		||||
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)?;
 | 
			
		||||
 
 | 
			
		||||
@@ -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
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user