diff --git a/Cargo.toml b/Cargo.toml index 69987c4..8194ea5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,9 +1,9 @@ [package] name = "ykre" -version = "0.1.0" +version = "0.2.0" authors = ["a-Sansara "] edition = "2018" -description = "Ykre is Yaml Kubernetes Resource Extractor" +description = "Ykre stand for Yaml Kubernetes Resource Extractor" license = "MIT" readme = "README.md" keywords = ["cli", "yaml", "kubernetes", "kustomize"] @@ -13,3 +13,4 @@ categories = ["command-line-utilities"] [dependencies] yaml-rust = "0.4" +colored = "2" diff --git a/README.md b/README.md index 05a5602..3e63074 100644 --- a/README.md +++ b/README.md @@ -3,15 +3,15 @@ **Ykre** is a small cli program written in rust wich purpose is to extract from a list of yaml documents, documents matching a specified condition. **Ykre** goal is to find specific Kubernetes Resource from the kustomize output. -**Ykre** stands for **Y**aml **K**ubernetes **R**esources **E**ctractor. +**Ykre** stands for **Y**aml **K**ubernetes **R**esources **E**xtractor. ## Install from a debian package : ```  -wget -q https://github.com/pluie-org/ykre/raw/master/dist/ykre_0.1.0_amd64.deb -sudo apt install ./ykre_0.1.0_amd64.deb +wget -q https://github.com/pluie-org/ykre/raw/master/dist/ykre_0.2.0_amd64.deb +sudo apt install ./ykre_0.2.0_amd64.deb ``` via Cargo diff --git a/dist/ykre_0.1.0_amd64.deb b/dist/ykre_0.1.0_amd64.deb deleted file mode 100644 index 92cc46a..0000000 Binary files a/dist/ykre_0.1.0_amd64.deb and /dev/null differ diff --git a/dist/ykre_0.2.0_amd64.deb b/dist/ykre_0.2.0_amd64.deb new file mode 100644 index 0000000..e12a975 Binary files /dev/null and b/dist/ykre_0.2.0_amd64.deb differ diff --git a/src/main.rs b/src/main.rs index dcf3e83..faf65ae 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,29 +1,8 @@ extern crate yaml_rust; +extern crate colored; + pub mod ykre; -use std::io; -use std::panic; - -const PANIC_BYPASS_FILE : &str = "src/ykre/pipin.rs"; -const PANIC_BYPASS_LINE : u32 = 9; - -fn main() -> io::Result<()> { - - panic::set_hook(Box::new(|_info| { - let mut bypass :bool = false; - if let Some(location) = &_info.location() { - bypass = location.file() == PANIC_BYPASS_FILE && location.line() == PANIC_BYPASS_LINE; - } - if !bypass { - //~ println!("{:?}", &_info); - if let Some(s) = &_info.payload().downcast_ref::<&str>() { - if s.len() > 1 { - println!("{}", s); - } - } - } - })); - - ykre::run(); - Ok(()) +fn main() -> std::io::Result<()> { + ykre::run() } diff --git a/src/ykre.rs b/src/ykre.rs index 47ea9ed..a808cd4 100644 --- a/src/ykre.rs +++ b/src/ykre.rs @@ -1,56 +1,52 @@ mod yaml; mod pipin; mod app; +mod echo; +mod color; pub use self::yaml::YamlDocument; -pub use self::pipin::{spawn_stdin, sleep}; -pub use self::app::{run}; +pub use self::pipin::*; +pub use self::echo::*; +pub use self::color::*; +pub use self::app::run; -const YKRE_LIMIT_ATTEMPT : u64 = 900; -const YKRE_SLEEP_START : u64 = 50; -const YKRE_SLEEP_DATA : u64 = 1; -const YKRE_SLEEP_NODATA : u64 = 1; -const YKRE_DEFAULT_DEF : &str = "metadata.name"; -const YKRE_ERROR_NOTFOUND : &str = r" - :: Ykre :: - - error : no match found for specified pattern -"; -const YKRE_ERROR_INVALID : &str = r" - :: Ykre :: - - error : invalid parameter. type ykre for usage -"; -const YKRE_ERROR_NOPIPE : &str = r" - :: Ykre :: - - error : you must send data using pipe -"; -const YKRE_HELP : &str = r" ------------------------------------------------------------------------------------ - :: Ykre :: v0.1 license : MIT - author : a-Sansara ------------------------------------------------------------------------------------ +const BG : Rgb = Rgb { r: 30, g: 85, b:125 }; +const CSEP : Rgb = Rgb { r: 30, g: 85, b:125 }; +const CTITLE : Rgb = Rgb { r:255, g:220, b:190 }; +const CTITLESEP : Rgb = Rgb { r:255, g:175, b: 35 }; +const CKEY1 : Rgb = Rgb { r: 23, g:141, b: 84 }; +const CVAL1 : Rgb = Rgb { r:149, g:197, b:157 }; +const CKEY2 : Rgb = Rgb { r:237, g:214, b:140 }; +const CVAL2 : Rgb = Rgb { r:238, g:194, b: 55 }; +const CTEXT : Rgb = Rgb { r:190, g:162, b:216 }; +const CPROG : Rgb = Rgb { r:255, g:255, b:255 }; +const COPTSEP : Rgb = Rgb { r:255, g:151, b: 75 }; +//~ const COPT : Rgb = Rgb { r: 23, g:141, b: 84 }; +const CARG : Rgb = Rgb { r: 90, g:205, b:255 }; +const CUSAGE : Rgb = Rgb { r:238, g:194, b: 55 }; +const CSTR : Rgb = Rgb { r: 66, g:135, b: 99 }; +const CCOM : Rgb = Rgb { r:105, g:103, b:149 }; +const CERR : Rgb = Rgb { r:175, g: 37, b: 21 }; +const CERRMSG : Rgb = Rgb { r:210, g: 99, b: 86 }; +const WIDTH : usize = 82; +const PANIC_BYPASS_LINE : u32 = 9; +const PANIC_BYPASS_FILE : &str = "src/ykre/pipin.rs"; +const YKRE_AUTHOR : &str = "a-Sansara"; +const YKRE_VERSION : &str = "0.2"; +const YKRE_LICENSE : &str = "MIT"; +const YKRE_NAME : &str = "Ykre"; +const YKRE_DEFAULT_DEF : &str = "metadata.name"; +const YKRE_LIMIT_ATTEMPT : u64 = 1500; +const YKRE_SLEEP_START : u64 = 50; +const YKRE_SLEEP_DATA : u64 = 1; +const YKRE_SLEEP_NODATA : u64 = 1; +const YKRE_ERROR_NOTFOUND : &str = "no match found for specified pattern"; +const YKRE_ERROR_INVALID : &str = "invalid parameter. Type ykre for help"; +const YKRE_ERROR_NOPIPE : &str = "you must send data using pipe. Type ykre for help"; +const YKRE_DESCRIPTION : &str = r" Ykre is a small program written in `rust` wich purpose is to extract from a list of yaml documents, documents matching a specified condition. Ykre goal is to find specific Kubernetes Resource from the kustomize output. - Ykre stands for Yaml Kubernetes Resources Ectractor. - - Usage : - - ykre SEARCH [DEF] - - you MUST use pipe with ykre command - - SEARCH - value of kubernetes resource name - DEF - the yaml node to look for - (default : 'metadata.name', dot is the separator for embed nodes) - - ex : - # display content of the kubernetes resource 'myResourceName' - cat kubresources.yaml | ykre 'myResourceName' - # write content of the kubernetes resource 'pv-dump' into a file - kustomize build ./config/volumes/local | ykre 'pv-dump' > ./tmp.yaml - # retriew kubernetes pv resources matching 2Gi disk capacity - kustomize build ./config/volumes/dev | ykre 2Gi spec.capacity.storage + Ykre stands for Yaml Kubernetes Resources Extractor. "; diff --git a/src/ykre/app.rs b/src/ykre/app.rs index b9d2cba..cd8c6de 100644 --- a/src/ykre/app.rs +++ b/src/ykre/app.rs @@ -1,5 +1,6 @@ use std::panic; use std::env; +use std::io; use std::sync::mpsc::TryRecvError; use crate::ykre::*; @@ -43,11 +44,15 @@ pub fn get_data(buf :&mut String, limit :u32) -> bool { return has_data } -pub fn run() { +pub fn run() -> io::Result<()> { + set_panic(); let args: Vec = env::args().collect(); if args.len() == 1 { - println!("{}", YKRE_HELP); - return + title(YKRE_NAME, YKRE_VERSION, YKRE_LICENSE, YKRE_AUTHOR); + description(YKRE_DESCRIPTION); + usage(); + example(); + return Ok(()); } else if args.len() > 1 && args.len() <= 3 { @@ -59,9 +64,32 @@ pub fn run() { }; let limit : u32 = env::var("YKRE_LIMIT_ATTEMPT").unwrap_or(format!("{}", YKRE_LIMIT_ATTEMPT).to_owned()).parse::().unwrap(); if get_data(&mut buf, limit) { - return find(search, def, buf); + find(search, def, buf); + return Ok(()); } panic!(YKRE_ERROR_NOPIPE) } panic!(YKRE_ERROR_INVALID) } + +pub fn set_panic() { + panic::set_hook(Box::new(|_info| { + let mut bypass :bool = false; + if let Some(location) = &_info.location() { + bypass = location.file() == PANIC_BYPASS_FILE && location.line() == PANIC_BYPASS_LINE; + } + if !bypass { + //~ println!("{:?}", &_info); + if let Some(s) = &_info.payload().downcast_ref::<&str>() { + if s.len() > 1 { + title(YKRE_NAME, YKRE_VERSION, YKRE_LICENSE, YKRE_AUTHOR); + perror(s); + if *s != &YKRE_ERROR_NOTFOUND { + usage(); + println!(""); + } + } + } + } + })); +} diff --git a/src/ykre/color.rs b/src/ykre/color.rs new file mode 100644 index 0000000..b3a652a --- /dev/null +++ b/src/ykre/color.rs @@ -0,0 +1,19 @@ +use colored::*; + +pub struct Rgb { + pub r: u8, + pub g: u8, + pub b: u8, +} + +impl Rgb { + pub fn new(r: u8, g: u8, b: u8) -> Self { + Self { r, g, b } + } + pub fn fg(self, label: &str) -> ColoredString { + label.truecolor(self.r, self.g, self.b) + } + pub fn bg(self, label: &str) -> ColoredString { + label.on_truecolor(self.r, self.g, self.b) + } +} diff --git a/src/ykre/echo.rs b/src/ykre/echo.rs new file mode 100644 index 0000000..be0085e --- /dev/null +++ b/src/ykre/echo.rs @@ -0,0 +1,76 @@ +use crate::ykre::*; +use colored::*; +use std::borrow::Cow; + +pub fn title(label :&str, version :&str, license: &str, author :&str) { + let space = 42+version.len()+label.len()+license.len()+author.len(); + let sep = format!("{}", CSEP.fg(&"―".repeat(WIDTH+1))); + let titlesep = CTITLESEP.fg(" :: "); + let ptitle = BG.bg(&format!("{}{}{}", titlesep, CTITLE.fg(label), titlesep)).bold(); + println!("{}" , sep); + print! (" {} " , ptitle); + print! ("{}" , keyval("version", version, CKEY1, CVAL1).bold()); + print! ("{}" , " ".repeat(WIDTH-space)); + print! ("{} " , keyval("license", license, CKEY1, CVAL1).bold()); + println!("{}" , keyval("author", author, CKEY2, CVAL2).bold()); + println!("{}" , sep); +} + +pub fn keyval (key :&str, val :&str, ck : Rgb, cv : Rgb) -> Cow<'static, str> { + format!("{} {}", ck.fg(&format!("{} :", key)), cv.fg(val)).into() +} + +pub fn description(description :&str) { + println!(" {}", CTEXT.fg(description)); +} + +pub fn usage() { + let space_arg : usize = 11; + let arg1 : &str = "SEARCH"; + let arg2 : &str = "DEF"; + println!(" {} :", CUSAGE.fg("Usage").bold()); + println!(""); + println!(" {}", format!("{} {} {}{}{}", + CPROG.fg(&YKRE_NAME.to_lowercase()), + CARG.fg(&arg1), + COPTSEP.fg("["), + CARG.fg(&arg2), + COPTSEP.fg("]") + ).bold()); + println!(""); + println!(" {}", CTEXT.fg("you MUST use pipe with ykre command")); + println!(""); + print! ("{}{} : ", " ".repeat(space_arg-arg1.len()), CARG.fg(arg1).bold()); + println!("{}" , CTEXT.fg("value of matching yaml node (kubernetes resource name)")); + println!(""); + print! ("{}{} : ", " ".repeat(space_arg-arg2.len()), CARG.fg(arg2).bold()); + println!("{}" , CTEXT.fg("the yaml node to look for")); + println!("{}{}" , " ".repeat(space_arg+3), CTEXT.fg("(default : 'metadata.name', dot is the separator for embed nodes)")); +} + +pub fn example() { + println!(""); + println!(" {} :" , CUSAGE.fg("Examples").bold()); + println!(""); + + println!(" {}", CCOM.fg("# display content of the kubernetes resource 'myResourceName'")); + print! (" {}", format!("{} {} {}", CPROG.fg("cat"), CARG.fg("'./kubresources.yaml'"), COPTSEP.fg("|")).bold()); + println!(" {}" , format!("{} {}" , CPROG.fg("ykre"), CARG.fg("'myResourceName'")).bold()); + println!(""); + + println!(" {}", CCOM.fg("# write content of the kubernetes resource 'pv-dump' into a file")); + print! (" {}", format!("{} {} {} {}", CPROG.fg("kustomize"), CARG.fg("build"), CARG.fg("'./config/volumes/local'"), COPTSEP.fg("|")).bold()); + println!(" {}" , format!("{} {} {} {}", CPROG.fg("ykre"), CARG.fg("'pv-dump'"), COPTSEP.fg(">"), CSTR.fg("./tmp.yaml")).bold()); + println!(""); + + println!(" {}", CCOM.fg("# retriew kubernetes pv resources matching 2Gi disk capacity")); + print! (" {}", format!("{} {} {} {}", CPROG.fg("kustomize"), CARG.fg("build"), CARG.fg("'./config/volumes/dev'"), COPTSEP.fg("|")).bold()); + println!(" {}" , format!("{} {} {}" , CPROG.fg("ykre"), CARG.fg("'2Gi'"), CARG.fg("'spec.capacity.storage'")).bold()); + println!(""); +} + +pub fn perror(msg: &str) { + println!(""); + println!(" {} : {}", format!("{}", CERR.fg("error")).bold(), CERRMSG.fg(msg)); + println!(""); +}