1
0
mirror of https://github.com/pcvolkmer/osc-variant.git synced 2025-04-19 11:46:50 +00:00

Add sub command 'tree' to show dependencies

This commit is contained in:
Paul-Christian Volkmer 2023-08-29 17:34:02 +02:00
parent 37c8b47d1f
commit 103075ab78
11 changed files with 272 additions and 7 deletions

2
Cargo.lock generated
View File

@ -126,7 +126,7 @@ checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d"
[[package]]
name = "osc-variant"
version = "0.2.0"
version = "0.3.0"
dependencies = [
"clap",
"console",

View File

@ -1,6 +1,6 @@
[package]
name = "osc-variant"
version = "0.2.0"
version = "0.3.0"
edition = "2021"
authors = ["Paul-Christian Volkmer <volkmer_p@ukw.de>"]
description = "Anwendung zum Anpassen einer OSC-Datei an einen Standort"

View File

@ -22,6 +22,15 @@ Zum Auflisten der Inhalte einer Datei wird folgender Befehl verwendet:
osc-variant list meine-beispieldatei.osc
```
Zum Auflisten der Inhalte mit allen Abhängigkeiten, z.B. Daten- und Merkmalkataloge und bei Formularen wird der Befehl
`tree` verwendet:
```
osc-variant tree meine-beispieldatei.osc
```
Achtung! Dies erzeugt eine sehr umfangreiche Ausgabe.
Zum Vergleich zweier OSC-Dateien wird der Unterbefehl `diff` verwendet.
Der optionale Parameter `--strict` vergleicht auch den Inhalt der OSC-Datei.
Ohne diesen wird nur das Vorhandensein von Inhalten und die Revision verglichen.

View File

@ -43,6 +43,15 @@ pub enum Command {
)]
sorted: bool,
},
#[command(about = "Zeigt Kataloge und Formulare mit Revision und Abhängigkeiten an.")]
Tree {
inputfile: String,
#[arg(
long = "sorted",
help = "Sortiere Kataloge und Formulare nach Name (Optional)"
)]
sorted: bool,
},
#[command(about = "Modifiziert die angegebene Datei anhand der Profildatei")]
Modify {
inputfile: String,

View File

@ -117,6 +117,13 @@ fn main() -> Result<(), Box<dyn Error>> {
}
data.print_list();
}
Command::Tree { inputfile, sorted } => {
let mut data = read_inputfile(inputfile)?;
if sorted {
data.sorted()
}
OnkostarEditor::print_tree(&data);
}
Command::Modify {
inputfile,
profile,

View File

@ -22,9 +22,13 @@
* SOFTWARE.
*/
use std::collections::HashSet;
use console::style;
use serde::{Deserialize, Serialize};
use crate::model::onkostar_editor::OnkostarEditor;
use crate::model::requirements::{Requirement, Requires};
use crate::model::{Comparable, Listable, Ordner, Sortable};
#[derive(Serialize, Deserialize, Debug)]
@ -92,6 +96,45 @@ impl Comparable for DataCatalogue {
}
}
impl Requires for DataCatalogue {
fn get_required_entries<'a>(&'a self, all: &'a OnkostarEditor) -> Vec<Requirement> {
self.entries
.entry
.iter()
.filter(|&entry| entry.property_catalogue.is_some())
.map(|entry| match &entry.property_catalogue {
Some(entry) => entry.to_string(),
_ => String::new(),
})
.collect::<HashSet<_>>()
.into_iter()
.map(|entry| all.find_property_catalogue(entry.as_str()))
.filter(Option::is_some)
.map(|entry| Requirement::PropertyCatalogue(entry.unwrap()))
.collect::<Vec<_>>()
}
fn to_requirement_string<'a>(&'a self, all: &'a OnkostarEditor) -> String {
format!(
"Datenkatalog '{}' in Revision '{}'\n{}",
style(&self.name).yellow(),
style(&self.revision).yellow(),
self.get_required_entries(all)
.iter()
.map(|entry| match entry {
Requirement::PropertyCatalogue(x) => {
Some(format!(" + {}\n", x.to_listed_string()))
}
_ => None,
})
.filter(Option::is_some)
.flatten()
.collect::<Vec<_>>()
.join("")
)
}
}
#[derive(Serialize, Deserialize, Debug)]
#[serde(deny_unknown_fields)]
pub struct Entries {

View File

@ -22,9 +22,13 @@
* SOFTWARE.
*/
use std::collections::HashSet;
use console::style;
use serde::{Deserialize, Serialize};
use crate::model::onkostar_editor::OnkostarEditor;
use crate::model::requirements::{Requirement, Requires};
use crate::model::{
apply_profile_to_form_entry, Ansichten, Comparable, Entries, Filter, FormEntry,
FormEntryContainer, Listable, MenuCategory, PlausibilityRules, Script, Sortable,
@ -227,6 +231,56 @@ impl Comparable for DataForm {
}
}
impl Requires for DataForm {
fn get_required_entries<'a>(&'a self, all: &'a OnkostarEditor) -> Vec<Requirement> {
self.data_catalogues
.data_catalogue
.iter()
.collect::<HashSet<_>>()
.into_iter()
.map(|entry| all.find_data_catalogue(entry.as_str()))
.filter(Option::is_some)
.map(|entry| Requirement::DataCatalogue(entry.unwrap()))
.collect::<Vec<_>>()
}
fn to_requirement_string<'a>(&'a self, all: &'a OnkostarEditor) -> String {
format!(
"Formular '{}' in Revision '{}'\n{}",
style(&self.name).yellow(),
style(&self.revision).yellow(),
self.get_required_entries(all)
.iter()
.map(|entry| match entry {
Requirement::DataCatalogue(x) => {
let inner = x
.get_required_entries(all)
.iter()
.map(|inner_entry| match inner_entry {
Requirement::PropertyCatalogue(y) => Some(y.to_listed_string()),
_ => None,
})
.filter(Option::is_some)
.map(|item| format!(" - {}\n", item.unwrap()))
.collect::<Vec<_>>()
.join("");
if inner.is_empty() {
Some(format!(" + {}\n", x.to_listed_string()))
} else {
Some(format!(" + {}\n{}", x.to_listed_string(), inner))
}
}
_ => None,
})
.filter(Option::is_some)
.flatten()
.collect::<Vec<_>>()
.join("")
)
}
}
#[derive(Serialize, Deserialize, Debug)]
#[serde(deny_unknown_fields)]
pub struct DataCatalogues {

View File

@ -22,16 +22,19 @@
* SOFTWARE.
*/
use crate::profile::{FormReference, Profile};
use serde::{Deserialize, Serialize};
use std::collections::hash_map::DefaultHasher;
use std::fmt::Debug;
use std::hash::{Hash, Hasher};
use serde::{Deserialize, Serialize};
use crate::profile::{FormReference, Profile};
pub mod data_catalogue;
pub mod data_form;
pub mod onkostar_editor;
pub mod property_catalogue;
pub mod requirements;
pub mod unterformular;
#[derive(Serialize, Deserialize, Debug)]

View File

@ -22,16 +22,18 @@
* SOFTWARE.
*/
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 console::style;
use quick_xml::de::from_str;
use serde::{Deserialize, Serialize};
use crate::model::data_catalogue::DataCatalogue;
use crate::model::data_form::DataForm;
use crate::model::property_catalogue::PropertyCatalogue;
use crate::model::requirements::Requires;
use crate::model::unterformular::Unterformular;
use crate::model::{Comparable, FormEntryContainer, Listable, Sortable};
use crate::profile::Profile;
@ -46,6 +48,32 @@ pub struct OnkostarEditor {
}
impl OnkostarEditor {
pub fn find_property_catalogue<'a>(&'a self, name: &str) -> Option<&'a PropertyCatalogue> {
match self
.editor
.property_catalogue
.iter()
.filter(|&item| item.get_name().eq_ignore_ascii_case(name))
.nth(0)
{
Some(x) => Some(x),
_ => None,
}
}
pub fn find_data_catalogue<'a>(&'a self, name: &str) -> Option<&'a DataCatalogue> {
match self
.editor
.data_catalogue
.iter()
.filter(|&item| item.get_name().eq_ignore_ascii_case(name))
.nth(0)
{
Some(x) => Some(x),
_ => None,
}
}
pub fn apply_profile(&mut self, profile: &Profile) {
self.editor.data_form.iter_mut().for_each(|data_form| {
data_form.apply_profile(profile);
@ -74,6 +102,26 @@ impl OnkostarEditor {
.for_each(|entry| println!("{}", entry.to_listed_string()));
}
pub fn print_tree(&self) {
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_tree("Datenkataloge", &self.editor.data_catalogue);
self.print_items_tree("Formulare", &self.editor.data_form);
self.print_items_tree("Unterformulare", &self.editor.unterformular);
}
fn print_items_tree(&self, title: &str, list: &[impl Requires]) {
println!("\n{} {}", list.len(), style(title).underlined());
list.iter()
.for_each(|entry| println!("{}", entry.to_requirement_string(self)));
}
pub fn sorted(&mut self) {
self.editor
.property_catalogue

38
src/model/requirements.rs Normal file
View File

@ -0,0 +1,38 @@
/*
* MIT License
*
* Copyright (c) 2023 Comprehensive Cancer Center Mainfranken
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
use crate::model::data_catalogue::DataCatalogue;
use crate::model::onkostar_editor::OnkostarEditor;
use crate::model::property_catalogue::PropertyCatalogue;
pub enum Requirement<'a> {
PropertyCatalogue(&'a PropertyCatalogue),
DataCatalogue(&'a DataCatalogue),
}
pub trait Requires {
fn get_required_entries<'a>(&'a self, all: &'a OnkostarEditor) -> Vec<Requirement>;
fn to_requirement_string<'a>(&'a self, all: &'a OnkostarEditor) -> String;
}

View File

@ -22,9 +22,13 @@
* SOFTWARE.
*/
use std::collections::HashSet;
use console::style;
use serde::{Deserialize, Serialize};
use crate::model::onkostar_editor::OnkostarEditor;
use crate::model::requirements::{Requirement, Requires};
use crate::model::{
apply_profile_to_form_entry, Ansichten, Comparable, Entries, Filter, FormEntry,
FormEntryContainer, Listable, MenuCategory, PlausibilityRules, Script, Sortable,
@ -246,6 +250,56 @@ impl Comparable for Unterformular {
}
}
impl Requires for Unterformular {
fn get_required_entries<'a>(&'a self, all: &'a OnkostarEditor) -> Vec<Requirement> {
self.data_catalogues
.data_catalogue
.iter()
.collect::<HashSet<_>>()
.into_iter()
.map(|entry| all.find_data_catalogue(entry.as_str()))
.filter(Option::is_some)
.map(|entry| Requirement::DataCatalogue(entry.unwrap()))
.collect::<Vec<_>>()
}
fn to_requirement_string<'a>(&'a self, all: &'a OnkostarEditor) -> String {
format!(
"Unterformular '{}' in Revision '{}'\n{}",
style(&self.name).yellow(),
style(&self.revision).yellow(),
self.get_required_entries(all)
.iter()
.map(|entry| match entry {
Requirement::DataCatalogue(x) => {
let inner = x
.get_required_entries(all)
.iter()
.map(|inner_entry| match inner_entry {
Requirement::PropertyCatalogue(y) => Some(y.to_listed_string()),
_ => None,
})
.filter(Option::is_some)
.map(|item| format!(" - {}\n", item.unwrap()))
.collect::<Vec<_>>()
.join("");
if inner.is_empty() {
Some(format!(" + {}\n", x.to_listed_string()))
} else {
Some(format!(" + {}\n{}", x.to_listed_string(), inner))
}
}
_ => None,
})
.filter(Option::is_some)
.flatten()
.collect::<Vec<_>>()
.join("")
)
}
}
#[derive(Serialize, Deserialize, Debug)]
#[serde(deny_unknown_fields)]
pub struct DataCatalogues {