mirror of
https://github.com/erg-lang/erg.git
synced 2025-09-27 19:59:07 +00:00
fix: path-related bugs
This commit is contained in:
parent
e7f1f6894d
commit
50c476b66f
7 changed files with 175 additions and 31 deletions
|
@ -13,6 +13,7 @@ use std::str::FromStr;
|
||||||
use crate::help_messages::{command_message, mode_message, OPTIONS};
|
use crate::help_messages::{command_message, mode_message, OPTIONS};
|
||||||
use crate::levenshtein::get_similar_name;
|
use crate::levenshtein::get_similar_name;
|
||||||
use crate::normalize_path;
|
use crate::normalize_path;
|
||||||
|
use crate::pathutil::add_postfix_foreach;
|
||||||
use crate::python_util::{detect_magic_number, get_python_version, PythonVersion};
|
use crate::python_util::{detect_magic_number, get_python_version, PythonVersion};
|
||||||
use crate::random::random;
|
use crate::random::random;
|
||||||
use crate::serialize::{get_magic_num_from_bytes, get_ver_from_magic_num};
|
use crate::serialize::{get_magic_num_from_bytes, get_ver_from_magic_num};
|
||||||
|
@ -342,39 +343,51 @@ impl Input {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn local_resolve(&self, path: &Path) -> Result<PathBuf, std::io::Error> {
|
pub fn local_resolve(&self, path: &Path) -> Result<PathBuf, std::io::Error> {
|
||||||
let mut dir = if let Self::File(mut path) = self.clone() {
|
let mut dir = if let Self::File(mut file_path) = self.clone() {
|
||||||
path.pop();
|
file_path.pop();
|
||||||
path
|
file_path
|
||||||
} else {
|
} else {
|
||||||
PathBuf::new()
|
PathBuf::new()
|
||||||
};
|
};
|
||||||
dir.push(path);
|
dir.push(path);
|
||||||
dir.set_extension("er");
|
dir.set_extension("er"); // {path}.er
|
||||||
|
let path = dir.canonicalize().or_else(|_| {
|
||||||
|
dir.pop();
|
||||||
|
dir.push(path);
|
||||||
|
dir.push("__init__.er"); // -> {path}/__init__.er
|
||||||
|
dir.canonicalize()
|
||||||
|
})?;
|
||||||
|
Ok(normalize_path(path))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn local_decl_resolve(&self, path: &Path) -> Result<PathBuf, std::io::Error> {
|
||||||
|
let mut dir = if let Self::File(mut file_path) = self.clone() {
|
||||||
|
file_path.pop();
|
||||||
|
file_path
|
||||||
|
} else {
|
||||||
|
PathBuf::new()
|
||||||
|
};
|
||||||
|
let path = add_postfix_foreach(path, ".d");
|
||||||
|
let mut comps = path.components();
|
||||||
|
let last = comps.next_back().unwrap();
|
||||||
|
let last_path = Path::new(&last);
|
||||||
|
dir.push(comps);
|
||||||
|
dir.push(last_path);
|
||||||
|
dir.set_extension("d.er"); // {path}.d.er
|
||||||
let path = dir
|
let path = dir
|
||||||
.canonicalize()
|
.canonicalize()
|
||||||
.or_else(|_| {
|
.or_else(|_| {
|
||||||
dir.pop();
|
dir.pop(); // {path}.d.er -> ./
|
||||||
dir.push(path);
|
dir.push(last_path); // -> {path}.d
|
||||||
dir.push("__init__.er"); // {path}/__init__.er
|
dir.push("__init__.d.er"); // -> {path}.d/__init__.d.er
|
||||||
dir.canonicalize()
|
dir.canonicalize()
|
||||||
})
|
})
|
||||||
.or_else(|_| {
|
.or_else(|_| {
|
||||||
dir.pop(); // {path}
|
dir.pop(); // -> {path}.d
|
||||||
dir.set_extension("d.er");
|
dir.pop(); // -> ./
|
||||||
dir.canonicalize()
|
|
||||||
})
|
|
||||||
.or_else(|_| {
|
|
||||||
dir.pop(); // {path}.d.er
|
|
||||||
dir.push(format!("{}.d", path.display())); // {path}.d
|
|
||||||
dir.push("__init__.d.er"); // {path}.d/__init__.d.er
|
|
||||||
dir.canonicalize()
|
|
||||||
})
|
|
||||||
.or_else(|_| {
|
|
||||||
dir.pop(); // {path}.d
|
|
||||||
dir.pop();
|
|
||||||
dir.push("__pycache__");
|
dir.push("__pycache__");
|
||||||
dir.push(path);
|
dir.push(last_path);
|
||||||
dir.set_extension("d.er"); // __pycache__/{path}.d.er
|
dir.set_extension("d.er"); // -> __pycache__/{path}.d.er
|
||||||
dir.canonicalize()
|
dir.canonicalize()
|
||||||
})?;
|
})?;
|
||||||
Ok(normalize_path(path))
|
Ok(normalize_path(path))
|
||||||
|
|
|
@ -62,6 +62,6 @@ pub fn erg_pystd_path() -> PathBuf {
|
||||||
ERG_PYSTD_PATH.with(|s| s.clone())
|
ERG_PYSTD_PATH.with(|s| s.clone())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn erg_external_lib_path() -> PathBuf {
|
pub fn erg_py_external_lib_path() -> PathBuf {
|
||||||
ERG_EXTERNAL_LIB_PATH.with(|s| s.clone())
|
ERG_EXTERNAL_LIB_PATH.with(|s| s.clone())
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,6 +20,7 @@ pub mod opcode;
|
||||||
pub mod opcode308;
|
pub mod opcode308;
|
||||||
pub mod opcode310;
|
pub mod opcode310;
|
||||||
pub mod opcode311;
|
pub mod opcode311;
|
||||||
|
pub mod pathutil;
|
||||||
pub mod python_util;
|
pub mod python_util;
|
||||||
pub mod random;
|
pub mod random;
|
||||||
pub mod serialize;
|
pub mod serialize;
|
||||||
|
|
94
crates/erg_common/pathutil.rs
Normal file
94
crates/erg_common/pathutil.rs
Normal file
|
@ -0,0 +1,94 @@
|
||||||
|
use std::path::{Component, Path, PathBuf};
|
||||||
|
|
||||||
|
pub fn is_cur_dir<P: AsRef<Path>>(path: P) -> bool {
|
||||||
|
path.as_ref()
|
||||||
|
.components()
|
||||||
|
.next()
|
||||||
|
.map_or(false, |c| c == Component::CurDir)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// ```
|
||||||
|
/// # use std::path::{PathBuf};
|
||||||
|
/// # use erg_common::pathutil::add_postfix_foreach;
|
||||||
|
/// let path = PathBuf::from("erg");
|
||||||
|
/// let path = add_postfix_foreach(path, ".d");
|
||||||
|
/// assert_eq!(path, PathBuf::from("erg.d"));
|
||||||
|
/// let path = PathBuf::from("erg/foo/bar");
|
||||||
|
/// let path = add_postfix_foreach(path, ".d");
|
||||||
|
/// assert_eq!(path, PathBuf::from("erg.d/foo.d/bar.d"));
|
||||||
|
/// ```
|
||||||
|
pub fn add_postfix_foreach<P: AsRef<Path>, Q: AsRef<Path>>(path: P, postfix: Q) -> PathBuf {
|
||||||
|
let mut result = PathBuf::new();
|
||||||
|
for c in path.as_ref().components() {
|
||||||
|
match c {
|
||||||
|
Component::Prefix(_) => result.push(c),
|
||||||
|
Component::RootDir => result.push(c),
|
||||||
|
Component::CurDir => result.push(c),
|
||||||
|
Component::ParentDir => result.push(c),
|
||||||
|
Component::Normal(os_str) => {
|
||||||
|
let mut os_string = os_str.to_os_string();
|
||||||
|
os_string.push(postfix.as_ref().as_os_str());
|
||||||
|
result.push(PathBuf::from(os_string));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
result
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn remove_postfix_foreach<P: AsRef<Path>>(path: P, extension: &str) -> PathBuf {
|
||||||
|
let mut result = PathBuf::new();
|
||||||
|
for c in path.as_ref().components() {
|
||||||
|
match c {
|
||||||
|
Component::Prefix(_) => result.push(c),
|
||||||
|
Component::RootDir => result.push(c),
|
||||||
|
Component::CurDir => result.push(c),
|
||||||
|
Component::ParentDir => result.push(c),
|
||||||
|
Component::Normal(os_str) => {
|
||||||
|
let string = os_str.to_string_lossy();
|
||||||
|
result.push(string.trim_end_matches(extension));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
result
|
||||||
|
}
|
||||||
|
|
||||||
|
/// cutout the extension from the path, and let file name be the directory name.
|
||||||
|
/// ```
|
||||||
|
/// # use std::path::{PathBuf};
|
||||||
|
/// # use erg_common::pathutil::remove_postfix;
|
||||||
|
/// let path = PathBuf::from("erg.d.er");
|
||||||
|
/// let path = remove_postfix(path, ".er");
|
||||||
|
/// assert_eq!(path, PathBuf::from("erg.d"));
|
||||||
|
pub fn remove_postfix<P: AsRef<Path>>(path: P, extension: &str) -> PathBuf {
|
||||||
|
let string = path.as_ref().to_string_lossy();
|
||||||
|
PathBuf::from(string.trim_end_matches(extension))
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// # use std::path::{PathBuf};
|
||||||
|
/// # use erg_common::pathutil::squash;
|
||||||
|
/// let path = PathBuf::from("erg/../foo");
|
||||||
|
/// let path = squash(path);
|
||||||
|
/// assert_eq!(path, PathBuf::from("foo"));
|
||||||
|
/// let path = PathBuf::from("erg/./foo");
|
||||||
|
/// let path = squash(path);
|
||||||
|
/// assert_eq!(path, PathBuf::from("erg/foo"));
|
||||||
|
/// ```
|
||||||
|
pub fn squash(path: PathBuf) -> PathBuf {
|
||||||
|
let mut result = PathBuf::new();
|
||||||
|
for c in path.components() {
|
||||||
|
match c {
|
||||||
|
Component::Prefix(_) => result.push(c),
|
||||||
|
Component::RootDir => result.push(c),
|
||||||
|
Component::CurDir => {}
|
||||||
|
Component::ParentDir => {
|
||||||
|
result.pop();
|
||||||
|
}
|
||||||
|
Component::Normal(os_str) => {
|
||||||
|
result.push(os_str);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
result
|
||||||
|
}
|
|
@ -117,6 +117,16 @@ impl From<&Str> for Str {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<Cow<'_, str>> for Str {
|
||||||
|
#[inline]
|
||||||
|
fn from(s: Cow<'_, str>) -> Self {
|
||||||
|
match s {
|
||||||
|
Cow::Borrowed(s) => Str::rc(s),
|
||||||
|
Cow::Owned(s) => Str::Rc(s.into()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Deref for Str {
|
impl Deref for Str {
|
||||||
type Target = str;
|
type Target = str;
|
||||||
fn deref(&self) -> &Self::Target {
|
fn deref(&self) -> &Self::Target {
|
||||||
|
@ -189,6 +199,14 @@ impl Str {
|
||||||
ret
|
ret
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn multi_replace(&self, paths: &[(&str, &str)]) -> Self {
|
||||||
|
let mut self_ = self.to_string();
|
||||||
|
for (from, to) in paths {
|
||||||
|
self_ = self_.replace(from, to);
|
||||||
|
}
|
||||||
|
Str::rc(&self_)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn is_snake_case(&self) -> bool {
|
pub fn is_snake_case(&self) -> bool {
|
||||||
self.chars().all(|c| !c.is_uppercase())
|
self.chars().all(|c| !c.is_uppercase())
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,9 +3,10 @@ use std::option::Option; // conflicting to Type::Option
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
|
|
||||||
use erg_common::config::{ErgConfig, Input};
|
use erg_common::config::{ErgConfig, Input};
|
||||||
use erg_common::env::{erg_pystd_path, erg_std_path};
|
use erg_common::env::{erg_py_external_lib_path, erg_pystd_path, erg_std_path};
|
||||||
use erg_common::error::{ErrorCore, ErrorKind, Location, SubMessage};
|
use erg_common::error::{ErrorCore, ErrorKind, Location, SubMessage};
|
||||||
use erg_common::levenshtein::get_similar_name;
|
use erg_common::levenshtein::get_similar_name;
|
||||||
|
use erg_common::pathutil::add_postfix_foreach;
|
||||||
use erg_common::set::Set;
|
use erg_common::set::Set;
|
||||||
use erg_common::traits::{Locational, NoTypeDisplay, Stream};
|
use erg_common::traits::{Locational, NoTypeDisplay, Stream};
|
||||||
use erg_common::vis::Visibility;
|
use erg_common::vis::Visibility;
|
||||||
|
@ -2106,15 +2107,30 @@ impl Context {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn resolve_decl_path(cfg: &ErgConfig, path: &Path) -> Option<PathBuf> {
|
pub(crate) fn resolve_decl_path(cfg: &ErgConfig, path: &Path) -> Option<PathBuf> {
|
||||||
if let Ok(path) = cfg.input.local_resolve(path) {
|
if let Ok(path) = cfg.input.local_decl_resolve(path) {
|
||||||
Some(path)
|
Some(path)
|
||||||
} else if let Ok(path) = erg_pystd_path()
|
} else {
|
||||||
.join(format!("{}.d.er", path.display()))
|
let py_roots = [erg_pystd_path, erg_py_external_lib_path];
|
||||||
.canonicalize()
|
for root in py_roots {
|
||||||
{
|
if let Some(path) = Self::resolve_std_decl_path(root(), path) {
|
||||||
|
return Some(path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn resolve_std_decl_path(root: PathBuf, path: &Path) -> Option<PathBuf> {
|
||||||
|
let mut path = add_postfix_foreach(path, ".d");
|
||||||
|
path.set_extension("d.er"); // set_extension overrides the previous one
|
||||||
|
if let Ok(path) = root.join(&path).canonicalize() {
|
||||||
Some(normalize_path(path))
|
Some(normalize_path(path))
|
||||||
} else if let Ok(path) = erg_pystd_path()
|
// d.er -> .d
|
||||||
.join(format!("{}.d", path.display()))
|
} else if let Ok(path) = root
|
||||||
|
.join({
|
||||||
|
path.set_extension("");
|
||||||
|
path
|
||||||
|
})
|
||||||
.join("__init__.d.er")
|
.join("__init__.d.er")
|
||||||
.canonicalize()
|
.canonicalize()
|
||||||
{
|
{
|
||||||
|
|
|
@ -2,6 +2,7 @@ use std::mem;
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
|
|
||||||
use erg_common::config::{ErgConfig, Input};
|
use erg_common::config::{ErgConfig, Input};
|
||||||
|
use erg_common::pathutil::squash;
|
||||||
use erg_common::python_util::BUILTIN_PYTHON_MODS;
|
use erg_common::python_util::BUILTIN_PYTHON_MODS;
|
||||||
use erg_common::traits::Locational;
|
use erg_common::traits::Locational;
|
||||||
use erg_common::Str;
|
use erg_common::Str;
|
||||||
|
@ -383,6 +384,7 @@ impl<'a> Linker<'a> {
|
||||||
&mod_name_str
|
&mod_name_str
|
||||||
};
|
};
|
||||||
dir.push(mod_name_str);
|
dir.push(mod_name_str);
|
||||||
|
let dir = squash(dir);
|
||||||
let mut comps = dir.components();
|
let mut comps = dir.components();
|
||||||
let _first = comps.next().unwrap();
|
let _first = comps.next().unwrap();
|
||||||
let path = dir.to_string_lossy().replace(['/', '\\'], ".");
|
let path = dir.to_string_lossy().replace(['/', '\\'], ".");
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue