use std::fs::{ self, File, }; use clap::{ Arg, ArgMatches, SubCommand, App, }; use crate::cmd::{ Command, CommandError, }; const CARGO_TOML_FILE: &str = "Cargo.toml"; const MAIN_RS: &str = include_str!("main.rs_template"); const CMD_RS: &str = include_str!("cmd.rs"); const CMD_DEFAULT_RS: &str = include_str!("cmd_default.rs"); const CMD_SAMPLE_RS: &str = include_str!("cmd_sample.rs"); const CARGO_TOML: &str = include_str!("Carto.toml_template"); pub struct CommandNewCliApp; impl Command for CommandNewCliApp { fn name(&self) -> &str { "newcliapp" } fn subcommand<'a>(&self) -> App<'a, 'a> { SubCommand::with_name(self.name()).about("New cli app") .arg(Arg::with_name("APP_NAME").required(true).index(1).help("App name")) .arg(Arg::with_name("verbose").long("verbose").short("V").help("Verbose")) } fn run(&self, _arg_matches: &ArgMatches, sub_arg_matches: &ArgMatches) -> CommandError { let is_verbose = sub_arg_matches.is_present("verbose"); if is_file_exists(CARGO_TOML_FILE) || is_file_exists("src") { println!("[ERROR] File exists: {}, or dir exists: src/", CARGO_TOML_FILE); return Ok(()); } let app_name = sub_arg_matches.value_of("APP_NAME").expect("APP_NAME is required!"); let cargo_toml = CARGO_TOML.replace("{{NAME}}", app_name); if is_verbose { println!("[INFO] Create dir: src/"); } fs::create_dir("src/")?; if is_verbose { println!("[INFO] Create file: src/main.rs"); } fs::write("src/main.rs", MAIN_RS.as_bytes())?; if is_verbose { println!("[INFO] Create file: src/cmd.rs"); } fs::write("src/cmd.rs", CMD_RS.as_bytes())?; if is_verbose { println!("[INFO] Create file: src/cmd_default.rs"); } fs::write("src/cmd_default.rs", CMD_DEFAULT_RS.as_bytes())?; if is_verbose { println!("[INFO] Create file: src/cmd_sample.rs"); } fs::write("src/cmd_sample.rs", CMD_SAMPLE_RS.as_bytes())?; if is_verbose { println!("[INFO] Create file: Cargo.toml"); } fs::write(CARGO_TOML_FILE, cargo_toml.as_bytes())?; println!("[INFO] Project created!"); Ok(()) } } fn is_file_exists(file_name: &str) -> bool { File::open(file_name).is_ok() }