From a7f9c8de31231b9fd9c67c57db659f7b01f1a3b0 Mon Sep 17 00:00:00 2001 From: Rutger Broekhoff Date: Mon, 29 Apr 2024 19:18:56 +0200 Subject: Rename crates (and therefore commands) --- gitolfs3-shell/src/main.rs | 145 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 145 insertions(+) create mode 100644 gitolfs3-shell/src/main.rs (limited to 'gitolfs3-shell/src/main.rs') diff --git a/gitolfs3-shell/src/main.rs b/gitolfs3-shell/src/main.rs new file mode 100644 index 0000000..f0c5f34 --- /dev/null +++ b/gitolfs3-shell/src/main.rs @@ -0,0 +1,145 @@ +use std::{os::unix::process::CommandExt, process::ExitCode}; + +fn main() -> ExitCode { + let bad_usage = ExitCode::from(2); + + let mut args = std::env::args().skip(1); + if args.next() != Some("-c".to_string()) { + eprintln!("Expected usage: shell -c "); + return bad_usage; + } + let Some(cmd) = args.next() else { + eprintln!("Missing argument for argument '-c'"); + return bad_usage; + }; + if args.next().is_some() { + eprintln!("Too many arguments passed"); + return bad_usage; + } + + let Some(mut cmd) = parse_cmd(&cmd) else { + eprintln!("Bad command"); + return bad_usage; + }; + + let Some(mut program) = cmd.drain(0..1).next() else { + eprintln!("Bad command"); + return bad_usage; + }; + if program == "git" { + let Some(subcommand) = cmd.drain(0..1).next() else { + eprintln!("Bad command"); + return bad_usage; + }; + program.push('-'); + program.push_str(&subcommand); + } + + let mut args = Vec::new(); + + let git_cmds = ["git-receive-pack", "git-upload-archive", "git-upload-pack"]; + if git_cmds.contains(&program.as_str()) { + if cmd.len() != 1 { + eprintln!("Bad command"); + return bad_usage; + } + let repository = cmd[0].trim_start_matches('/'); + args.push(repository); + } else if program == "git-lfs-authenticate" { + program.clear(); + program.push_str("gitolfs3-authenticate"); + if cmd.len() != 2 { + eprintln!("Bad command"); + return bad_usage; + } + let repository = cmd[0].trim_start_matches('/'); + args.push(repository); + args.push(&cmd[1]); + } else { + eprintln!("Unknown command"); + return bad_usage; + } + + let e = std::process::Command::new(program).args(args).exec(); + eprintln!("Error: {e}"); + ExitCode::FAILURE +} + +fn parse_cmd(mut cmd: &str) -> Option> { + let mut args = Vec::::new(); + + cmd = cmd.trim_matches(is_posix_space); + while !cmd.is_empty() { + if cmd.starts_with('\'') { + let (arg, remaining) = parse_sq(cmd)?; + args.push(arg); + cmd = remaining.trim_start_matches(is_posix_space); + } else if let Some((arg, remaining)) = cmd.split_once(is_posix_space) { + args.push(arg.to_owned()); + cmd = remaining.trim_start_matches(is_posix_space); + } else { + args.push(cmd.to_owned()); + cmd = ""; + } + } + + Some(args) +} + +fn is_posix_space(c: char) -> bool { + // Form feed: 0x0c + // Vertical tab: 0x0b + c == ' ' || c == '\x0c' || c == '\n' || c == '\r' || c == '\t' || c == '\x0b' +} + +fn parse_sq(s: &str) -> Option<(String, &str)> { + #[derive(PartialEq, Eq)] + enum SqState { + Quoted, + Unquoted { may_escape: bool }, + UnquotedEscaped, + } + + let mut result = String::new(); + let mut state = SqState::Unquoted { may_escape: false }; + let mut remaining = ""; + for (i, c) in s.char_indices() { + match state { + SqState::Unquoted { may_escape: false } => { + if c != '\'' { + return None; + } + state = SqState::Quoted + } + SqState::Quoted => { + if c == '\'' { + state = SqState::Unquoted { may_escape: true }; + continue; + } + result.push(c); + } + SqState::Unquoted { may_escape: true } => { + if is_posix_space(c) { + remaining = &s[i..]; + break; + } + if c != '\\' { + return None; + } + state = SqState::UnquotedEscaped; + } + SqState::UnquotedEscaped => { + if c != '\\' && c != '!' { + return None; + } + result.push(c); + state = SqState::Unquoted { may_escape: false }; + } + } + } + + if state != (SqState::Unquoted { may_escape: true }) { + return None; + } + Some((result, remaining)) +} -- cgit v1.2.3