Skip to content

Commit

Permalink
Merge branch 'ssh-quoting'
Browse files Browse the repository at this point in the history
  • Loading branch information
Byron committed Feb 2, 2023
2 parents 56f5593 + deed1f1 commit cc35025
Show file tree
Hide file tree
Showing 7 changed files with 73 additions and 4 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions git-quote/src/ansi_c.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
///
pub mod undo {
use bstr::{BStr, BString};
use quick_error::quick_error;

quick_error! {
/// The error returned by [ansi_c][crate::ansi_c::undo()].
#[derive(Debug)]
#[allow(missing_docs)]
pub enum Error {
InvalidInput { message: String, input: BString } {
display("{}: {:?}", message, input)
Expand Down
6 changes: 5 additions & 1 deletion git-quote/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
#![deny(rust_2018_idioms)]
//! Provides functions to quote and possibly unquote strings with different quoting styles.
#![deny(rust_2018_idioms, missing_docs)]
#![forbid(unsafe_code)]

///
pub mod ansi_c;

mod single;
pub use single::single;
21 changes: 21 additions & 0 deletions git-quote/src/single.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
use bstr::{BStr, BString, ByteSlice};

/// Transforms the given `value` to be suitable for use as an argument for Bourne shells by wrapping it into single quotes.
///
/// Every single-quote `'` is escaped with `\'`, every exclamation mark `!` is escaped with `\!`, and the entire string is enclosed
/// in single quotes.
pub fn single(mut value: &BStr) -> BString {
let mut quoted = BString::new(b"'".to_vec());

while let Some(pos) = value.find_byteset(b"!'") {
quoted.extend_from_slice(&value[..pos]);
quoted.push(b'\\');
quoted.push(value[pos]);

value = &value[pos + 1..];
}

quoted.extend_from_slice(value);
quoted.push(b'\'');
quoted
}
36 changes: 36 additions & 0 deletions git-quote/tests/quote.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,39 @@
mod single {
use git_quote::single;

#[test]
fn empty() {
assert_eq!(single("".into()), "''");
}

#[test]
fn unquoted_becomes_quoted() {
assert_eq!(single("a".into()), "'a'");
assert_eq!(single("a b".into()), "'a b'");
assert_eq!(single("a\nb".into()), "'a\nb'", "newlines play no role");
}

#[test]
fn existing_exclamation_mark_gets_escaped() {
assert_eq!(single(r"a!b".into()), r"'a\!b'");
assert_eq!(single(r"!".into()), r"'\!'");
assert_eq!(single(r"\!".into()), r"'\\!'");
}

#[test]
fn existing_quote_gets_escaped() {
assert_eq!(single(r"a'b".into()), r"'a\'b'");
assert_eq!(single(r"'".into()), r"'\''");
assert_eq!(single(r"'\''".into()), r"'\'\\'\''");
}

#[test]
fn complex() {
let expected = "'\0cmd `arg` $var\\\\'ring\\// arg \"quoted\\!\"'";
assert_eq!(single("\0cmd `arg` $var\\'ring\\// arg \"quoted!\"".into()), expected);
}
}

mod ansi_c {
mod undo {
use bstr::ByteSlice;
Expand Down
1 change: 1 addition & 0 deletions git-transport/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ git-url = { version = "^0.13.1", path = "../git-url" }
git-sec = { version = "^0.6.1", path = "../git-sec" }
git-packetline = { version = "^0.14.1", path = "../git-packetline" }
git-credentials = { version = "^0.9.0", path = "../git-credentials", optional = true }
git-quote = { version = "^0.4.0", path = "../git-quote" }

serde = { version = "1.0.114", optional = true, default-features = false, features = ["std", "derive"]}
bstr = { version = "1.0.1", default-features = false, features = ["std", "unicode"] }
Expand Down
9 changes: 6 additions & 3 deletions git-transport/src/client/blocking_io/file.rs
Original file line number Diff line number Diff line change
Expand Up @@ -213,10 +213,13 @@ impl client::Transport for SpawnProcessOnDemand {
};
cmd.stdin = Stdio::piped();
cmd.stdout = Stdio::piped();
if self.ssh_cmd.is_some() {
let repo_path = if self.ssh_cmd.is_some() {
cmd.args.push(service.as_str().into());
}
cmd.args.push(self.path.to_os_str_lossy().into_owned());
git_quote::single(self.path.as_ref()).to_os_str_lossy().into_owned()
} else {
self.path.to_os_str_lossy().into_owned()
};
cmd.args.push(repo_path);

let mut cmd = std::process::Command::from(cmd);
for env_to_remove in ENV_VARS_TO_REMOVE {
Expand Down

0 comments on commit cc35025

Please sign in to comment.