From 2903c0696ff1851cf6598bff456c30b9f64529a6 Mon Sep 17 00:00:00 2001
From: iximeow <git@iximeow.net>
Date: Wed, 28 Dec 2022 10:00:27 +0000
Subject: support Build.run parameters, more consistently insert tmpdir/ into
 paths

---
 src/ci_runner.rs | 29 ++++++++++++++++--
 src/lua/mod.rs   | 91 +++++++++++++++++++++++++++++++++++++++++++++++++-------
 2 files changed, 107 insertions(+), 13 deletions(-)

(limited to 'src')

diff --git a/src/ci_runner.rs b/src/ci_runner.rs
index de423eb..a88b135 100644
--- a/src/ci_runner.rs
+++ b/src/ci_runner.rs
@@ -291,15 +291,40 @@ impl RunningJob {
         }
     }
 
-    async fn run_command(&self, command: &[String]) -> Result<(), String> {
+    async fn run_command(&mut self, command: &[String], working_dir: Option<&str>) -> Result<(), String> {
+        self.client.send(serde_json::json!({
+            "kind": "command",
+            "state": "started",
+            "command": command,
+            "cwd": working_dir,
+            "id": 1,
+        })).await.unwrap();
+
         let mut cmd = Command::new(&command[0]);
+        let cwd = match working_dir {
+            Some(dir) => {
+                format!("tmpdir/{}", dir)
+            },
+            None => {
+                "tmpdir".to_string()
+            }
+        };
+        eprintln!("running {:?} in {}", &command, &cwd);
         let human_name = command.join(" ");
         cmd
-            .current_dir("tmpdir")
+            .current_dir(cwd)
             .args(&command[1..]);
 
         let cmd_res = self.execute_command(cmd, &format!("{} log", human_name), &human_name).await?;
 
+        self.client.send(serde_json::json!({
+            "kind": "command",
+            "state": "finished",
+            "exit_code": cmd_res.code(),
+            "id": 1,
+        })).await.unwrap();
+
+
         if !cmd_res.success() {
             return Err(format!("{} failed: {:?}", &human_name, cmd_res));
         }
diff --git a/src/lua/mod.rs b/src/lua/mod.rs
index 034f766..936c94a 100644
--- a/src/lua/mod.rs
+++ b/src/lua/mod.rs
@@ -1,13 +1,9 @@
-use crate::RunnerClient;
 use crate::RunningJob;
 
 use rlua::prelude::*;
 
-use tokio::io::{AsyncRead, AsyncReadExt, AsyncWrite, AsyncWriteExt};
-use tokio::process::Command;
-use std::process::ExitStatus;
-use std::process::Stdio;
 use std::sync::{Arc, Mutex};
+use std::path::PathBuf;
 
 pub const DEFAULT_RUST_GOODFILE: &'static [u8] = include_bytes!("../../config/goodfiles/rust.lua");
 
@@ -59,13 +55,67 @@ impl BuildEnv {
                     return Err(LuaError::RuntimeError(format!("argument 1 was not a table: {:?}", other)));
                 }
             };
+
+            #[derive(Debug)]
+            struct RunParams {
+                step: Option<String>,
+                name: Option<String>,
+                cwd: Option<String>,
+            }
+
+            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,
+                    }
+                },
+                other => {
+                    return Err(LuaError::RuntimeError(format!("argument 2 was not a table: {:?}", other)));
+                }
+            };
             eprintln!("args: {:?}", args);
             let rt = tokio::runtime::Builder::new_current_thread()
                 .enable_all()
                 .build()
                 .unwrap();
             rt.block_on(async move {
-                job_ref.lock().unwrap().run_command(&args).await
+                job_ref.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)))
             })
         })
@@ -86,17 +136,36 @@ impl BuildEnv {
             .map_err(|e| format!("problem defining metric function: {:?}", e))?;
 
         let job_ref = Arc::clone(&self.job);
-        let artifact = lua_ctx.create_function(move |_, (name, path): (String, String)| {
+        let artifact = lua_ctx.create_function(move |_, (path, name): (String, Option<String>)| {
+            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 job_ref: Arc<Mutex<RunningJob>> = Arc::clone(&job_ref);
             let rt = tokio::runtime::Builder::new_current_thread()
                 .enable_all()
                 .build()
                 .unwrap();
             rt.block_on(async move {
-                let artifact = job_ref.lock().unwrap().create_artifact(&name, &format!("{} (from {})", name, path)).await
+                let artifact = job_ref.lock().unwrap().create_artifact(&name, &format!("{} (from {})", name, path.display())).await
                     .map_err(|e| LuaError::RuntimeError(format!("create_artifact error: {:?}", e)))
                     .unwrap();
-                crate::forward_data(tokio::fs::File::open(path).await.unwrap(), artifact).await
+                crate::forward_data(tokio::fs::File::open(&format!("tmpdir/{}", path.display())).await.unwrap(), artifact).await
                     .map_err(|e| LuaError::RuntimeError(format!("failed uploading data for {}: {:?}", name, e)))
             })
         })
@@ -115,7 +184,7 @@ impl BuildEnv {
         }).unwrap();
 
         let size_of_file = lua_ctx.create_function(move |_, name: String| {
-            Ok(std::fs::metadata(&name)
+            Ok(std::fs::metadata(&format!("tmpdir/{}", name))
                 .map_err(|e| LuaError::RuntimeError(format!("could not stat {:?}", name)))?
                 .len())
         }).unwrap();
@@ -138,7 +207,7 @@ impl BuildEnv {
         ).unwrap();
         build_functions.set("environment", build_environment).unwrap();
         let globals = lua_ctx.globals();
-        globals.set("Build", build_functions);
+        globals.set("Build", build_functions).unwrap();
         Ok(())
     }
 
-- 
cgit v1.1