Merge pull request #1144 from RustPython/env-var-processing

Move processing of PYTHONPATH out of vm.
This commit is contained in:
Noah
2019-07-14 16:46:10 -05:00
committed by GitHub
3 changed files with 116 additions and 48 deletions

View File

@@ -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<u8, std::env::VarError> {
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<String> {
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<dyn std::error::Error>> {
fn write_profile(matches: &ArgMatches) -> Result<(), Box<dyn std::error::Error>> {
use std::fs::File;
enum ProfileFormat {
@@ -163,7 +244,7 @@ fn write_profile(matches: ArgMatches) -> Result<(), Box<dyn std::error::Error>>
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") {

View File

@@ -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<String> {
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()

View File

@@ -88,6 +88,9 @@ pub struct PySettings {
/// -q
pub quiet: bool,
/// Environment PYTHONPATH and RUSTPYTHONPATH:
pub path_list: Vec<String>,
}
/// 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![],
}
}
}