summaryrefslogtreecommitdiff
path: root/src/lua
diff options
context:
space:
mode:
Diffstat (limited to 'src/lua')
-rw-r--r--src/lua/mod.rs411
1 files changed, 0 insertions, 411 deletions
diff --git a/src/lua/mod.rs b/src/lua/mod.rs
deleted file mode 100644
index 6c4a281..0000000
--- a/src/lua/mod.rs
+++ /dev/null
@@ -1,411 +0,0 @@
-use crate::RunningJob;
-
-use rlua::prelude::*;
-
-use std::sync::{Arc, Mutex};
-use std::path::PathBuf;
-
-pub const DEFAULT_RUST_GOODFILE: &'static [u8] = include_bytes!("../../config/goodfiles/rust.lua");
-
-pub struct BuildEnv {
- lua: Lua,
- job: Arc<Mutex<RunningJob>>,
-}
-
-#[derive(Debug)]
-pub struct RunParams {
- step: Option<String>,
- name: Option<String>,
- cwd: Option<String>,
-}
-
-pub struct CommandOutput {
- pub exit_status: std::process::ExitStatus,
- pub stdout: Vec<u8>,
- pub stderr: Vec<u8>,
-}
-
-mod lua_exports {
- use crate::RunningJob;
- use crate::lua::{CommandOutput, RunParams};
-
- use std::sync::{Arc, Mutex};
- use std::path::PathBuf;
-
- use rlua::prelude::*;
-
- pub fn collect_build_args(command: LuaValue, params: LuaValue) -> Result<(Vec<String>, RunParams), rlua::Error> {
- let args = match command {
- LuaValue::Table(table) => {
- let len = table.len().expect("command table has a length");
- let mut command_args = Vec::new();
- for i in 0..len {
- let value = table.get(i + 1).expect("command arg is gettble");
- match value {
- LuaValue::String(s) => {
- command_args.push(s.to_str().unwrap().to_owned());
- },
- other => {
- return Err(LuaError::RuntimeError(format!("argument {} was not a string, was {:?}", i, other)));
- }
- };
- }
-
- command_args
- },
- other => {
- return Err(LuaError::RuntimeError(format!("argument 1 was not a table: {:?}", other)));
- }
- };
-
- let params = match params {
- LuaValue::Table(table) => {
- let step = match table.get("step").expect("can get from table") {
- LuaValue::String(v) => {
- Some(v.to_str()?.to_owned())
- },
- LuaValue::Nil => {
- None
- },
- other => {
- return Err(LuaError::RuntimeError(format!("params[\"step\"] must be a string")));
- }
- };
- let name = match table.get("name").expect("can get from table") {
- LuaValue::String(v) => {
- Some(v.to_str()?.to_owned())
- },
- LuaValue::Nil => {
- None
- },
- other => {
- return Err(LuaError::RuntimeError(format!("params[\"name\"] must be a string")));
- }
- };
- let cwd = match table.get("cwd").expect("can get from table") {
- LuaValue::String(v) => {
- Some(v.to_str()?.to_owned())
- },
- LuaValue::Nil => {
- None
- },
- other => {
- return Err(LuaError::RuntimeError(format!("params[\"cwd\"] must be a string")));
- }
- };
-
- RunParams {
- step,
- name,
- cwd,
- }
- },
- LuaValue::Nil => {
- RunParams {
- step: None,
- name: None,
- cwd: None,
- }
- }
- other => {
- return Err(LuaError::RuntimeError(format!("argument 2 was not a table: {:?}", other)));
- }
- };
-
- Ok((args, params))
- }
-
- pub fn build_command_impl(command: LuaValue, params: LuaValue, job_ctx: Arc<Mutex<RunningJob>>) -> Result<(), rlua::Error> {
- let (args, params) = collect_build_args(command, params)?;
- eprintln!("args: {:?}", args);
- eprintln!(" params: {:?}", params);
- let rt = tokio::runtime::Builder::new_current_thread()
- .enable_all()
- .build()
- .unwrap();
- rt.block_on(async move {
- job_ctx.lock().unwrap().run_command(&args, params.cwd.as_ref().map(|x| x.as_str())).await
- .map_err(|e| LuaError::RuntimeError(format!("run_command error: {:?}", e)))
- })
- }
-
- pub fn check_output_impl<'lua>(ctx: rlua::Context<'lua>, command: LuaValue<'lua>, params: LuaValue<'lua>, job_ctx: Arc<Mutex<RunningJob>>) -> Result<rlua::Table<'lua>, rlua::Error> {
- let (args, params) = collect_build_args(command, params)?;
- eprintln!("args: {:?}", args);
- eprintln!(" params: {:?}", params);
- let rt = tokio::runtime::Builder::new_current_thread()
- .enable_all()
- .build()
- .unwrap();
- let command_output = rt.block_on(async move {
- job_ctx.lock().unwrap().run_with_output(&args, params.cwd.as_ref().map(|x| x.as_str())).await
- .map_err(|e| LuaError::RuntimeError(format!("run_command error: {:?}", e)))
- })?;
-
- let stdout = ctx.create_string(command_output.stdout.as_slice())?;
- let stderr = ctx.create_string(command_output.stderr.as_slice())?;
-
- let result = ctx.create_table()?;
- result.set("stdout", stdout)?;
- result.set("stderr", stderr)?;
- result.set("status", command_output.exit_status.code())?;
- Ok(result)
- }
-
- pub fn check_dependencies(commands: Vec<String>) -> Result<(), rlua::Error> {
- let mut missing_deps = Vec::new();
- for command in commands.iter() {
- if !has_cmd(command)? {
- missing_deps.push(command.clone());
- }
- }
-
- if missing_deps.len() > 0 {
- return Err(LuaError::RuntimeError(format!("missing dependencies: {}", missing_deps.join(", "))));
- }
-
- Ok(())
- }
-
- pub fn metric(name: String, value: String, job_ctx: Arc<Mutex<RunningJob>>) -> Result<(), rlua::Error> {
- let rt = tokio::runtime::Builder::new_current_thread()
- .enable_all()
- .build()
- .unwrap();
- rt.block_on(async move {
- job_ctx.lock().unwrap().send_metric(&name, value).await
- .map_err(|e| LuaError::RuntimeError(format!("send_metric error: {:?}", e)))
- })
- }
-
- pub fn artifact(path: String, name: Option<String>, job_ctx: Arc<Mutex<RunningJob>>) -> Result<(), rlua::Error> {
- let path: PathBuf = path.into();
-
- let default_name: String = match (path.file_name(), path.parent()) {
- (Some(name), _) => name
- .to_str()
- .ok_or(LuaError::RuntimeError("artifact name is not a unicode string".to_string()))?
- .to_string(),
- (_, Some(parent)) => format!("{}", parent.display()),
- (None, None) => {
- // one day using directories for artifacts might work but / is still not going
- // to be accepted
- return Err(LuaError::RuntimeError(format!("cannot infer a default path name for {}", path.display())));
- }
- };
-
- let name: String = match name {
- Some(name) => name,
- None => default_name,
- };
- let rt = tokio::runtime::Builder::new_current_thread()
- .enable_all()
- .build()
- .unwrap();
- rt.block_on(async move {
- let mut artifact = job_ctx.lock().unwrap().create_artifact(&name, &format!("{} (from {})", name, path.display())).await
- .map_err(|e| LuaError::RuntimeError(format!("create_artifact error: {:?}", e)))
- .unwrap();
- let mut file = tokio::fs::File::open(&format!("tmpdir/{}", path.display())).await.unwrap();
- eprintln!("uploading...");
- crate::io::forward_data(&mut file, &mut artifact).await
- .map_err(|e| LuaError::RuntimeError(format!("failed uploading data for {}: {:?}", name, e)))?;
- std::mem::drop(artifact);
- Ok(())
- })
- }
-
- pub fn has_cmd(name: &str) -> Result<bool, rlua::Error> {
- Ok(std::process::Command::new("which")
- .arg(name)
- .status()
- .map_err(|e| LuaError::RuntimeError(format!("could not fork which? {:?}", e)))?
- .success())
- }
-
- pub fn file_size(path: &str) -> Result<u64, rlua::Error> {
- Ok(std::fs::metadata(&format!("tmpdir/{}", path))
- .map_err(|e| LuaError::RuntimeError(format!("could not stat {:?}", path)))?
- .len())
- }
-
- pub mod step {
- use crate::RunningJob;
- use std::sync::{Arc, Mutex};
-
- pub fn start(job_ref: Arc<Mutex<RunningJob>>, name: String) -> Result<(), rlua::Error> {
- let mut job = job_ref.lock().unwrap();
- job.current_step.clear();
- job.current_step.push(name);
- Ok(())
- }
-
- pub fn push(job_ref: Arc<Mutex<RunningJob>>, name: String) -> Result<(), rlua::Error> {
- let mut job = job_ref.lock().unwrap();
- job.current_step.push(name);
- Ok(())
- }
-
- pub fn advance(job_ref: Arc<Mutex<RunningJob>>, name: String) -> Result<(), rlua::Error> {
- let mut job = job_ref.lock().unwrap();
- job.current_step.pop();
- job.current_step.push(name);
- Ok(())
- }
- }
-}
-
-struct DeclEnv<'lua, 'env> {
- lua_ctx: &'env rlua::Context<'lua>,
- job_ref: &'env Arc<Mutex<RunningJob>>,
-}
-impl<'lua, 'env> DeclEnv<'lua, 'env> {
- fn create_function<A, R, F>(&self, name: &str, f: F) -> Result<rlua::Function<'lua>, String>
- where
- A: FromLuaMulti<'lua>,
- R: ToLuaMulti<'lua>,
- F: 'static + Send + Fn(rlua::Context<'lua>, Arc<Mutex<RunningJob>>, A) -> Result<R, rlua::Error> {
-
- let job_ref = Arc::clone(self.job_ref);
- self.lua_ctx.create_function(move |ctx, args| {
- let job_ref = Arc::clone(&job_ref);
- f(ctx, job_ref, args)
- })
- .map_err(|e| format!("problem defining {} function: {:?}", name, e))
- }
-}
-
-impl BuildEnv {
- pub fn new(job: &Arc<Mutex<RunningJob>>) -> Self {
- let env = BuildEnv {
- lua: Lua::new(),
- job: Arc::clone(job),
- };
- env.lua.context(|lua_ctx| {
- env.define_env(lua_ctx)
- }).expect("can define context");
- env
- }
-
- fn define_env(&self, lua_ctx: rlua::Context) -> Result<(), String> {
- let decl_env = DeclEnv {
- lua_ctx: &lua_ctx,
- job_ref: &self.job,
- };
-
- let hello = decl_env.create_function("hello", |_, _, ()| {
- eprintln!("hello from lua!!!");
- Ok(())
- })?;
-
- let check_dependencies = decl_env.create_function("dependencies", move |_, job_ref, commands: Vec<String>| {
- lua_exports::check_dependencies(commands)
- })?;
-
- let build = decl_env.create_function("build", move |_, job_ref, (command, params): (LuaValue, LuaValue)| {
- lua_exports::build_command_impl(command, params, job_ref)
- })?;
-
- let check_output = decl_env.create_function("check_output", move |ctx, job_ref, (command, params): (LuaValue, LuaValue)| {
- lua_exports::check_output_impl(ctx, command, params, job_ref)
- })?;
-
- let metric = decl_env.create_function("metric", move |_, job_ref, (name, value): (String, String)| {
- lua_exports::metric(name, value, job_ref)
- })?;
-
- let now_ms = decl_env.create_function("now_ms", move |_, job_ref, ()| Ok(crate::io::now_ms()))?;
-
- let artifact = decl_env.create_function("artifact", move |_, job_ref, (path, name): (String, Option<String>)| {
- lua_exports::artifact(path, name, job_ref)
- })?;
-
- let error = decl_env.create_function("error", move |_, job_ref, msg: String| {
- Err::<(), LuaError>(LuaError::RuntimeError(format!("explicit error: {}", msg)))
- })?;
-
- let path_has_cmd = decl_env.create_function("path_has_cmd", move |_, job_ref, name: String| {
- lua_exports::has_cmd(&name)
- })?;
-
- let size_of_file = decl_env.create_function("size_of_file", move |_, job_ref, name: String| {
- lua_exports::file_size(&name)
- })?;
-
- let native_rust_triple = match std::env::consts::ARCH {
- "x86_64" => "x86_64-unknown-linux-gnu",
- "aarch64" => "aarch64-unknown-linux-gnu",
- other => { panic!("dunno native rust triple for arch {}", other); }
- };
- let native_rust_triple = lua_ctx.create_string(native_rust_triple).unwrap();
- let build_env_vars = lua_ctx.create_table_from(
- vec![
- ("native_rust_triple", native_rust_triple)
- ]
- ).unwrap();
-
- let build_environment = lua_ctx.create_table_from(
- vec![
- ("has", path_has_cmd),
- ("size", size_of_file),
- ]
- ).unwrap();
- build_environment.set("vars", build_env_vars).unwrap();
-
- let build_functions = lua_ctx.create_table_from(
- vec![
- ("hello", hello),
- ("run", build),
- ("dependencies", check_dependencies),
- ("metric", metric),
- ("error", error),
- ("artifact", artifact),
- ("now_ms", now_ms),
- ("check_output", check_output),
- ]
- ).unwrap();
- build_functions.set("environment", build_environment).unwrap();
- let current_commit = self.job.lock().unwrap().job.commit.clone();
- build_functions.set("sha", lua_ctx.create_string(current_commit.as_bytes()).unwrap()).unwrap();
- let globals = lua_ctx.globals();
- globals.set("Build", build_functions).unwrap();
-
-
- let step_start = decl_env.create_function("step_start", move |_, job_ref, name: String| {
- lua_exports::step::start(job_ref, name)
- })?;
-
- let step_push = decl_env.create_function("step_push", move |_, job_ref, name: String| {
- lua_exports::step::push(job_ref, name)
- })?;
-
- let step_advance = decl_env.create_function("step_advance", move |_, job_ref, name: String| {
- lua_exports::step::advance(job_ref, name)
- })?;
-
- let step_functions = lua_ctx.create_table_from(
- vec![
- ("start", step_start),
- ("push", step_push),
- ("advance", step_advance),
- ]
- ).unwrap();
- globals.set("Step", step_functions).unwrap();
- Ok(())
- }
-
- pub async fn run_build(self, script: &[u8]) -> Result<(), LuaError> {
- let script = script.to_vec();
- let res: Result<(), LuaError> = tokio::task::spawn_blocking(|| {
- std::thread::spawn(move || {
- self.lua.context(|lua_ctx| {
- lua_ctx.load(&script)
- .set_name("goodfile")?
- .exec()
- })
- }).join().unwrap()
- }).await.unwrap();
- eprintln!("lua res: {:?}", res);
- res
- }
-}