Skip to content

Commit

Permalink
hooks: ability to call scripts
Browse files Browse the repository at this point in the history
  • Loading branch information
BrettMayson committed Nov 9, 2024
1 parent 821dfc9 commit 95245d2
Show file tree
Hide file tree
Showing 7 changed files with 80 additions and 15 deletions.
2 changes: 1 addition & 1 deletion bin/src/commands/script.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,5 +30,5 @@ pub fn execute(matches: &ArgMatches) -> Result<Report, Error> {
let name = matches
.get_one::<String>("name")
.expect("name to be set as required");
Hooks::run_file(&ctx, name)
Hooks::run_file(&ctx, name).map(|(report, _)| report)
}
37 changes: 35 additions & 2 deletions bin/src/modules/hook/libraries/hemtt.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use hemtt_common::version::Version;
use rhai::plugin::{
export_module, Dynamic, FnNamespace, FuncRegistration, Module, NativeCallContext, PluginFunc,
RhaiResult, TypeId,
export_module, mem, Dynamic, FnNamespace, FuncRegistration, ImmutableString, Module,
NativeCallContext, PluginFunc, RhaiResult, TypeId,
};

use crate::context::Context;
Expand All @@ -11,6 +11,7 @@ use super::project::RhaiProject;
#[allow(clippy::module_name_repetitions)]
#[derive(Debug, Clone)]
pub struct RhaiHemtt {
ctx: Context,
version: Version,
project: RhaiProject,
folder: String,
Expand All @@ -19,6 +20,7 @@ pub struct RhaiHemtt {
impl RhaiHemtt {
pub fn new(ctx: &Context) -> Self {
Self {
ctx: ctx.clone(),
version: Version::try_from(env!("HEMTT_VERSION"))
.expect("hemtt version should be valid"),
project: RhaiProject::new(ctx),
Expand All @@ -31,6 +33,14 @@ impl RhaiHemtt {
#[allow(clippy::unwrap_used)] // coming from rhai codegen
#[export_module]
pub mod project_functions {
use rhai::EvalAltResult;

use crate::{
modules::{hook::error::bhe1_script_not_found::ScriptNotFound, Hooks},
report::Report,
Error,
};

#[rhai_fn(global, pure)]
pub fn version(hemtt: &mut RhaiHemtt) -> Version {
hemtt.version.clone()
Expand Down Expand Up @@ -65,4 +75,27 @@ pub mod project_functions {
pub fn is_release(hemtt: &mut RhaiHemtt) -> bool {
hemtt.folder == "release"
}

#[rhai_fn(global, pure, return_raw)]
pub fn script(hemtt: &mut RhaiHemtt, name: &str) -> Result<Dynamic, Box<EvalAltResult>> {
fn inner_script(hemtt: &mut RhaiHemtt, name: &str) -> Result<(Report, Dynamic), Error> {
let scripts = hemtt.ctx.workspace_path().join(".hemtt")?.join("scripts")?;
let path = scripts.join(name)?.with_extension("rhai")?;
trace!("running script: {}", path.as_str());
if !path.exists()? {
return Ok((
{
let mut report = Report::new();
report.push(ScriptNotFound::code(name.to_owned(), &scripts)?);
report
},
Dynamic::UNIT,
));
}
Hooks::run(&hemtt.ctx, path, false)
}
inner_script(hemtt, name)
.map_err(|e| e.to_string().into())
.map(|(_, d)| d)
}
}
27 changes: 16 additions & 11 deletions bin/src/modules/hook/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ use std::sync::{Arc, Mutex};

use ::rhai::{packages::Package, Engine, Scope};
use hemtt_workspace::WorkspacePath;
use rhai::Dynamic;

use crate::{context::Context, error::Error, report::Report};

Expand Down Expand Up @@ -102,7 +103,7 @@ impl Hooks {
"Running hook: {}",
file.as_str().trim_start_matches("/.hemtt/hooks/")
);
report.merge(Self::run(ctx, file, vfs)?);
report.merge(Self::run(ctx, file, vfs)?.0);
ctx.config().version().invalidate();
}
Ok(report)
Expand All @@ -117,22 +118,22 @@ impl Hooks {
///
/// # Panics
/// If a file path is not a valid [`OsStr`] (UTF-8)
pub fn run_file(ctx: &Context, name: &str) -> Result<Report, Error> {
pub fn run_file(ctx: &Context, name: &str) -> Result<(Report, Dynamic), Error> {
let mut report = Report::new();
let scripts = ctx.workspace_path().join(".hemtt")?.join("scripts")?;
let path = scripts.join(name)?.with_extension("rhai")?;
trace!("running script: {}", path.as_str());
if !path.exists()? {
report.push(ScriptNotFound::code(name.to_owned(), &scripts)?);
return Ok(report);
return Ok((report, Dynamic::UNIT));
}
let res = Self::run(ctx, path, false);
ctx.config().version().invalidate();
res
}

#[allow(clippy::needless_pass_by_value)] // rhai things
fn run(ctx: &Context, path: WorkspacePath, vfs: bool) -> Result<Report, Error> {
fn run(ctx: &Context, path: WorkspacePath, vfs: bool) -> Result<(Report, Dynamic), Error> {
let mut report = Report::new();
let mut engine = engine(vfs);
let mut scope = scope(ctx, vfs)?;
Expand Down Expand Up @@ -171,14 +172,18 @@ impl Hooks {
.lock()
.expect("told_to_fail mutex poisoned") = true;
});
if let Err(e) = engine.run_with_scope(&mut scope, &path.read_to_string()?) {
report.push(RuntimeError::code(path, &e));
return Ok(report);
}
if *told_to_fail.lock().expect("told_to_fail mutex poisoned") {
report.push(ScriptFatal::code(name));
match engine.eval_with_scope(&mut scope, &path.read_to_string()?) {
Err(e) => {
report.push(RuntimeError::code(path, &e));
Ok((report, Dynamic::UNIT))
}
Ok(ret) => {
if *told_to_fail.lock().expect("told_to_fail mutex poisoned") {
report.push(ScriptFatal::code(name));
}
Ok((report, ret))
}
}
Ok(report)
}
}

Expand Down
4 changes: 4 additions & 0 deletions bin/tests/bravo/.hemtt/hooks/post_release/02_test_rhs.rhai
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,7 @@ if !include.is_file() {
if include.is_dir() {
fatal("{} is a directory", include);
}

if HEMTT.script("test") != 42 {
fatal("HEMTT.script(\"test\") != 42");
}
1 change: 1 addition & 0 deletions bin/tests/bravo/.hemtt/scripts/test.rhai
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
print("Just a test");
print(date("[year]-[month]-[day] [hour]:[minute]:[second]"));
print(date("[year repr:last_two][month][day]"));
42
22 changes: 22 additions & 0 deletions book/rhai/scripts/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,25 @@ The files are located in the `.hemtt/scripts` folder, and are written in [Rhai](
They have access to all the same [libraries](../library/index.md) as [hooks](../hooks.md), but only use the [real file system](../library/filesystem.md#hemtt_rfs---real-file-system), since they run outside of the build process.

Scripts are useful for automating tasks that are not part of the build process, such as creating a new addon, or updating the version number.

## Calling from Hooks

Scripts can be called from hooks using `HEMTT.script(<script>)`. The script will still only have access to the real file system.

The script can return a value that will be passed back to the hook.

**.hemtt/scripts/value.rhai**

```js
1 + 1 * 2
```

**.hemtt/hooks/post_release/print_value.rhai**

```js
let value = HEMTT.script("value");
if value != 3 {
fatal("Value is not 3");
}
println(value)
```
2 changes: 1 addition & 1 deletion libs/workspace/src/reporting/diagnostic/label.rs
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ impl Label {
.chars()
.next()
.map_or(true, |c| c.is_lowercase() || !c.is_alphabetic()),
"All label messages should be lowercase (except for text copied from the source)"
"All label messages should be lowercase (except for text copied from the source), got: {message:?}",
);
label = label.with_message(message.clone());
}
Expand Down

0 comments on commit 95245d2

Please sign in to comment.