fix: retry path resolution if failed

This commit is contained in:
Shunsuke Shibayama 2023-05-25 11:58:09 +09:00
parent a9025507d3
commit dab9def08a
2 changed files with 51 additions and 7 deletions

View file

@ -2,6 +2,7 @@
//!
//! コマンドオプション(パーサー)を定義する
use std::env;
use std::ffi::OsStr;
use std::fmt;
use std::fs::File;
use std::io::{stdin, BufRead, BufReader, Read, Write};
@ -319,6 +320,26 @@ impl Input {
}
}
pub fn module_name(&self) -> String {
match &self.kind {
InputKind::File(filename) => {
let file_stem = if filename.file_stem() == Some(OsStr::new("__init__")) {
filename.parent().and_then(|p| p.file_stem())
} else {
filename.file_stem()
};
file_stem
.and_then(|f| f.to_str())
.unwrap_or("_")
.to_string()
}
InputKind::REPL | InputKind::Pipe(_) => "<stdin>".to_string(),
InputKind::DummyREPL(stdin) => stdin.name.clone(),
InputKind::Str(_) => "<string>".to_string(),
InputKind::Dummy => "<dummy>".to_string(),
}
}
pub fn read(&mut self) -> String {
match &mut self.kind {
InputKind::File(filename) => {

View file

@ -1,9 +1,11 @@
use std::fmt;
use std::io::BufRead;
use std::fs::{metadata, remove_file, File};
use std::io::{BufRead, BufReader};
use std::option::Option;
use std::path::{Path, PathBuf};
use std::process::{Command, Stdio};
use std::time::SystemTime;
use std::thread::sleep;
use std::time::{Duration, SystemTime};
use erg_common::config::ErgMode;
use erg_common::consts::{ERG_MODE, PYTHON_MODE};
@ -1953,15 +1955,22 @@ impl Context {
Str::from(name)
}
fn analysis_in_progress(path: &Path) -> bool {
let Ok(meta) = metadata(path) else {
return false;
};
!is_std_decl_path(path) && meta.len() == 0
}
fn availability(path: &Path) -> Availability {
let Ok(file) = std::fs::File::open(path) else {
let Ok(file) = File::open(path) else {
return Availability::NotFound;
};
if is_std_decl_path(path) {
return Availability::Available;
}
let mut line = "".to_string();
let Ok(_) = std::io::BufReader::new(file).read_line(&mut line) else {
let Ok(_) = BufReader::new(file).read_line(&mut line) else {
return Availability::Unreadable;
};
if line.is_empty() {
@ -1970,7 +1979,7 @@ impl Context {
let Ok(status) = line.parse::<PylyzerStatus>() else {
return Availability::Available;
};
let Some(meta) = std::fs::metadata(&status.file).ok() else {
let Some(meta) = metadata(&status.file).ok() else {
return Availability::NotFound;
};
let dummy_hash = meta.len();
@ -1987,6 +1996,12 @@ impl Context {
if self.cfg.input.decl_file_is(&path) {
return Ok(path);
}
for _ in 0..600 {
if !Self::analysis_in_progress(&path) {
break;
}
sleep(Duration::from_millis(100));
}
if matches!(Self::availability(&path), OutOfDate | NotFound | Unreadable) {
let _ = self.try_gen_py_decl_file(__name__);
}
@ -2038,7 +2053,7 @@ impl Context {
// It can convert a Python script to an Erg AST for code analysis.
// There is also an option to output the analysis result as `d.er`. Use this if the system have pylyzer installed.
// A type definition file may be generated even if not all type checks succeed.
if let Ok(_status) = Command::new("pylyzer")
if let Ok(status) = Command::new("pylyzer")
.arg("--dump-decl")
.arg(path.to_str().unwrap())
.stdout(out)
@ -2047,7 +2062,15 @@ impl Context {
.and_then(|mut child| child.wait())
{
if let Some(path) = self.cfg.input.resolve_decl_path(Path::new(&__name__[..])) {
return Ok(path);
let size = metadata(&path).unwrap().len();
// if pylyzer crashed
if !status.success() && size == 0 {
// The presence of the decl file indicates that the analysis is in progress or completed,
// so if pylyzer crashes in the middle of the analysis, delete the file.
remove_file(&path).unwrap();
} else {
return Ok(path);
}
}
}
}