Skip to content

Commit

Permalink
feat: add ion template inspect command (#11)
Browse files Browse the repository at this point in the history
  • Loading branch information
diversable authored Feb 16, 2023
1 parent a5df9c3 commit 592c434
Show file tree
Hide file tree
Showing 4 changed files with 181 additions and 3 deletions.
27 changes: 25 additions & 2 deletions src/bin/ion/commands/template.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
use clap::parser::ArgMatches;
use clap::Command;
use ion::blueprints::list_templates;
use clap::{arg, Command};
use ion::blueprints::{
ask_inspect_template, inspect_all_templates, inspect_template, list_templates,
};
use ion::config::Config;
use ion::errors::CliResult;
use ion::template::RemoteTemplate;
Expand All @@ -10,6 +12,12 @@ pub fn cli() -> Command {
.about("template management")
.subcommand(Command::new("list").about("list all available templates"))
.subcommand(Command::new("update").about("update the templates from registry"))
.subcommand(
Command::new("inspect")
.about("inspect the contents of a template")
.arg(arg!([TEMPLATE] "Selects which template to print out"))
.arg(arg!(--"all" "Inspect all installed templates")),
)
.arg_required_else_help(true)
}

Expand All @@ -19,6 +27,21 @@ pub fn exec(config: &mut Config, matches: &ArgMatches) -> CliResult {
Some(("update", _)) => {
RemoteTemplate::new(config).download()?;
}
Some(("inspect", matches)) => {
// Iff a template name is provided, inspect template; otherwise, check for --all flag; if no --all, ask user to select template from list

match matches.get_one::<String>("TEMPLATE") {
Some(template) => inspect_template(config, template.to_owned())?,
None => {
let all_flag = matches.get_flag("all");
if all_flag {
inspect_all_templates(config)?;
} else {
ask_inspect_template(config)?;
}
}
};
}
_ => unreachable!(),
}
Ok(())
Expand Down
105 changes: 104 additions & 1 deletion src/ion/blueprints/utils.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use crate::blueprints::*;
use crate::spec::Author;
use anyhow::{format_err, Error, Result};
use dialoguer::{Confirm, Input};
use dialoguer::{theme::ColorfulTheme, Confirm, Input, Select};

pub fn git_get_user() -> Result<(String, String)> {
let user = if let Some(name) = git_config_get("user.name") {
Expand Down Expand Up @@ -112,6 +112,109 @@ pub fn list_templates(config: &Config) -> Result<()> {
Ok(())
}

pub fn inspect_template(config: &Config, template_name: String) -> Result<()> {
let templates = config.template_dir().read_dir()?;

let mut template_found: bool = false;

for entry in templates {
let entry = match entry {
Ok(e) => e,
Err(e) => {
return Err(Error::new(e));
}
};

let path = entry.path();
if path.is_dir() {
let source = std::fs::read_to_string(path.join("template.toml"))?;

let template = match toml::from_str::<Template>(&source) {
Ok(t) => t,
Err(e) => {
return Err(format_err!("Error parsing template: {}", e));
}
};
if template.name == template_name {
template_found = true;
println!("{}", source);
}
}
}

// If the template the user requested is not in the list of downloaded templates, ask user to select existing template to inspect
if !template_found {
println!(
"The {} template was not found.\nInstalled templates are:",
template_name
);
ask_inspect_template(config)?
}
Ok(())
}

pub fn inspect_all_templates(config: &Config) -> Result<()> {
let templates = config.template_dir().read_dir()?;

for entry in templates {
let entry = match entry {
Ok(e) => e,
Err(e) => {
return Err(Error::new(e));
}
};

let path = entry.path();
if path.is_dir() {
let source = std::fs::read_to_string(path.join("template.toml"))?;

println!("\n{}\n**********", source);
}
}
Ok(())
}

pub fn ask_inspect_template(config: &Config) -> Result<()> {
// Get selection options from installed templates
let mut selection_options = vec![];

let templates = config.template_dir().read_dir()?;
for entry in templates {
let entry = match entry {
Ok(e) => e,
Err(e) => {
return Err(Error::new(e));
}
};

let path = entry.path();
if path.is_dir() {
let source = std::fs::read_to_string(path.join("template.toml"))?;

let template = match toml::from_str::<Template>(&source) {
Ok(t) => t,
Err(e) => {
return Err(format_err!("Error parsing template: {}", e));
}
};

selection_options.push(template.name);
}
}

// Ask for template to print to console
let template_name = Select::with_theme(&ColorfulTheme::default())
.items(&selection_options)
.default(1)
.interact_opt()?;

if let Some(template_name) = template_name {
inspect_template(config, selection_options[template_name].to_owned())?
};

Ok(())
}

pub fn git_config_get(key: &str) -> Option<String> {
let output = std::process::Command::new("git")
.arg("config")
Expand Down
1 change: 1 addition & 0 deletions tests/bin/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ pub mod clone;
pub mod new;
pub mod pkg;
pub mod script;
pub mod template;

pub mod utils;
pub use utils::*;
Expand Down
51 changes: 51 additions & 0 deletions tests/bin/template.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
use super::*;
use anyhow::{Ok, Result};

#[test]
fn test_template() -> Result<()> {
Ion::new().arg("template").arg("list").assert().success();

Ion::new().arg("template").arg("update").assert().success();

Ion::new()
.arg("template")
.arg("inspect")
.arg("--all")
.assert()
.success();

Ion::new()
.arg("template")
.arg("inspect")
.arg("package")
.assert()
.success();

// Test escape from input / Ctrl+C behaviour with `ion template inspect` (cf. ask_inspect_input fn)
let mut p = Ion::new()
.arg("template")
.arg("inspect")
.arg("nonce")
.spawn(Some(30_000))?;

p.send_control('c')?;
p.exp_eof()?;

Ok(())?;

// Test nonce input
let mut ps = Ion::new()
.arg("template")
.arg("inspect")
.arg("nonce")
.spawn(Some(5_000))?;

ps.exp_string("Installed templates are:")?;

// Send <ENTER> keycode to pty
ps.send_control('j')?;
ps.exp_string("name")?;
ps.exp_eof()?;

Ok(())
}

0 comments on commit 592c434

Please sign in to comment.