mirror of
				https://github.com/pcvolkmer/osc-variant.git
				synced 2025-10-29 23:56:11 +00:00 
			
		
		
		
	Add sub command 'tree' to show dependencies
This commit is contained in:
		
							
								
								
									
										2
									
								
								Cargo.lock
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										2
									
								
								Cargo.lock
									
									
									
										generated
									
									
									
								
							| @@ -126,7 +126,7 @@ checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" | ||||
|  | ||||
| [[package]] | ||||
| name = "osc-variant" | ||||
| version = "0.2.0" | ||||
| version = "0.3.0" | ||||
| dependencies = [ | ||||
|  "clap", | ||||
|  "console", | ||||
|   | ||||
| @@ -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" | ||||
|   | ||||
| @@ -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.  | ||||
|   | ||||
| @@ -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, | ||||
|   | ||||
| @@ -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, | ||||
|   | ||||
| @@ -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 { | ||||
|   | ||||
| @@ -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 { | ||||
|   | ||||
| @@ -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)] | ||||
|   | ||||
| @@ -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
									
								
							
							
						
						
									
										38
									
								
								src/model/requirements.rs
									
									
									
									
									
										Normal 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; | ||||
| } | ||||
| @@ -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 { | ||||
|   | ||||
		Reference in New Issue
	
	Block a user