///|
// Temporary file and directory management for MoonBit
// Similar to Rust's tempfile crate
///|
let default_temp_dir : String = "/tmp"
///|
priv struct RandomState {
mut counter : UInt64
}
///|
let random_state : RandomState = { counter: 0 }
///|
fn generate_random_name(prefix : String, suffix : String, len : Int) -> String {
let now = @env.now()
random_state.counter += 1
let seed_val = now + random_state.counter
let seed_arr : FixedArray[Byte] = FixedArray::make(32, b'\x00')
for i in 0..<8 {
seed_arr[i] = ((seed_val >> (i * 8)) & 0xFF).to_byte()
}
for i in 0..<8 {
seed_arr[i + 8] = ((random_state.counter >> (i * 8)) & 0xFF).to_byte()
}
let seed_bytes = Bytes::from_array(seed_arr.iter().collect())
let rand = @random.Rand::chacha8(seed=seed_bytes)
let chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
let buf = StringBuilder::new()
buf.write_string(prefix)
for _ in 0.. Builder {
{ prefix: ".tmp", suffix: "", random_len: 10, temp_dir: default_temp_dir }
}
///|
/// Set the prefix for the temporary file/directory name.
pub fn Builder::prefix(self : Builder, prefix : String) -> Builder {
{ ..self, prefix, }
}
///|
/// Set the suffix for the temporary file/directory name.
pub fn Builder::suffix(self : Builder, suffix : String) -> Builder {
{ ..self, suffix, }
}
///|
/// Set the length of the random portion of the name.
pub fn Builder::random_len(self : Builder, len : Int) -> Builder {
{ ..self, random_len: len }
}
///|
/// Set the directory where temporary files/directories will be created.
pub fn Builder::temp_dir(self : Builder, dir : String) -> Builder {
{ ..self, temp_dir: dir }
}
///|
/// A named temporary file that can be accessed via its path.
/// Call `cleanup()` to delete the file when done.
pub struct NamedTempFile {
path : String
}
///|
/// Get the path of the temporary file.
pub fn NamedTempFile::path(self : NamedTempFile) -> String {
self.path
}
///|
/// Write string content to the temporary file.
pub fn NamedTempFile::write_string(
self : NamedTempFile,
content : String,
) -> Unit raise @fs.IOError {
@fs.write_string_to_file(self.path, content)
}
///|
/// Write bytes content to the temporary file.
pub fn NamedTempFile::write_bytes(
self : NamedTempFile,
content : Bytes,
) -> Unit raise @fs.IOError {
@fs.write_bytes_to_file(self.path, content)
}
///|
/// Read the file content as string.
pub fn NamedTempFile::read_string(
self : NamedTempFile,
) -> String raise @fs.IOError {
@fs.read_file_to_string(self.path)
}
///|
/// Read the file content as bytes.
pub fn NamedTempFile::read_bytes(
self : NamedTempFile,
) -> Bytes raise @fs.IOError {
@fs.read_file_to_bytes(self.path)
}
///|
/// Delete the file from the filesystem.
pub fn NamedTempFile::cleanup(self : NamedTempFile) -> Unit raise @fs.IOError {
@fs.remove_file(self.path)
}
///|
/// Keep the file without deleting it. Returns the path.
pub fn NamedTempFile::keep(self : NamedTempFile) -> String {
self.path
}
///|
/// Create a named temporary file using the builder options.
pub fn Builder::create_temp_file(
self : Builder,
) -> NamedTempFile raise @fs.IOError {
let name = generate_random_name(self.prefix, self.suffix, self.random_len)
let path = self.temp_dir + "/" + name
@fs.write_bytes_to_file(path, b"")
{ path, }
}
///|
/// A temporary directory that can be accessed via its path.
/// Call `cleanup()` to delete the directory and its contents when done.
pub struct TempDir {
path : String
}
///|
/// Get the path of the temporary directory.
pub fn TempDir::path(self : TempDir) -> String {
self.path
}
///|
/// Delete the directory. Note: directory must be empty.
/// Use `cleanup_recursive` for non-empty directories.
pub fn TempDir::cleanup(self : TempDir) -> Unit raise @fs.IOError {
@fs.remove_dir(self.path)
}
///|
/// Recursively delete the directory and all its contents.
pub fn TempDir::cleanup_recursive(self : TempDir) -> Unit raise @fs.IOError {
fn remove_recursive(path : String) -> Unit raise @fs.IOError {
if @fs.is_dir(path) {
let entries = @fs.read_dir(path)
for entry in entries {
remove_recursive(path + "/" + entry)
}
@fs.remove_dir(path)
} else {
@fs.remove_file(path)
}
}
remove_recursive(self.path)
}
///|
/// Keep the directory without deleting it. Returns the path.
pub fn TempDir::keep(self : TempDir) -> String {
self.path
}
///|
/// Create a temporary directory using the builder options.
pub fn Builder::create_temp_dir(self : Builder) -> TempDir raise @fs.IOError {
let name = generate_random_name(self.prefix, self.suffix, self.random_len)
let path = self.temp_dir + "/" + name
@fs.create_dir(path)
{ path, }
}
///|
/// Create a named temporary file with default options.
pub fn tempfile() -> NamedTempFile raise @fs.IOError {
Builder::new().create_temp_file()
}
///|
/// Create a temporary directory with default options.
pub fn tempdir() -> TempDir raise @fs.IOError {
Builder::new().create_temp_dir()
}