diff --git a/Cargo.lock b/Cargo.lock index 9e4cdfd..e821bbe 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1211,6 +1211,12 @@ version = "0.3.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2a60c7ce501c71e03a9c9c0d35b861413ae925bd979cc7a4e30d060069aaac8d" +[[package]] +name = "minimal-lexical" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" + [[package]] name = "miniz_oxide" version = "0.6.2" @@ -1246,6 +1252,16 @@ dependencies = [ "static_assertions", ] +[[package]] +name = "nom" +version = "7.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5507769c4919c998e69e49c839d9dc6e693ede4cc4290d6ad8b41d4f09c548c" +dependencies = [ + "memchr", + "minimal-lexical", +] + [[package]] name = "num-integer" version = "0.1.45" @@ -1710,6 +1726,7 @@ dependencies = [ "log", "merge", "nix", + "nom", "path-dedot", "quickcheck", "quickcheck_macros", diff --git a/Cargo.toml b/Cargo.toml index 01dfbd9..43fda00 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -72,6 +72,7 @@ cachedir = "0.3" clap = { version = "3", features = ["derive", "env"] } clap_complete = "3.2.4" directories = "4" +nom = "7" toml = "0.5" merge = "0.1" serde_with = "2.2" diff --git a/src/repository/mod.rs b/src/repository/mod.rs index 6d95aae..fcfa6d2 100644 --- a/src/repository/mod.rs +++ b/src/repository/mod.rs @@ -7,6 +7,15 @@ use anyhow::{bail, Context, Result}; use clap::Parser; use log::*; use merge::Merge; +use nom::{ + branch::alt, + bytes::complete::{is_not, tag}, + character::complete::multispace1, + error::ParseError, + multi::separated_list0, + sequence::delimited, + IResult, +}; use rpassword::{prompt_password, read_password_from_bufread}; use serde::Deserialize; @@ -68,6 +77,20 @@ pub struct RepositoryOptions { cache_dir: Option, } +// parse a command +fn parse_command<'a, E: ParseError<&'a str>>(input: &'a str) -> IResult<&'a str, Vec<&'a str>, E> { + separated_list0( + // a command is a list + multispace1, // separated by one or more spaces + alt(( + // and containing either + delimited(tag("\""), is_not("\""), tag("\"")), // strings wrapped in "", or + delimited(tag("'"), is_not("'"), tag("'")), // strigns wrapped in '', or + is_not(" \t\r\n"), // strings not containing any space + )), + )(input) +} + pub struct Repository { pub(crate) name: String, pub(crate) be: HotColdBackend, @@ -120,7 +143,8 @@ impl Repository { )) } (_, _, Some(command)) => { - let mut commands: Vec<_> = command.split(' ').collect(); + let mut commands = parse_command::<()>(command)?.1; + debug!("commands: {commands:?}"); let output = Command::new(commands[0]) .args(&mut commands[1..]) .output()