pretty printing (#15)

* pretty printing for `backup list` and `backup list --long`

* switch coloring crate from colored to console

- console can handle Style separately

* Style for storage list
This commit is contained in:
qwjyh 2024-06-27 18:06:27 +09:00 committed by GitHub
parent a7c81d5976
commit ea0acf177c
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 111 additions and 28 deletions

View file

@ -5,7 +5,8 @@ use std::{
};
use anyhow::{anyhow, Context, Ok, Result};
use chrono::Local;
use chrono::{Local, TimeDelta};
use console::Style;
use dunce::canonicalize;
use git2::Repository;
use unicode_width::UnicodeWidthStr;
@ -153,6 +154,17 @@ pub fn cmd_backup_list(
Ok(())
}
fn duration_style(time: TimeDelta) -> Style {
match time {
x if x < TimeDelta::days(7) => Style::new().green(),
x if x < TimeDelta::days(14) => Style::new().yellow(),
x if x < TimeDelta::days(28) => Style::new().magenta(),
x if x < TimeDelta::days(28 * 3) => Style::new().red(),
x if x < TimeDelta::days(180) => Style::new().red().bold(),
_ => Style::new().on_red().black(),
}
}
/// TODO: status printing
fn write_backups_list(
mut writer: impl io::Write,
@ -188,39 +200,71 @@ fn write_backups_list(
// main printing
for ((dev, _name), backup) in &backups {
let device = backup.device(devices).context(format!(
"Couldn't find device specified in backup config {}",
"Couldn't find the device specified in the backup config: {}",
backup.name()
))?;
let src = backup.source().path(storages, device)?;
let dest = backup.destination().path(storages, device)?;
let cmd_name = backup.command().name();
let last_backup_elapsed = match backup.last_backup() {
let (last_backup_elapsed, style_on_time_elapsed) = match backup.last_backup() {
Some(log) => {
let time = Local::now() - log.datetime;
util::format_summarized_duration(time)
let s = util::format_summarized_duration(time);
let style = duration_style(time);
(style.apply_to(s), style)
}
None => "---".to_string(),
None => {
let style = Style::new().red();
(style.apply_to("---".to_string()), style)
},
};
writeln!(
writer,
"{name:<name_width$} [{dev:<dev_width$}] {src:<src_storage_width$} → {dest:<dest_storage_width$} {last_backup_elapsed}",
name = backup.name(),
src = backup.source().storage,
dest = backup.destination().storage,
)?;
if longprint {
let cmd_note = backup.command().note();
writeln!(writer, " src : {src:<src_width$}", src = src.display())?;
if !longprint {
writeln!(
writer,
" dest: {dest:<dest_width$}",
"{name:<name_width$} [{dev:<dev_width$}] {src:<src_storage_width$} → {dest:<dest_storage_width$} {last_backup_elapsed}",
name = style_on_time_elapsed.apply_to(backup.name()),
dev = console::style(dev).blue(),
src = backup.source().storage,
dest = backup.destination().storage,
)?;
} else {
writeln!(
writer,
"[{dev:<dev_width$}] {name:<name_width$} {last_backup_elapsed}",
dev = console::style(dev).blue(),
name = style_on_time_elapsed.bold().apply_to(backup.name()),
)?;
let last_backup_date = match backup.last_backup() {
Some(date) => date.datetime.format("%Y-%m-%d %T").to_string(),
None => "never".to_string(),
};
let cmd_note = backup.command().note();
writeln!(
writer,
"{s_src} {src}",
s_src = console::style("src :").italic().bright().black(),
src = src.display()
)?;
writeln!(
writer,
"{s_dest} {dest}",
s_dest = console::style("dest:").italic().bright().black(),
dest = dest.display()
)?;
writeln!(
writer,
" {cmd_name:<cmd_name_width$}({note})",
note = cmd_note,
"{s_last} {last}",
s_last = console::style("last:").italic().bright().black(),
last = last_backup_date,
)?;
writeln!(
writer,
"{s_cmd} {cmd_name}({note})",
s_cmd = console::style("cmd :").italic().bright().black(),
cmd_name = console::style(cmd_name).underlined(),
note = console::style(cmd_note).italic(),
)?;
writeln!(writer)?;
}
}
Ok(())

View file

@ -7,6 +7,7 @@ use std::{
use anyhow::{anyhow, Context, Result};
use byte_unit::{Byte, UnitType};
use console::style;
use dunce::canonicalize;
use git2::Repository;
use inquire::{Confirm, CustomType, Text};
@ -211,7 +212,7 @@ fn write_storages_list(
"-"
}
} else {
" "
""
};
let path = storage.mount_path(device).map_or_else(
|e| {
@ -227,23 +228,24 @@ fn write_storages_list(
} else {
""
};
let typestyle = storage.typestyle();
writeln!(
writer,
"{stype}{isremovable}: {name:<name_width$} {size:>10} {parent:<name_width$} {path}",
stype = storage.shorttypename(),
"{stype}{isremovable:<1}: {name:<name_width$} {size:>10} {parent:<name_width$} {path}",
stype = typestyle.apply_to(storage.shorttypename()),
isremovable = isremovable,
name = storage.name(),
name = typestyle.apply_to(storage.name()),
size = size_str,
parent = parent_name,
parent = console::style(parent_name).bright().black(),
path = path,
)?;
if long_display {
let note = match storage {
Storage::Physical(s) => s.kind(),
Storage::SubDirectory(s) => &s.notes,
Storage::Online(s) => &s.provider,
Storage::Physical(s) => format!("kind: {}", s.kind()),
Storage::SubDirectory(s) => s.notes.clone(),
Storage::Online(s) => s.provider.clone(),
};
writeln!(writer, " {}", note)?;
writeln!(writer, " {}", style(note).italic())?;
}
}
Ok(())

View file

@ -1,5 +1,6 @@
//! Manipulates storages.
use console::{style, Style, StyledObject};
use crate::devices;
use crate::storages::{
directory::Directory, online_storage::OnlineStorage,
@ -9,7 +10,7 @@ use anyhow::{anyhow, Context, Result};
use clap::ValueEnum;
use core::panic;
use serde::{Deserialize, Serialize};
use std::{collections::BTreeMap, fmt, fs, io, path, u64};
use std::{collections::BTreeMap, fmt, fs, io, path};
/// YAML file to store known storages..
pub const STORAGESFILE: &str = "storages.yml";
@ -50,6 +51,14 @@ impl Storage {
Self::Online(_) => "O",
}
}
pub fn typestyle(&self) -> Style {
match self {
Storage::Physical(_) => Style::new().cyan(),
Storage::SubDirectory(_) => Style::new().yellow(),
Storage::Online(_) => Style::new().green(),
}
}
}
impl StorageExt for Storage {

View file

@ -1,6 +1,7 @@
use std::path::{self, PathBuf};
use anyhow::{Context, Result};
use console::Style;
use crate::{
devices::Device,