-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
+ new -y, --delete option to always delete
- Loading branch information
1 parent
1eefb39
commit a638532
Showing
6 changed files
with
283 additions
and
105 deletions.
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,118 +1,36 @@ | ||
use std::{env, fs, io, path::Path, process::Command}; | ||
|
||
use anyhow::{bail, Ok}; | ||
use chrono::Local; | ||
use clap::Parser; | ||
use directories_next::ProjectDirs; | ||
use templates::Templates; | ||
|
||
pub mod templates; | ||
|
||
pub const EDITOR_KEY: &str = "VISUAL"; | ||
pub const ALWAYS_DELETE_KEY: &str = "ATMPT_ALWAYS_DELETE"; | ||
pub const TEMPLATE_DIR_KEY: &str = "ATMPT_DATA_DIR"; | ||
|
||
#[derive(Debug, Parser)] | ||
#[command(author, version, about)] | ||
pub struct Atmpt { | ||
#[command(flatten)] | ||
required: RequiredArgs, | ||
pub required: RequiredArgs, | ||
|
||
#[arg(short, long, env = EDITOR_KEY, help = "Use given editor for this run")] | ||
pub editor: Option<String>, | ||
|
||
#[arg(short, long, env = "VISUAL", help = "Use given editor for this run")] | ||
editor: Option<String>, | ||
#[arg(short = 'y', long, env = ALWAYS_DELETE_KEY, help = "Autodelete project on exit")] | ||
pub delete: bool, | ||
|
||
#[arg(long, hide = true, env = TEMPLATE_DIR_KEY)] // override template dir | ||
pub template_dir: Option<String>, | ||
} | ||
|
||
#[derive(Debug, Parser)] | ||
#[group(required = true)] | ||
pub struct RequiredArgs { | ||
#[arg(group = "main")] | ||
template: Option<String>, | ||
pub template: Option<String>, | ||
|
||
#[arg( | ||
group = "main", | ||
short = 'd', | ||
long = "template-dir", | ||
help = "Output template directory" | ||
)] | ||
list_template_dir: bool, | ||
#[arg(group = "main", short = 'd', long, help = "Output template directory")] | ||
pub list_template_dir: bool, | ||
|
||
#[arg(group = "main", short, long, help = "List available templates")] | ||
list_templates: bool, | ||
} | ||
|
||
impl Atmpt { | ||
pub fn parse_with(dirs: &ProjectDirs) -> anyhow::Result<()> { | ||
let args = Self::parse(); | ||
let req = args.required; | ||
let data_dir = dirs.data_dir(); | ||
|
||
if let Some(template) = req.template { | ||
let Some(editor) = args.editor else { | ||
bail!("No editor to use!"); // really should not happen | ||
}; | ||
|
||
try_template(&template, &editor, data_dir)?; | ||
} else if req.list_template_dir { | ||
println!("{}", data_dir.display()); | ||
} else { | ||
println!("{}", Templates::try_from(data_dir)?); | ||
} | ||
|
||
Ok(()) | ||
} | ||
} | ||
|
||
fn try_template(template: &str, editor: &str, data_dir: &Path) -> anyhow::Result<()> { | ||
let templates = Templates::try_from(data_dir)?; | ||
let wanted_dir = templates.find(template)?; | ||
|
||
let time = Local::now().format("%Y_%m_%d-%H_%M_%S"); | ||
let tmp_dir = env::temp_dir() | ||
.join("atmpt") // store tmp projects in folder | ||
.join(format!("{template}_{time}")); | ||
copy_dir_recursively(wanted_dir, &tmp_dir)?; | ||
|
||
std::env::set_current_dir(&tmp_dir).expect("Could not change to temp directory!"); | ||
Command::new(editor) | ||
.arg(&tmp_dir) | ||
.spawn()? | ||
.wait() | ||
.expect("Could not launch editor!"); | ||
|
||
if ask_y_n("Would you like to delete this project?")? { | ||
fs::remove_dir_all(&tmp_dir)?; | ||
println!("Deleted.") | ||
} else { | ||
println!("Saved as {tmp_dir:?}."); | ||
} | ||
|
||
Ok(()) | ||
} | ||
|
||
fn ask_y_n(question: &str) -> anyhow::Result<bool> { | ||
println!("{question} (Y/n)"); | ||
|
||
let mut input = String::new(); | ||
io::stdin().read_line(&mut input)?; | ||
|
||
match input.to_lowercase().trim() { | ||
"" => Ok(true), // default to yes if only enter is pressed | ||
"y" => Ok(true), | ||
"n" => Ok(false), | ||
_ => ask_y_n(question), | ||
} | ||
} | ||
|
||
// modified from https://stackoverflow.com/a/65192210/15425442 | ||
fn copy_dir_recursively(from: &Path, to: &Path) -> anyhow::Result<()> { | ||
fs::create_dir_all(to)?; | ||
|
||
for entry in fs::read_dir(from)? { | ||
let entry = entry?; | ||
let path = entry.path(); | ||
|
||
if path.is_dir() { | ||
copy_dir_recursively(&path, &to.join(entry.file_name()))?; | ||
} else { | ||
fs::copy(path, to.join(entry.file_name()))?; | ||
} | ||
} | ||
|
||
Ok(()) | ||
pub list_templates: bool, | ||
} |
Oops, something went wrong.