perf: reduce IO

This commit is contained in:
Shunsuke Shibayama 2024-11-10 13:32:13 +09:00
parent a7dbdb7c8d
commit 9e782bef2e
5 changed files with 51 additions and 21 deletions

View file

@ -3,7 +3,7 @@ use std::path::{Path, PathBuf};
use std::sync::OnceLock;
use crate::normalize_path;
use crate::python_util::get_sys_path;
use crate::python_util::{_opt_which_python, get_sys_path};
use crate::style::colors::*;
use crate::style::RESET;
@ -115,6 +115,7 @@ pub static ERG_PYSTD_PATH: OnceLock<PathBuf> = OnceLock::new();
pub static ERG_PKGS_PATH: OnceLock<PathBuf> = OnceLock::new();
pub static PYTHON_SYS_PATH: OnceLock<Vec<PathBuf>> = OnceLock::new();
pub static PYTHON_SITE_PACKAGES: OnceLock<Vec<PathBuf>> = OnceLock::new();
pub static PYTHON_PATH: OnceLock<Result<String, String>> = OnceLock::new();
/// == `Path::new("~/.erg")` if ERG_PATH is not set
pub fn erg_path() -> &'static PathBuf {
@ -154,6 +155,10 @@ pub fn python_site_packages() -> &'static Vec<PathBuf> {
PYTHON_SITE_PACKAGES.get_or_init(|| _python_site_packages().collect())
}
pub fn opt_which_python() -> Result<&'static String, &'static String> {
PYTHON_PATH.get_or_init(_opt_which_python).as_ref()
}
pub fn is_std_decl_path(path: &Path) -> bool {
path.starts_with(erg_pystd_path().as_path())
}

View file

@ -1,6 +1,6 @@
//! provides utilities for parser, compiler, and vm crate.
use std::fmt;
use std::path::PathBuf;
use std::path::{Component, Path, PathBuf};
pub mod cache;
pub mod config;
@ -192,6 +192,33 @@ pub fn normalize_path(path: PathBuf) -> PathBuf {
PathBuf::from(lower)
}
pub fn cheap_canonicalize_path(path: &Path) -> PathBuf {
let mut components = path.components().peekable();
let mut ret = if let Some(c @ Component::Prefix(..)) = components.peek().cloned() {
components.next();
PathBuf::from(c.as_os_str())
} else {
PathBuf::new()
};
for component in components {
match component {
Component::Prefix(..) => unreachable!(),
Component::RootDir => {
ret.push(component.as_os_str());
}
Component::CurDir => {}
Component::ParentDir => {
ret.pop();
}
Component::Normal(c) => {
ret.push(c);
}
}
}
ret
}
/// ```
/// use erg_common::trim_eliminate_top_indent;
/// let code = r#"

View file

@ -7,7 +7,8 @@ use std::path::{Component, Path, PathBuf};
use crate::consts::PYTHON_MODE;
use crate::env::erg_pkgs_path;
use crate::traits::Immutable;
use crate::{normalize_path, Str};
use crate::vfs::VFS;
use crate::{cheap_canonicalize_path, normalize_path, Str};
/// Guaranteed equivalence path.
///
@ -59,7 +60,7 @@ impl Deref for NormalizedPathBuf {
impl NormalizedPathBuf {
pub fn new(path: PathBuf) -> Self {
NormalizedPathBuf(normalize_path(path.canonicalize().unwrap_or(path)))
NormalizedPathBuf(normalize_path(cheap_canonicalize_path(&path)))
}
pub fn as_path(&self) -> &Path {
@ -71,7 +72,7 @@ impl NormalizedPathBuf {
}
pub fn try_read(&self) -> std::io::Result<String> {
std::fs::read_to_string(&self.0)
VFS.read(self)
}
}

View file

@ -7,6 +7,7 @@ use std::io::Write;
use std::path::{Path, PathBuf};
use std::process::{Command, ExitStatus, Stdio};
use crate::env::opt_which_python;
use crate::fn_name_full;
use crate::io::Output;
use crate::pathutil::remove_verbatim;
@ -608,7 +609,7 @@ fn get_poetry_virtualenv_path() -> Option<String> {
.then_some(path.trim().to_string())
}
pub fn opt_which_python() -> Result<String, String> {
pub fn _opt_which_python() -> Result<String, String> {
if let Some(path) = which_python_from_toml() {
return Ok(path);
}
@ -642,8 +643,8 @@ pub fn opt_which_python() -> Result<String, String> {
Ok(res)
}
fn which_python() -> String {
opt_which_python().unwrap()
fn which_python() -> &'static str {
opt_which_python().as_ref().unwrap()
}
pub fn detect_magic_number(py_command: &str) -> u32 {
@ -672,7 +673,7 @@ pub fn detect_magic_number(py_command: &str) -> u32 {
}
pub fn env_magic_number() -> u32 {
detect_magic_number(&which_python())
detect_magic_number(which_python())
}
pub fn module_exists(py_command: &str, module: &str) -> bool {
@ -786,7 +787,7 @@ pub fn get_python_version(py_command: &str) -> Option<PythonVersion> {
}
pub fn env_python_version() -> Option<PythonVersion> {
get_python_version(&which_python())
get_python_version(which_python())
}
pub fn get_sys_path(working_dir: Option<&Path>) -> Result<Vec<PathBuf>, std::io::Error> {
@ -834,9 +835,7 @@ fn exec_pyc_in(
"import marshal; exec(marshal.loads(open(r\"{}\", \"rb\").read()[16:]))",
file.as_ref().display()
);
let command = py_command
.map(ToString::to_string)
.unwrap_or(which_python());
let command = py_command.map_or_else(|| which_python().to_string(), ToString::to_string);
let mut out = if cfg!(windows) {
Command::new("cmd")
.arg("/C")
@ -876,9 +875,7 @@ pub fn exec_pyc(
if let Some(working_dir) = working_dir {
return exec_pyc_in(file, py_command, working_dir, args, stdout);
}
let command = py_command
.map(ToString::to_string)
.unwrap_or_else(which_python);
let command = py_command.map_or_else(|| which_python().to_string(), ToString::to_string);
let mut out = if cfg!(windows) {
Command::new("cmd")
.arg("/C")
@ -902,9 +899,7 @@ pub fn exec_pyc(
/// evaluates over a shell, cause `python` may not exist as an executable file (like pyenv)
pub fn _eval_pyc<S: Into<String>>(file: S, py_command: Option<&str>) -> String {
let command = py_command
.map(ToString::to_string)
.unwrap_or_else(which_python);
let command = py_command.map_or_else(|| which_python().to_string(), ToString::to_string);
let out = if cfg!(windows) {
Command::new("cmd")
.arg("/C")
@ -966,7 +961,7 @@ pub fn env_spawn_py(code: &str) {
pub fn spawn_py(py_command: Option<&str>, code: &str) {
if cfg!(windows) {
Command::new(py_command.unwrap_or(&which_python()))
Command::new(py_command.unwrap_or(which_python()))
.arg("-c")
.arg(code)
.spawn()
@ -974,7 +969,7 @@ pub fn spawn_py(py_command: Option<&str>, code: &str) {
} else {
let exec_command = format!(
"{} -c \"{}\"",
py_command.unwrap_or(&which_python()),
py_command.unwrap_or(which_python()),
escape_py_code(code)
);
Command::new("sh")

View file

@ -27,6 +27,7 @@ use erg_common::spawn::spawn_new_thread;
use erg_common::str::Str;
use erg_common::traits::{ExitStatus, New, Runnable, Stream};
use erg_common::vfs::VFS;
use erg_parser::ast::{ClassAttr, Expr, InlineModule, Record, RecordAttrOrIdent, VarName, AST};
use erg_parser::build_ast::{ASTBuildable, ASTBuilder as DefaultASTBuilder};
use erg_parser::parse::SimpleParser;
@ -703,6 +704,7 @@ impl<ASTBuilder: ASTBuildable, HIRBuilder: Buildable>
.resolve_decl_path(path, cfg)
.or_else(|| cfg.input.resolve_real_path(path, cfg))
};
VFS.cache_path(cfg.input.clone(), path.to_path_buf(), resolved.clone());
let import_path = match resolved {
Some(path) => path,
None if ERG_MODE => {