diff --git a/src/main.rs b/src/main.rs index deec991d6..1da922848 100644 --- a/src/main.rs +++ b/src/main.rs @@ -17,14 +17,36 @@ use rustpython_vm::{ }; use std::convert::TryInto; +use std::env; use std::path::PathBuf; use std::process; +use std::str::FromStr; fn main() { #[cfg(feature = "flame-it")] let main_guard = flame::start_guard("RustPython main"); env_logger::init(); - let app = App::new("RustPython") + let app = App::new("RustPython"); + let matches = parse_arguments(app); + let settings = create_settings(&matches); + let vm = VirtualMachine::new(settings); + + let res = run_rustpython(&vm, &matches); + // See if any exception leaked out: + handle_exception(&vm, res); + + #[cfg(feature = "flame-it")] + { + main_guard.end(); + if let Err(e) = write_profile(&matches) { + error!("Error writing profile information: {}", e); + process::exit(1); + } + } +} + +fn parse_arguments<'a>(app: App<'a, '_>) -> ArgMatches<'a> { + let app = app .version(crate_version!()) .author(crate_authors!()) .about("Rust implementation of the Python language") @@ -62,6 +84,11 @@ fn main() { .short("S") .help("don't imply 'import site' on initialization"), ) + .arg( + Arg::with_name("ignore-environment") + .short("E") + .help("Ignore environment variables PYTHON* such as PYTHONPATH"), + ) .arg( Arg::with_name("c") .short("c") @@ -89,38 +116,92 @@ fn main() { .takes_value(true) .help("the profile format to output the profiling information in"), ); - let matches = app.get_matches(); + app.get_matches() +} - let opt_level: u8 = matches.occurrences_of("optimize").try_into().unwrap(); - let verbosity_level: u8 = matches.occurrences_of("verbose").try_into().unwrap(); - - // Construct vm: +/// Create settings by examining command line arguments and environment +/// variables. +fn create_settings(matches: &ArgMatches) -> PySettings { + let ignore_environment = matches.is_present("ignore-environment"); let mut settings: PySettings = Default::default(); - settings.debug = matches.is_present("debug"); - settings.inspect = matches.is_present("inspect"); - settings.optimize = opt_level; - settings.no_site = matches.is_present("no-site"); - settings.no_user_site = matches.is_present("no-user-site"); - settings.verbose = verbosity_level; - settings.quiet = matches.is_present("quiet"); - let vm = VirtualMachine::new(settings); + settings.ignore_environment = ignore_environment; - let res = run_rustpython(&vm, matches); - // See if any exception leaked out: - handle_exception(&vm, res); + if !ignore_environment { + settings.path_list.append(&mut get_paths("RUSTPYTHONPATH")); + settings.path_list.append(&mut get_paths("PYTHONPATH")); + } - #[cfg(feature = "flame-it")] + // Now process command line flags: + if matches.is_present("debug") || (!ignore_environment && env::var_os("PYTHONDEBUG").is_some()) { - main_guard.end(); - if let Err(e) = write_profile(matches) { - error!("Error writing profile information: {}", e); - process::exit(1); + settings.debug = true; + } + + if matches.is_present("inspect") + || (!ignore_environment && env::var_os("PYTHONINSPECT").is_some()) + { + settings.inspect = true; + } + + if matches.is_present("optimize") { + settings.optimize = matches.occurrences_of("optimize").try_into().unwrap(); + } else if !ignore_environment { + if let Ok(value) = get_env_var_value("PYTHONOPTIMIZE") { + settings.optimize = value; } } + + if matches.is_present("verbose") { + settings.verbose = matches.occurrences_of("verbose").try_into().unwrap(); + } else if !ignore_environment { + if let Ok(value) = get_env_var_value("PYTHONVERBOSE") { + settings.verbose = value; + } + } + + settings.no_site = matches.is_present("no-site"); + + if matches.is_present("no-user-site") + || (!ignore_environment && env::var_os("PYTHONNOUSERSITE").is_some()) + { + settings.no_user_site = true; + } + + if matches.is_present("quiet") { + settings.quiet = true; + } + + settings +} + +/// Get environment variable and turn it into integer. +fn get_env_var_value(name: &str) -> Result { + env::var(name).map(|value| { + if let Ok(value) = u8::from_str(&value) { + value + } else { + 1 + } + }) +} + +/// Helper function to retrieve a sequence of paths from an environment variable. +fn get_paths(env_variable_name: &str) -> Vec { + let paths = env::var_os(env_variable_name); + match paths { + Some(paths) => env::split_paths(&paths) + .map(|path| { + path.into_os_string() + .into_string() + .unwrap_or_else(|_| panic!("{} isn't valid unicode", env_variable_name)) + }) + .collect(), + None => vec![], + } } #[cfg(feature = "flame-it")] -fn write_profile(matches: ArgMatches) -> Result<(), Box> { +fn write_profile(matches: &ArgMatches) -> Result<(), Box> { use std::fs::File; enum ProfileFormat { @@ -163,7 +244,7 @@ fn write_profile(matches: ArgMatches) -> Result<(), Box> Ok(()) } -fn run_rustpython(vm: &VirtualMachine, matches: ArgMatches) -> PyResult<()> { +fn run_rustpython(vm: &VirtualMachine, matches: &ArgMatches) -> PyResult<()> { import::init_importlib(&vm, true)?; if let Some(paths) = option_env!("BUILDTIME_RUSTPYTHONPATH") { diff --git a/vm/src/sysmodule.rs b/vm/src/sysmodule.rs index 5f0c71996..d45070aeb 100644 --- a/vm/src/sysmodule.rs +++ b/vm/src/sysmodule.rs @@ -163,30 +163,13 @@ pub fn make_module(vm: &VirtualMachine, module: PyObjectRef, builtins: PyObjectR "cache_tag" => ctx.new_str("rustpython-01".to_string()), }); - let path_list = if cfg!(target_arch = "wasm32") { - vec![] - } else { - fn get_paths(env_variable_name: &str) -> Vec { - let paths = env::var_os(env_variable_name); - match paths { - Some(paths) => env::split_paths(&paths) - .map(|path| { - path.into_os_string() - .into_string() - .unwrap_or_else(|_| panic!("{} isn't valid unicode", env_variable_name)) - }) - .collect(), - None => vec![], - } - } - - get_paths("RUSTPYTHONPATH") - .into_iter() - .chain(get_paths("PYTHONPATH").into_iter()) - .map(|path| ctx.new_str(path)) - .collect() - }; - let path = ctx.new_list(path_list); + let path = ctx.new_list( + vm.settings + .path_list + .iter() + .map(|path| ctx.new_str(path.clone())) + .collect(), + ); let platform = if cfg!(target_os = "linux") { "linux".to_string() diff --git a/vm/src/vm.rs b/vm/src/vm.rs index af528521f..4c0ea1678 100644 --- a/vm/src/vm.rs +++ b/vm/src/vm.rs @@ -88,6 +88,9 @@ pub struct PySettings { /// -q pub quiet: bool, + + /// Environment PYTHONPATH and RUSTPYTHONPATH: + pub path_list: Vec, } /// Trace events for sys.settrace and sys.setprofile. @@ -118,6 +121,7 @@ impl Default for PySettings { ignore_environment: false, verbose: 0, quiet: false, + path_list: vec![], } } }