Fix quoting for command line args (#5384)

* Fix quoting for command line args

* Replace custom quoting with escape_quote_string

* Use raw string for now
This commit is contained in:
Tomoki Aonuma 2022-05-01 03:23:05 +09:00 committed by GitHub
parent 9da2e142b2
commit ae9c0fc138
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 39 additions and 46 deletions

View File

@ -1,7 +1,7 @@
use crate::CliError; use crate::CliError;
use log::trace; use log::trace;
use nu_engine::eval_block; use nu_engine::eval_block;
use nu_parser::{lex, parse, unescape_unquote_string, Token, TokenContents}; use nu_parser::{escape_quote_string, lex, parse, unescape_unquote_string, Token, TokenContents};
use nu_protocol::engine::StateWorkingSet; use nu_protocol::engine::StateWorkingSet;
use nu_protocol::{ use nu_protocol::{
engine::{EngineState, Stack}, engine::{EngineState, Stack},
@ -36,20 +36,9 @@ fn gather_env_vars(vars: impl Iterator<Item = (String, String)>, engine_state: &
} }
fn put_env_to_fake_file(name: &str, val: &str, fake_env_file: &mut String) { fn put_env_to_fake_file(name: &str, val: &str, fake_env_file: &mut String) {
fn push_string_literal(s: &str, fake_env_file: &mut String) { fake_env_file.push_str(&escape_quote_string(name));
fake_env_file.push('"');
for c in s.chars() {
if c == '\\' || c == '"' {
fake_env_file.push('\\');
}
fake_env_file.push(c);
}
fake_env_file.push('"');
}
push_string_literal(name, fake_env_file);
fake_env_file.push('='); fake_env_file.push('=');
push_string_literal(val, fake_env_file); fake_env_file.push_str(&escape_quote_string(val));
fake_env_file.push('\n'); fake_env_file.push('\n');
} }

View File

@ -1,5 +1,6 @@
use core::fmt::Write; use core::fmt::Write;
use nu_engine::get_columns; use nu_engine::get_columns;
use nu_parser::escape_quote_string;
use nu_protocol::ast::{Call, RangeInclusion}; use nu_protocol::ast::{Call, RangeInclusion};
use nu_protocol::engine::{Command, EngineState, Stack}; use nu_protocol::engine::{Command, EngineState, Stack};
use nu_protocol::{ use nu_protocol::{
@ -137,15 +138,10 @@ fn value_to_string(v: &Value, span: Span) -> Result<String, ShellError> {
} }
Ok(format!("{{{}}}", collection.join(", "))) Ok(format!("{{{}}}", collection.join(", ")))
} }
Value::String { val, .. } => Ok(format!("\"{}\"", escape(val))), Value::String { val, .. } => Ok(escape_quote_string(val)),
} }
} }
fn escape(input: &str) -> String {
let output = input.replace('\\', "\\\\");
output.replace('"', "\\\"")
}
fn to_nuon(call: &Call, input: PipelineData) -> Result<String, ShellError> { fn to_nuon(call: &Call, input: PipelineData) -> Result<String, ShellError> {
let v = input.into_value(call.head); let v = input.into_value(call.head);

View File

@ -0,0 +1,14 @@
pub fn escape_quote_string(input: &str) -> String {
let mut output = String::with_capacity(input.len() + 2);
output.push('"');
for c in input.chars() {
if c == '"' || c == '\\' {
output.push('\\');
}
output.push(c);
}
output.push('"');
output
}

View File

@ -1,3 +1,4 @@
mod deparse;
mod errors; mod errors;
mod flatten; mod flatten;
mod known_external; mod known_external;
@ -7,6 +8,7 @@ mod parse_keywords;
mod parser; mod parser;
mod type_check; mod type_check;
pub use deparse::escape_quote_string;
pub use errors::ParseError; pub use errors::ParseError;
pub use flatten::{flatten_block, flatten_expression, flatten_pipeline, FlatShape}; pub use flatten::{flatten_block, flatten_expression, flatten_pipeline, FlatShape};
pub use known_external::KnownExternal; pub use known_external::KnownExternal;

View File

@ -17,7 +17,7 @@ use nu_cli::{
}; };
use nu_command::{create_default_context, BufferedReader}; use nu_command::{create_default_context, BufferedReader};
use nu_engine::{get_full_help, CallExt}; use nu_engine::{get_full_help, CallExt};
use nu_parser::parse; use nu_parser::{escape_quote_string, parse};
use nu_protocol::{ use nu_protocol::{
ast::{Call, Expr, Expression}, ast::{Call, Expr, Expression},
engine::{Command, EngineState, Stack, StateWorkingSet}, engine::{Command, EngineState, Stack, StateWorkingSet},
@ -79,36 +79,28 @@ fn main() -> Result<()> {
// Would be nice if we had a way to parse this. The first flags we see will be going to nushell // Would be nice if we had a way to parse this. The first flags we see will be going to nushell
// then it'll be the script name // then it'll be the script name
// then the args to the script // then the args to the script
let mut collect_arg_nushell = false; let mut args = std::env::args().skip(1);
for arg in std::env::args().skip(1) { while let Some(arg) = args.next() {
if !script_name.is_empty() { if !script_name.is_empty() {
args_to_script.push(if arg.contains(' ') { args_to_script.push(escape_quote_string(&arg));
format!("`{}`", arg)
} else {
arg
});
} else if collect_arg_nushell {
args_to_nushell.push(if arg.contains(' ') {
format!("`{}`", arg)
} else {
arg
});
collect_arg_nushell = false;
} else if arg.starts_with('-') { } else if arg.starts_with('-') {
// Cool, it's a flag // Cool, it's a flag
if arg == "-c" let flag_value = match arg.as_ref() {
|| arg == "--commands" "--commands" | "-c" => {
|| arg == "--testbin" // FIXME: Use proper quoting. `escape_quote_string()` can't be used for now due to https://github.com/nushell/nushell/issues/5383.
|| arg == "--log-level"
|| arg == "--config" args.next().map(|a| format!("`{}`", a))
|| arg == "--env-config"
|| arg == "--threads"
|| arg == "-t"
{
collect_arg_nushell = true;
} }
"--config" | "--env-config" => args.next().map(|a| escape_quote_string(&a)),
"--log-level" | "--testbin" | "--threads" | "-t" => args.next(),
_ => None,
};
args_to_nushell.push(arg); args_to_nushell.push(arg);
if let Some(flag_value) = flag_value {
args_to_nushell.push(flag_value);
}
} else { } else {
// Our script file // Our script file
script_name = arg; script_name = arg;