From de3c59661abe7f38e99ac414bbbf33745434dd31 Mon Sep 17 00:00:00 2001 From: Justin Wernick Date: Sun, 12 Mar 2023 11:11:41 +0200 Subject: Added an batch mode --- Cargo.lock | 122 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Cargo.toml | 1 + src/main.rs | 89 ++++++++++++++++++++++++++++-------------- src/parser.rs | 1 + tests/cli.rs | 2 +- 5 files changed, 186 insertions(+), 29 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 7c5d618..4fa6c51 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -70,6 +70,43 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +[[package]] +name = "clap" +version = "4.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3d7ae14b20b94cb02149ed21a86c423859cbe18dc7ed69845cace50e52b40a5" +dependencies = [ + "bitflags", + "clap_derive", + "clap_lex", + "is-terminal", + "once_cell", + "strsim", + "termcolor", +] + +[[package]] +name = "clap_derive" +version = "4.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44bec8e5c9d09e439c4335b1af0abaab56dcf3b94999a936e1bb47b9134288f0" +dependencies = [ + "heck", + "proc-macro-error", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "clap_lex" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "350b9cf31731f9957399229e9b2adc51eeabdfbe9d71d9a0552275fd12710d09" +dependencies = [ + "os_str_bytes", +] + [[package]] name = "comma" version = "1.0.0" @@ -152,6 +189,18 @@ dependencies = [ "url", ] +[[package]] +name = "heck" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" + +[[package]] +name = "hermit-abi" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fed44880c466736ef9a5c5b5facefb5ed0785676d0c02d612db14e54f0d84286" + [[package]] name = "idna" version = "0.3.0" @@ -181,6 +230,18 @@ dependencies = [ "windows-sys 0.45.0", ] +[[package]] +name = "is-terminal" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21b6b32576413a8e69b90e952e4a026476040d81017b80445deda5f2d3921857" +dependencies = [ + "hermit-abi", + "io-lifetimes", + "rustix", + "windows-sys 0.45.0", +] + [[package]] name = "itertools" version = "0.10.5" @@ -295,6 +356,12 @@ version = "1.17.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b7e5500299e16ebb147ae15a00a942af264cf3688f47923b8fc2cd5858f23ad3" +[[package]] +name = "os_str_bytes" +version = "6.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b7820b9daea5457c9f21c69448905d723fbd21136ccf521748f23fd49e723ee" + [[package]] name = "percent-encoding" version = "2.2.0" @@ -340,6 +407,30 @@ dependencies = [ "termtree", ] +[[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.51" @@ -429,6 +520,7 @@ version = "0.1.0" dependencies = [ "anyhow", "assert_cmd", + "clap", "get-port", "git2", "nom", @@ -438,6 +530,12 @@ dependencies = [ "thiserror", ] +[[package]] +name = "strsim" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" + [[package]] name = "syn" version = "1.0.107" @@ -462,6 +560,15 @@ dependencies = [ "windows-sys 0.42.0", ] +[[package]] +name = "termcolor" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be55cf8942feac5c765c2c993422806843c9a9a45d4d5c407ad6dd2ea95eb9b6" +dependencies = [ + "winapi-util", +] + [[package]] name = "termtree" version = "0.4.0" @@ -541,6 +648,12 @@ version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" +[[package]] +name = "version_check" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" + [[package]] name = "wait-timeout" version = "0.2.0" @@ -566,6 +679,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", +] + [[package]] name = "winapi-x86_64-pc-windows-gnu" version = "0.4.0" diff --git a/Cargo.toml b/Cargo.toml index 75dec3a..81d8115 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,6 +6,7 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] +clap = { version = "4.1.8", features = ["derive"] } git2 = { version = "0.16.1", default-features = false, features = ["vendored-libgit2"] } nom = "7.1.3" rexpect = "0.5.0" diff --git a/src/main.rs b/src/main.rs index ebbf23a..ba29032 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,10 +1,19 @@ -use std::{io, io::Write, process}; -use thiserror::Error; - mod git; mod parser; +use clap::Parser; use parser::Command; +use std::{io, io::Write, ops::ControlFlow, process}; +use thiserror::Error; + +/// Shackle Shell - A replacement for git-shell with repo management commands built in. +#[derive(Parser, Debug)] +#[command(author, version, about, long_about = None)] +struct Args { + /// Run a single shell command and exit + #[arg(short, long)] + command: Option, +} fn prompt() -> Result<(), ShackleError> { print!("> "); @@ -19,39 +28,63 @@ fn read_stdin() -> Result { } fn main() -> Result<(), ShackleError> { + let args = Args::parse(); + match args.command { + Some(user_input) => { + run_command(user_input)?; + } + None => { + run_interactive_loop()?; + } + } + + Ok(()) +} + +fn run_command(user_input: String) -> Result, ShackleError> { + match user_input.parse::() { + Err(unknown_input) => { + println!("Unknown input \"{}\"", unknown_input); + } + Ok(Command::Whitespace) => {} + Ok(Command::Exit) => { + return Ok(ControlFlow::Break(())); + } + Ok(Command::GitInit(repo_name)) => { + git::init(&repo_name)?; // TODO should report this error differently + println!("Successfully created {}.git", repo_name); + } + Ok(Command::GitUploadPack(git_dir)) => { + process::Command::new("git") + .args(["upload-pack", &git_dir]) + .spawn()? + .wait()?; + } + Ok(Command::GitReceivePack(git_dir)) => { + process::Command::new("git") + .args(["receive-pack", &git_dir]) + .spawn()? + .wait()?; + } + } + Ok(ControlFlow::Continue(())) +} + +fn run_interactive_loop() -> Result<(), ShackleError> { loop { prompt()?; let user_input = read_stdin()?; - - match user_input.parse::() { - Err(unknown_input) => { - println!("Unknown input \"{}\"", unknown_input); - } - Ok(Command::Whitespace) => {} - Ok(Command::Exit) => { - break; - } - Ok(Command::GitInit(repo_name)) => { - git::init(&repo_name)?; // TODO should report this error differently - println!("Successfully created {}.git", repo_name); - } - Ok(Command::GitUploadPack(git_dir)) => { - process::Command::new("git") - .args(["upload-pack", &git_dir]) - .spawn()? - .wait()?; - } - Ok(Command::GitReceivePack(git_dir)) => { - process::Command::new("git") - .args(["receive-pack", &git_dir]) - .spawn()? - .wait()?; - } + // TODO: should this report errors differently? Most of the errors are from user actions. + let control_flow = run_command(user_input)?; + if control_flow.is_break() { + break; } } Ok(()) } +pub enum FlowControl {} + #[derive(Error, Debug)] pub enum ShackleError { #[error(transparent)] diff --git a/src/parser.rs b/src/parser.rs index 64ebf5b..75ac333 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -10,6 +10,7 @@ use nom::{ }; use std::str::FromStr; +// TODO: It might work well to use clap and parse_from for this particular case #[derive(Clone)] pub enum Command { Whitespace, diff --git a/tests/cli.rs b/tests/cli.rs index fcd1437..e642781 100644 --- a/tests/cli.rs +++ b/tests/cli.rs @@ -106,7 +106,7 @@ fn can_init_a_new_git_repo() -> Result<()> { #[test] fn runs_a_single_command_and_exit_with_cli_flag() -> Result<()> { let mut c = run_batch_command("git-init another-new-repo")?; - c.p.exp_string("Successfully created my-new-repo.git")?; + c.p.exp_string("Successfully created another-new-repo.git")?; c.p.exp_eof()?; Ok(()) } -- cgit v1.2.3