feat: multiple files & glob input

This commit is contained in:
Shunsuke Shibayama 2025-02-21 12:48:06 +09:00
parent 71f5da0963
commit fd4b5895f3
6 changed files with 58 additions and 6 deletions

7
Cargo.lock generated
View File

@ -245,6 +245,12 @@ version = "0.31.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f"
[[package]]
name = "glob"
version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a8d1add55171497b4705a648c6b583acafb01d58050a51727785f0b2c8e0a2b2"
[[package]] [[package]]
name = "hashbrown" name = "hashbrown"
version = "0.14.5" version = "0.14.5"
@ -726,6 +732,7 @@ dependencies = [
"els", "els",
"erg_common", "erg_common",
"erg_compiler", "erg_compiler",
"glob",
"pylyzer_core", "pylyzer_core",
] ]

View File

@ -53,6 +53,7 @@ traditional_chinese = ["erg_common/traditional_chinese", "els/traditional_chines
pylyzer_core = { version = "0.0.80", path = "./crates/pylyzer_core" } pylyzer_core = { version = "0.0.80", path = "./crates/pylyzer_core" }
erg_common = { workspace = true } erg_common = { workspace = true }
els = { workspace = true } els = { workspace = true }
glob = "0.3.2"
[dev-dependencies] [dev-dependencies]
erg_compiler = { workspace = true } erg_compiler = { workspace = true }

View File

@ -41,6 +41,13 @@ Make sure that `cargo`/`rustc` is up-to-date, as pylyzer may be written with the
pylyzer file.py pylyzer file.py
``` ```
## Check multiple files
```sh
# glob patterns are supported
pylyzer file1.py file2.py dir/file*.py
```
### Check an entire package ### Check an entire package
If you don't specify a file path, pylyzer will automatically search for the entry point. If you don't specify a file path, pylyzer will automatically search for the entry point.
@ -177,7 +184,7 @@ pylyzer converts Python ASTs to Erg ASTs and passes them to Erg's type checker.
* [x] type assertion (`typing.cast`) * [x] type assertion (`typing.cast`)
* [x] type narrowing (`is`, `isinstance`) * [x] type narrowing (`is`, `isinstance`)
* [x] `pyi` (stub) files support * [x] `pyi` (stub) files support
* [ ] glob pattern file check * [x] glob pattern file check
* [x] type comment (`# type: ...`) * [x] type comment (`# type: ...`)
* [x] virtual environment support * [x] virtual environment support
* [x] package manager support * [x] package manager support

View File

@ -295,7 +295,7 @@ impl PythonAnalyzer {
res res
} }
pub fn run(&mut self) { pub fn run(&mut self) -> i32 {
/*if self.cfg.dist_dir.is_some() { /*if self.cfg.dist_dir.is_some() {
reserve_decl_er(self.cfg.input.clone()); reserve_decl_er(self.cfg.input.clone());
}*/ }*/
@ -317,7 +317,7 @@ impl PythonAnalyzer {
dump_decl_package(&self.checker.shared().mod_cache); dump_decl_package(&self.checker.shared().mod_cache);
println!("A declaration file has been generated to __pycache__ directory."); println!("A declaration file has been generated to __pycache__ directory.");
} }
std::process::exit(0); 0
} }
Err(artifact) => { Err(artifact) => {
if !artifact.warns.is_empty() { if !artifact.warns.is_empty() {
@ -345,7 +345,7 @@ impl PythonAnalyzer {
dump_decl_package(&self.checker.shared().mod_cache); dump_decl_package(&self.checker.shared().mod_cache);
println!("A declaration file has been generated to __pycache__ directory."); println!("A declaration file has been generated to __pycache__ directory.");
} }
std::process::exit(code); code
} }
} }
} }

View File

@ -212,3 +212,25 @@ For more information try `pylyzer --help`"
cfg.runtime_args = runtime_args.into(); cfg.runtime_args = runtime_args.into();
cfg cfg
} }
pub(crate) fn files_to_be_checked() -> Vec<PathBuf> {
let file_or_patterns = env::args()
.skip(1)
.rev()
.take_while(|arg| !arg.starts_with("-"));
let mut files = vec![];
for file_or_pattern in file_or_patterns {
if PathBuf::from(&file_or_pattern).is_file() {
files.push(PathBuf::from(&file_or_pattern));
} else {
for entry in glob::glob(&file_or_pattern).expect("Failed to read glob pattern") {
match entry {
Err(e) => eprintln!("err: {e}"),
Ok(path) if path.is_file() => files.push(path),
_ => {}
}
}
}
}
files
}

View File

@ -6,6 +6,7 @@ use erg_common::config::ErgMode;
use erg_common::spawn::exec_new_thread; use erg_common::spawn::exec_new_thread;
use pylyzer_core::{PythonAnalyzer, SimplePythonParser}; use pylyzer_core::{PythonAnalyzer, SimplePythonParser};
use crate::config::files_to_be_checked;
use crate::copy::copy_dot_erg; use crate::copy::copy_dot_erg;
fn run() { fn run() {
@ -15,8 +16,22 @@ fn run() {
let lang_server = Server::<PythonAnalyzer, SimplePythonParser>::new(cfg, None); let lang_server = Server::<PythonAnalyzer, SimplePythonParser>::new(cfg, None);
lang_server.run(); lang_server.run();
} else { } else {
let mut analyzer = PythonAnalyzer::new(cfg); let mut code = 0;
analyzer.run(); let files = files_to_be_checked();
if files.is_empty() {
let mut analyzer = PythonAnalyzer::new(cfg);
code = analyzer.run();
} else {
for path in files {
let cfg = cfg.inherit(path);
let mut analyzer = PythonAnalyzer::new(cfg);
let c = analyzer.run();
if c != 0 {
code = 1;
}
}
}
std::process::exit(code);
} }
} }