Implement walk_dir and more robust globbing
This commit is contained in:
@@ -9,15 +9,15 @@ repository.workspace = true
|
||||
|
||||
[features]
|
||||
task = ["tokio/rt", "tokio/time"]
|
||||
fs = ["tokio/fs", "dep:glob"]
|
||||
fs = ["tokio/fs", "dep:walkdir", "dep:globset"]
|
||||
net = ["tokio/net"]
|
||||
glob = ["dep:glob"]
|
||||
|
||||
[dependencies]
|
||||
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" }
|
||||
luajit = { path = "../luajit" }
|
||||
sysexits = "0.9.0"
|
||||
thiserror = "2.0.12"
|
||||
tokio = { version = "1.45.1" }
|
||||
walkdir = { version = "2.5.0", optional = true }
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
//! See [`lb_fslib`] for items exported by this library.
|
||||
use derive_more::From;
|
||||
use luaffi::{cdef, metatype};
|
||||
use std::time::SystemTime;
|
||||
use std::{path::PathBuf, time::SystemTime};
|
||||
use thiserror::Error;
|
||||
|
||||
/// Errors that can be thrown by this library.
|
||||
@@ -26,12 +26,12 @@ pub enum Error {
|
||||
/// I/O error.
|
||||
#[error("{0}")]
|
||||
Io(#[from] std::io::Error),
|
||||
/// Glob error.
|
||||
/// Walk directory error.
|
||||
#[error("{0}")]
|
||||
Glob(#[from] glob::GlobError),
|
||||
Walk(#[from] walkdir::Error),
|
||||
/// Glob pattern error.
|
||||
#[error("{0}")]
|
||||
GlobPattern(#[from] glob::PatternError),
|
||||
Glob(#[from] globset::Error),
|
||||
}
|
||||
|
||||
type Result<T> = std::result::Result<T, Error>;
|
||||
@@ -77,8 +77,26 @@ impl lb_fslib {
|
||||
Ok(std::fs::read_dir(path)?.into())
|
||||
}
|
||||
|
||||
pub extern "Lua-C" fn glob(&self, pattern: &str) -> Result<lb_glob_paths> {
|
||||
Ok(glob::glob(pattern)?.into())
|
||||
pub extern "Lua-C" fn walk_dir(&self, path: &str) -> lb_walk_dir {
|
||||
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)]
|
||||
#[cdef]
|
||||
pub struct lb_glob_paths(#[opaque] glob::Paths);
|
||||
pub struct lb_walk_dir(#[opaque] walkdir::IntoIter);
|
||||
|
||||
#[metatype]
|
||||
impl lb_glob_paths {
|
||||
impl lb_walk_dir {
|
||||
#[call]
|
||||
pub extern "Lua-C" fn next(&mut self) -> Result<Option<String>> {
|
||||
Ok(self
|
||||
.0
|
||||
.next()
|
||||
.transpose()?
|
||||
.map(|s| s.to_string_lossy().into()))
|
||||
pub extern "Lua-C" fn next(&mut self) -> Result<Option<lb_walk_dir_entry>> {
|
||||
Ok(self.0.next().transpose()?.map(Into::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)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user