Add lua dir definition support

main
trivernis 8 months ago
parent ae13b467e6
commit b034617e73
Signed by: Trivernis
GPG Key ID: 7E6D18B61C8D2F4B

@ -0,0 +1,5 @@
[build]
rustflags = [
"-C", "link-arg=-undefined",
"-C", "link-arg=dynamic_lookup",
]

94
Cargo.lock generated

@ -1019,6 +1019,7 @@ dependencies = [
"lazy_static", "lazy_static",
"log", "log",
"miette 5.10.0", "miette 5.10.0",
"mlua",
"pretty_env_logger", "pretty_env_logger",
"rusty-value", "rusty-value",
"serde", "serde",
@ -1026,7 +1027,7 @@ dependencies = [
"sys-info", "sys-info",
"tempfile", "tempfile",
"toml", "toml",
"which", "which 5.0.0",
] ]
[[package]] [[package]]
@ -2626,6 +2627,34 @@ dependencies = [
"nu-ansi-term", "nu-ansi-term",
] ]
[[package]]
name = "lua-src"
version = "546.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2da0daa7eee611a4c30c8f5ee31af55266e26e573971ba9336d2993e2da129b2"
dependencies = [
"cc",
]
[[package]]
name = "luajit-src"
version = "210.5.6+9cc2e42"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "23b365d859c9ffc187f48bb3e25ec80c3b40cf3f68f53544f4adeaee70554157"
dependencies = [
"cc",
"which 6.0.0",
]
[[package]]
name = "luau0-src"
version = "0.8.3+luau614"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4d0dc9f950d074893d18af156124f8296e7477f96dfbdc0520fb8df5a8aa3898"
dependencies = [
"cc",
]
[[package]] [[package]]
name = "mach2" name = "mach2"
version = "0.4.2" version = "0.4.2"
@ -2769,6 +2798,37 @@ dependencies = [
"windows-sys 0.48.0", "windows-sys 0.48.0",
] ]
[[package]]
name = "mlua"
version = "0.9.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "868d02cb5eb97761bbf6bd6922c1c7a88b8ea252bbf43bd8350a0bf8497a1fc0"
dependencies = [
"bstr",
"erased-serde",
"libloading",
"mlua-sys",
"num-traits",
"once_cell",
"rustc-hash",
"serde",
"serde-value",
]
[[package]]
name = "mlua-sys"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2847b42764435201d8cbee1f517edb79c4cca4181877b90047587c89e1b7bce4"
dependencies = [
"cc",
"cfg-if",
"lua-src",
"luajit-src",
"luau0-src",
"pkg-config",
]
[[package]] [[package]]
name = "native-tls" name = "native-tls"
version = "0.2.11" version = "0.2.11"
@ -3273,6 +3333,15 @@ version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d" checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d"
[[package]]
name = "ordered-float"
version = "2.10.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "68f19d67e5a2795c94e73e0bb1cc1a7edeb2e28efd39e2e1c9b7a40c1108b11c"
dependencies = [
"num-traits",
]
[[package]] [[package]]
name = "os_display" name = "os_display"
version = "0.1.3" version = "0.1.3"
@ -4063,6 +4132,16 @@ dependencies = [
"serde_derive", "serde_derive",
] ]
[[package]]
name = "serde-value"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f3a1a3341211875ef120e117ea7fd5228530ae7e7036a779fdc9117be6b3282c"
dependencies = [
"ordered-float",
"serde",
]
[[package]] [[package]]
name = "serde_derive" name = "serde_derive"
version = "1.0.195" version = "1.0.195"
@ -5098,6 +5177,19 @@ dependencies = [
"windows-sys 0.48.0", "windows-sys 0.48.0",
] ]
[[package]]
name = "which"
version = "6.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7fa5e0c10bf77f44aac573e498d1a82d5fbd5e91f6fc0a99e7be4b38e85e101c"
dependencies = [
"either",
"home",
"once_cell",
"rustix",
"windows-sys 0.52.0",
]
[[package]] [[package]]
name = "wild" name = "wild"
version = "2.2.1" version = "2.2.1"

@ -24,6 +24,7 @@ handlebars_switch = "0.6.0"
lazy_static = "1.4.0" lazy_static = "1.4.0"
log = "0.4.20" log = "0.4.20"
miette = { version = "5.10.0", features = ["serde", "fancy"] } miette = { version = "5.10.0", features = ["serde", "fancy"] }
mlua = { version = "0.9.6", features = ["serialize", "luau", "vendored"] }
pretty_env_logger = "0.5.0" pretty_env_logger = "0.5.0"
rusty-value = "0.6.0" rusty-value = "0.6.0"
serde = { version = "1.0.195", features = ["derive"] } serde = { version = "1.0.195", features = ["derive"] }

@ -10,8 +10,11 @@ mod args;
mod config; mod config;
mod fs_access; mod fs_access;
mod repo; mod repo;
mod scripting;
mod templating; mod templating;
pub(crate) mod utils;
fn main() -> Result<()> { fn main() -> Result<()> {
let args: Args = Args::parse(); let args: Args = Args::parse();
init_logging(args.verbose); init_logging(args.verbose);

@ -4,12 +4,13 @@ use std::{
rc::Rc, rc::Rc,
}; };
use crate::templating; use crate::{scripting::create_lua, templating, utils::Describe};
use super::{ApplyContext, ParseContext}; use super::{ApplyContext, ParseContext};
use globset::{Glob, GlobSet, GlobSetBuilder}; use globset::{Glob, GlobSet, GlobSetBuilder};
use lazy_static::lazy_static; use lazy_static::lazy_static;
use miette::{Context, IntoDiagnostic, Result}; use miette::{Context, IntoDiagnostic, Result};
use mlua::LuaSerdeExt;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
@ -32,6 +33,7 @@ lazy_static! {
static ref IGNORED_PATHS: GlobSet = GlobSetBuilder::new() static ref IGNORED_PATHS: GlobSet = GlobSetBuilder::new()
.add(Glob::new("**/.git").unwrap()) .add(Glob::new("**/.git").unwrap())
.add(Glob::new("**/dir.{toml,toml.tmpl}").unwrap()) .add(Glob::new("**/dir.{toml,toml.tmpl}").unwrap())
.add(Glob::new("**/silo.{dir,config}.lua").unwrap())
.build() .build()
.unwrap(); .unwrap();
} }
@ -50,9 +52,20 @@ impl DirEntry {
let meta_file = path.join("dir.toml"); let meta_file = path.join("dir.toml");
let meta_tmpl = path.join("dir.toml.tmpl"); let meta_tmpl = path.join("dir.toml.tmpl");
let script_tmpl = path.join("silo.dir.lua");
let metadata = if meta_file.exists() { let metadata = if script_tmpl.exists() {
log::debug!("Found script template");
let metadata = RootDirData::read_lua(&script_tmpl, &ctx.config.template_context)?;
ctx = Rc::new(ParseContext::new(
metadata.ignored.clone(),
ctx.config.clone(),
));
Some(metadata)
} else if meta_file.exists() {
log::debug!("Found metadata file"); log::debug!("Found metadata file");
log::warn!("Old toml metadata files are deprecated. Please migrate to the `silo.dir.lua` syntax");
let metadata = RootDirData::read(&meta_file)?; let metadata = RootDirData::read(&meta_file)?;
ctx = Rc::new(ParseContext::new( ctx = Rc::new(ParseContext::new(
metadata.ignored.clone(), metadata.ignored.clone(),
@ -62,6 +75,7 @@ impl DirEntry {
Some(metadata) Some(metadata)
} else if meta_tmpl.exists() { } else if meta_tmpl.exists() {
log::debug!("Found metadata template"); log::debug!("Found metadata template");
log::warn!("Old template metadata files are deprecated. Please migrate to the `silo.dir.lua` syntax");
let metadata = let metadata =
RootDirData::read_template(&meta_tmpl, &ctx.config.template_context)?; RootDirData::read_template(&meta_tmpl, &ctx.config.template_context)?;
ctx = Rc::new(ParseContext::new( ctx = Rc::new(ParseContext::new(
@ -197,4 +211,15 @@ impl RootDirData {
.into_diagnostic() .into_diagnostic()
.with_context(|| format!("parsing metadata file {path:?}")) .with_context(|| format!("parsing metadata file {path:?}"))
} }
fn read_lua<T: Serialize>(path: &Path, ctx: T) -> Result<Self> {
let contents =
fs::read_to_string(path).with_describe(|| format!("reading metadata file {path:?}"))?;
let lua = create_lua(&ctx)?;
let cfg = lua
.from_value(lua.load(contents).eval().describe("evaluating script")?)
.describe("deserialize lua value")?;
Ok(cfg)
}
} }

@ -0,0 +1,36 @@
use log::Level;
use mlua::{Error, Lua, Result, Table};
pub fn log_module(lua: &Lua) -> Result<Table> {
let exports = lua.create_table()?;
for level in [
Level::Trace,
Level::Debug,
Level::Info,
Level::Warn,
Level::Error,
] {
exports.set(
level.as_str().to_lowercase(),
lua.create_function(move |_, v| lua_log(v, level))?,
)?;
}
Ok(exports)
}
fn lua_log(value: mlua::Value, level: log::Level) -> Result<()> {
match level {
Level::Error | Level::Warn | Level::Info => {
log::log!(target: "lua", level, "{}", value.to_string()?)
}
Level::Debug | Level::Trace => log::log!(
target: "lua",
level,
"{}",
serde_json::to_string(&value).map_err(Error::external)?
),
};
Ok(())
}

@ -0,0 +1,25 @@
pub mod log_module;
mod require;
pub mod silo_module;
use miette::Result;
use mlua::{Lua, LuaSerdeExt};
use serde::Serialize;
use crate::utils::Describe;
pub fn create_lua<T: Serialize>(ctx: &T) -> Result<Lua> {
let lua = Lua::new();
{
let globals = lua.globals();
require::register_require(&lua).describe("registering custom require")?;
globals
.set(
"silo_ctx",
lua.to_value(ctx).describe("serializing context to lua")?,
)
.describe("registering silo context")?;
}
Ok(lua)
}

@ -0,0 +1,24 @@
use mlua::{Lua, Result, Table};
use super::log_module::log_module;
use super::silo_module::silo_module;
pub fn register_require(lua: &Lua) -> Result<()> {
let globals = lua.globals();
let old_require: mlua::Function = globals.get("require")?;
globals.set("old_require", old_require)?;
globals.set("require", lua.create_function(lua_require)?)?;
Ok(())
}
fn lua_require<'a>(lua: &'a Lua, module: String) -> Result<Table<'a>> {
match module.as_str() {
"silo" => silo_module(&lua),
"log" => log_module(&lua),
_ => {
let old_require: mlua::Function = lua.globals().get("old_require")?;
old_require.call(module)
}
}
}

@ -0,0 +1,15 @@
use mlua::{Lua, LuaSerdeExt, Result, Table};
use crate::templating::ContextData;
pub fn silo_module(lua: &Lua) -> Result<Table> {
let silo_ctx = ContextData::default();
let exports = lua.create_table()?;
exports.set("dirs", lua.to_value(&silo_ctx.dirs)?)?;
exports.set("flags", lua.to_value(&silo_ctx.flags)?)?;
exports.set("system", lua.to_value(&silo_ctx.system)?)?;
exports.set("usercfg", lua.globals().get::<_, mlua::Value>("silo_ctx")?)?;
Ok(exports)
}

@ -0,0 +1,27 @@
use std::fmt;
use miette::{Context, IntoDiagnostic};
pub trait Describe<T, E>: miette::IntoDiagnostic<T, E> {
fn describe<S: fmt::Display + Send + Sync + 'static>(self, s: S) -> miette::Result<T>;
fn with_describe<F: FnOnce() -> S, S: fmt::Display + Send + Sync + 'static>(
self,
f: F,
) -> miette::Result<T>;
}
impl<T, E: std::error::Error + Send + Sync + 'static> Describe<T, E> for Result<T, E> {
fn describe<S: fmt::Display + Send + Sync + 'static>(self, s: S) -> miette::Result<T> {
self.into_diagnostic().context(s)
}
fn with_describe<F: FnOnce() -> S, S: fmt::Display + Send + Sync + 'static>(
self,
f: F,
) -> miette::Result<T> {
match &self {
Ok(_) => self.into_diagnostic(),
Err(_) => self.into_diagnostic().context(f()),
}
}
}
Loading…
Cancel
Save