From a4b998d9d40b355835272a0decd246cc69d4ebbb Mon Sep 17 00:00:00 2001 From: Till Wegmueller Date: Sat, 24 Apr 2021 23:19:25 -0300 Subject: [PATCH] First CI/CD feature --- libips/src/actions/mod.rs | 21 ++++-- pkg6dev/src/main.rs | 137 ++++++++++++++++++++++++++++++-------- 2 files changed, 124 insertions(+), 34 deletions(-) diff --git a/libips/src/actions/mod.rs b/libips/src/actions/mod.rs index ecd0e94..812aa65 100644 --- a/libips/src/actions/mod.rs +++ b/libips/src/actions/mod.rs @@ -55,7 +55,7 @@ impl FacetedAction for Action { } } -#[derive(Debug, Default, PartialEq)] +#[derive(Debug, Default, PartialEq, Clone)] pub struct Dir { pub path: String, pub group: String, @@ -106,7 +106,7 @@ impl FacetedAction for Dir { } } -#[derive(Debug, Default, PartialEq)] +#[derive(Debug, Default, PartialEq, Clone)] pub struct File { pub payload: Option, pub path: String, @@ -137,6 +137,15 @@ impl File { Ok(f) } + + pub fn get_original_path(&self) ->Option { + for p in &self.properties { + if p.key.as_str() == "original-path" { + return Some(p.value.clone()); + } + } + None + } } impl From for File { @@ -155,7 +164,7 @@ impl From for File { } else { file.properties.push(Property{ key: "original-path".to_string(), - value: act.payload_string.replace("\"", "") + value: act.payload_string.replace("\"", "").replace("\\", "") }); } } else { @@ -218,7 +227,7 @@ pub enum FileError { } //TODO implement multiple FMRI for require-any -#[derive(Debug, Default, PartialEq)] +#[derive(Debug, Default, PartialEq, Clone)] pub struct Dependency { pub fmri: String, //TODO make FMRI pub dependency_type: String, //TODO make enum @@ -283,7 +292,7 @@ impl Facet { } } -#[derive(Debug, Default, PartialEq)] +#[derive(Debug, Default, PartialEq, Clone)] pub struct Attr { pub key: String, pub values: Vec, @@ -383,7 +392,7 @@ pub struct Property { pub value: String, } -#[derive(Debug, Default, PartialEq)] +#[derive(Debug, Default, PartialEq, Clone)] pub struct Manifest { pub attributes: Vec, pub directories: Vec, diff --git a/pkg6dev/src/main.rs b/pkg6dev/src/main.rs index 6f0cb0a..9a92c44 100644 --- a/pkg6dev/src/main.rs +++ b/pkg6dev/src/main.rs @@ -1,7 +1,7 @@ -#[macro_use] -extern crate failure_derive; +//#[macro_use] +//extern crate failure_derive; -use clap::app_from_crate; +use clap::{app_from_crate, ArgMatches}; use clap::{Arg, App}; use libips::actions::{File, Manifest}; @@ -13,40 +13,121 @@ mod errors { } use errors::Result; +use std::collections::HashMap; +use std::fs::{read_dir}; +use std::path::Path; fn main() { - let opts = app_from_crate!().arg(Arg::new("proto_dir") - .short('p') - .long("proto-dir") - .value_name("PROTO_DIR") - .about("The Prototype directory where files are located after build") - .takes_value(true)//.required(true) - .default_value("../sample_data/pkgs/cups/build/prototype/i386") - ).subcommand(App::new("diff-manifests") - .about("shows differences between two manifests") - .arg(Arg::new("manifests") - .value_name("MANIFESTS") - .multiple(true) - .number_of_values(2) + let opts = app_from_crate!().subcommand(App::new("diff-component") + .about("shows differences between sample-manifest and manifests") + .arg(Arg::new("component") + .takes_value(true) + .default_value("../sample_data/pkgs/cups") ) ).get_matches(); + //.get_matches_from(vec!["pkg6dev", "diff-component"]); - let proto_dir = opts.value_of("proto_dir").expect("proto_dir is a mandatory variable. clap::Arg::required must be true"); - - //let manifests: Vec<_> = opts.values_of("manifests").unwrap().collect(); - - //let files = find_removed_files(String::from(&manifests[0]), String::from(&manifests[1])).unwrap(); - let _ = find_removed_files(String::from("../sample_data/pkgs/cups/cups.p5m"), String::from("../sample_data/pkgs/cups/manifests/sample-manifest.p5m")).unwrap(); + if let Some(diff_component_opts) = opts.subcommand_matches("diff-component") { + let res = diff_component(diff_component_opts); + if res.is_err() { + println!("error: {:?}", res.unwrap_err()) + } + } } -fn find_removed_files(manifest_file: String, other_manifest_file: String) -> Result> { - let manifest = Manifest::parse_file(manifest_file)?; - let other_manifest = Manifest::parse_file(other_manifest_file)?; +fn diff_component(matches: &ArgMatches) -> Result<()> { + let component_path = matches.value_of("component").unwrap(); - println!("{:#?}", manifest); - println!("{:#?}", other_manifest); + let files = read_dir(component_path)?; + let manifest_files: Vec = files + .filter_map(std::result::Result::ok) + .filter(|d| if let Some(e) = d.path().extension() { e == "p5m" } else {false}) + .map(|e| e.path().into_os_string().into_string().unwrap()).collect(); - Ok(vec![File::default()]) + let sample_manifest_file = component_path.to_string() + "/manifests/sample-manifest.p5m"; + + let manifests_res: Result> = manifest_files.iter().map(|f|{ + Manifest::parse_file(f.to_string()) + }).collect(); + let sample_manifest = Manifest::parse_file(sample_manifest_file)?; + + let manifests: Vec = manifests_res.unwrap(); + + let missing_files = find_files_missing_in_manifests(&sample_manifest, manifests.clone())?; + + for f in missing_files { + println!("file {} is missing in the manifests", f.path); + } + + let removed_files = find_removed_files(&sample_manifest, manifests.clone(), component_path)?; + + for f in removed_files { + println!("file path={} has been removed from the sample-manifest", f.path); + } + + Ok(()) +} + +// Show all files that have been removed in the sample-manifest +fn find_removed_files(sample_manifest: &Manifest, manifests: Vec, component_path: &str) -> Result> { + let f_map = make_file_map(sample_manifest.files.clone()); + let all_files: Vec = manifests.iter().map(|m| m.files.clone()).flatten().collect(); + + let mut removed_files: Vec = Vec::new(); + + for f in all_files { + match f.get_original_path() { + Some(path) => { + if !f_map.contains_key(path.as_str()) { + if !Path::new(&(component_path.to_string() + "/" + path.as_str())).exists() { + removed_files.push(f) + } + } + }, + None => { + if !f_map.contains_key(f.path.as_str()) { + removed_files.push(f) + } + } + } + } + + Ok(removed_files) +} + +// Show all files missing in the manifests that are in sample_manifest +fn find_files_missing_in_manifests(sample_manifest: &Manifest, manifests: Vec) -> Result> { + let all_files: Vec = manifests.iter().map(|m| m.files.clone()).flatten().collect(); + let f_map = make_file_map(all_files); + + let mut missing_files: Vec = Vec::new(); + + for f in sample_manifest.files.clone() { + match f.get_original_path() { + Some(path) => { + if !f_map.contains_key(path.as_str()) { + missing_files.push(f) + } + }, + None => { + if !f_map.contains_key(f.path.as_str()) { + missing_files.push(f) + } + } + } + } + + Ok(missing_files) +} + +fn make_file_map(files: Vec) -> HashMap { + files.iter().map(|f| { + let orig_path_opt = f.get_original_path(); + if orig_path_opt == None { + return (f.path.clone(), f.clone()); + } + (orig_path_opt.unwrap(), f.clone()) + }).collect() }