- Commit
- 63a11a42223272cc5a7df11a6106377bdfb35145
- Parent
- 98ee25f2cf656060d36c1afd6089bdafde29387d
- Author
- Pablo <pablo-pie@riseup.net>
- Date
Implemented the 'delete' feature
Yet another static site generator for Git 🙀️
Implemented the 'delete' feature
4 files changed, 118 insertions, 25 deletions
Status | Name | Changes | Insertions | Deletions |
Modified | TODO.md | 2 files changed | 1 | 2 |
Modified | src/command.rs | 2 files changed | 21 | 1 |
Modified | src/log.rs | 2 files changed | 34 | 7 |
Modified | src/main.rs | 2 files changed | 62 | 15 |
diff --git a/TODO.md b/TODO.md @@ -1,4 +1,3 @@ # TODO -* Add functionality: - * subcommand for deleting an existing repo +* add a testing framework
diff --git a/src/command.rs b/src/command.rs @@ -3,6 +3,7 @@ use std::{env, ops::BitOrAssign}; const RENDER_BATCH_CMD: &str = "render-batch"; const RENDER_CMD: &str = "render"; const INIT_CMD: &str = "init"; +const DELETE_CMD: &str = "delete"; const FULL_BUILD_FLAG: &str = "--full-build"; const PRIVATE_FLAG: &str = "--private"; @@ -18,6 +19,7 @@ enum CmdTag { RenderBatch, Render, Init, + Delete, } #[derive(Clone, Debug)] @@ -29,7 +31,10 @@ pub enum SubCmd { Init { repo_name: String, description: String, - } + }, + Delete { + repo_name: String, + }, } impl Cmd { @@ -40,6 +45,7 @@ impl Cmd { Some(arg) if arg == RENDER_BATCH_CMD => break CmdTag::RenderBatch, Some(arg) if arg == RENDER_CMD => break CmdTag::Render, Some(arg) if arg == INIT_CMD => break CmdTag::Init, + Some(arg) if arg == DELETE_CMD => break CmdTag::Delete, Some(arg) if arg == FULL_BUILD_FLAG => { flags |= Flags::FULL_BUILD; @@ -100,6 +106,17 @@ impl Cmd { SubCmd::Init { repo_name, description, } } + CmdTag::Delete => { + let repo_name = if let Some(name) = args.next() { + name + } else { + errorln!("No repository name providade"); + usage(program_name, Some(tag)); + return Err(()); + }; + + SubCmd::Delete { repo_name, } + } }; if args.next().is_some() { @@ -151,5 +168,8 @@ fn usage(program_name: &str, tag: Option) { Some(CmdTag::Init) => { usageln!("{program_name} [{PRIVATE_FLAG}] {INIT_CMD} <repo-name>"); } + Some(CmdTag::Delete) => { + usageln!("{program_name} [{PRIVATE_FLAG}] {DELETE_CMD} <repo-name>"); + } } }
diff --git a/src/log.rs b/src/log.rs @@ -39,22 +39,22 @@ struct Counter { pub(crate) fn log(level: Level, args: &Arguments<'_>) { match level { Level::Error => { - eprint!("{BOLD_RED} Error{RESET} "); + eprint!("{BOLD_RED} Error{RESET} "); eprintln!("{}", args); // shouldn't print the job counter because we are about to die } Level::Info => { - print!("{BOLD_BLUE} Info{RESET} "); + print!("{BOLD_BLUE} Info{RESET} "); println!("{}", args); log_current_job(); } Level::Warn => { - print!("{BOLD_YELLOW} Warning{RESET} "); + print!("{BOLD_YELLOW} Warning{RESET} "); println!("{}", args); log_current_job(); } Level::Usage => { - print!("{BOLD_YELLOW} Usage{RESET} "); + print!("{BOLD_YELLOW} Usage{RESET} "); println!("{}", args); println!(" For more information check the {UNDERLINE}yagit(1){RESET} man page."); log_current_job(); @@ -62,6 +62,25 @@ pub(crate) fn log(level: Level, args: &Arguments<'_>) { } } +pub(crate) fn query(args: &Arguments<'_>) -> String { + let mut stdout = io::stdout(); + let stdin = io::stdin(); + let mut result = String::new(); + + let _ = write!(stdout, "{BOLD_YELLOW} Confirm{RESET} {} ", args); + let _ = stdout.flush(); + + if stdin.read_line(&mut result).is_err() { + result.clear(); + } else if result.ends_with('\n') { + let _ = result.pop(); + } + + // shouldn't print the job counter because we are should be running the + // 'delete' command, so there are no jobs + result +} + pub fn set_job_count(total: usize) { unsafe { COUNTER.total = total; @@ -87,7 +106,7 @@ pub fn render_done() { let space_padding = "... [/]".len() + 2 * crate::log_floor(COUNTER.total); println!( - "{BOLD_GREEN} Rendered{RESET} {name}{empty:space_padding$}", + "{BOLD_GREEN} Rendered{RESET} {name}{empty:space_padding$}", name = COUNTER.current_repo_name, empty = "", ); @@ -104,7 +123,7 @@ fn log_current_job() { let _ = write!( stdout, - "{BOLD_CYAN}Rendering{RESET} {name}... {BOLD_WHITE}[{count:>padding$}/{total}]{RESET}\r", + "{BOLD_CYAN} Rendering{RESET} {name}... {BOLD_WHITE}[{count:>padding$}/{total}]{RESET}\r", count = COUNTER.count, total = COUNTER.total, padding = crate::log_floor(COUNTER.total), @@ -158,12 +177,20 @@ macro_rules! usageln { }); } +#[macro_export] +macro_rules! query { + // query!("a {}", "question?"); + ($($arg:tt)+) => ({ + $crate::log::query(&std::format_args!($($arg)+)) + }); +} + pub fn finished(duration: Duration) { let duration = duration.as_millis() / 100; let secs = duration / 10; let dsecs = duration % 10; - println!("{BOLD_GREEN} Finished{RESET} Rendering took {secs}.{dsecs}s"); + println!("{BOLD_GREEN} Finished{RESET} Rendering took {secs}.{dsecs}s"); } #[cfg(target_arch = "x86_64")]
diff --git a/src/main.rs b/src/main.rs @@ -5,7 +5,6 @@ use std::{ mem, env, fmt::{self, Display}, - ffi::OsStr, collections::HashMap, time::{Duration, SystemTime, Instant}, process::ExitCode, @@ -61,6 +60,7 @@ struct RepoInfo { pub name: String, pub owner: String, pub description: Option<String>, + pub path: PathBuf, pub repo: Repository, pub last_commit: Time, @@ -68,9 +68,8 @@ struct RepoInfo { } impl RepoInfo { - fn open<P, S>(path: P, name: S) -> Result<Self, ()> + fn open<S>(path: PathBuf, name: S) -> Result<Self, ()> where - P: AsRef<Path> + AsRef<OsStr> + fmt::Debug, S: AsRef<str>, { let repo = match Repository::open(&path) { @@ -113,13 +112,9 @@ impl RepoInfo { return Err(()); } - let mut path = PathBuf::from(&path); - if !repo.is_bare() { - path.push(".git"); - } - let owner = { let mut owner_path = path.clone(); + if !repo.is_bare() { owner_path.push(".git"); } owner_path.push("owner"); let mut owner = String::with_capacity(32); @@ -141,6 +136,7 @@ impl RepoInfo { let description = { let mut dsc_path = path.clone(); + if !repo.is_bare() { dsc_path.push(".git"); } dsc_path.push("description"); let mut dsc = String::with_capacity(512); @@ -164,6 +160,7 @@ impl RepoInfo { name: String::from(name.as_ref()), owner, description, + path, repo, first_commit, last_commit, @@ -189,7 +186,7 @@ impl RepoInfo { let repo_name = entry.file_name(); result.push( - RepoInfo::open(&repo_path, repo_name.to_string_lossy())? + RepoInfo::open(repo_path, repo_name.to_string_lossy())? ); } _ => continue, @@ -1628,6 +1625,8 @@ fn main() -> ExitCode { } log::render_done(); } + + log::finished(start.elapsed()); } SubCmd::Render { repo_name } => { let repos = if let Ok(repos) = RepoInfo::index(cmd.flags.private()) { @@ -1662,18 +1661,18 @@ fn main() -> ExitCode { log::render_start("repository index"); if let Err(e) = render_index(&repos, cmd.flags.private()) { - errorln!("Failed rendering global repository index: {e}"); + errorln!("Failed rendering repository index: {e}"); } log::render_done(); log::render_start(&repo.name); - if let Err(e) = renderer.render() { errorln!("Failed rendering pages for {name:?}: {e}", name = renderer.name); } - log::render_done(); + + log::finished(start.elapsed()); } SubCmd::Init { repo_name, description } => { let mut repo_path = if cmd.flags.private() { @@ -1686,8 +1685,6 @@ fn main() -> ExitCode { let mut opts = RepositoryInitOptions::new(); opts.bare(false).no_reinit(true); - infoln!("Initializing empty {repo_name:?} repository in {repo_path:?}"); - if let Err(e) = Repository::init_opts(&repo_path, &opts) { errorln!("Couldn't initialize {repo_name:?}: {e}", e = e.message()); return ExitCode::FAILURE; @@ -1697,9 +1694,59 @@ fn main() -> ExitCode { .is_err() { return ExitCode::FAILURE; } + + infoln!("Initialized empty repository in {repo_path:?}"); + } + SubCmd::Delete { repo_name } => { + let mut repos = if let Ok(repos) = RepoInfo::index(cmd.flags.private()) { + repos + } else { + return ExitCode::FAILURE; + }; + + let mut repo = None; + for i in 0..repos.len() { + if repos[i].name == *repo_name { + repo = Some(repos.remove(i)); + break; + } + } + + if repo.is_none() { + errorln!("Couldnt' find repository {repo_name:?} in {repos_dir:?}"); + return ExitCode::FAILURE; + } + let repo = repo.unwrap(); + + let answer = query!( + "Would you like to remove {repo_path:?}?", + repo_path = repo.path + ); + + if answer != "y" && answer != "Y" { + infoln!("Not deleting {repo_name:?}", repo_name = repo.name); + return ExitCode::SUCCESS; + } + + log::set_job_count(1); // tasks: render index + + if let Err(e) = fs::remove_dir_all(&repo.path) { + errorln!("Couldnt' remove {repo_path:?}: {e}", repo_path = repo.path); + return ExitCode::FAILURE; + } + + log::render_start("repository index"); + infoln!("Removed {repo_path:?}", repo_path = repo.path); + log::render_done(); + + if let Err(e) = render_index(&repos, cmd.flags.private()) { + errorln!("Failed rendering repository index: {e}"); + return ExitCode::FAILURE; + } + + log::finished(start.elapsed()); } } - log::finished(start.elapsed()); ExitCode::SUCCESS }