From a4ffc797bb1d07ba8f6cf56d75b07ccaea3c97f6 Mon Sep 17 00:00:00 2001 From: coolreader18 <33094578+coolreader18@users.noreply.github.com> Date: Thu, 8 Aug 2019 00:02:14 -0500 Subject: [PATCH] Fix clap command line parsing of pyargs --- src/main.rs | 49 ++++++++++++++++++++++++++++++++++++++++----- vm/src/sysmodule.rs | 14 ++++++++----- vm/src/vm.rs | 4 ++++ 3 files changed, 57 insertions(+), 10 deletions(-) diff --git a/src/main.rs b/src/main.rs index 3d63be519..ea58c5643 100644 --- a/src/main.rs +++ b/src/main.rs @@ -50,7 +50,15 @@ fn parse_arguments<'a>(app: App<'a, '_>) -> ArgMatches<'a> { .version(crate_version!()) .author(crate_authors!()) .about("Rust implementation of the Python language") - .arg(Arg::with_name("script").required(false).index(1)) + .usage("rustpython [OPTIONS] [-c CMD | -m MODULE | FILE | -] [PYARGS]...") + .arg( + Arg::with_name("script") + .required(false) + .multiple(true) + .min_values(1) + .allow_hyphen_values(true) + .value_names(&["script", "args..."]), + ) .arg( Arg::with_name("optimize") .short("O") @@ -104,9 +112,12 @@ fn parse_arguments<'a>(app: App<'a, '_>) -> ArgMatches<'a> { Arg::with_name("m") .short("m") .takes_value(true) + .allow_hyphen_values(true) + .multiple(true) + // .value + .value_names(&["module", "args..."]) .help("run library module as script"), - ) - .arg(Arg::from_usage("[pyargs] 'args for python'").multiple(true)); + ); #[cfg(feature = "flame-it")] let app = app .arg( @@ -182,6 +193,34 @@ fn create_settings(matches: &ArgMatches) -> PySettings { settings.dont_write_bytecode = true; } + let mut argv = if let Some(script) = matches.values_of("script") { + script.map(ToOwned::to_owned).collect() + } else if let Some(mut module) = matches.values_of("m") { + let argv0 = if let Ok(module_path) = std::fs::canonicalize(module.next().unwrap()) { + module_path + .into_os_string() + .into_string() + .expect("invalid utf8 in module path") + } else { + // if it's not a real file/don't have permissions it'll probably fail anyway + String::new() + }; + std::iter::once(argv0) + .chain(module.map(ToOwned::to_owned)) + .collect() + } else { + vec![] + }; + + argv.extend( + matches + .values_of("pyargs") + .unwrap_or_default() + .map(ToOwned::to_owned), + ); + + settings.argv = argv; + settings } @@ -283,9 +322,9 @@ fn run_rustpython(vm: &VirtualMachine, matches: &ArgMatches) -> PyResult<()> { run_module(&vm, module)?; } else { // Figure out if a script was passed: - match matches.value_of("script") { + match matches.values_of("script") { None => run_shell(&vm)?, - Some(filename) => run_script(&vm, filename)?, + Some(mut filename) => run_script(&vm, filename.next().unwrap())?, } } diff --git a/vm/src/sysmodule.rs b/vm/src/sysmodule.rs index dc80d695b..0df867b73 100644 --- a/vm/src/sysmodule.rs +++ b/vm/src/sysmodule.rs @@ -14,10 +14,14 @@ use crate::vm::{PySettings, VirtualMachine}; * The magic sys module. */ -fn argv(ctx: &PyContext) -> PyObjectRef { - let mut argv: Vec = env::args().map(|x| ctx.new_str(x)).collect(); - argv.remove(0); - ctx.new_list(argv) +fn argv(vm: &VirtualMachine) -> PyObjectRef { + vm.ctx.new_list( + vm.settings + .argv + .iter() + .map(|arg| vm.new_str(arg.to_owned())) + .collect(), + ) } fn executable(ctx: &PyContext) -> PyObjectRef { @@ -295,7 +299,7 @@ settrace() -- set the global debug tracing function extend_module!(vm, module, { "__name__" => ctx.new_str(String::from("sys")), - "argv" => argv(ctx), + "argv" => argv(vm), "builtin_module_names" => builtin_module_names, "byteorder" => ctx.new_str(bytorder), "copyright" => ctx.new_str(copyright.to_string()), diff --git a/vm/src/vm.rs b/vm/src/vm.rs index bbfea7fb6..fdeff8e12 100644 --- a/vm/src/vm.rs +++ b/vm/src/vm.rs @@ -96,6 +96,9 @@ pub struct PySettings { /// Environment PYTHONPATH and RUSTPYTHONPATH: pub path_list: Vec, + + /// sys.argv + pub argv: Vec, } /// Trace events for sys.settrace and sys.setprofile. @@ -128,6 +131,7 @@ impl Default for PySettings { quiet: false, dont_write_bytecode: false, path_list: vec![], + argv: vec![], } } }