1
0
mirror of https://github.com/pcvolkmer/osc-variant.git synced 2025-07-03 09:12:54 +00:00

Add subcommand 'diff' to compare two OSC files

This commit is contained in:
2023-07-01 17:29:53 +02:00
parent b04ee563f2
commit b030ce6a53
9 changed files with 209 additions and 7 deletions

View File

@ -25,7 +25,7 @@
use console::style;
use serde::{Deserialize, Serialize};
use crate::model::{Listable, Ordner, Sortable};
use crate::model::{Comparable, Listable, Ordner, Sortable};
#[derive(Serialize, Deserialize, Debug)]
#[serde(deny_unknown_fields)]
@ -72,6 +72,16 @@ impl Sortable for DataCatalogue {
}
}
impl Comparable for DataCatalogue {
fn get_name(&self) -> String {
self.name.clone()
}
fn get_revision(&self) -> u16 {
self.revision
}
}
#[derive(Serialize, Deserialize, Debug)]
#[serde(deny_unknown_fields)]
pub struct Entries {

View File

@ -26,8 +26,8 @@ use console::style;
use serde::{Deserialize, Serialize};
use crate::model::{
apply_profile_to_form_entry, Ansichten, Entries, Filter, FormEntry, FormEntryContainer,
Listable, MenuCategory, PlausibilityRules, Script, Sortable,
apply_profile_to_form_entry, Ansichten, Comparable, Entries, Filter, FormEntry,
FormEntryContainer, Listable, MenuCategory, PlausibilityRules, Script, Sortable,
};
use crate::model::{Haeufigkeiten, Ordner};
use crate::profile::Profile;
@ -194,6 +194,16 @@ impl Sortable for DataForm {
}
}
impl Comparable for DataForm {
fn get_name(&self) -> String {
self.name.clone()
}
fn get_revision(&self) -> u16 {
self.revision
}
}
#[derive(Serialize, Deserialize, Debug)]
#[serde(deny_unknown_fields)]
pub struct DataCatalogues {

View File

@ -24,6 +24,9 @@
use crate::profile::{FormReference, Profile};
use serde::{Deserialize, Serialize};
use std::collections::hash_map::DefaultHasher;
use std::fmt::Debug;
use std::hash::{Hash, Hasher};
pub mod data_catalogue;
pub mod data_form;
@ -238,6 +241,16 @@ pub trait Sortable {
fn sorting_key(&self) -> String;
}
pub trait Comparable: Debug {
fn get_name(&self) -> String;
fn get_revision(&self) -> u16;
fn get_hash(&self) -> String {
let mut h = DefaultHasher::new();
format!("{:?}", self).hash(&mut h);
h.finish().to_string()
}
}
pub trait FormEntry {
fn get_name(&self) -> String;
fn get_type(&self) -> String;

View File

@ -25,13 +25,15 @@
use console::style;
use quick_xml::de::from_str;
use serde::{Deserialize, Serialize};
use std::cmp::Ordering;
use std::fmt::Debug;
use std::str::FromStr;
use crate::model::data_catalogue::DataCatalogue;
use crate::model::data_form::DataForm;
use crate::model::property_catalogue::PropertyCatalogue;
use crate::model::unterformular::Unterformular;
use crate::model::{FormEntryContainer, Listable, Sortable};
use crate::model::{Comparable, FormEntryContainer, Listable, Sortable};
use crate::profile::Profile;
#[derive(Serialize, Deserialize, Debug)]
@ -89,6 +91,115 @@ impl OnkostarEditor {
.unterformular
.sort_unstable_by_key(|e| e.sorting_key());
}
pub fn print_diff(&mut self, other: &mut Self, strict: bool) {
self.sorted();
other.sorted();
Self::print_item_diff(
"Merkmalskataloge",
&self.editor.property_catalogue,
&other.editor.property_catalogue,
strict,
);
Self::print_item_diff(
"Datenkataloge",
&self.editor.data_catalogue,
&other.editor.data_catalogue,
strict,
);
Self::print_item_diff(
"Formulare",
&self.editor.data_form,
&other.editor.data_form,
strict,
);
Self::print_item_diff(
"Unterformulare",
&self.editor.unterformular,
&other.editor.unterformular,
strict,
);
}
fn print_item_diff(
title: &str,
list_a: &[impl Comparable],
list_b: &[impl Comparable],
strict: bool,
) {
println!("\n{}", style(title).underlined());
let mut has_diff = false;
let names_a = list_a
.iter()
.map(|entry| entry.get_name())
.collect::<Vec<_>>();
let names_b = list_b
.iter()
.map(|entry| entry.get_name())
.collect::<Vec<_>>();
names_b.iter().for_each(|entry| {
if !names_a.contains(entry) {
println!("{}: {}", entry, style("Nicht in Datei A enthalten!").red());
has_diff = true;
}
});
names_a.iter().for_each(|entry| {
if !names_b.contains(entry) {
println!("{}: {}", entry, style("Nicht in Datei B enthalten!").red());
has_diff = true;
}
});
list_a.iter().for_each(|entry_a| {
list_b.iter().for_each(|entry_b| {
if entry_a.get_name() == entry_b.get_name() {
match entry_a.get_revision().cmp(&entry_b.get_revision()) {
Ordering::Less => {
println!(
"{}: {} (Revision {} < Revision {})",
entry_a.get_name(),
style("Neuer in Datei B").yellow(),
style(entry_a.get_revision()).blue(),
style(entry_b.get_revision()).green()
);
has_diff = true;
}
Ordering::Greater => {
println!(
"{}: {} (Revision {} > Revision {})",
entry_a.get_name(),
style("Neuer in Datei A").yellow(),
style(entry_a.get_revision()).green(),
style(entry_b.get_revision()).blue()
);
has_diff = true;
}
_ => {
if strict && entry_a.get_hash() != entry_b.get_hash() {
println!(
"{}: {} (z.B. Reihenfolge von Unterelementen)",
entry_a.get_name(),
style("Inhaltlich verschieden").yellow()
);
has_diff = true;
} else if strict {
println!("{}: {}", entry_a.get_name(), style("Identisch").green())
}
}
}
}
});
});
if !has_diff {
println!("Keine Unterschiede")
}
}
}
impl FromStr for OnkostarEditor {

View File

@ -25,7 +25,7 @@
use console::style;
use serde::{Deserialize, Serialize};
use crate::model::{Listable, Ordner, Sortable};
use crate::model::{Comparable, Listable, Ordner, Sortable};
#[derive(Serialize, Deserialize, Debug)]
#[serde(deny_unknown_fields)]
@ -69,6 +69,16 @@ impl Sortable for PropertyCatalogue {
}
}
impl Comparable for PropertyCatalogue {
fn get_name(&self) -> String {
self.name.clone()
}
fn get_revision(&self) -> u16 {
self.revision
}
}
#[derive(Serialize, Deserialize, Debug)]
#[serde(deny_unknown_fields)]
pub struct Versions {

View File

@ -26,8 +26,8 @@ use console::style;
use serde::{Deserialize, Serialize};
use crate::model::{
apply_profile_to_form_entry, Ansichten, Entries, Filter, FormEntry, FormEntryContainer,
Listable, MenuCategory, PlausibilityRules, Script, Sortable,
apply_profile_to_form_entry, Ansichten, Comparable, Entries, Filter, FormEntry,
FormEntryContainer, Listable, MenuCategory, PlausibilityRules, Script, Sortable,
};
use crate::model::{Haeufigkeiten, Ordner};
use crate::profile::Profile;
@ -213,6 +213,16 @@ impl Sortable for Unterformular {
}
}
impl Comparable for Unterformular {
fn get_name(&self) -> String {
self.name.clone()
}
fn get_revision(&self) -> u16 {
self.revision
}
}
#[derive(Serialize, Deserialize, Debug)]
#[serde(deny_unknown_fields)]
pub struct DataCatalogues {