diff --git a/Cargo.lock b/Cargo.lock index 0009c50..03b9ad0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1671,11 +1671,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "tmpo" -version = "2.4.1" +version = "2.5.1" dependencies = [ "assert_cli 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)", "assert_cmd 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", "base64 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)", + "chrono 0.4.15 (registry+https://github.com/rust-lang/crates.io-index)", "clap 3.0.0-beta.2 (registry+https://github.com/rust-lang/crates.io-index)", "colored 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "convert_case 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/Cargo.toml b/Cargo.toml index 61e7f64..b2ec01d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "tmpo" description = "Command line utility to create new workspaces based on predefined templates" -version = "2.4.1" +version = "2.5.1" authors = ["Thomas Pöhlmann "] edition = "2018" license = "MIT" @@ -13,7 +13,6 @@ serde_json = "1.0.62" serde_yaml = "0.8.17" dirs = "3.0.1" log = "0.4.14" -log4rs = "1.0.0" git2 = "0.13" colored = "2.0.0" dialoguer = "0.7.1" @@ -27,6 +26,10 @@ base64 = "0.13.0" semver = "0.11.0" convert_case = "0.4.0" linked_hash_set = "0.1.4" +chrono = "0.4.13" + +[dependencies.log4rs] +version = "1.0.0" [dependencies.reqwest] version = "0.11.0" diff --git a/changelog.md b/changelog.md index aaadf8f..0cce198 100644 --- a/changelog.md +++ b/changelog.md @@ -1,5 +1,18 @@ # What's new in Tmpo +### 2.5.1 + +### Fix + +- Setup timebased rolling log files + +## 2.5.0 + +### Feature + +- Add template note. `note` property is printed after initialization of a template +- Make all repository add inputs available through args + ## 2.4.1 ### Fix diff --git a/media/logo_v3.svg b/media/logo_v3.svg index 6ba9d5b..0e3fc44 100644 --- a/media/logo_v3.svg +++ b/media/logo_v3.svg @@ -37,18 +37,18 @@ borderopacity="1.0" inkscape:pageopacity="0.0" inkscape:pageshadow="2" - inkscape:zoom="0.8625" + inkscape:zoom="0.57848045" inkscape:cx="306.74548" - inkscape:cy="367.07793" + inkscape:cy="251.21888" inkscape:document-units="mm" inkscape:current-layer="layer1" inkscape:document-rotation="0" showgrid="false" - inkscape:window-width="923" + inkscape:window-width="1846" inkscape:window-height="1006" inkscape:window-x="74" inkscape:window-y="38" - inkscape:window-maximized="0" + inkscape:window-maximized="1" inkscape:snap-global="true" /> @@ -67,12 +67,12 @@ inkscape:label="Layer 1" inkscape:groupmode="layer" id="layer1" - style="opacity:0.99998869"> + style="opacity:0.99998869;"> + style="fill:#f69200;fill-opacity:1;stroke:#383838;stroke-width:3.027;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + d="m 107.56751,65.365787 c -1.68462,0.01282 -3.24723,0.07736 -4.5612,0.205162 -3.684293,0.367155 -7.729352,1.02205 -8.888759,1.441351 -1.700427,0.628907 -1.777837,0.943447 -1.932444,6.630117 l -0.128451,5.083665 -3.401151,1.126853 c -3.658477,1.231658 -8.167231,3.144711 -10.279888,4.350167 l -1.314141,0.759828 -0.489004,-0.550007 c -0.257326,-0.314155 -1.958474,-1.965326 -3.762001,-3.668729 -3.040174,-2.908816 -3.349431,-3.118637 -4.302723,-3.118637 -1.159365,0 -3.375122,1.414979 -7.755039,4.952746 -5.204381,4.192919 -13.989893,13.810669 -15.484218,16.981579 -0.82446,1.755758 -0.515135,2.305938 3.529856,6.236768 l 3.504005,3.43312 -1.15956,2.2011 c -1.623148,3.06607 -2.936976,6.15854 -4.070604,9.56535 l -0.953288,2.88257 -5.333044,0.1308 -5.333553,0.13078 -0.695322,0.81241 c -0.747165,0.8386 -0.927454,1.65078 -1.880729,7.83535 -0.437992,2.85642 -0.41223,13.99425 0,17.03415 0.541049,3.64257 1.056057,6.49886 1.339463,7.20641 0.541054,1.31027 1.030647,1.44118 6.67302,1.57219 l 5.230165,0.13079 0.953288,2.88308 c 1.133628,3.40672 2.447456,6.4986 4.070604,9.53843 l 1.15956,2.22746 -3.632731,3.53773 c -4.070753,4.00947 -4.302885,4.45526 -3.40113,6.21103 1.777731,3.38056 10.382894,12.8146 15.484218,16.90271 4.379917,3.53777 6.595674,4.95275 7.755039,4.95275 0.953292,0 1.262549,-0.20944 4.302723,-3.11813 1.803527,-1.7034 3.504336,-3.35478 3.762001,-3.66924 l 0.489004,-0.55005 1.314141,0.75984 c 2.112657,1.2055 6.621411,3.1185 10.279888,4.35021 l 3.401151,1.1268 0.128451,5.13629 0.128451,5.13623 0.772867,0.78611 c 0.695628,0.6814 1.107985,0.81241 3.993552,1.28411 8.347653,1.36271 15.793313,1.4151 24.475833,0.15729 5.61665,-0.8386 5.66858,-0.89066 5.66858,-7.78279 v -4.79605 l 2.03534,-0.57629 c 3.19473,-0.89101 6.82748,-2.35848 10.12528,-4.00943 1.67473,-0.8386 3.09172,-1.41519 3.16904,-1.31035 0.0772,0.1308 1.75173,1.75559 3.73559,3.64241 4.71487,4.53357 4.56035,4.50749 10.15119,0.20986 6.64718,-5.11013 14.84015,-13.67954 17.54537,-18.39656 1.10786,-1.91302 0.902,-2.33227 -3.24607,-6.42034 l -3.63271,-3.56401 1.44285,-2.72537 c 1.52013,-2.93506 3.22013,-7.10161 4.14765,-10.08907 l 0.56713,-1.83457 5.33305,-0.1308 5.35886,-0.13078 0.69584,-0.81237 c 0.56679,-0.65514 0.82463,-1.33667 1.15953,-3.27593 1.49436,-8.54308 1.52001,-17.05949 0.12845,-25.31428 -0.28318,-1.6248 -0.61826,-3.22339 -0.77286,-3.5641 -0.54102,-1.23165 -1.05631,-1.36278 -6.64719,-1.49383 l -5.25597,-0.13079 -0.56714,-1.83462 c -0.92756,-2.98746 -2.62752,-7.15396 -4.14765,-10.08903 l -1.44284,-2.72532 3.6327,-3.5641 c 4.07083,-3.98327 4.30243,-4.42898 3.40064,-6.184743 -1.59737,-3.039864 -8.50218,-10.848811 -13.29433,-15.015528 -5.25593,-4.585975 -8.55373,-6.839896 -9.97076,-6.839896 -0.92751,0 -1.26242,0.262009 -4.58603,3.433091 -1.98387,1.886809 -3.65831,3.511351 -3.73559,3.642399 -0.0772,0.105147 -1.49431,-0.471787 -3.16905,-1.310387 -3.2978,-1.650958 -6.93054,-3.118382 -10.12528,-4.009384 L 127.2241,78.80507 v -4.848114 c 0,-5.162523 -0.10302,-5.712785 -1.28829,-6.577587 -1.48566,-1.128478 -11.06831,-2.066711 -18.3683,-2.013368 z m 0.61622,20.183821 c 3.11614,0.02137 7.99138,0.304323 10.02867,0.623094 4.78227,0.750382 9.37509,2.143775 13.68672,4.09038 h -20.42781 l 11.80375,11.070258 h 24.69297 c 7.18795,7.11438 12.49072,16.22188 14.99107,26.4664 1.19404,4.97942 1.49244,7.59045 1.49244,13.51109 0,5.92064 -0.29844,8.53167 -1.49244,13.51109 -5.37319,21.98237 -23.43305,38.49986 -45.64209,41.77898 -2.48567,0.37058 -7.46329,0.47534 -11.35523,0.31373 -1.52979,-0.0636 -2.89192,-0.1684 -3.86895,-0.31373 -2.574703,-0.37997 -5.093739,-0.93822 -7.543633,-1.66211 -18.682357,-5.52028 -33.348194,-20.68296 -38.098436,-40.11687 -1.19403,-4.97942 -1.492485,-7.59045 -1.492485,-13.51109 0,-5.92064 0.298447,-8.53167 1.492485,-13.51109 2.495203,-10.22969 7.778245,-19.34051 14.993595,-26.4664 H 103.09161 L 91.33006,90.263082 h -3.757824 c 2.251791,-1.012647 4.583577,-1.877832 6.983701,-2.583334 3.555377,-1.042395 7.178713,-1.579877 11.326273,-2.060214 0.48617,-0.05556 1.30355,-0.0765 2.30152,-0.0701 z m -5.09212,15.783732 v 23.2683 l -4.95876,-4.67825 v 43.51316 l 4.95876,-4.67829 v 28.05654 l 13.15735,-12.49576 V 146.3456 l 4.94528,-4.66565 -4.94528,-4.66564 v -23.38752 z" + sodipodi:nodetypes="scccccccccscccccccccccccccccccccscccccccccccsccccccccccccccccccccccccccscccccscssccccccsccscscscccccccscccccccccccccc" /> info, + Err(error) => { + log::error!("{}", error); + eprintln!("{}", error); + exit(1); + } + }; + + // Print template info + if template_info.is_some() { + let info = renderer::render(&template_info.unwrap(), &render_context); + out::success::workspace_info(&info); + } } } diff --git a/src/action/repository/add.rs b/src/action/repository/add.rs index ecd3aab..13b06a6 100644 --- a/src/action/repository/add.rs +++ b/src/action/repository/add.rs @@ -23,6 +23,9 @@ impl Action { let repository_authentication = args.value_of("authentication"); let repository_url = args.value_of("url"); let repository_branch = args.value_of("branch"); + let username = args.value_of("username"); + let password = args.value_of("password"); + let token = args.value_of("token"); let mut git_options = git::Options::new(); @@ -125,24 +128,35 @@ impl Action { // Get credentials for different auth types match git_options.auth.clone().unwrap() { git::AuthType::BASIC => { - git_options.username = match input::text("Enter your git username", false) { - Ok(value) => Some(value), - Err(error) => { - log::error!("{}", error); - eprintln!("{}", error); - exit(1); + // Get username + git_options.username = if username.is_none() { + match input::text("Enter your git username", false) { + Ok(value) => Some(value), + Err(error) => { + log::error!("{}", error); + eprintln!("{}", error); + exit(1); + } } + } else { + Some(String::from(username.unwrap())) }; - git_options.password = match input::password("Enter your git password") { - Ok(value) => Some(value), - Err(error) => { - log::error!("{}", error); - eprintln!("{}", error); - exit(1); + // Get password + git_options.password = if password.is_none() { + match input::password("Enter your git password") { + Ok(value) => Some(value), + Err(error) => { + log::error!("{}", error); + eprintln!("{}", error); + exit(1); + } } + } else { + Some(String::from(password.unwrap())) } } git::AuthType::SSH => { + // Get ssh private key git_options.token = match input::text("Enter your git username", false) { Ok(value) => Some(value), Err(error) => { @@ -153,13 +167,18 @@ impl Action { } } git::AuthType::TOKEN => { - git_options.token = match input::text("Enter your access token", false) { - Ok(value) => Some(value), - Err(error) => { - log::error!("{}", error); - eprintln!("{}", error); - exit(1); + // Get token + git_options.token = if token.is_none() { + match input::text("Enter your access token", false) { + Ok(value) => Some(value), + Err(error) => { + log::error!("{}", error); + eprintln!("{}", error); + exit(1); + } } + } else { + Some(String::from(token.unwrap())) } } git::AuthType::NONE => { diff --git a/src/logger/mod.rs b/src/logger/mod.rs index c688fb9..a455c62 100644 --- a/src/logger/mod.rs +++ b/src/logger/mod.rs @@ -1,3 +1,4 @@ +use chrono::Local; use log::LevelFilter; use log4rs::{ append::{ @@ -21,7 +22,7 @@ pub fn init() { .build(); // Logging to log file - let logfile_path = config::directory().join("log/output.log"); + let logfile_path = config::directory().join(get_log_file_name()); let logfile = FileAppender::builder() .encoder(Box::new(PatternEncoder::new( @@ -47,3 +48,9 @@ pub fn init() { log4rs::init_config(config).unwrap(); } + +fn get_log_file_name() -> String { + let local = Local::now(); + let timestamp = local.format("%Y-%m-%d").to_string(); + return String::from("log/") + ×tamp + ".log"; +} diff --git a/src/main.rs b/src/main.rs index 79ade89..75749d0 100644 --- a/src/main.rs +++ b/src/main.rs @@ -187,6 +187,27 @@ fn main() { .takes_value(true) .about("Remote repository branch") .required(false), + ) + .arg( + Arg::new("username") + .long("username") + .takes_value(true) + .about("Username for authentication") + .required(false), + ) + .arg( + Arg::new("password") + .long("password") + .takes_value(true) + .about("Password for basic authentication") + .required(false), + ) + .arg( + Arg::new("token") + .long("token") + .takes_value(true) + .about("Token for authentication") + .required(false), ), ) .subcommand( diff --git a/src/meta/mod.rs b/src/meta/mod.rs index 42cb99c..50e7eac 100644 --- a/src/meta/mod.rs +++ b/src/meta/mod.rs @@ -29,6 +29,7 @@ pub struct TemplateMeta { pub extend: Option>, pub exclude: Option>, pub renderer: Option, + pub info: Option, } #[derive(Serialize, Deserialize, PartialEq, Clone, Debug)] @@ -157,6 +158,7 @@ impl TemplateMeta { exclude: None, values: None, }), + info: None, } } diff --git a/src/out/success.rs b/src/out/success.rs index 99f0775..d05c632 100644 --- a/src/out/success.rs +++ b/src/out/success.rs @@ -10,6 +10,11 @@ pub fn workspace_created(name: &str) { println!("{}", text); } +pub fn workspace_info(info: &str) { + println!(""); + println!("{}", info) +} + pub fn template_created(path: &str) { let text = format!("Created template: {}", path).green(); println!("{}", text); diff --git a/src/repository/custom_repository.rs b/src/repository/custom_repository.rs index 364434b..771c673 100644 --- a/src/repository/custom_repository.rs +++ b/src/repository/custom_repository.rs @@ -9,7 +9,7 @@ use crate::config::{Config, RepositoryOptions}; use crate::context::Context; use crate::error::RunError; use crate::git; -use crate::meta::{self, TemplateMeta, RepositoryMeta, Value}; +use crate::meta::{self, RepositoryMeta, TemplateMeta, Value}; use crate::repository::{CopyOptions, Repository}; use crate::template; use crate::template::Template; @@ -48,6 +48,28 @@ impl Repository for CustomRepository { Ok(()) } + fn get_template_info(&self, template_name: &str) -> Result, RunError> { + let template = self.get_template_by_name(template_name)?; + + if template.meta.info.is_some() { + return Ok(template.meta.info.to_owned()); + } + + // Get list of all super templates + let super_templates = match self.get_super_templates(template, &mut HashSet::new()) { + Ok(templates) => templates, + Err(error) => return Err(error), + }; + + for template in super_templates.iter().rev() { + if template.meta.info.is_some() { + return Ok(template.meta.info.to_owned()); + } + } + + Ok(None) + } + fn get_template_values(&self, template_name: &str) -> Result, RunError> { let template = self.get_template_by_name(&template_name)?; diff --git a/src/repository/default_repository.rs b/src/repository/default_repository.rs index 6ac1ec9..38ad674 100644 --- a/src/repository/default_repository.rs +++ b/src/repository/default_repository.rs @@ -40,8 +40,14 @@ impl Repository for DefaultRepository { Ok(()) } + fn get_template_info(&self, template_name: &str) -> Result, RunError> { + let template = self.get_template_by_name(template_name)?; + + Ok(template.meta.info.to_owned()) + } + fn get_template_values(&self, template_name: &str) -> Result, RunError> { - let template = self.get_template_by_name(&template_name)?; + let template = self.get_template_by_name(template_name)?; let mut values = LinkedHashSet::new(); values.extend(template.meta.get_values()); diff --git a/src/repository/mod.rs b/src/repository/mod.rs index 73de258..f1a1829 100644 --- a/src/repository/mod.rs +++ b/src/repository/mod.rs @@ -14,6 +14,7 @@ pub mod default_repository; pub trait Repository { fn get_config(&self) -> RepositoryOptions; fn copy_template(&self, ctx: &Context, opts: &CopyOptions) -> Result<(), RunError>; + fn get_template_info(&self, template_name: &str) -> Result, RunError>; fn get_template_values(&self, template_name: &str) -> Result, RunError>; fn get_template_names(&self) -> Vec; fn get_template_by_name(&self, name: &str) -> Result<&template::Template, RunError>;