From 7e5bef43081c441398934d0892cfa864fa3f9327 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin?= <94377405+kevin-legion@users.noreply.github.com> Date: Thu, 27 Jan 2022 15:44:14 -0500 Subject: [PATCH 1/2] Update dependencies and make the project compile, no code cleanup --- Cargo.lock | 206 +++++++++++++++++++++++++++++++++++--------------- Cargo.toml | 32 ++++---- rustfmt.toml | 1 - src/lib.rs | 29 +++---- src/main.rs | 62 +++++++-------- src/render.rs | 24 +++--- src/repo.rs | 4 +- src/types.rs | 1 + 8 files changed, 216 insertions(+), 143 deletions(-) delete mode 100644 rustfmt.toml diff --git a/Cargo.lock b/Cargo.lock index bd47a7a..7d17c02 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,21 +1,14 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. +version = 3 + [[package]] name = "aho-corasick" version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ca972c2ea5f742bfce5687b9aef75506a764f61d37f8f649047846a9686ddb66" dependencies = [ - "memchr", -] - -[[package]] -name = "ansi_term" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b" -dependencies = [ - "winapi 0.3.9", + "memchr 0.1.11", ] [[package]] @@ -66,6 +59,17 @@ version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" +[[package]] +name = "cargo_toml" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "31f61f8437a6b96dfb0be4aad6b222e01d5681b1ceacac7251501389e169e219" +dependencies = [ + "serde", + "serde_derive", + "toml", +] + [[package]] name = "case" version = "1.0.0" @@ -93,19 +97,32 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +[[package]] +name = "chrono" +version = "0.4.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "670ad68c9088c2a963aaa298cb369688cf3f9465ce5e2d4ca10e6e0098a1ce73" +dependencies = [ + "libc", + "num-integer", + "num-traits", + "time", + "winapi 0.3.9", +] + [[package]] name = "clap" -version = "2.33.3" +version = "3.0.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37e58ac78573c40708d45522f0d80fa2f01cc4f9b4e2bf749807255454312002" +checksum = "08799f92c961c7a1cf0cc398a9073da99e21ce388b46372c37f3191f2f3eed3e" dependencies = [ - "ansi_term", "atty", "bitflags", + "indexmap", + "os_str_bytes", "strsim", + "termcolor", "textwrap", - "unicode-width", - "vec_map", "yaml-rust", ] @@ -116,7 +133,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "329b012f8172800c7ba02414b726d8664c342e58de6b7adba0b90823544806fc" dependencies = [ "colored", - "dirs", + "dirs 3.0.2", ] [[package]] @@ -149,6 +166,15 @@ dependencies = [ "dirs-sys", ] +[[package]] +name = "dirs" +version = "4.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca3aa72a6f96ea37bbc5aa912f6788242832f75369bdfdadcb0e38423f100059" +dependencies = [ + "dirs-sys", +] + [[package]] name = "dirs-sys" version = "0.3.6" @@ -198,9 +224,9 @@ dependencies = [ [[package]] name = "git2" -version = "0.13.18" +version = "0.13.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b483c6c2145421099df1b4efd50e0f6205479a072199460eff852fa15e5603c7" +checksum = "f29229cc1b24c0e6062f6e742aa3e256492a5323365e5ed3413599f8a5eff7d6" dependencies = [ "bitflags", "libc", @@ -211,14 +237,17 @@ dependencies = [ "url", ] +[[package]] +name = "hashbrown" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e" + [[package]] name = "heck" -version = "0.3.2" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87cbf45460356b7deeb5e3415b5563308c0a9b057c85e12b06ad551f98d0a6ac" -dependencies = [ - "unicode-segmentation", -] +checksum = "2540771e65fc8cb83cd6e8a237f70c319bd5c29f78ed1084ba5d50eeac86f7f9" [[package]] name = "hermit-abi" @@ -240,6 +269,16 @@ dependencies = [ "unicode-normalization", ] +[[package]] +name = "indexmap" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282a6247722caba404c065016bbfa522806e51714c34f5dfc3e4a3a46fcb4223" +dependencies = [ + "autocfg", + "hashbrown", +] + [[package]] name = "jobserver" version = "0.1.22" @@ -267,15 +306,15 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" -version = "0.2.94" +version = "0.2.115" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18794a8ad5b29321f790b55d93dfba91e125cb1a9edbd4f8e3150acc771c1a5e" +checksum = "0a8d982fa7a96a000f6ec4cfe966de9703eccde29750df2bb8949da91b0e818d" [[package]] name = "libgit2-sys" -version = "0.12.19+1.1.0" +version = "0.12.26+1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f322155d574c8b9ebe991a04f6908bb49e68a79463338d24a43d6274cb6443e6" +checksum = "19e1c899248e606fbfe68dcb31d8b0176ebab833b103824af31bddf4b7457494" dependencies = [ "cc", "libc", @@ -311,6 +350,12 @@ dependencies = [ "vcpkg", ] +[[package]] +name = "linked-hash-map" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fb9b38af92608140b86b693604b9ffcc5824240a484d1ecd4795bacb2fe88f3" + [[package]] name = "log" version = "0.4.14" @@ -335,6 +380,31 @@ dependencies = [ "libc", ] +[[package]] +name = "memchr" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a" + +[[package]] +name = "num-integer" +version = "0.1.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2cc698a63b549a70bc047073d2949cce27cd1c7b0a4a862d08a8031bc2801db" +dependencies = [ + "autocfg", + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a64b1ec5cda2586e284722486d802acf1f7dbdc623e2bfc57e65ca1cd099290" +dependencies = [ + "autocfg", +] + [[package]] name = "openssl-probe" version = "0.1.2" @@ -354,6 +424,15 @@ dependencies = [ "vcpkg", ] +[[package]] +name = "os_str_bytes" +version = "6.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e22443d1643a904602595ba1cd8f7d896afe56d26712531c5ff73a15b2fbf64" +dependencies = [ + "memchr 2.4.1", +] + [[package]] name = "percent-encoding" version = "2.1.0" @@ -379,11 +458,13 @@ dependencies = [ name = "project_init" version = "3.1.23" dependencies = [ + "cargo_toml", "case", + "chrono", "clap", "cli-setup", "colored", - "dirs", + "dirs 4.0.0", "git2", "heck", "rustache-lists", @@ -391,7 +472,6 @@ dependencies = [ "serde_derive", "tempdir", "text_io", - "time", "toml", ] @@ -467,7 +547,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4fd4ace6a8cf7860714a2c2280d6c1f7e6a413486c13298bbc86fd3da019402f" dependencies = [ "aho-corasick", - "memchr", + "memchr 0.1.11", "regex-syntax", "thread_local", "utf8-ranges", @@ -513,15 +593,15 @@ checksum = "dcf128d1287d2ea9d80910b5f1120d0b8eede3fbf1abe91c40d39ea7d51e6fda" [[package]] name = "serde" -version = "1.0.125" +version = "1.0.136" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "558dc50e1a5a5fa7112ca2ce4effcb321b0300c0d4ccf0776a9f60cd89031171" +checksum = "ce31e24b01e1e524df96f1c2fdd054405f8d7376249a5110886fb4b658484789" [[package]] name = "serde_derive" -version = "1.0.125" +version = "1.0.136" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b093b7a2bb58203b5da3056c05b4ec1fed827dcfdb37347a8841695263b3d06d" +checksum = "08597e7152fcd306f41838ed3e37be9eaeed2b61c42e2117266a554fab4662f9" dependencies = [ "proc-macro2", "quote", @@ -530,9 +610,9 @@ dependencies = [ [[package]] name = "strsim" -version = "0.8.0" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a" +checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" [[package]] name = "syn" @@ -555,20 +635,26 @@ dependencies = [ "remove_dir_all", ] +[[package]] +name = "termcolor" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dfed899f0eb03f32ee8c6a0aabdb8a7949659e3466561fc0adf54e26d88c5f4" +dependencies = [ + "winapi-util", +] + [[package]] name = "text_io" -version = "0.1.6" +version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "090d2ee73ae8f01646d500fbb72f99f0b2aea174b7b15d58359bbdf083f73e6d" +checksum = "ee74b5019b48991b09803402aaf9e65a053b3993fe9d9c475ab67a395358ba76" [[package]] name = "textwrap" -version = "0.11.0" +version = "0.14.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060" -dependencies = [ - "unicode-width", -] +checksum = "0066c8d12af8b5acd21e00547c3797fde4e8677254a7ee429176ccebbe93dd80" [[package]] name = "thread-id" @@ -641,18 +727,6 @@ dependencies = [ "tinyvec", ] -[[package]] -name = "unicode-segmentation" -version = "1.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb0d2e7be6ae3a5fa87eed5fb451aff96f2573d2694942e40543ae0bbe19c796" - -[[package]] -name = "unicode-width" -version = "0.1.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9337591893a19b88d8d87f2cec1e73fad5cdfd10e5a6f349f498ad6ea2ffb1e3" - [[package]] name = "unicode-xid" version = "0.2.2" @@ -683,12 +757,6 @@ version = "0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cbdbff6266a24120518560b5dc983096efb98462e51d0d68169895b237be3e5d" -[[package]] -name = "vec_map" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191" - [[package]] name = "wasi" version = "0.10.2+wasi-snapshot-preview1" @@ -723,6 +791,15 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" +[[package]] +name = "winapi-util" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" +dependencies = [ + "winapi 0.3.9", +] + [[package]] name = "winapi-x86_64-pc-windows-gnu" version = "0.4.0" @@ -731,6 +808,9 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] name = "yaml-rust" -version = "0.3.5" +version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e66366e18dc58b46801afbf2ca7661a9f59cc8c5962c29892b6039b4f86fa992" +checksum = "56c1936c4cc7a1c9ab21a1ebb602eb942ba868cbd44a99cb7cdc5892335e1c85" +dependencies = [ + "linked-hash-map", +] diff --git a/Cargo.toml b/Cargo.toml index 6ccaa74..3090ef9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,33 +4,35 @@ version = "3.1.23" authors = ["Vanessa McHale "] description = "Quickly initialize projects from a template." license-file = "LICENSE" -exclude = [ "./.gitignore" ] +exclude = ["./.gitignore"] readme = "README.md" repository = "https://github.com/vmchale/project-init" documentation = "https://github.com/vmchale/project-init#README" homepage = "https://github.com/vmchale/project-init" build = "build.rs" +edition = "2021" [build-dependencies] -cli-setup = "0.2" +cli-setup = "0.2.7" [profile.release] lto = true [dependencies] -heck = "0.3" -case = "1.0" -toml = "0.5" -colored = "2.0" -clap = {version = "2.29", features = ["yaml"]} -time = "0.1" -rustache-lists = "0.1.0" -serde_derive = "1.0" -serde = "1.0" -text_io = "<= 0.1.6" -git2 = "0.13" -tempdir = "0.3" -dirs = "3.0" +cargo_toml = "0.11.3" +case = "1.0.0" +chrono = "0.4.19" +clap = { version = "3.0.13", features = ["yaml"] } +colored = "2.0.0" +dirs = "4.0.0" +git2 = "0.13.25" +heck = "0.4.0" +rustache-lists = "0.1.2" +serde = "1.0.136" +serde_derive = "1.0.136" +tempdir = "0.3.7" +text_io = "0.1.9" +toml = "0.5.8" [[bin]] name = "pi" diff --git a/rustfmt.toml b/rustfmt.toml deleted file mode 100644 index 44148a2..0000000 --- a/rustfmt.toml +++ /dev/null @@ -1 +0,0 @@ -reorder_imports = true diff --git a/src/lib.rs b/src/lib.rs index 59a2344..df5afe7 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,30 +1,18 @@ //! This library provides the functions/structs/methods used by the main //! binary. They are included //! here in the hopes that they can be illuminating to users. -#![allow(clippy::too_many_arguments)] -#![allow(clippy::cognitive_complexity)] +// #![allow(clippy::cognitive_complexity)] -extern crate case; -extern crate clap; -extern crate colored; -extern crate git2; -extern crate heck; -extern crate rustache; -#[macro_use] -extern crate serde_derive; -extern crate tempdir; -extern crate time; -extern crate toml; - -use case::*; -use colored::*; -use heck::*; -use rustache::{HashBuilder, VecBuilder}; use std::fs; use std::fs::File; use std::io::prelude::*; use std::path::Path; use std::path::PathBuf; + +use case::*; +use colored::*; +use heck::ToLowerCamelCase; +use rustache::{HashBuilder, VecBuilder}; use toml::Value::Table; pub mod includes; @@ -75,7 +63,7 @@ pub fn read_toml_str(template: &str, template_path: &str) -> types::Project { } /// Given a `PathBuf`, read the .toml file there as a configuration file. -pub fn read_toml_config(config_path: &std::path::PathBuf) -> types::Config { +pub fn read_toml_config(config_path: &Path) -> types::Config { let file = if let Ok(f) = File::open(&config_path) { Some(f) } else { @@ -112,6 +100,7 @@ pub fn read_toml_config(config_path: &std::path::PathBuf) -> types::Config { } } +#[allow(clippy::too_many_arguments)] pub fn init_helper( home: PathBuf, project_dir: &str, @@ -232,7 +221,7 @@ pub fn init_helper( hash = hash .insert("project", name) .insert("Project", name.to_capitalized()) - .insert("ProjectCamelCase", name.to_camel_case()) + .insert("ProjectCamelCase", name.to_lower_camel_case()) .insert("year", year) .insert("name", author.name) .insert("version", version) diff --git a/src/main.rs b/src/main.rs index 409fcc7..e86d7cf 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,20 +1,19 @@ //! Source file for the binary. -#[macro_use] -extern crate clap; -#[macro_use] -extern crate text_io; - -extern crate case; -extern crate colored; -extern crate dirs; -extern crate git2; -extern crate project_init; -extern crate rustache; -extern crate tempdir; -extern crate time; -extern crate toml; +use std::fs; +#[cfg(not(target_os = "windows"))] +use std::fs::set_permissions; +#[cfg(not(target_os = "windows"))] +use std::fs::File; +use std::path::Path; +use std::path::PathBuf; +use std::process::Command; + +use cargo_toml::Manifest; use case::*; +use chrono::Datelike; +use chrono::Utc; +use clap::load_yaml; use clap::{App, AppSettings}; use colored::*; use git2::Repository; @@ -22,14 +21,8 @@ use project_init::render::*; use project_init::types::*; use project_init::*; use rustache::*; -use std::fs; -use std::fs::set_permissions; -use std::fs::File; -use std::path::Path; -use std::path::PathBuf; -use std::process::Command; use tempdir::TempDir; -use time::strftime; +use text_io::read; #[cfg(not(target_os = "windows"))] use std::os::unix::fs::PermissionsExt; @@ -44,18 +37,22 @@ fn mk_executable>(p: P) { } #[cfg(target_os = "windows")] -fn mk_executable>(_: P) -> () { - () -} +fn mk_executable>(_: P) {} #[allow(clippy::cognitive_complexity)] #[allow(clippy::print_literal)] fn main() { + let cargo_manifest = Manifest::from_path("./cargo.toml").unwrap(); + let version = match cargo_manifest.package { + Some(package) => package.version, + None => "unknown".to_string(), + }; + // command-line parser let yaml = load_yaml!("options-en.yml"); let matches = App::from_yaml(yaml) - .version(crate_version!()) - .set_term_width(80) + .version(&*version) + .term_width(80) .setting(AppSettings::SubcommandRequired) .get_matches(); @@ -83,14 +80,19 @@ fn main() { }; // get year - let now = time::now(); - let year = now.tm_year + 1900; - let current_date = strftime("%m-%d-%Y", &now).unwrap(); + let now = Utc::now(); + let year = now.year(); + let current_date = format!( + "{month}-{day}-{year}", + month = now.month0(), + day = now.day0(), + year = year + ); if let Some(x) = matches.subcommand_matches("update") { let force = x.is_present("force"); - println!("current version: {}", crate_version!()); + println!("current version: {}", version); let s = if force { "curl -LSfs https://japaric.github.io/trust/install.sh | sh -s -- --git vmchale/project-init --force" diff --git a/src/render.rs b/src/render.rs index 105ed9d..9e5d2db 100644 --- a/src/render.rs +++ b/src/render.rs @@ -1,7 +1,5 @@ //! Module containing functions for rendering templates -extern crate rustache; -use self::rustache::*; use std::fs; use std::fs::File; use std::io::prelude::*; @@ -10,9 +8,11 @@ use std::io::Cursor; use std::os::unix::fs::PermissionsExt; use std::process::*; +use rustache::*; + /// Trait allowing us to create dirs/templates/files. pub trait Create { - fn create_dirs(&self, name: &str) -> (); + fn create_dirs(&self, name: &str); } /// Render a list of directories, substituting in templates @@ -90,11 +90,11 @@ pub fn render_templates( if let Some(t) = templates_pre { // create Vec of paths to templates let templates: Vec = t - .into_iter() + .iter() .map(|file| { let mut p = project.to_string(); p.push('/'); - p.push_str(&file); + p.push_str(file); if executable { p.push_str(".bat"); } @@ -104,7 +104,7 @@ pub fn render_templates( // read all the template files let template_files: Vec = templates - .into_iter() + .iter() .map(|p| { let template_f_pre = File::open(&p); let mut t = String::new(); @@ -123,31 +123,31 @@ pub fn render_templates( // create Vec of paths to rendered templates let templates_new: Vec = t - .into_iter() + .iter() .map(|file| { let mut p = name.to_string(); p.push('/'); - p.push_str(&file); + p.push_str(file); p }) .collect(); // subtitute into template names let templates_named: Vec = templates_new - .into_iter() + .iter() .map(|n| { let mut o = Cursor::new(Vec::new()); - hash.render(&n, &mut o).unwrap(); + hash.render(n, &mut o).unwrap(); String::from_utf8(o.into_inner()).unwrap() }) .collect(); // render all the template files let s: Vec = template_files - .into_iter() + .iter() .map(|file| { let mut o = Cursor::new(Vec::new()); - hash.render(&file, &mut o).unwrap(); + hash.render(file, &mut o).unwrap(); String::from_utf8(o.into_inner()).unwrap() }) .collect(); diff --git a/src/repo.rs b/src/repo.rs index b36e0e0..fe13270 100644 --- a/src/repo.rs +++ b/src/repo.rs @@ -1,7 +1,7 @@ -use colored::*; -use std; use std::process::Command; +use colored::*; + pub fn git_init(name: &str) { let mut cmd = "cd ".to_string(); cmd.push_str(name); diff --git a/src/types.rs b/src/types.rs index 3dd900a..26b7e4a 100644 --- a/src/types.rs +++ b/src/types.rs @@ -1,5 +1,6 @@ //! This module contains the structs for the configuration files. +use serde_derive::Deserialize; use toml::value::Value; /// Struct for the author. This is read from the global From 9f9cc8c56220bc1e126e10367c3f066d50a3e32f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin?= <94377405+kevin-legion@users.noreply.github.com> Date: Thu, 27 Jan 2022 16:42:26 -0500 Subject: [PATCH 2/2] Cleanup some code, update args handling, possibly breaks some thing --- Cargo.lock | 153 ++++++---- Cargo.toml | 2 +- src/args.rs | 59 ++++ src/lib.rs | 189 ++++++------ src/main.rs | 746 ++++++++++++++++++++++----------------------- src/options-en.yml | 77 ----- src/render.rs | 17 +- src/repo.rs | 88 ++++-- 8 files changed, 671 insertions(+), 660 deletions(-) create mode 100644 src/args.rs delete mode 100644 src/options-en.yml diff --git a/Cargo.lock b/Cargo.lock index 7d17c02..6bef416 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -55,9 +55,9 @@ dependencies = [ [[package]] name = "bitflags" -version = "1.2.1" +version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "cargo_toml" @@ -78,9 +78,9 @@ checksum = "fd6c0e7b807d60291f42f33f58480c0bfafe28ed08286446f45e463728cf9c1c" [[package]] name = "cc" -version = "1.0.67" +version = "1.0.72" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3c69b077ad434294d3ce9f1f6143a2a4b89a8a2d54ef813d85003a4fd1137fd" +checksum = "22a9137b95ea06864e018375b72adfb7db6e6f68cfc8df5a04d00288050485ee" dependencies = [ "jobserver", ] @@ -118,12 +118,26 @@ checksum = "08799f92c961c7a1cf0cc398a9073da99e21ce388b46372c37f3191f2f3eed3e" dependencies = [ "atty", "bitflags", + "clap_derive", "indexmap", + "lazy_static", "os_str_bytes", "strsim", "termcolor", "textwrap", - "yaml-rust", +] + +[[package]] +name = "clap_derive" +version = "3.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fd2078197a22f338bd4fbf7d6387eb6f0d6a3c69e6cbc09f5c93e97321fd92a" +dependencies = [ + "heck", + "proc-macro-error", + "proc-macro2", + "quote", + "syn", ] [[package]] @@ -213,9 +227,9 @@ checksum = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba" [[package]] name = "getrandom" -version = "0.2.2" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c9495705279e7140bf035dde1f6e750c162df8b625267cd52cc44e0b156732c8" +checksum = "418d37c8b1d42553c93648be529cb70f920d3baf8ef469b74b9638df426e0b4c" dependencies = [ "cfg-if 1.0.0", "libc", @@ -251,9 +265,9 @@ checksum = "2540771e65fc8cb83cd6e8a237f70c319bd5c29f78ed1084ba5d50eeac86f7f9" [[package]] name = "hermit-abi" -version = "0.1.18" +version = "0.1.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "322f4de77956e22ed0e5032c359a0f1273f1f7f0d79bfa3b8ffbc730d7fbcc5c" +checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" dependencies = [ "libc", ] @@ -281,9 +295,9 @@ dependencies = [ [[package]] name = "jobserver" -version = "0.1.22" +version = "0.1.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "972f5ae5d1cb9c6ae417789196c803205313edde988685da5e3aae0827b9e7fd" +checksum = "af25a77299a7f711a01975c35a6a424eb6862092cc2d6c72c4ed6cbc56dfc1fa" dependencies = [ "libc", ] @@ -326,9 +340,9 @@ dependencies = [ [[package]] name = "libssh2-sys" -version = "0.2.21" +version = "0.2.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0186af0d8f171ae6b9c4c90ec51898bad5d08a2d5e470903a50d9ad8959cbee" +checksum = "b094a36eb4b8b8c8a7b4b8ae43b2944502be3e59cd87687595cf6b0a71b3f4ca" dependencies = [ "cc", "libc", @@ -350,12 +364,6 @@ dependencies = [ "vcpkg", ] -[[package]] -name = "linked-hash-map" -version = "0.5.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fb9b38af92608140b86b693604b9ffcc5824240a484d1ecd4795bacb2fe88f3" - [[package]] name = "log" version = "0.4.14" @@ -367,9 +375,9 @@ dependencies = [ [[package]] name = "matches" -version = "0.1.8" +version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ffc5c5338469d4d3ea17d269fa8ea3512ad247247c30bd2df69e68309ed0a08" +checksum = "a3e378b66a060d48947b590737b30a1be76706c8dd7b8ba0f2fe3989c68a853f" [[package]] name = "memchr" @@ -407,15 +415,15 @@ dependencies = [ [[package]] name = "openssl-probe" -version = "0.1.2" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77af24da69f9d9341038eba93a073b1fdaaa1b788221b00a69bce9e762cb32de" +checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" [[package]] name = "openssl-sys" -version = "0.9.62" +version = "0.9.72" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa52160d45fa2e7608d504b7c3a3355afed615e6d8b627a74458634ba21b69bd" +checksum = "7e46109c383602735fa0a2e48dd2b7c892b048e1bf69e5c3b1d804b7d9c203cb" dependencies = [ "autocfg", "cc", @@ -441,15 +449,39 @@ checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e" [[package]] name = "pkg-config" -version = "0.3.19" +version = "0.3.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3831453b3449ceb48b6d9c7ad7c96d5ea673e9b470a1dc578c2ce6521230884c" +checksum = "58893f751c9b0412871a09abd62ecd2a00298c6c83befa223ef98c52aef40cbe" + +[[package]] +name = "proc-macro-error" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" +dependencies = [ + "proc-macro-error-attr", + "proc-macro2", + "quote", + "syn", + "version_check", +] + +[[package]] +name = "proc-macro-error-attr" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" +dependencies = [ + "proc-macro2", + "quote", + "version_check", +] [[package]] name = "proc-macro2" -version = "1.0.26" +version = "1.0.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a152013215dca273577e18d2bf00fa862b89b24169fb78c4c95aeb07992c9cec" +checksum = "c7342d5883fbccae1cc37a2353b09c87c9b0f3afd73f5fb9bba687a1f733b029" dependencies = [ "unicode-xid", ] @@ -477,9 +509,9 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.9" +version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3d0b9745dc2debf507c8422de05d7226cc1f0644216dfdfead988f9b1ab32a7" +checksum = "864d3e96a899863136fc6e99f3d7cae289dafe43bf2c5ac19b70df7210c0a145" dependencies = [ "proc-macro2", ] @@ -523,9 +555,9 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.2.8" +version = "0.2.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "742739e41cd49414de871ea5e549afb7e2a3ac77b589bcbebe8c82fab37147fc" +checksum = "8383f39639269cde97d255a32bdb68c047337295414940c68bdd30c2e13203ff" dependencies = [ "bitflags", ] @@ -581,9 +613,9 @@ dependencies = [ [[package]] name = "rustc-demangle" -version = "0.1.19" +version = "0.1.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "410f7acf3cb3a44527c5d9546bad4bf4e6c460915d5f9f2fc524498bfe8f70ce" +checksum = "7ef03e0a2b150c7a90d01faf6254c9c48a41e95fb2a8c2ac1c6f0d2b9aefc342" [[package]] name = "rustc-serialize" @@ -616,9 +648,9 @@ checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" [[package]] name = "syn" -version = "1.0.72" +version = "1.0.86" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1e8cdbefb79a9a5a65e0db8b47b723ee907b7c7f8496c76a1770b5c310bab82" +checksum = "8a65b3f4ffa0092e9887669db0eae07941f023991ab58ea44da8fe8e2d511c6b" dependencies = [ "proc-macro2", "quote", @@ -677,19 +709,20 @@ dependencies = [ [[package]] name = "time" -version = "0.1.43" +version = "0.1.44" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca8a50ef2360fbd1eeb0ecd46795a87a19024eb4b53c5dc916ca1fd95fe62438" +checksum = "6db9e6914ab8b1ae1c260a4ae7a49b6c5611b40328a735b21862567685e73255" dependencies = [ "libc", + "wasi", "winapi 0.3.9", ] [[package]] name = "tinyvec" -version = "1.2.0" +version = "1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b5220f05bb7de7f3f53c7c065e1199b3172696fe2db9f9c4d8ad9b4ee74c342" +checksum = "2c1c1d5a42b6245520c249549ec267180beaffcc0615401ac8e31853d4b6d8d2" dependencies = [ "tinyvec_macros", ] @@ -711,18 +744,15 @@ dependencies = [ [[package]] name = "unicode-bidi" -version = "0.3.5" +version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eeb8be209bb1c96b7c177c7420d26e04eccacb0eeae6b980e35fcb74678107e0" -dependencies = [ - "matches", -] +checksum = "1a01404663e3db436ed2746d9fefef640d868edae3cceb81c3b8d5732fda678f" [[package]] name = "unicode-normalization" -version = "0.1.17" +version = "0.1.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07fbfce1c8a97d547e8b5334978438d9d6ec8c20e38f56d4a4374d181493eaef" +checksum = "d54590932941a9e9266f0832deed84ebe1bf2e4c9e4a3554d393d18f5e854bf9" dependencies = [ "tinyvec", ] @@ -735,9 +765,9 @@ checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3" [[package]] name = "url" -version = "2.2.1" +version = "2.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ccd964113622c8e9322cfac19eb1004a07e636c545f325da085d5cdde6f1f8b" +checksum = "a507c383b2d33b5fc35d1861e77e6b383d158b2da5e14fe51b83dfedf6fd578c" dependencies = [ "form_urlencoded", "idna", @@ -753,15 +783,21 @@ checksum = "a1ca13c08c41c9c3e04224ed9ff80461d97e121589ff27c753a16cb10830ae0f" [[package]] name = "vcpkg" -version = "0.2.12" +version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cbdbff6266a24120518560b5dc983096efb98462e51d0d68169895b237be3e5d" +checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" + +[[package]] +name = "version_check" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" [[package]] name = "wasi" -version = "0.10.2+wasi-snapshot-preview1" +version = "0.10.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6" +checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f" [[package]] name = "winapi" @@ -805,12 +841,3 @@ name = "winapi-x86_64-pc-windows-gnu" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" - -[[package]] -name = "yaml-rust" -version = "0.4.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56c1936c4cc7a1c9ab21a1ebb602eb942ba868cbd44a99cb7cdc5892335e1c85" -dependencies = [ - "linked-hash-map", -] diff --git a/Cargo.toml b/Cargo.toml index 3090ef9..85615ed 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -22,7 +22,7 @@ lto = true cargo_toml = "0.11.3" case = "1.0.0" chrono = "0.4.19" -clap = { version = "3.0.13", features = ["yaml"] } +clap = { version = "3.0.13", features = ["derive"] } colored = "2.0.0" dirs = "4.0.0" git2 = "0.13.25" diff --git a/src/args.rs b/src/args.rs new file mode 100644 index 0000000..527af9f --- /dev/null +++ b/src/args.rs @@ -0,0 +1,59 @@ +use clap::{Parser, Subcommand}; + +#[derive(Subcommand, Debug)] +pub enum Subcommands { + /// Fetch a template from github. + #[clap(alias = "g")] + Git { + /// User and repository name where the template is located + #[clap(value_name = "USER/REPO")] + repo: String, + /// Project name to be used for project directory. + #[clap(value_name = "NAME")] + name: String, + /// Initialize project even if directory already exists. + #[clap(long, short)] + force: bool, + }, + /// List available templates. User templates can be added by placing them in ~/.pi_templates + #[clap(alias = "l")] + List, + /// Update pi (only works on UNIX). + #[clap(alias = "u")] + Update { + /// Force installation even when binary already exists. + #[clap(long, short)] + force: bool, + }, + /// Use a template from a folder. + #[clap(alias = "i")] + Init { + /// Directory containing your template, either in the current directory or in $HOME/.pi_templates/ + #[clap(value_name = "TEMPLATE_DIR")] + directory: String, + /// Project name to be used for project directory. + #[clap(value_name = "NAME")] + name: String, + /// Initialize project even if directory already exists. + #[clap(long, short)] + force: bool, + }, + /// Use a built-in template. + #[clap(alias = "n")] + New { + /// Template to used. Currently supported are Rust, Haskell, Idris, Elm, Python, Vimscript, Miso, and Julia. + template: String, + /// Project name to be used for project directory. + #[clap(value_name = "NAME")] + name: String, + /// Initialize project even if directory already exists. + #[clap(long, short)] + force: bool, + }, +} +#[derive(Parser, Debug)] +#[clap(author, version, about, long_about = None, term_width = 80, after_help = "See 'man pi' for more information")] +pub struct Args { + #[clap(subcommand)] + pub subcommand: Subcommands, +} diff --git a/src/lib.rs b/src/lib.rs index df5afe7..f8ae0cf 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,20 +1,19 @@ //! This library provides the functions/structs/methods used by the main //! binary. They are included //! here in the hopes that they can be illuminating to users. -// #![allow(clippy::cognitive_complexity)] use std::fs; use std::fs::File; use std::io::prelude::*; use std::path::Path; -use std::path::PathBuf; use case::*; use colored::*; -use heck::ToLowerCamelCase; +use heck::ToUpperCamelCase; use rustache::{HashBuilder, VecBuilder}; use toml::Value::Table; +pub mod args; pub mod includes; pub mod render; pub mod repo; @@ -24,67 +23,76 @@ pub mod types; /// directories/templates. /// If no such file is found, read from global template directory in /// `$HOME/.pi_templates/`. -pub fn read_toml_dir(template_path: &str, home: PathBuf) -> (types::Project, bool) { - let (mut template_file, is_global_template) = if let Ok(f) = File::open(&template_path) { - (f, false) - } else if let Ok(f) = { - let mut p = home; - p.push(".pi_templates/"); - p.push(template_path); - File::open(p) - } { - (f, true) - } else { - println!( - "{}: File {:?} could not be opened. Check that it exists.", - "Error".red(), - template_path - ); - std::process::exit(0x0f00); +pub fn read_toml_dir, HP: AsRef>( + template_path: TP, + home: HP, +) -> (types::Project, bool) { + let (mut template_file, is_global_template) = match File::open(&template_path) { + Ok(file) => (file, false), + Err(_) => { + let mut p = home.as_ref().to_path_buf(); + p.push(".pi_templates/"); + p.push(&template_path); + + match File::open(p) { + Ok(file) => (file, true), + Err(_) => { + println!( + "{}: File {:?} could not be opened. Check that it exists.", + "Error".red(), + template_path.as_ref() + ); + std::process::exit(0x0f00); + } + } + } }; + let mut template = String::new(); + template_file .read_to_string(&mut template) .expect("Failed to read file"); // we can panic because we already errored if the file didn't exist. + (read_toml_str(&template, template_path), is_global_template) } /// Read a string containing a toml file -pub fn read_toml_str(template: &str, template_path: &str) -> types::Project { - let extract = toml::from_str(template); - if let Ok(t) = extract { - t - } else if let Err(e) = extract { - println!("Error parsing {:?}: {}", template_path, e); - std::process::exit(0x0f00); - } else { - std::process::exit(0x0f00); +pub fn read_toml_str>(template: &str, template_path: P) -> types::Project { + match toml::from_str(template) { + Ok(t) => t, + Err(e) => { + println!("Error parsing {:?}: {}", template_path.as_ref(), e); + std::process::exit(0x0f00); + } } } -/// Given a `PathBuf`, read the .toml file there as a configuration file. -pub fn read_toml_config(config_path: &Path) -> types::Config { - let file = if let Ok(f) = File::open(&config_path) { - Some(f) - } else { - println!( - "{}: File {:?} could not be opened. Check that it exists.", - "Warning".yellow(), - config_path - ); - None +/// Given a `Path`, read the .toml file there as a configuration file. +pub fn read_toml_config>(config_path: P) -> types::Config { + let file = match File::open(&config_path) { + Ok(file) => Some(file), + Err(_) => { + println!( + "{}: File {:?} could not be opened. Check that it exists.", + "Warning".yellow(), + config_path.as_ref() + ); + None + } }; + let mut toml_str = String::new(); - let maybe_file = file.map(|mut x| x.read_to_string(&mut toml_str)); - let extract = toml::from_str(&toml_str); - if maybe_file.is_some() && maybe_file.unwrap().is_ok() { - if let Ok(t) = extract { - t - } else if let Err(e) = extract { - println!("Error parsing {:?}: {}", config_path, e); - std::process::exit(0x0f00); - } else { - std::process::exit(0x0f00); + + let maybe_file = file.and_then(|mut f| f.read_to_string(&mut toml_str).ok()); + + if maybe_file.is_some() { + match toml::from_str(&toml_str) { + Ok(t) => t, + Err(e) => { + println!("Error parsing {:?}: {}", config_path.as_ref(), e); + std::process::exit(0x0f00); + } } } else { eprintln!( @@ -101,8 +109,8 @@ pub fn read_toml_config(config_path: &Path) -> types::Config { } #[allow(clippy::too_many_arguments)] -pub fn init_helper( - home: PathBuf, +pub fn init_helper>( + home: P, project_dir: &str, decoded: types::Config, author: types::Author, @@ -114,13 +122,16 @@ pub fn init_helper( is_global_project: bool, ) { let project = if is_global_project { - let mut p = home; + let mut p = home.as_ref().to_path_buf(); + p.push(".pi_templates/"); p.push(project_dir); - p.to_str().unwrap().to_string() + + p.to_string_lossy().into_owned() } else { project_dir.to_string() }; + let parsed_dirs = parsed_toml.files; let parsed_config = parsed_toml.config; @@ -150,57 +161,48 @@ pub fn init_helper( } } else { - (None,"") + (None, "") }; // set version - let version = if let Some(config) = parsed_config.clone() { - if let Some(v) = config.version { - v - } else { + let version = match parsed_config.clone().and_then(|c| c.version) { + Some(v) => v, + None => { + eprintln!( + "{}: no version info found, defaulting to '0.1.0'", + "Warning".yellow() + ); "0.1.0".to_string() } - } else { - eprintln!( - "{}: no version info found, defaulting to '0.1.0'", - "Warning".yellow() - ); - "0.1.0".to_string() }; // set github username to null if it's not provided - let github_username = if let Some(uname) = author.github_username { - uname - } else { - eprintln!( - "{}: no github username found, defaulting to null", - "Warning".yellow() - ); - "".to_string() + let github_username = match author.github_username { + Some(uname) => uname, + None => { + eprintln!( + "{}: no github username found, defaulting to null", + "Warning".yellow() + ); + "".to_string() + } }; // make user_keys into a vector; prepare to insert them into the `HashBuilder` - let user_keys = if let Some(u) = parsed_toml.user { - match u.toml { - Table(t) => Some(t), - _ => None, - } - } else { - None + let user_keys = match parsed_toml.user.map(|u| u.toml) { + Some(Table(t)) => Some(t), + _ => None, }; // make user_keys into a vector; prepare to insert them into the `HashBuilder` - let user_keys_global = if let Some(u) = decoded.user { - match u.toml { - Table(t) => Some(t), - _ => None, - } - } else { - None + let user_keys_global = match decoded.user.map(|u| u.toml) { + Some(Table(t)) => Some(t), + _ => None, }; // Make a hash for inserting stuff into templates. let mut hash = HashBuilder::new(); + // project-specific if let Some(x) = user_keys { for (key, value) in &x { @@ -209,6 +211,7 @@ pub fn init_helper( } } } + // global if let Some(x) = user_keys_global { for (key, value) in &x { @@ -217,11 +220,12 @@ pub fn init_helper( } } } + // add the normal stuff hash = hash .insert("project", name) .insert("Project", name.to_capitalized()) - .insert("ProjectCamelCase", name.to_lower_camel_case()) + .insert("ProjectCamelCase", name.to_upper_camel_case()) .insert("year", year) .insert("name", author.name) .insert("version", version) @@ -241,16 +245,17 @@ pub fn init_helper( // create directories let _ = fs::create_dir(name); + if let Some(dirs_pre) = parsed_dirs.directories { render::render_dirs(dirs_pre, &hash, name); } // create a list of files contained in the project, and create those files. // TODO should include templates/scripts/etc. - let files = if let Some(files_pre) = parsed_dirs.files { - render::render_files(files_pre, &hash, name) // FIXME files need to have a newline insert in between them? - } else { - VecBuilder::new() + let files = match parsed_dirs.files { + // FIXME files need to have a newline insert in between them? + Some(files_pre) => render::render_files(files_pre, &hash, name), + None => VecBuilder::new(), }; // create license if it was asked for diff --git a/src/main.rs b/src/main.rs index e86d7cf..a2263da 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,22 +1,19 @@ //! Source file for the binary. -use std::fs; +use std::fs::{create_dir, read_dir}; #[cfg(not(target_os = "windows"))] -use std::fs::set_permissions; -#[cfg(not(target_os = "windows"))] -use std::fs::File; +use std::fs::{set_permissions, File}; use std::path::Path; -use std::path::PathBuf; use std::process::Command; use cargo_toml::Manifest; -use case::*; +use case::CaseExt; use chrono::Datelike; use chrono::Utc; -use clap::load_yaml; -use clap::{App, AppSettings}; +use clap::StructOpt; use colored::*; use git2::Repository; +use project_init::args::{Args, Subcommands}; use project_init::render::*; use project_init::types::*; use project_init::*; @@ -48,13 +45,7 @@ fn main() { None => "unknown".to_string(), }; - // command-line parser - let yaml = load_yaml!("options-en.yml"); - let matches = App::from_yaml(yaml) - .version(&*version) - .term_width(80) - .setting(AppSettings::SubcommandRequired) - .get_matches(); + let args = Args::parse(); // set path to .pi.toml let home = dirs::home_dir().expect("Couldn't determine home directory."); @@ -89,165 +80,148 @@ fn main() { year = year ); - if let Some(x) = matches.subcommand_matches("update") { - let force = x.is_present("force"); - - println!("current version: {}", version); - - let s = if force { - "curl -LSfs https://japaric.github.io/trust/install.sh | sh -s -- --git vmchale/project-init --force" - } else { - "curl -LSfs https://japaric.github.io/trust/install.sh | sh -s -- --git vmchale/project-init" - }; - - let script = Command::new("bash") - .arg("-c") - .arg(s) - .output() - .expect("failed to execute update script."); - - let script_string = String::from_utf8(script.stderr).unwrap(); - - println!("{}", script_string); - } else if matches.subcommand_matches("list").is_some() { - let remote = vec!["vmchale/haskell-ats", "vmchale/madlang-miso"]; - let builtin = vec![ - "rust", "vim", "python", "haskell", "idris", "julia", "elm", "miso", "plain", "kmett", - "madlang", - ]; - println!("{}", "Remote Templates:".cyan()); - for b in remote { - println!(" - {}", b); - } - println!(); - println!("{}", "Builtin Templates:".cyan()); - for b in builtin { - println!(" - {}", b); + match args.subcommand { + Subcommands::Update { force } => { + println!("current version: {}", version); + + let s = if force { + "curl -LSfs https://japaric.github.io/trust/install.sh | sh -s -- --git vmchale/project-init --force" + } else { + "curl -LSfs https://japaric.github.io/trust/install.sh | sh -s -- --git vmchale/project-init" + }; + + let script = Command::new("bash") + .arg("-c") + .arg(s) + .output() + .expect("failed to execute update script."); + + let script_string = String::from_utf8(script.stderr).unwrap(); + + println!("{}", script_string); } - let mut p = home; - p.push(".pi_templates"); - println!("{}", "\nUser Templates:".cyan()); - let iter = std::fs::read_dir(&p); - match iter { - Ok(x) => { - for dir in x { - if let Ok(x) = dir { - if x.path().is_dir() - && x.file_name().to_str().map(|c| c.chars().next().unwrap()) - != Some('.') - && x.file_name().to_str().map(|c| c.chars().next().unwrap()) - != Some('_') - { - println!(" - {}", x.file_name().to_string_lossy()); + Subcommands::List => { + let remote = vec!["vmchale/haskell-ats", "vmchale/madlang-miso"]; + let builtin = vec![ + "rust", "vim", "python", "haskell", "idris", "julia", "elm", "miso", "plain", + "kmett", "madlang", + ]; + println!("{}", "Remote Templates:".cyan()); + for b in remote { + println!(" - {}", b); + } + println!(); + println!("{}", "Builtin Templates:".cyan()); + for b in builtin { + println!(" - {}", b); + } + let mut p = home; + p.push(".pi_templates"); + println!("{}", "\nUser Templates:".cyan()); + let iter = read_dir(&p); + match iter { + Ok(x) => { + for dir in x { + if let Ok(x) = dir { + if x.path().is_dir() + && x.file_name().to_str().map(|c| c.chars().next().unwrap()) + != Some('.') + && x.file_name().to_str().map(|c| c.chars().next().unwrap()) + != Some('_') + { + println!(" - {}", x.file_name().to_string_lossy()); + } + } else { } - } else { } } + _ => eprintln!("{}: Could not access {}", "Warning".yellow(), p.display()), } - _ => eprintln!("{}: Could not access {}", "Warning".yellow(), p.display()), } - } else if let Some(matches_init) = matches.subcommand_matches("git") { - // whether to overwrite - let force = matches_init.is_present("force"); - - // get repository name - let repo = matches_init - .value_of("repo") - .expect("Clap failed to supply repository name"); - - // get project name - let name = matches_init - .value_of("name") - .expect("Clap failed to supply project name"); - - // form the URL - let mut url = "https://github.com/".to_string(); - url.push_str(repo); - - // create a temporary directory to hold the template - let dir_name = repo.replace("/", "-"); - let tmp_dir = TempDir::new(&dir_name); - let file = match tmp_dir { - Ok(t) => t, - Err(_) => { - eprintln!("{}: failed to create temporary directory", "Error".red()); - std::process::exit(1) - } - }; - - // clone into the temporary directory - let file_path = file.path(); - match Repository::clone(&url, file_path) { - Ok(_) => (), - Err(_) => { - eprintln!("{}: failed to clone repo at {}", "Error".red(), url); - std::process::exit(1) - } - }; - - let string_dir = file_path.to_string_lossy().to_string(); - let mut toml_string = string_dir.clone(); - toml_string.push_str("/template.toml"); + Subcommands::Git { repo, name, force } => { + // form the URL + let mut url = "https://github.com/".to_string(); + url.push_str(&repo); + + // create a temporary directory to hold the template + let dir_name = repo.replace("/", "-"); + let tmp_dir = TempDir::new(&dir_name); + let file = match tmp_dir { + Ok(t) => t, + Err(_) => { + eprintln!("{}: failed to create temporary directory", "Error".red()); + std::process::exit(1) + } + }; - // get the parsed TOML file from the repo. - let (parsed_toml, _) = read_toml_dir(&toml_string, PathBuf::from(".")); + // clone into the temporary directory + let file_path = file.path(); + match Repository::clone(&url, file_path) { + Ok(_) => (), + Err(_) => { + eprintln!("{}: failed to clone repo at {}", "Error".red(), url); + std::process::exit(1) + } + }; - // initialize the project - init_helper( - home, - &string_dir, - decoded, - author, + let string_dir = file_path.to_string_lossy().to_string(); + let mut toml_string = string_dir.clone(); + toml_string.push_str("/template.toml"); + + // get the parsed TOML file from the repo. + let (parsed_toml, _) = read_toml_dir(&toml_string, "."); + + // initialize the project + init_helper( + home, + &string_dir, + decoded, + author, + &name, + year, + ¤t_date, + force, + parsed_toml, + false, + ); + } + Subcommands::New { name, - year, - ¤t_date, + template, force, - parsed_toml, - false, - ) - } else if let Some(matches_init) = matches.subcommand_matches("new") { - let force: bool = matches_init.occurrences_of("force") == 1; - - // get project name - let name = matches_init - .value_of("name") - .expect("Clap failed to supply project name"); - - // get project template type - let template_str_lower: String = matches_init - .value_of("template") - .expect("Clap failed to supply project directory") - .to_string() - .chars() - .map(|c| c.to_lowercase().to_string()) - .collect::>() - .join(""); - - let template_str = template_str_lower.as_str(); - - // read template.toml - let toml_file = match template_str { - "rust" => includes::RUST_TEMPLATE, - "vim" | "vimscript" => includes::VIM_TEMPLATE, - "python" => includes::PY_TEMPLATE, - "haskell" | "kmett" => includes::HASK_TEMPLATE, - "mad" | "madlang" => includes::MADLANG_TEMPLATE, - "idris" => includes::IDRIS_TEMPLATE, - "julia" => includes::JULIA_TEMPLATE, - "miso" => includes::MISO_TEMPLATE, - "plain" => includes::PLAIN_TEMPLATE, - "ats" => includes::ATS_TEMPLATE, - _ => { - println!("The requested template is not a built-in :("); - std::process::exit(0x0f00) - } - }; - let parsed_toml = read_toml_str(toml_file, "BUILTIN"); - let parsed_dirs = parsed_toml.files; - let parsed_config = parsed_toml.config; + } => { + // get project template type + let template_str_lower: String = template + .chars() + .map(|c| c.to_lowercase().to_string()) + .collect::>() + .join(""); + + let template_str = template_str_lower.as_str(); + + // read template.toml + let toml_file = match template_str { + "rust" => includes::RUST_TEMPLATE, + "vim" | "vimscript" => includes::VIM_TEMPLATE, + "python" => includes::PY_TEMPLATE, + "haskell" | "kmett" => includes::HASK_TEMPLATE, + "mad" | "madlang" => includes::MADLANG_TEMPLATE, + "idris" => includes::IDRIS_TEMPLATE, + "julia" => includes::JULIA_TEMPLATE, + "miso" => includes::MISO_TEMPLATE, + "plain" => includes::PLAIN_TEMPLATE, + "ats" => includes::ATS_TEMPLATE, + _ => { + println!("The requested template is not a built-in :("); + std::process::exit(0x0f00) + } + }; + let parsed_toml = read_toml_str(toml_file, "BUILTIN"); + let parsed_dirs = parsed_toml.files; + let parsed_config = parsed_toml.config; - // set license if it's set - let (license_contents, license_name) = + // set license if it's set + let (license_contents, license_name) = // prefer global license over builtin if let Some(l) = decoded.license { match l.as_str() { @@ -275,260 +249,254 @@ fn main() { (None,"") }; - // set version - let version = if let Some(config) = parsed_config { - if let Some(v) = config.version { - v + // set version + let version = if let Some(config) = parsed_config { + if let Some(v) = config.version { + v + } else { + "0.1.0".to_string() + } } else { + println!( + "{}: no version info found, defaulting to '0.1.0'", + "Warning".yellow() + ); "0.1.0".to_string() - } - } else { - println!( - "{}: no version info found, defaulting to '0.1.0'", - "Warning".yellow() - ); - "0.1.0".to_string() - }; - - // set github username to null if it's not provided - let github_username = if let Some(uname) = author.github_username { - uname - } else { - println!( - "{}: No github username found, defaulting to null.", - "Warning".yellow() - ); - "".to_string() - }; - - // Make a hash for inserting stuff into templates. - let hash = HashBuilder::new() - .insert("project", name) - .insert("Project", name.to_capitalized()) - .insert("year", year) - .insert("name", author.name) - .insert("version", version) - .insert("email", author.email) - .insert("github_username", github_username) - .insert("license", license_name) - .insert("date", current_date); - - // check if the directory exists and exit, if we haven't forced an overwrite. - if Path::new(name).exists() && !force { - println!( - "Path '{}' already exists. Rerun with -f or --force to overwrite.", - name - ); - std::process::exit(0x0f00); - }; - - // create directories - let _ = fs::create_dir(name); - if let Some(dirs_pre) = parsed_dirs.directories { - render_dirs(dirs_pre, &hash, name); - } + }; - // Create files. - let files = if let Some(files_pre) = parsed_dirs.files { - render_files(files_pre, &hash, name) - } else { - VecBuilder::new() - }; + // set github username to null if it's not provided + let github_username = if let Some(uname) = author.github_username { + uname + } else { + println!( + "{}: No github username found, defaulting to null.", + "Warning".yellow() + ); + "".to_string() + }; - // create license if it was asked for - if let Some(lic) = license_contents { - render_file(lic, name, "LICENSE", &hash); - } + // Make a hash for inserting stuff into templates. + let hash = HashBuilder::new() + .insert("project", &*name) + .insert("Project", &*name.to_capitalized()) + .insert("year", year) + .insert("name", author.name) + .insert("version", version) + .insert("email", author.email) + .insert("github_username", github_username) + .insert("license", license_name) + .insert("date", current_date); + + // check if the directory exists and exit, if we haven't forced an overwrite. + if Path::new(&name).exists() && !force { + println!( + "Path '{}' already exists. Rerun with -f or --force to overwrite.", + name + ); + std::process::exit(0x0f00); + }; - // render readme if requested - if let Some(readme) = parsed_toml.with_readme { - if readme { - render_file(includes::README, name, "README.md", &hash); + // create directories + let _ = create_dir(&name); + if let Some(dirs_pre) = parsed_dirs.directories { + render_dirs(dirs_pre, &hash, &name); } - } - let hash_with_files = HashBuilder::new().insert("files", files); - - // render appropriate stuff by name. - match template_str { - "plain" => (), - - "rust" => { - let mut bench_path = "benches/".to_string(); - bench_path.push_str(name); - bench_path.push_str(".rs"); - write_file_plain(includes::RUST_LIB, name, "src/lib.rs"); - write_file_plain(includes::RUST_MAIN, name, "src/main.rs"); - write_file_plain(includes::RUST_TRAVIS_CI, name, ".travis.yml"); - write_file_plain(includes::RUST_GITIGNORE, name, ".gitignore"); - write_file_plain(includes::RUST_BENCHMARKS, name, &bench_path); - render_file(includes::CARGO_TOML, name, "Cargo.toml", &hash) - } + // Create files. + let files = if let Some(files_pre) = parsed_dirs.files { + render_files(files_pre, &hash, &name) + } else { + VecBuilder::new() + }; - "vim" | "vimscript" => { - write_file_plain(includes::VIM_GITIGNORE, name, ".gitignore"); - render_file(includes::VIM_TRAVIS, name, ".travis.yml", &hash_with_files); - render_file(includes::VIMBALL, name, "vimball.txt", &hash_with_files) + // create license if it was asked for + if let Some(lic) = license_contents { + render_file(lic, &name, "LICENSE", &hash); } - "python" => { - render_file(includes::PY_SETUP, name, "setup.py", &hash); - write_file_plain(includes::PY_CFG, name, "setup.cfg"); - write_file_plain(includes::PY_GITIGNORE, name, ".gitignore"); - let mut bin_path = "bin/".to_string(); - bin_path.push_str(name); - render_file(includes::PY_BIN, name, &bin_path, &hash); + // render readme if requested + if let Some(readme) = parsed_toml.with_readme { + if readme { + render_file(includes::README, &name, "README.md", &hash); + } } - "miso" => { - write_file_plain(includes::MISO_SETUP_HS, name, "Setup.hs"); - write_file_plain(includes::MISO_MAIN, name, "app/Main.hs"); - write_file_plain(includes::MISO_LIB, name, "src/Lib.hs"); - let mut cabal_path = name.to_string(); - cabal_path.push_str(".cabal"); - render_file(includes::MISO_CABAL, name, &cabal_path, &hash); - write_file_plain(includes::MISO_GITIGNORE, name, ".gitignore"); - render_file(includes::MISO_STACK, name, "stack.yaml", &hash); - write_file_plain(includes::HLINT_TEMPLATE, name, ".hlint.yaml"); - write_file_plain(includes::SHAKE_STACK, name, "stack-shake.yaml"); - write_file_plain(includes::MISO_TRAVIS, name, ".travis.yml"); - render_file(includes::MISO_SHAKE, name, "shake.hs", &hash); - render_file(includes::MISO_HTML, name, "web-src/index.html", &hash); - write_file_plain(includes::HASKELL_TRAVIS_CI, name, ".travis.yml"); - write_file_plain(includes::STYLISH_HASKELL, name, ".stylish-haskell.yaml"); - let mut shake_path = name.to_string(); - shake_path.push_str("/shake.hs"); - mk_executable(shake_path); - } + let hash_with_files = HashBuilder::new().insert("files", files); + + // render appropriate stuff by name. + match template_str { + "plain" => (), + + "rust" => { + let mut bench_path = "benches/".to_string(); + bench_path.push_str(&name); + bench_path.push_str(".rs"); + write_file_plain(includes::RUST_LIB, &name, "src/lib.rs"); + write_file_plain(includes::RUST_MAIN, &name, "src/main.rs"); + write_file_plain(includes::RUST_TRAVIS_CI, &name, ".travis.yml"); + write_file_plain(includes::RUST_GITIGNORE, &name, ".gitignore"); + write_file_plain(includes::RUST_BENCHMARKS, &name, &bench_path); + render_file(includes::CARGO_TOML, &name, "Cargo.toml", &hash) + } - "madlang" | "mad" => { - let mut src_path = "src/".to_string(); - src_path.push_str(name); - src_path.push_str(".mad"); - render_file(includes::MADLANG_SRC, name, &src_path, &hash); - } + "vim" | "vimscript" => { + write_file_plain(includes::VIM_GITIGNORE, &name, ".gitignore"); + render_file(includes::VIM_TRAVIS, &name, ".travis.yml", &hash_with_files); + render_file(includes::VIMBALL, &name, "vimball.txt", &hash_with_files) + } - "idris" => { - let mut pkg_path = name.to_string(); - pkg_path.push_str(".ipkg"); - write_file_plain(includes::IDRIS_GITIGNORE, name, ".gitignore"); - write_file_plain(includes::IDRIS_CTAGS, name, ".ctags"); - let mut main_path = name.to_capitalized(); - main_path.push_str(".idr"); - render_file(includes::IPKG, name, &pkg_path, &hash); - render_file(includes::IPKG_TEST, name, "test.ipkg", &hash); - // render_file(includes::IDRIS_EXE, name, &main_path, &hash); - render_file(includes::IDRIS_TEST, name, "src/Test/Spec.idr", &hash); - let mut lib_path = "src/".to_string(); - lib_path.push_str(&name.to_capitalized()); - lib_path.push('/'); - lib_path.push_str("Lib.idr"); - render_file(includes::IDRIS_LIB, name, &lib_path, &hash); - } + "python" => { + render_file(includes::PY_SETUP, &name, "setup.py", &hash); + write_file_plain(includes::PY_CFG, &name, "setup.cfg"); + write_file_plain(includes::PY_GITIGNORE, &name, ".gitignore"); + let mut bin_path = "bin/".to_string(); + bin_path.push_str(&name); + render_file(includes::PY_BIN, &name, &bin_path, &hash); + } - "julia" => { - write_file_plain(includes::JULIA_REQUIRE, name, "REQUIRE"); - let mut project_path = "src/".to_string(); - project_path.push_str(name.to_capitalized().as_str()); - project_path.push_str(".jl"); - write_file_plain(includes::JULIA_GITIGNORE, name, ".gitignore"); - write_file_plain(includes::JULIA_SRC, name, &project_path); - write_file_plain(includes::JULIA_TEST, name, "test/test.jl"); - } + "miso" => { + write_file_plain(includes::MISO_SETUP_HS, &name, "Setup.hs"); + write_file_plain(includes::MISO_MAIN, &name, "app/Main.hs"); + write_file_plain(includes::MISO_LIB, &name, "src/Lib.hs"); + let mut cabal_path = name.clone(); + cabal_path.push_str(".cabal"); + render_file(includes::MISO_CABAL, &name, &cabal_path, &hash); + write_file_plain(includes::MISO_GITIGNORE, &name, ".gitignore"); + render_file(includes::MISO_STACK, &name, "stack.yaml", &hash); + write_file_plain(includes::HLINT_TEMPLATE, &name, ".hlint.yaml"); + write_file_plain(includes::SHAKE_STACK, &name, "stack-shake.yaml"); + write_file_plain(includes::MISO_TRAVIS, &name, ".travis.yml"); + render_file(includes::MISO_SHAKE, &name, "shake.hs", &hash); + render_file(includes::MISO_HTML, &name, "web-src/index.html", &hash); + write_file_plain(includes::HASKELL_TRAVIS_CI, &name, ".travis.yml"); + write_file_plain(includes::STYLISH_HASKELL, &name, ".stylish-haskell.yaml"); + let mut shake_path = name.clone(); + shake_path.push_str("/shake.hs"); + mk_executable(shake_path); + } - "ats" => { - write_file_plain(includes::ATS_CTAGS, name, ".ctags"); - let mut src_path = "src/".to_string(); - src_path.push_str(name); - src_path.push_str(".dats"); - render_file(includes::ATS_SRC, name, &src_path, &hash); - write_file_plain(includes::ATS_FORMAT, name, ".atsfmt.toml"); - write_file_plain(includes::ATS_TRAVIS, name, ".clang-format"); - render_file(includes::ATS_PKG, name, "atspkg.dhall", &hash); - render_file(includes::ATS_LIB, name, "pkg.dhall", &hash); - render_file(includes::ATS_TRAVIS, name, ".travis.yml", &hash); - render_file(includes::ATS_GITIGNORE, name, ".gitignore", &hash); - } + "madlang" | "mad" => { + let mut src_path = "src/".to_string(); + src_path.push_str(&name); + src_path.push_str(".mad"); + render_file(includes::MADLANG_SRC, &name, &src_path, &hash); + } - "haskell" | "kmett" => { - write_file_plain(includes::SETUP_HS, name, "Setup.hs"); - write_file_plain(includes::MAIN, name, "app/Main.hs"); - render_file(includes::LIB, name, "src/Lib.hs", &hash); - write_file_plain(includes::BENCH, name, "bench/Bench.hs"); - write_file_plain(includes::TEST, name, "test/Spec.hs"); - write_file_plain(includes::HLINT_TEMPLATE, name, ".hlint.yaml"); - write_file_plain(includes::STYLISH_HASKELL, name, ".stylish-haskell.yaml"); - render_file(includes::DEFAULT_NIX, name, "default.nix", &hash); - render_file(includes::RELEASE_NIX, name, "release.nix", &hash); - let mut cabal_path = name.to_string(); - cabal_path.push_str(".cabal"); - if template_str == "haskell" { - render_file(includes::CABAL, name, &cabal_path, &hash); - } else { - render_file(includes::KMETT, name, &cabal_path, &hash); + "idris" => { + let mut pkg_path = name.clone(); + pkg_path.push_str(".ipkg"); + write_file_plain(includes::IDRIS_GITIGNORE, &name, ".gitignore"); + write_file_plain(includes::IDRIS_CTAGS, &name, ".ctags"); + let mut main_path = name.to_capitalized(); + main_path.push_str(".idr"); + render_file(includes::IPKG, &name, &pkg_path, &hash); + render_file(includes::IPKG_TEST, &name, "test.ipkg", &hash); + // render_file(includes::IDRIS_EXE, &name, &main_path, &hash); + render_file(includes::IDRIS_TEST, &name, "src/Test/Spec.idr", &hash); + let mut lib_path = "src/".to_string(); + lib_path.push_str(&name.to_capitalized()); + lib_path.push('/'); + lib_path.push_str("Lib.idr"); + render_file(includes::IDRIS_LIB, &name, &lib_path, &hash); } - write_file_plain(includes::HASKELL_GITIGNORE, name, ".gitignore"); - write_file_plain(includes::RELEASE_NIX, name, "release.nix"); - write_file_plain(includes::HSPEC, name, ".hspec"); - write_file_plain(includes::HS_GITATTRIBUTES, name, ".gitattributes"); - render_file(includes::STACK_YAML, name, "stack.yaml", &hash); - render_file(includes::CABAL_PROJECT, name, "cabal.project.local", &hash); - render_file(includes::HASKELL_TRAVIS_CI, name, ".travis.yml", &hash); - render_file(includes::HASKELL_APPVEYOR, name, "appveyor.yml", &hash); - render_file(includes::HS_CHANGELOG, name, "CHANGELOG.md", &hash); - } - _ => std::process::exit(0x0f01), - }; + "julia" => { + write_file_plain(includes::JULIA_REQUIRE, &name, "REQUIRE"); + let mut project_path = "src/".to_string(); + project_path.push_str(&name.to_capitalized()); + project_path.push_str(".jl"); + write_file_plain(includes::JULIA_GITIGNORE, &name, ".gitignore"); + write_file_plain(includes::JULIA_SRC, &name, &project_path); + write_file_plain(includes::JULIA_TEST, &name, "test/test.jl"); + } - // initialize version control - if let Some(vc) = decoded.version_control { - match vc.as_str() { - "git" => repo::git_init(name), - "hg" | "mercurial" => repo::hg_init(name), - "pijul" => repo::pijul_init(name), - "darcs" => repo::darcs_init(name), - _ => { - eprintln!( + "ats" => { + write_file_plain(includes::ATS_CTAGS, &name, ".ctags"); + let mut src_path = "src/".to_string(); + src_path.push_str(&name); + src_path.push_str(".dats"); + render_file(includes::ATS_SRC, &name, &src_path, &hash); + write_file_plain(includes::ATS_FORMAT, &name, ".atsfmt.toml"); + write_file_plain(includes::ATS_TRAVIS, &name, ".clang-format"); + render_file(includes::ATS_PKG, &name, "atspkg.dhall", &hash); + render_file(includes::ATS_LIB, &name, "pkg.dhall", &hash); + render_file(includes::ATS_TRAVIS, &name, ".travis.yml", &hash); + render_file(includes::ATS_GITIGNORE, &name, ".gitignore", &hash); + } + + "haskell" | "kmett" => { + write_file_plain(includes::SETUP_HS, &name, "Setup.hs"); + write_file_plain(includes::MAIN, &name, "app/Main.hs"); + render_file(includes::LIB, &name, "src/Lib.hs", &hash); + write_file_plain(includes::BENCH, &name, "bench/Bench.hs"); + write_file_plain(includes::TEST, &name, "test/Spec.hs"); + write_file_plain(includes::HLINT_TEMPLATE, &name, ".hlint.yaml"); + write_file_plain(includes::STYLISH_HASKELL, &name, ".stylish-haskell.yaml"); + render_file(includes::DEFAULT_NIX, &name, "default.nix", &hash); + render_file(includes::RELEASE_NIX, &name, "release.nix", &hash); + let mut cabal_path = name.clone(); + cabal_path.push_str(".cabal"); + if template_str == "haskell" { + render_file(includes::CABAL, &name, &cabal_path, &hash); + } else { + render_file(includes::KMETT, &name, &cabal_path, &hash); + } + write_file_plain(includes::HASKELL_GITIGNORE, &name, ".gitignore"); + write_file_plain(includes::RELEASE_NIX, &name, "release.nix"); + write_file_plain(includes::HSPEC, &name, ".hspec"); + write_file_plain(includes::HS_GITATTRIBUTES, &name, ".gitattributes"); + render_file(includes::STACK_YAML, &name, "stack.yaml", &hash); + render_file(includes::CABAL_PROJECT, &name, "cabal.project.local", &hash); + render_file(includes::HASKELL_TRAVIS_CI, &name, ".travis.yml", &hash); + render_file(includes::HASKELL_APPVEYOR, &name, "appveyor.yml", &hash); + render_file(includes::HS_CHANGELOG, &name, "CHANGELOG.md", &hash); + } + + _ => std::process::exit(0x0f01), + }; + + // initialize version control + if let Some(vc) = decoded.version_control { + match vc.as_str() { + "git" => repo::git_init(&name), + "hg" | "mercurial" => repo::hg_init(&name), + "pijul" => repo::pijul_init(&name), + "darcs" => repo::darcs_init(&name), + _ => { + eprintln!( "{}: version control {} is not yet supported. Supported version control tools are darcs, pijul, mercurial, and git.", "Error".red(), vc ); + } } } - } - // Print that we're done - println!("Finished initializing project in {}/", name); - } else if let Some(matches_init) = matches.subcommand_matches("init") { - let force: bool = matches_init.occurrences_of("force") == 1; - - // get project name - let name = matches_init - .value_of("name") - .expect("Failed to supply project name"); - - // get project directory - let project_dir = matches_init - .value_of("directory") - .expect("Failed to supply project directory"); - - // read template.toml for template - let mut template_path = project_dir.to_string(); - template_path.push_str("/template.toml"); - let (parsed_toml, is_global_project) = read_toml_dir(&template_path, home.clone()); - - init_helper( - home, - project_dir, - decoded, - author, + // Print that we're done + println!("Finished initializing project in {}/", name); + } + Subcommands::Init { + directory, name, - year, - ¤t_date, force, - parsed_toml, - is_global_project, - ) + } => { + // read template.toml for template + let mut template_path = directory.clone(); + template_path.push_str("/template.toml"); + let (parsed_toml, is_global_project) = read_toml_dir(&template_path, &home); + + init_helper( + home, + &directory, + decoded, + author, + &name, + year, + ¤t_date, + force, + parsed_toml, + is_global_project, + ) + } } } diff --git a/src/options-en.yml b/src/options-en.yml deleted file mode 100644 index 7299ad3..0000000 --- a/src/options-en.yml +++ /dev/null @@ -1,77 +0,0 @@ ---- -name: Project Init (pi) -author: Vanessa McHale -about: Initialize projects from a template. -after_help: See 'man pi' for more information -subcommands: - - git: - visible_alias: "g" - about: Fetch a template from github. - args: - - repo: - index: 1 - value_name: USER/REPO - help: User and repository name where the template is located - takes_value: true - required: true - - name: - value_name: NAME - help: Project name to be used for project directory - index: 2 - takes_value: true - required: true - - force: - short: f - long: force - help: Initialize project even if directory already exists. - - list: - visible_alias: "l" - about: List available templates. User templates can be added by placing them in ~/.pi_templates - - update: - visible_alias: "u" - about: Update pi (only works on UNIX) - args: - - force: - short: f - long: force - help: Force installation even when binary already exists. - - init: - about: Use a template from a folder - alias: "i" - args: - - directory: - value_name: TEMPLATE_DIR - help: Directory containing your template, either in the current directory or in $HOME/.pi_templates/ - index: 1 - takes_value: true - required: true - - name: - value_name: NAME - help: Project name to be used for project directory - index: 2 - takes_value: true - required: true - - force: - short: f - long: force - help: Initialize project even if directory already exists. - - new: - about: Use a built-in template - alias: "n" - args: - - template: - index: 1 - takes_value: true - required: true - help: Template to be used - long_help: Template to used. Currently supported are Rust, Haskell, Idris, Elm, Python, Vimscript, Miso, and Julia. - - name: - value_name: NAME - help: Project name to be used for project directory - index: 2 - takes_value: true - required: true - - force: - short: f - long: force - help: Initialize project even if directory already exists. diff --git a/src/render.rs b/src/render.rs index 9e5d2db..97d6a59 100644 --- a/src/render.rs +++ b/src/render.rs @@ -154,6 +154,7 @@ pub fn render_templates( // write the rendered templates let files_to_write = templates_named.iter().zip(s.iter()); + let _ = files_to_write .into_iter() .map(|(path, contents)| { @@ -243,6 +244,7 @@ pub fn render_templates( // write the rendered templates let files_to_write = templates_named.iter().zip(s.iter()); + let _ = files_to_write .map(|(path, contents)| { let c = File::create(&path); @@ -299,14 +301,17 @@ pub fn render_file(static_template: &'static str, name: &str, filename: &str, ha p.push_str(filename); // write the rendered template - let c = File::create(&p); - if let Ok(mut f) = c { - let _ = f.write(contents.as_bytes()); - } else { - eprintln!( + match File::create(&p) { + Ok(mut f) => { + let _ = f.write(contents.as_bytes()); + } + Err(_) => { + eprintln!( "Failed to create file: {:?}. Check that the directory is included in your template.toml", p ); - exit(0x0f01); + + exit(0x0f01); + } } } diff --git a/src/repo.rs b/src/repo.rs index fe13270..15e6037 100644 --- a/src/repo.rs +++ b/src/repo.rs @@ -4,84 +4,108 @@ use colored::*; pub fn git_init(name: &str) { let mut cmd = "cd ".to_string(); + cmd.push_str(name); cmd.push_str("&&"); cmd.push_str("git init && git add *"); - if let Ok(c) = Command::new("sh") + + match Command::new("sh") .arg("-c") .arg(cmd) .stdout(std::process::Stdio::null()) .spawn() { - c.wait_with_output().expect("failed to wait on child"); - } else { - eprintln!( - "{}, git failed to initialize. Is git on your path?", - "Error".red() - ); - std::process::exit(0x0f01); + Ok(c) => { + c.wait_with_output().expect("failed to wait on child"); + } + Err(_) => { + eprintln!( + "{}, git failed to initialize. Is git on your path?", + "Error".red() + ); + + std::process::exit(0x0f01); + } } } pub fn pijul_init(name: &str) { let mut cmd = "cd ".to_string(); + cmd.push_str(name); cmd.push_str("&&"); cmd.push_str("pijul init && pijul add **"); - if let Ok(c) = Command::new("sh") + + match Command::new("sh") .arg("-c") .arg(cmd) .stdout(std::process::Stdio::null()) .spawn() { - c.wait_with_output().expect("failed to wait on child"); - } else { - eprintln!( - "{}, Pijul failed to initialize. Is it on your path?", - "Error".red() - ); - std::process::exit(0x0f01); + Ok(c) => { + c.wait_with_output().expect("failed to wait on child"); + } + Err(_) => { + eprintln!( + "{}, Pijul failed to initialize. Is it on your path?", + "Error".red() + ); + + std::process::exit(0x0f01); + } } } pub fn darcs_init(name: &str) { let mut cmd = "cd ".to_string(); + cmd.push_str(name); cmd.push_str("&&"); cmd.push_str("darcs init && darcs add **"); - if let Ok(c) = Command::new("sh") + + match Command::new("sh") .arg("-c") .arg(cmd) .stdout(std::process::Stdio::null()) .spawn() { - c.wait_with_output().expect("failed to wait on child"); - } else { - eprintln!( - "{}, Darcs failed to initialize. Is hg on your path?", - "Error".red() - ); - std::process::exit(0x0f01); + Ok(c) => { + c.wait_with_output().expect("failed to wait on child"); + } + Err(_) => { + eprintln!( + "{}, Darcs failed to initialize. Is hg on your path?", + "Error".red() + ); + + std::process::exit(0x0f01); + } } } pub fn hg_init(name: &str) { let mut cmd = "cd ".to_string(); + cmd.push_str(name); cmd.push_str("&&"); cmd.push_str("hg init && hg add *"); - if let Ok(c) = Command::new("sh") + + match Command::new("sh") .arg("-c") .arg(cmd) .stdout(std::process::Stdio::null()) .spawn() { - c.wait_with_output().expect("failed to wait on child"); - } else { - eprintln!( - "{}, Mercurial failed to initialize. Is it on your path?", - "Error".red() - ); - std::process::exit(0x0f01); + Ok(c) => { + c.wait_with_output().expect("failed to wait on child"); + } + Err(_) => { + eprintln!( + "{}, Mercurial failed to initialize. Is it on your path?", + "Error".red() + ); + + std::process::exit(0x0f01); + } } }