Add a visual separation between commands and for the summary

This commit is contained in:
Zykino 2023-06-26 00:32:58 +02:00
parent 9bff5b2f81
commit 7b9c487650
3 changed files with 48 additions and 24 deletions

View File

@ -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:

View File

@ -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 structs names for the `topgrade`s one. They are much better.
/// Root of the machines 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)?;

View File

@ -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