autosway 0.5.0

Automation program
Documentation
use super::*;
use std::sync::Arc;
use std::{fs, io::BufReader};
use std::{os::unix::fs::PermissionsExt, path::PathBuf};

pub struct FSFile(fs::File);
impl From<fs::File> for FSFile {
    fn from(value: fs::File) -> Self {
        Self(value)
    }
}

impl LuaUserData for FSFile {
    fn add_methods<M: LuaUserDataMethods<Self>>(methods: &mut M) {
        methods.add_method_mut("write", |_, this, data: String| {
            this.0.write_all(data.as_bytes())?;
            Ok(())
        });

        methods.add_method_mut("read_line", |_, this, _: ()| {
            let mut buf = BufReader::new(this.0.try_clone()?);
            let mut str = String::new();
            buf.read_line(&mut str)?;
            Ok(str.trim().to_owned())
        });

        methods.add_method_mut("read_all", |_, this, _: ()| {
            let mut str = String::new();
            this.0.read_to_string(&mut str)?;
            Ok(str)
        });

        methods.add_method_mut("flush", |_, this, _: ()| {
            this.0.flush()?;
            Ok(())
        });

        methods.add_method("metadata", |_, this, _: ()| {
            Ok(Metadata(this.0.metadata()?))
        });
    }
}

pub struct Directory(fs::ReadDir);
impl LuaUserData for Directory {
    fn add_methods<M: LuaUserDataMethods<Self>>(methods: &mut M) {
        methods.add_method_mut("next", |_, this, _: ()| match this.0.next() {
            Some(Ok(entry)) => Ok(Some(DirectoryEntry(entry))),
            Some(Err(e)) => Err(LuaError::external(Arc::new(e))),
            None => Ok(None),
        });
    }
}

pub struct DirectoryEntry(fs::DirEntry);
impl LuaUserData for DirectoryEntry {
    fn add_methods<M: LuaUserDataMethods<Self>>(methods: &mut M) {
        methods.add_method("path", |_, this, _: ()| Ok(this.0.path()));

        methods.add_method("metadata", |_, this, _: ()| {
            Ok(Metadata(this.0.metadata()?))
        });
    }
}

pub struct Metadata(std::fs::Metadata);
impl LuaUserData for Metadata {
    fn add_methods<M: LuaUserDataMethods<Self>>(methods: &mut M) {
        methods.add_method("is_file", |_, this, _: ()| Ok(this.0.is_file()));

        methods.add_method("is_symlink", |_, this, _: ()| Ok(this.0.is_symlink()));

        methods.add_method("is_dir", |_, this, _: ()| Ok(this.0.is_dir()));
    }
}

pub struct Fs;
impl Module for Fs {
    fn load(&self, state: &mut State) -> Result<(), LuaError> {
        let module = state.lua.create_table()?;

        module.set(
            "create",
            state
                .lua
                .create_function(|_, path: PathBuf| match fs::File::create(path) {
                    Ok(f) => Ok(FSFile::from(f)),
                    Err(e) => Err(e.into()),
                })?,
        )?;

        module.set(
            "open",
            state
                .lua
                .create_function(|_, path: PathBuf| match fs::File::open(path) {
                    Ok(f) => Ok(FSFile::from(f)),
                    Err(e) => Err(e.into()),
                })?,
        )?;

        module.set(
            "exists",
            state
                .lua
                .create_function(|_, path: PathBuf| match fs::exists(path) {
                    Ok(b) => Ok(b),
                    Err(e) => Err(e.into()),
                })?,
        )?;

        module.set(
            "rename",
            state
                .lua
                .create_function(|_, (from, to): (PathBuf, PathBuf)| {
                    match fs::rename(from, to) {
                        Ok(_) => Ok(()),
                        Err(e) => Err(e.into()),
                    }
                })?,
        )?;

        module.set(
            "copy",
            state
                .lua
                .create_function(
                    |_, (from, to): (PathBuf, PathBuf)| match fs::copy(from, to) {
                        Ok(written) => Ok(written),
                        Err(e) => Err(e.into()),
                    },
                )?,
        )?;

        module.set(
            "remove",
            state
                .lua
                .create_function(|_, (path, recursive): (PathBuf, Option<bool>)| {
                    let metadata = match fs::metadata(&path) {
                        Ok(m) => m,
                        Err(e) => return Err(e.into()),
                    };
                    let recursive = recursive.unwrap_or(false);

                    let mut result = Ok(());

                    if metadata.is_dir() {
                        if recursive {
                            if let Err(e) = fs::remove_dir_all(path) {
                                result = Err(e.into())
                            }
                        } else if let Err(e) = fs::remove_dir(path) {
                            result = Err(e.into())
                        }
                    } else if let Err(e) = fs::remove_file(path) {
                        result = Err(e.into())
                    }

                    result
                })?,
        )?;

        module.set(
            "mkdir",
            state.lua.create_function(|_, path: PathBuf| {
                fs::create_dir_all(path)?;

                Ok(())
            })?,
        )?;

        module.set(
            "set_mode",
            state
                .lua
                .create_function(|_, (path, mode): (PathBuf, u32)| {
                    fs::set_permissions(path, std::fs::Permissions::from_mode(mode))?;
                    Ok(())
                })?,
        )?;

        module.set(
            "symlink",
            state
                .lua
                .create_function(|_, (from, to): (PathBuf, PathBuf)| {
                    std::os::unix::fs::symlink(from, to)?;
                    Ok(())
                })?,
        )?;

        module.set(
            "canonicalize",
            state
                .lua
                .create_function(|_, path: PathBuf| Ok(fs::canonicalize(path)?))?,
        )?;

        module.set(
            "follow_link",
            state
                .lua
                .create_function(|_, path: PathBuf| Ok(fs::read_link(path)?))?,
        )?;

        module.set(
            "read_dir",
            state
                .lua
                .create_function(|_, path: PathBuf| Ok(Directory(fs::read_dir(path)?)))?,
        )?;

        create_module(&state.lua, "autosway.fs", module)?;

        Ok(())
    }
}