diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ea8c4bf --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +/target diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..d0492a3 --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,361 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "anstream" +version = "0.6.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43d5b281e737544384e969a5ccad3f1cdd24b48086a0fc1b2a5262a26b8f4f4a" +dependencies = [ + "anstyle", + "anstyle-parse", + "anstyle-query", + "anstyle-wincon", + "colorchoice", + "is_terminal_polyfill", + "utf8parse", +] + +[[package]] +name = "anstyle" +version = "1.0.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5192cca8006f1fd4f7237516f40fa183bb07f8fbdfedaa0036de5ea9b0b45e78" + +[[package]] +name = "anstyle-parse" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e7644824f0aa2c7b9384579234ef10eb7efb6a0deb83f9630a49594dd9c15c2" +dependencies = [ + "utf8parse", +] + +[[package]] +name = "anstyle-query" +version = "1.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "40c48f72fd53cd289104fc64099abca73db4166ad86ea0b4341abe65af83dadc" +dependencies = [ + "windows-sys", +] + +[[package]] +name = "anstyle-wincon" +version = "3.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "291e6a250ff86cd4a820112fb8898808a366d8f9f58ce16d1f538353ad55747d" +dependencies = [ + "anstyle", + "once_cell_polyfill", + "windows-sys", +] + +[[package]] +name = "bitflags" +version = "2.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "812e12b5285cc515a9c72a5c1d3b6d46a19dac5acfef5265968c166106e31dd3" + +[[package]] +name = "cfg-if" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" + +[[package]] +name = "clap" +version = "4.5.53" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c9e340e012a1bf4935f5282ed1436d1489548e8f72308207ea5df0e23d2d03f8" +dependencies = [ + "clap_builder", + "clap_derive", +] + +[[package]] +name = "clap_builder" +version = "4.5.53" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d76b5d13eaa18c901fd2f7fca939fefe3a0727a953561fefdf3b2922b8569d00" +dependencies = [ + "anstream", + "anstyle", + "clap_lex", + "strsim", +] + +[[package]] +name = "clap_derive" +version = "4.5.49" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a0b5487afeab2deb2ff4e03a807ad1a03ac532ff5a2cee5d86884440c7f7671" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "clap_lex" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1d728cc89cf3aee9ff92b05e62b19ee65a02b5702cff7d5a377e32c6ae29d8d" + +[[package]] +name = "colorchoice" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b05b61dc5112cbb17e4b6cd61790d9845d13888356391624cbe7e41efeac1e75" + +[[package]] +name = "directories" +version = "6.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16f5094c54661b38d03bd7e50df373292118db60b585c08a411c6d840017fe7d" +dependencies = [ + "dirs-sys", +] + +[[package]] +name = "dirs-sys" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e01a3366d27ee9890022452ee61b2b63a67e6f13f58900b651ff5665f0bb1fab" +dependencies = [ + "libc", + "option-ext", + "redox_users", + "windows-sys", +] + +[[package]] +name = "fs_extra" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42703706b716c37f96a77aea830392ad231f44c9e9a67872fa5548707e11b11c" + +[[package]] +name = "getrandom" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + +[[package]] +name = "is_terminal_polyfill" +version = "1.70.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6cb138bb79a146c1bd460005623e142ef0181e3d0219cb493e02f7d08a35695" + +[[package]] +name = "itoa" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" + +[[package]] +name = "libc" +version = "0.2.177" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2874a2af47a2325c2001a6e6fad9b16a53b802102b528163885171cf92b15976" + +[[package]] +name = "libredox" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "416f7e718bdb06000964960ffa43b4335ad4012ae8b99060261aa4a8088d5ccb" +dependencies = [ + "bitflags", + "libc", +] + +[[package]] +name = "memchr" +version = "2.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273" + +[[package]] +name = "once_cell_polyfill" +version = "1.70.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe" + +[[package]] +name = "option-ext" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d" + +[[package]] +name = "pcode-cli" +version = "0.1.0" +dependencies = [ + "clap", + "directories", + "fs_extra", + "serde", + "serde_json", + "thiserror", +] + +[[package]] +name = "proc-macro2" +version = "1.0.103" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ee95bc4ef87b8d5ba32e8b7714ccc834865276eab0aed5c9958d00ec45f49e8" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.42" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a338cc41d27e6cc6dce6cefc13a0729dfbb81c262b1f519331575dd80ef3067f" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "redox_users" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4e608c6638b9c18977b00b475ac1f28d14e84b27d8d42f70e0bf1e3dec127ac" +dependencies = [ + "getrandom", + "libredox", + "thiserror", +] + +[[package]] +name = "ryu" +version = "1.0.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" + +[[package]] +name = "serde" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" +dependencies = [ + "serde_core", + "serde_derive", +] + +[[package]] +name = "serde_core" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_json" +version = "1.0.145" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "402a6f66d8c709116cf22f558eab210f5a50187f702eb4d7e5ef38d9a7f1c79c" +dependencies = [ + "itoa", + "memchr", + "ryu", + "serde", + "serde_core", +] + +[[package]] +name = "strsim" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" + +[[package]] +name = "syn" +version = "2.0.110" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a99801b5bd34ede4cf3fc688c5919368fea4e4814a4664359503e6015b280aea" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "thiserror" +version = "2.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f63587ca0f12b72a0600bcba1d40081f830876000bb46dd2337a3051618f4fc8" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "2.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ff15c8ecd7de3849db632e14d18d2571fa09dfc5ed93479bc4485c7a517c913" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "unicode-ident" +version = "1.0.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5" + +[[package]] +name = "utf8parse" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" + +[[package]] +name = "wasi" +version = "0.11.1+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" + +[[package]] +name = "windows-link" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" + +[[package]] +name = "windows-sys" +version = "0.61.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" +dependencies = [ + "windows-link", +] diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..c8b1773 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,12 @@ +[package] +name = "pcode-cli" +version = "0.1.0" +edition = "2024" + +[dependencies] +clap = { version = "4.5.53", features = ["derive"] } +directories = "6.0.0" +fs_extra = "1.3.0" +serde = { version = "1.0.228", features = ["derive"] } +serde_json = "1.0.145" +thiserror = "2.0.17" diff --git a/flake.lock b/flake.lock new file mode 100644 index 0000000..03f86c8 --- /dev/null +++ b/flake.lock @@ -0,0 +1,96 @@ +{ + "nodes": { + "flake-utils": { + "inputs": { + "systems": "systems" + }, + "locked": { + "lastModified": 1731533236, + "narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=", + "owner": "numtide", + "repo": "flake-utils", + "rev": "11707dc2f618dd54ca8739b309ec4fc024de578b", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "flake-utils", + "type": "github" + } + }, + "nixpkgs": { + "locked": { + "lastModified": 1763283776, + "narHash": "sha256-Y7TDFPK4GlqrKrivOcsHG8xSGqQx3A6c+i7novT85Uk=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "50a96edd8d0db6cc8db57dab6bb6d6ee1f3dc49a", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixos-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs_2": { + "locked": { + "lastModified": 1744536153, + "narHash": "sha256-awS2zRgF4uTwrOKwwiJcByDzDOdo3Q1rPZbiHQg/N38=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "18dd725c29603f582cf1900e0d25f9f1063dbf11", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixpkgs-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "root": { + "inputs": { + "flake-utils": "flake-utils", + "nixpkgs": "nixpkgs", + "rust-overlay": "rust-overlay" + } + }, + "rust-overlay": { + "inputs": { + "nixpkgs": "nixpkgs_2" + }, + "locked": { + "lastModified": 1763347184, + "narHash": "sha256-6QH8hpCYJxifvyHEYg+Da0BotUn03BwLIvYo3JAxuqQ=", + "owner": "oxalica", + "repo": "rust-overlay", + "rev": "08895cce80433978d5bfd668efa41c5e24578cbd", + "type": "github" + }, + "original": { + "owner": "oxalica", + "repo": "rust-overlay", + "type": "github" + } + }, + "systems": { + "locked": { + "lastModified": 1681028828, + "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", + "owner": "nix-systems", + "repo": "default", + "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", + "type": "github" + }, + "original": { + "owner": "nix-systems", + "repo": "default", + "type": "github" + } + } + }, + "root": "root", + "version": 7 +} diff --git a/flake.nix b/flake.nix new file mode 100644 index 0000000..1c09c34 --- /dev/null +++ b/flake.nix @@ -0,0 +1,60 @@ +{ + description = ""; + + inputs = { + nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable"; + rust-overlay.url = "github:oxalica/rust-overlay"; + flake-utils.url = "github:numtide/flake-utils"; + }; + + outputs = + { + nixpkgs, + rust-overlay, + flake-utils, + ... + }: + flake-utils.lib.eachDefaultSystem ( + system: + let + overlays = [ (import rust-overlay) ]; + pkgs = import nixpkgs { + inherit system overlays; + }; + in + { + devShells.default = + with pkgs; + mkShell { + nativeBuildInput = with pkgs; [ + (pkgs.rust-bin.stable.latest.default.override { + extensions = [ + "rust-src" + "cargo" + "rustc" + "rustfmt" + ]; + }) + gcc + ]; + + RUST_SRC_PATH = "${ + pkgs.rust-bin.stable.latest.default.override { + extensions = [ "rust-src" ]; + } + }/lib/rustlib/src/rust/library"; + + buildInputs = [ + openssl.dev + glib.dev + pkg-config + + rust-analyzer + rustfmt + + bacon + ]; + }; + } + ); +} diff --git a/src/cli.rs b/src/cli.rs new file mode 100644 index 0000000..48d72d1 --- /dev/null +++ b/src/cli.rs @@ -0,0 +1,34 @@ +use clap::{Args, Parser, Subcommand}; + +#[derive(Parser)] +#[command(name = "my-cli-name", version, about = "my-cli-about")] +pub struct CLI { + #[command(subcommand)] + pub command: Option, +} + +#[derive(Subcommand)] +pub enum Commands { + // Work with templates + Template(TemplateCommand), +} + +#[derive(Args)] +pub struct TemplateCommand { + #[command(subcommand)] + pub action: TemplateAction, +} + +#[derive(Subcommand)] +pub enum TemplateAction { + // List of all user templates + List, + + // Load user specific template + Load { + name: String, + + #[arg(short = 'v', long = "var")] + vars: Vec, + }, +} diff --git a/src/config/config.rs b/src/config/config.rs new file mode 100644 index 0000000..3c2ffbb --- /dev/null +++ b/src/config/config.rs @@ -0,0 +1,15 @@ +use serde::{Deserialize, Serialize}; +use std::path::PathBuf; + +#[derive(Debug, Deserialize, Serialize)] +pub struct Config { + pub templates_dir: PathBuf, +} + +impl Config { + pub fn new_default(templates_dir: PathBuf) -> Config { + Config { + templates_dir: templates_dir, + } + } +} diff --git a/src/config/defaults.rs b/src/config/defaults.rs new file mode 100644 index 0000000..6b2b87d --- /dev/null +++ b/src/config/defaults.rs @@ -0,0 +1,13 @@ +use directories::ProjectDirs; +use std::path::PathBuf; + +pub fn xdg_paths(application: &str) -> (PathBuf, PathBuf) { + if let Some(dirs) = ProjectDirs::from("", "", application) { + let config_dir = dirs.config_dir().to_path_buf(); + let data_dir = dirs.data_dir().to_path_buf(); + + (config_dir, data_dir) + } else { + todo!("Process None ProjectDirs"); + } +} diff --git a/src/config/loader.rs b/src/config/loader.rs new file mode 100644 index 0000000..01f99b8 --- /dev/null +++ b/src/config/loader.rs @@ -0,0 +1,53 @@ +use crate::config::Config; +use crate::config::defaults::xdg_paths; +use crate::core::util::ensure_dir; +use crate::misc::{APP_NAME, CONFIG_FILE_NAME}; +use std::fs::File; +use std::io::Read; +use thiserror::Error; + +#[derive(Debug, Error)] +pub enum ConfigError { + #[error("IO error: {0}")] + Io(#[from] std::io::Error), + + #[error("JSON parse error: {0}")] + Parse(#[from] serde_json::Error), + + #[error("Validation error: {0}")] + Validation(String), +} + +pub fn load_config() -> Result { + let (config_dir, data_dir) = xdg_paths(APP_NAME); + + let mut path = config_dir.clone(); + path.push(CONFIG_FILE_NAME); + + if !path.exists() { + ensure_dir(&config_dir).map_err(ConfigError::Io)?; + ensure_dir(&data_dir).map_err(ConfigError::Io)?; + + let cfg = Config::new_default(config_dir.join("templates")); + + return Ok(cfg); + } else { + let mut file = File::open(path)?; + let mut content = String::new(); + + file.read_to_string(&mut content)?; + + let cfg: Config = serde_json::from_str(&content)?; + validate_config(&cfg)?; + + return Ok(cfg); + } +} + +fn validate_config(cfg: &Config) -> Result<(), ConfigError> { + if cfg.templates_dir.as_os_str().is_empty() { + return Err(ConfigError::Validation("templates_dir is empty".into())); + } else { + Ok(()) + } +} diff --git a/src/config/mod.rs b/src/config/mod.rs new file mode 100644 index 0000000..da81555 --- /dev/null +++ b/src/config/mod.rs @@ -0,0 +1,6 @@ +pub mod config; +pub mod defaults; +pub mod loader; + +pub use config::Config; +pub use loader::load_config; diff --git a/src/core/mod.rs b/src/core/mod.rs new file mode 100644 index 0000000..812d1ed --- /dev/null +++ b/src/core/mod.rs @@ -0,0 +1 @@ +pub mod util; diff --git a/src/core/util.rs b/src/core/util.rs new file mode 100644 index 0000000..0ae70ed --- /dev/null +++ b/src/core/util.rs @@ -0,0 +1,11 @@ +use std::fs; +use std::path::Path; + +/// Ensure directory exists +pub fn ensure_dir(path: &Path) -> Result<(), std::io::Error> { + if path.exists() { + return Ok(()); + } + fs::create_dir_all(path)?; + Ok(()) +} diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 0000000..e556a77 --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,67 @@ +mod cli; +mod config; +mod core; +mod misc; +mod templates; + +use std::process; + +use clap::Parser; +use cli::{CLI, Commands, TemplateAction}; +use config::{Config, load_config}; +use templates::{list_templates, load_template}; + +fn parse_config() -> Config { + let cfg: Config = match load_config() { + Ok(cfg) => cfg, + Err(err) => { + eprintln!("{}", err); + process::exit(1); + } + }; + + cfg +} + +fn process_command(cfg: Config) { + let cli = CLI::parse(); + + match cli.command { + Some(Commands::Template(template_command)) => match template_command.action { + TemplateAction::List => { + let templates = match list_templates(&cfg.templates_dir) { + Ok(temps) => temps, + Err(err) => { + eprintln!("{}", err); + process::exit(1); + } + }; + + // TODO: Add grouping by language. + for template in templates { + eprintln!("{} >- {}", template.language, template.name); + } + } + TemplateAction::Load { name, vars } => match load_template(&cfg.templates_dir, &name) { + Ok(_) => { + eprintln!("Template succesfully copied!"); + eprintln!("Vars: {:?}", vars); + } + Err(err) => { + eprintln!("{}", err); + process::exit(1) + } + }, + }, + None => { + eprintln!("No command provided. Use --help for usage."); + process::exit(1); + } + } +} + +pub fn run() { + let cfg = parse_config(); + + process_command(cfg); +} diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..935517e --- /dev/null +++ b/src/main.rs @@ -0,0 +1,5 @@ +use pcode_cli; + +fn main() { + pcode_cli::run(); +} diff --git a/src/misc.rs b/src/misc.rs new file mode 100644 index 0000000..7647779 --- /dev/null +++ b/src/misc.rs @@ -0,0 +1,2 @@ +pub const CONFIG_FILE_NAME: &str = "config.json"; +pub const APP_NAME: &str = "pcode-cli"; diff --git a/src/templates/mod.rs b/src/templates/mod.rs new file mode 100644 index 0000000..8424f19 --- /dev/null +++ b/src/templates/mod.rs @@ -0,0 +1,3 @@ +pub mod templates; + +pub use templates::{list_templates, load_template}; diff --git a/src/templates/templates.rs b/src/templates/templates.rs new file mode 100644 index 0000000..01621dd --- /dev/null +++ b/src/templates/templates.rs @@ -0,0 +1,108 @@ +use fs_extra::dir::{CopyOptions, copy}; +use std::io::{self, Error}; +use std::path::{Path, PathBuf}; +use std::{env, fs}; + +/// Description for template +pub struct TemplateEntry { + pub language: String, + pub name: String, + pub _path: PathBuf, +} + +fn is_hidden_name(os: &std::ffi::OsStr) -> bool { + os.to_str().map(|s| s.starts_with('.')).unwrap_or(false) +} + +pub fn list_templates(templates_dir: &Path) -> Result, Error> { + let mut out = Vec::new(); + + if !templates_dir.exists() { + return Ok(out); + } + + for lang_entry in fs::read_dir(templates_dir)? { + let lang_entry = lang_entry?; + let lang_path = lang_entry.path(); + + if !lang_path.is_dir() || is_hidden_name(lang_path.file_name().unwrap_or_default()) { + continue; + } + let language = lang_path + .file_name() + .and_then(|s| s.to_str()) + .unwrap_or_default() + .to_string(); + + for template_entry in fs::read_dir(&lang_path)? { + let template_entry = template_entry?; + let template_path = template_entry.path(); + + if !template_path.is_dir() { + continue; + } + + let name = template_path + .file_name() + .and_then(|s| s.to_str()) + .unwrap_or_default() + .to_string(); + + out.push(TemplateEntry { + language: language.clone(), + name: name, + _path: template_path, + }); + } + } + + Ok(out) +} + +pub fn load_template(templates_dir: &Path, template_name: &str) -> Result<(), Error> { + let requested = Path::new(template_name); + let requested_components = requested.components().count(); + + let mut candidate_path = match requested_components { + ..2 => templates_dir.join(requested), + _ => { + return Err(Error::new( + io::ErrorKind::InvalidInput, + "You need to use syntax / or !", + )); + } + }; + + if requested_components == 1 { + candidate_path.push("default"); + } + + let candidate_name = candidate_path.to_str().unwrap_or_default(); + + if !candidate_path.is_dir() { + return Err(Error::new( + io::ErrorKind::NotFound, + format!("Your template {} not found!", candidate_name), + )); + } + + let dst = env::current_dir()?; + + dbg!(&candidate_path); + dbg!(&dst); + + let mut options = CopyOptions::new(); + + options.copy_inside = true; + options.content_only = true; + + match copy(&candidate_path, &dst, &options) { + Ok(_) => return Ok(()), + Err(err) => { + return Err(Error::new( + io::ErrorKind::Other, + format!("Copy error: {}!", err), + )); + } + }; +}