1
0
mirror of https://github.com/pcvolkmer/osc-variant.git synced 2025-12-12 14:13:20 +00:00

feat: add more verbose output (#63)

Using -v the list and tree sub-command will show hash value
based on catalogue or form contents.
This commit is contained in:
2025-12-07 12:59:55 +01:00
committed by GitHub
parent 3c0c6ca0be
commit 46d4156bb6
9 changed files with 92 additions and 54 deletions

View File

@@ -65,6 +65,9 @@ Mit der Option `--filter` kann die Ausgabe eingeschränkt werden.
*Bei Verwendung der OSB-Funktionalität kann die Eingabe eines Passworts erforderlich sein.*
Die Option `-v` sorgt dafür, dass die eine Prüfsumme für Kataloge und Formulare berechnet und angezeigt wird.
Dadurch können inhaltliche Unterschiede bei identischer Revisionsnummer erkannt werden.
#### Unterbefehl `tree`
Zum Auflisten der Inhalte mit allen Abhängigkeiten, z.B. Daten- und Merkmalskataloge und bei Formularen wird der Befehl
@@ -87,6 +90,9 @@ Achtung! Dies erzeugt eine sehr umfangreiche Ausgabe.
Mit der Option `--filter` kann auch hier die Ausgabe eingeschränkt werden.
Wie bei `list` sorgt auch hier die Option `-v` dafür,
dass die eine Prüfsumme für Kataloge und Formulare berechnet und angezeigt wird.
#### Unterbefehl `diff`
Zum Vergleich zweier OSC-Dateien wird der Unterbefehl `diff` verwendet.

View File

@@ -27,6 +27,9 @@ use clap_complete::Shell;
pub struct Cli {
#[command(subcommand)]
pub cmd: SubCommand,
#[arg(short = 'v', global = true, help = "Zeige umfangreichere Ausgaben")]
pub verbose: bool,
}
#[derive(Subcommand)]

View File

@@ -17,13 +17,13 @@
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
use crate::checks::{check_file, print, CheckNotice};
use crate::checks::{CheckNotice, check_file, print};
use crate::cli::{Cli, SubCommand};
use crate::file_io::{FileError, FileReader, InputFile};
use crate::model::onkostar_editor::OnkostarEditor;
use crate::profile::Profile;
use clap::CommandFactory;
use clap_complete::{generate, Shell};
use clap_complete::{Shell, generate};
use console::style;
use quick_xml::se::Serializer;
use serde::Serialize;
@@ -35,19 +35,19 @@ use std::io::Write;
use std::ops::Add;
use std::path::{Path, PathBuf};
pub fn handle(command: SubCommand) -> Result<(), Box<dyn Error>> {
pub fn handle(command: SubCommand, verbose: bool) -> Result<(), Box<dyn Error>> {
match command {
SubCommand::Completion { shell } => handle_completion(shell),
SubCommand::List {
inputfile,
sorted,
filter,
} => handle_list(inputfile, sorted, filter)?,
} => handle_list(inputfile, sorted, filter, verbose)?,
SubCommand::Tree {
inputfile,
sorted,
filter,
} => handle_tree(inputfile, sorted, filter)?,
} => handle_tree(inputfile, sorted, filter, verbose)?,
SubCommand::Modify {
inputfile,
profile,
@@ -106,6 +106,7 @@ fn handle_list(
inputfile: String,
sorted: bool,
filter: Option<String>,
verbose: bool,
) -> Result<(), Box<dyn Error>> {
match InputFile::read(inputfile, None)? {
osc @ InputFile::Osc { .. } => {
@@ -114,10 +115,10 @@ fn handle_list(
content.sorted();
}
if let Some(name) = filter {
OnkostarEditor::print_list_filtered(&mut content, name.as_str());
OnkostarEditor::print_list_filtered(&mut content, name.as_str(), verbose);
return Ok(());
}
content.print_list();
content.print_list(verbose);
}
InputFile::Osb { content, .. } => {
for file in content {
@@ -141,10 +142,14 @@ fn handle_list(
content.sorted();
}
if let Some(name) = filter {
OnkostarEditor::print_list_filtered(&mut content, name.as_str());
OnkostarEditor::print_list_filtered(
&mut content,
name.as_str(),
verbose,
);
return Ok(());
}
content.print_list();
content.print_list(verbose);
println!();
}
_ => {
@@ -172,6 +177,7 @@ fn handle_tree(
inputfile: String,
sorted: bool,
filter: Option<String>,
verbose: bool,
) -> Result<(), Box<dyn Error>> {
match InputFile::read(inputfile, None)? {
osc @ InputFile::Osc { .. } => {
@@ -180,10 +186,10 @@ fn handle_tree(
content.sorted();
}
if let Some(name) = filter {
OnkostarEditor::print_tree_filtered(&mut content, name.as_str());
OnkostarEditor::print_tree_filtered(&mut content, name.as_str(), verbose);
return Ok(());
}
OnkostarEditor::print_tree(&content);
OnkostarEditor::print_tree(&content, verbose);
}
InputFile::Osb { filename, .. } => {
return Err(Box::new(FileError::Reading(
@@ -248,9 +254,7 @@ fn handle_modify(
let output = &"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
.to_string()
.add(
buf.as_str(),
);
.add(buf.as_str());
match outputfile {
Some(filename) => write_outputfile(filename, output)?,

View File

@@ -34,6 +34,6 @@ mod unzip_osb;
fn main() -> Result<(), Box<dyn Error>> {
let cli = Cli::parse();
handle(cli.cmd)?;
handle(cli.cmd, cli.verbose)?;
Ok(())
}

View File

@@ -121,10 +121,14 @@ impl Requires for DataCatalogue {
result
}
fn to_requirement_string<'a>(&'a self, all: &'a OnkostarEditor) -> String {
fn to_requirement_string<'a>(&'a self, all: &'a OnkostarEditor, verbose: bool) -> String {
format!(
"{}\n{}",
self.to_listed_string(),
if verbose {
self.to_verbose_listed_string()
} else {
self.to_listed_string()
},
self.get_required_entries(all)
.iter()
.filter_map(|entry| match entry {

View File

@@ -23,9 +23,9 @@ use crate::model::onkostar_editor::OnkostarEditor;
use crate::model::other::Entry;
use crate::model::requirements::{Requirement, Requires};
use crate::model::{
apply_profile_to_form_entry, apply_profile_to_form_field, Ansichten, Comparable, Entries, FolderContent, FormEntry,
FormEntryContainer, Kennzahlen, Listable, MenuCategory, PlausibilityRules, PunkteKategorien,
Script, Sortable,
Ansichten, Comparable, Entries, FolderContent, FormEntry, FormEntryContainer, Kennzahlen,
Listable, MenuCategory, PlausibilityRules, PunkteKategorien, Script, Sortable,
apply_profile_to_form_entry, apply_profile_to_form_field,
};
use crate::model::{Haeufigkeiten, Ordner};
use crate::profile::Profile;
@@ -250,7 +250,10 @@ impl<Type: 'static> FormEntryContainer for Form<Type> {
}
}
impl<Type: 'static> Listable for Form<Type> {
impl<Type: 'static> Listable for Form<Type>
where
Form<Type>: Comparable,
{
fn to_listed_string(&self) -> String {
format!(
"{} ({}) '{}' in Revision '{}'",
@@ -673,8 +676,8 @@ pub struct DataFormEntries {
mod tests {
use std::str::FromStr;
use crate::model::onkostar_editor::OnkostarEditor;
use crate::model::Script;
use crate::model::onkostar_editor::OnkostarEditor;
use crate::profile::Profile;
#[test]

View File

@@ -18,16 +18,15 @@
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
use crate::model::requirements::Requires;
use crate::profile::{FormField, FormReference, Profile, WithScriptsCode};
use console::style;
use serde::{Deserialize, Serialize};
use std::cmp::Ordering;
use std::collections::hash_map::DefaultHasher;
use std::fmt::Debug;
use std::hash::{Hash, Hasher};
use serde::{Deserialize, Serialize};
use crate::model::requirements::Requires;
use crate::profile::{FormField, FormReference, Profile, WithScriptsCode};
pub mod data_catalogue;
pub mod form;
pub mod onkostar_editor;
@@ -354,8 +353,19 @@ pub trait FormEntryContainer {
fn apply_profile(&mut self, profile: &Profile);
}
pub trait Listable {
pub trait Listable
where
Self: Comparable,
{
fn to_listed_string(&self) -> String;
fn to_verbose_listed_string(&self) -> String {
format!(
"{} {}",
self.to_listed_string(),
style(format!("[{}]", &self.get_hash()[..7])).dim()
)
}
}
pub trait Sortable {
@@ -375,7 +385,7 @@ pub trait Comparable: Debug {
fn get_hash(&self) -> String {
let mut h = DefaultHasher::new();
format!("{self:?}").hash(&mut h);
h.finish().to_string()
format!("{:x}", h.finish())
}
fn compare_by_requirement(_: &Self, _: &Self) -> Ordering
where

View File

@@ -114,17 +114,17 @@ impl OnkostarEditor {
});
}
pub fn print_list(&self) {
pub fn print_list(&self, verbose: bool) {
println!(
"Die Datei wurde am {} mit {} in Version {} erstellt.\n\nFolgende Inhalte sind gespeichert",
style(&self.info_xml.datum_xml).yellow(),
style(&self.info_xml.name).yellow(),
style(&self.info_xml.version).yellow()
);
Self::print_items("Merkmalskataloge", &self.editor.property_catalogue);
Self::print_items("Datenkataloge", &self.editor.data_catalogue);
Self::print_items("Formulare", &self.editor.data_form);
Self::print_items("Unterformulare", &self.editor.unterformular);
Self::print_items("Merkmalskataloge", &self.editor.property_catalogue, verbose);
Self::print_items("Datenkataloge", &self.editor.data_catalogue, verbose);
Self::print_items("Formulare", &self.editor.data_form, verbose);
Self::print_items("Unterformulare", &self.editor.unterformular, verbose);
}
fn filter_by_name_contains(&mut self, name: &str) {
@@ -141,7 +141,7 @@ impl OnkostarEditor {
.unterformular
.retain(|e| e.get_name().contains(name));
}
pub fn print_list_filtered(&mut self, name: &str) {
pub fn print_list_filtered(&mut self, name: &str, verbose: bool) {
println!(
"Die Datei wurde am {} mit {} in Version {} erstellt.\n\nFolgende Inhalte für '{}' sind gespeichert",
style(&self.info_xml.datum_xml).yellow(),
@@ -152,24 +152,28 @@ impl OnkostarEditor {
self.filter_by_name_contains(name);
Self::print_items("Merkmalskataloge", &self.editor.property_catalogue);
Self::print_items("Datenkataloge", &self.editor.data_catalogue);
Self::print_items("Formulare", &self.editor.data_form);
Self::print_items("Unterformulare", &self.editor.unterformular);
Self::print_items("Merkmalskataloge", &self.editor.property_catalogue, verbose);
Self::print_items("Datenkataloge", &self.editor.data_catalogue, verbose);
Self::print_items("Formulare", &self.editor.data_form, verbose);
Self::print_items("Unterformulare", &self.editor.unterformular, verbose);
}
fn print_items(title: &str, list: &[impl Listable]) {
fn print_items(title: &str, list: &[impl Listable], verbose: bool) {
print!("\n{} {}", list.len(), style(title).underlined());
println!(
" - Inhalte der Systembibliothek sind mit ({}), der Benutzerbibliothek mit (u) markiert",
style("S").yellow()
);
for entry in list {
if verbose {
println!("{}", entry.to_verbose_listed_string());
continue;
}
println!("{}", entry.to_listed_string());
}
}
pub fn print_tree(&self) {
pub fn print_tree(&self, verbose: bool) {
println!(
"Die Datei wurde am {} mit {} in Version {} erstellt.\n\nFolgende Inhalte sind gespeichert",
style(&self.info_xml.datum_xml).yellow(),
@@ -177,13 +181,13 @@ impl OnkostarEditor {
style(&self.info_xml.version).yellow()
);
Self::print_items("Merkmalskataloge", &self.editor.property_catalogue);
self.print_items_tree("Datenkataloge", &self.editor.data_catalogue);
self.print_items_tree("Formulare", &self.editor.data_form);
self.print_items_tree("Unterformulare", &self.editor.unterformular);
Self::print_items("Merkmalskataloge", &self.editor.property_catalogue, verbose);
self.print_items_tree("Datenkataloge", &self.editor.data_catalogue, verbose);
self.print_items_tree("Formulare", &self.editor.data_form, verbose);
self.print_items_tree("Unterformulare", &self.editor.unterformular, verbose);
}
pub fn print_tree_filtered(&mut self, name: &str) {
pub fn print_tree_filtered(&mut self, name: &str, verbose: bool) {
println!(
"Die Datei wurde am {} mit {} in Version {} erstellt.\n\nFolgende Inhalte für '{}' sind gespeichert",
style(&self.info_xml.datum_xml).yellow(),
@@ -194,20 +198,20 @@ impl OnkostarEditor {
self.filter_by_name_contains(name);
Self::print_items("Merkmalskataloge", &self.editor.property_catalogue);
self.print_items_tree("Datenkataloge", &self.editor.data_catalogue);
self.print_items_tree("Formulare", &self.editor.data_form);
self.print_items_tree("Unterformulare", &self.editor.unterformular);
Self::print_items("Merkmalskataloge", &self.editor.property_catalogue, verbose);
self.print_items_tree("Datenkataloge", &self.editor.data_catalogue, verbose);
self.print_items_tree("Formulare", &self.editor.data_form, verbose);
self.print_items_tree("Unterformulare", &self.editor.unterformular, verbose);
}
fn print_items_tree(&self, title: &str, list: &[impl Requires]) {
fn print_items_tree(&self, title: &str, list: &[impl Requires], verbose: bool) {
print!("\n{} {}", list.len(), style(title).underlined());
println!(
" - Inhalte der Systembibliothek sind mit ({}), der Benutzerbibliothek mit (u) markiert",
style("S").yellow()
);
for entry in list {
println!("{}", entry.to_requirement_string(self));
println!("{}", entry.to_requirement_string(self, verbose));
}
}

View File

@@ -110,10 +110,14 @@ where
fn get_required_entries<'a>(&'a self, all: &'a OnkostarEditor) -> Vec<Requirement<'a>>;
fn to_requirement_string<'a>(&'a self, all: &'a OnkostarEditor) -> String {
fn to_requirement_string<'a>(&'a self, all: &'a OnkostarEditor, verbose: bool) -> String {
format!(
"{}\n{}",
self.to_listed_string(),
if verbose {
self.to_verbose_listed_string()
} else {
self.to_listed_string()
},
self.get_required_entries(all)
.iter()
.filter_map(|entry| match entry {