Implement walk_dir and more robust globbing

This commit is contained in:
lumi 2025-06-27 01:36:08 +10:00
parent 2964ebbe1b
commit db4faea821
Signed by: luaneko
GPG Key ID: 406809B8763FF07A
3 changed files with 146 additions and 19 deletions

44
Cargo.lock generated
View File

@ -691,6 +691,19 @@ version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a8d1add55171497b4705a648c6b583acafb01d58050a51727785f0b2c8e0a2b2" checksum = "a8d1add55171497b4705a648c6b583acafb01d58050a51727785f0b2c8e0a2b2"
[[package]]
name = "globset"
version = "0.4.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "54a1028dfc5f5df5da8a56a73e6c153c9a9708ec57232470703592a3f18e49f5"
dependencies = [
"aho-corasick",
"bstr",
"log",
"regex-automata 0.4.9",
"regex-syntax 0.8.5",
]
[[package]] [[package]]
name = "h2" name = "h2"
version = "0.4.10" version = "0.4.10"
@ -1032,12 +1045,13 @@ name = "lb"
version = "0.0.1" version = "0.0.1"
dependencies = [ dependencies = [
"derive_more", "derive_more",
"glob", "globset",
"luaffi", "luaffi",
"luajit", "luajit",
"sysexits", "sysexits",
"thiserror", "thiserror",
"tokio", "tokio",
"walkdir",
] ]
[[package]] [[package]]
@ -1579,6 +1593,15 @@ version = "1.0.20"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f"
[[package]]
name = "same-file"
version = "1.0.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502"
dependencies = [
"winapi-util",
]
[[package]] [[package]]
name = "semver" name = "semver"
version = "1.0.26" version = "1.0.26"
@ -2070,6 +2093,16 @@ dependencies = [
"rustversion", "rustversion",
] ]
[[package]]
name = "walkdir"
version = "2.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b"
dependencies = [
"same-file",
"winapi-util",
]
[[package]] [[package]]
name = "want" name = "want"
version = "0.3.1" version = "0.3.1"
@ -2121,6 +2154,15 @@ version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
[[package]]
name = "winapi-util"
version = "0.1.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb"
dependencies = [
"windows-sys 0.59.0",
]
[[package]] [[package]]
name = "winapi-x86_64-pc-windows-gnu" name = "winapi-x86_64-pc-windows-gnu"
version = "0.4.0" version = "0.4.0"

View File

@ -9,15 +9,15 @@ repository.workspace = true
[features] [features]
task = ["tokio/rt", "tokio/time"] task = ["tokio/rt", "tokio/time"]
fs = ["tokio/fs", "dep:glob"] fs = ["tokio/fs", "dep:walkdir", "dep:globset"]
net = ["tokio/net"] net = ["tokio/net"]
glob = ["dep:glob"]
[dependencies] [dependencies]
derive_more = { version = "2.0.1", features = ["full"] } derive_more = { version = "2.0.1", features = ["full"] }
glob = { version = "0.3.2", optional = true } globset = { version = "0.4.16", optional = true }
luaffi = { path = "../luaffi" } luaffi = { path = "../luaffi" }
luajit = { path = "../luajit" } luajit = { path = "../luajit" }
sysexits = "0.9.0" sysexits = "0.9.0"
thiserror = "2.0.12" thiserror = "2.0.12"
tokio = { version = "1.45.1" } tokio = { version = "1.45.1" }
walkdir = { version = "2.5.0", optional = true }

View File

@ -14,7 +14,7 @@
//! See [`lb_fslib`] for items exported by this library. //! See [`lb_fslib`] for items exported by this library.
use derive_more::From; use derive_more::From;
use luaffi::{cdef, metatype}; use luaffi::{cdef, metatype};
use std::time::SystemTime; use std::{path::PathBuf, time::SystemTime};
use thiserror::Error; use thiserror::Error;
/// Errors that can be thrown by this library. /// Errors that can be thrown by this library.
@ -26,12 +26,12 @@ pub enum Error {
/// I/O error. /// I/O error.
#[error("{0}")] #[error("{0}")]
Io(#[from] std::io::Error), Io(#[from] std::io::Error),
/// Glob error. /// Walk directory error.
#[error("{0}")] #[error("{0}")]
Glob(#[from] glob::GlobError), Walk(#[from] walkdir::Error),
/// Glob pattern error. /// Glob pattern error.
#[error("{0}")] #[error("{0}")]
GlobPattern(#[from] glob::PatternError), Glob(#[from] globset::Error),
} }
type Result<T> = std::result::Result<T, Error>; type Result<T> = std::result::Result<T, Error>;
@ -77,8 +77,26 @@ impl lb_fslib {
Ok(std::fs::read_dir(path)?.into()) Ok(std::fs::read_dir(path)?.into())
} }
pub extern "Lua-C" fn glob(&self, pattern: &str) -> Result<lb_glob_paths> { pub extern "Lua-C" fn walk_dir(&self, path: &str) -> lb_walk_dir {
Ok(glob::glob(pattern)?.into()) walkdir::WalkDir::new(path).into_iter().into()
}
pub extern "Lua-C" fn glob(&self, pattern: &str) -> Result<lb_glob_dir> {
self.glob_dir(".", pattern)
}
pub extern "Lua-C" fn glob_dir(&self, path: &str, pattern: &str) -> Result<lb_glob_dir> {
let prefix = PathBuf::from(path);
let iter = walkdir::WalkDir::new(path).min_depth(1).into_iter();
let matcher = globset::GlobSet::builder()
.add(globset::Glob::new(pattern)?)
.build()?;
Ok(lb_glob_dir {
iter,
matcher,
prefix,
})
} }
} }
@ -300,19 +318,86 @@ impl lb_file_perms {
} }
} }
/// Iterator that yields paths from the filesystem that match a particular pattern. /// Iterator for recursively descending into a directory.
#[derive(Debug, From)] #[derive(Debug, From)]
#[cdef] #[cdef]
pub struct lb_glob_paths(#[opaque] glob::Paths); pub struct lb_walk_dir(#[opaque] walkdir::IntoIter);
#[metatype] #[metatype]
impl lb_glob_paths { impl lb_walk_dir {
#[call] #[call]
pub extern "Lua-C" fn next(&mut self) -> Result<Option<String>> { pub extern "Lua-C" fn next(&mut self) -> Result<Option<lb_walk_dir_entry>> {
Ok(self Ok(self.0.next().transpose()?.map(Into::into))
.0 }
.next() }
.transpose()?
.map(|s| s.to_string_lossy().into())) /// Entry inside of a directory on the filesystem obtained from [`lb_walk_dir`].
#[derive(Debug, From)]
#[cdef]
pub struct lb_walk_dir_entry(#[opaque] walkdir::DirEntry);
#[metatype]
impl lb_walk_dir_entry {
pub extern "Lua-C" fn path(&self) -> String {
self.0.path().to_string_lossy().into()
}
pub extern "Lua-C" fn name(&self) -> String {
self.0.file_name().to_string_lossy().into()
}
pub extern "Lua-C" fn r#type(&self) -> lb_file_type {
self.0.file_type().into()
}
pub extern "Lua-C" fn metadata(&self) -> Result<lb_file_meta> {
Ok(self.0.metadata()?.into())
}
pub extern "Lua-C" fn is_symlink(&self) -> bool {
self.0.path_is_symlink()
}
pub extern "Lua-C" fn depth(&self) -> u32 {
self.0.depth() as u32
}
#[cfg(unix)]
pub extern "Lua-C" fn ino(&self) -> u64 {
use walkdir::DirEntryExt;
self.0.ino()
}
#[tostring]
pub extern "Lua" fn tostring(&self) -> String {
self.path()
}
}
/// Iterator that yields paths from the filesystem that match a particular pattern.
#[derive(Debug)]
#[cdef]
pub struct lb_glob_dir {
#[opaque]
iter: walkdir::IntoIter,
#[opaque]
matcher: globset::GlobSet,
#[opaque]
prefix: PathBuf,
}
#[metatype]
impl lb_glob_dir {
#[call]
pub extern "Lua-C" fn next(&mut self) -> Result<Option<lb_walk_dir_entry>> {
while let Some(res) = self.iter.next() {
let entry = res?;
let path = entry.path().strip_prefix(&self.prefix).unwrap();
if self.matcher.is_match(path) {
return Ok(Some(entry.into()));
}
}
Ok(None)
} }
} }