diff --git a/Cargo.lock b/Cargo.lock index 0192bf8..c751684 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -579,6 +579,12 @@ dependencies = [ "windows-sys 0.60.2", ] +[[package]] +name = "fastrand" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" + [[package]] name = "flate2" version = "1.1.2" @@ -1049,6 +1055,7 @@ dependencies = [ "luaffi", "luajit", "sysexits", + "tempfile", "thiserror", "tokio", "walkdir", @@ -1732,6 +1739,19 @@ version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "198f60d1f7f003f168507691e42d082df109ef0f05c6fd006e22528371a5f1b4" +[[package]] +name = "tempfile" +version = "3.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8a64e3985349f2441a1a9ef0b853f869006c3855f2cda6862a94d26ebb9d6a1" +dependencies = [ + "fastrand", + "getrandom 0.3.3", + "once_cell", + "rustix", + "windows-sys 0.59.0", +] + [[package]] name = "thiserror" version = "2.0.12" diff --git a/crates/lb/Cargo.toml b/crates/lb/Cargo.toml index 01eac32..36f6dc6 100644 --- a/crates/lb/Cargo.toml +++ b/crates/lb/Cargo.toml @@ -9,7 +9,7 @@ repository.workspace = true [features] task = ["tokio/rt", "tokio/time"] -fs = ["tokio/fs", "dep:walkdir", "dep:globset"] +fs = ["tokio/fs", "dep:walkdir", "dep:globset", "dep:tempfile"] net = ["tokio/net"] [dependencies] @@ -18,6 +18,7 @@ globset = { version = "0.4.16", optional = true } luaffi = { path = "../luaffi" } luajit = { path = "../luajit" } sysexits = "0.9.0" +tempfile = { version = "3.20.0", optional = true } thiserror = "2.0.12" tokio = { version = "1.45.1" } walkdir = { version = "2.5.0", optional = true } diff --git a/crates/lb/src/fs.rs b/crates/lb/src/fs.rs index bc825dc..d1bdfc2 100644 --- a/crates/lb/src/fs.rs +++ b/crates/lb/src/fs.rs @@ -98,6 +98,14 @@ impl lb_fslib { prefix, }) } + + pub extern "Lua-C" fn temp_dir(&self) -> Result { + Ok(tempfile::tempdir()?.into()) + } + + pub extern "Lua-C" fn temp_dir_in(&self, path: &str) -> Result { + Ok(tempfile::tempdir_in(path)?.into()) + } } /// Iterator over the entries in a directory. @@ -401,3 +409,20 @@ impl lb_glob_dir { Ok(None) } } + +/// Directory in the filesystem that is automatically deleted when it is garbage-collected. +#[derive(Debug, From)] +#[cdef] +pub struct lb_temp_dir(#[opaque] tempfile::TempDir); + +#[metatype] +impl lb_temp_dir { + pub extern "Lua-C" fn path(&self) -> String { + self.0.path().to_string_lossy().into() + } + + #[tostring] + pub extern "Lua" fn tostring(&self) -> String { + self.path() + } +} diff --git a/crates/lb/tests/fs.lua b/crates/lb/tests/fs.lua new file mode 100644 index 0000000..808561b --- /dev/null +++ b/crates/lb/tests/fs.lua @@ -0,0 +1,17 @@ +local ok, fs = pcall(require, "lb:fs") +if not ok then return end + +describe("temp files", function() + test("temp_dir cleans itself", function() + local path + do + local dir = fs:temp_dir() + path = dir:path() + assert(path and path ~= "") + fs:write(path .. "/test.txt", "test file") + assert(fs:read(path .. "/test.txt") == "test file") + end + collectgarbage() + assert(not pcall(fs.read, fs, path .. "/test.txt")) + end) +end)