Add example user creation script and execution logic

init-main
trivernis 2 years ago
parent 9db6b249c3
commit a1b8750a8e
Signed by: Trivernis
GPG Key ID: DFFFCC2C7A02DB45

1
.gitignore vendored

@ -10,3 +10,4 @@ Cargo.lock
# These are backup files generated by rustfmt # These are backup files generated by rustfmt
**/*.rs.bk **/*.rs.bk
.env

9
Cargo.lock generated

@ -658,6 +658,12 @@ dependencies = [
"winapi 0.3.9", "winapi 0.3.9",
] ]
[[package]]
name = "dotenv"
version = "0.15.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "77c90badedccf4105eca100756a0b1289e191f6fcbdadd3cee1d2f614f97da8f"
[[package]] [[package]]
name = "dtparse" name = "dtparse"
version = "1.3.0" version = "1.3.0"
@ -3277,6 +3283,7 @@ version = "0.1.0"
dependencies = [ dependencies = [
"clap", "clap",
"color-eyre", "color-eyre",
"dotenv",
"lazy_static", "lazy_static",
"miette 5.3.0", "miette 5.3.0",
"nu-cli", "nu-cli",
@ -3284,6 +3291,8 @@ dependencies = [
"nu-engine", "nu-engine",
"nu-parser", "nu-parser",
"nu-protocol", "nu-protocol",
"serde",
"serde_json",
"thiserror", "thiserror",
"tokio", "tokio",
"tracing", "tracing",

@ -15,6 +15,7 @@ path = "src/main.rs"
[dependencies] [dependencies]
clap = "3.2.22" clap = "3.2.22"
color-eyre = "0.6.2" color-eyre = "0.6.2"
dotenv = "0.15.0"
lazy_static = "1.4.0" lazy_static = "1.4.0"
miette = "5.3.0" miette = "5.3.0"
nu-cli = "0.68.1" nu-cli = "0.68.1"
@ -22,6 +23,8 @@ nu-command = "0.68.1"
nu-engine = "0.68.1" nu-engine = "0.68.1"
nu-parser = "0.68.1" nu-parser = "0.68.1"
nu-protocol = "0.68.1" nu-protocol = "0.68.1"
serde = { version = "1.0.144", features = ["derive"] }
serde_json = "1.0.85"
thiserror = "1.0.35" thiserror = "1.0.35"
tokio = { version = "1.21.1", features = ["rt", "io-std", "io-util", "process", "time", "macros", "tracing", "fs"] } tokio = { version = "1.21.1", features = ["rt", "io-std", "io-util", "process", "time", "macros", "tracing", "fs"] }
tracing = "0.1.36" tracing = "0.1.36"

@ -0,0 +1,9 @@
def main [cfg] {
$cfg | get users | each {|$it| create_user $it } | ignore
}
def create_user [user] {
echo "This would create a user with:"
echo $user
echo
}

@ -14,11 +14,15 @@ pub enum AppError {
#[error("Could not find the script file {0}")] #[error("Could not find the script file {0}")]
ScriptNotFound(PathBuf), ScriptNotFound(PathBuf),
#[diagnostic()]
#[error("Could not parse the source file {0}")] #[error("Could not parse the source file {0}")]
ParseError(#[from] nu_parser::ParseError), ParseError(#[from] nu_parser::ParseError),
#[error("Could not find the main mehod in the script file {0}")] #[error("Could not find the main mehod in the script file {0}")]
MissingMain(PathBuf), MissingMain(PathBuf),
#[error("Failed to execute script")]
FailedToExecuteScript,
} }
impl From<miette::Error> for AppError { impl From<miette::Error> for AppError {

@ -1,40 +1,29 @@
use error::AppResult; use error::AppResult;
use scripting::{ use scripting::{loader::ScriptLoader, script::JSONArgs};
loader::ScriptLoader, use tasks::{SetupUsersScript, UsersConfig};
script::{Script, ScriptArgs},
};
pub mod error; pub mod error;
pub(crate) mod scripting; pub(crate) mod scripting;
pub mod tasks;
pub(crate) mod utils; pub(crate) mod utils;
pub struct TestScript; pub struct TaskExecutor {
loader: ScriptLoader,
impl Script for TestScript {
type Args = TestScriptArgs;
fn get_name() -> &'static str {
"test.nu"
}
} }
pub struct TestScriptArgs { impl TaskExecutor {
pub msg: String, pub fn new() -> Self {
Self {
loader: ScriptLoader::new(),
} }
impl ScriptArgs for TestScriptArgs {
fn get_args(self) -> Vec<String> {
vec![self.msg]
} }
}
pub async fn test_execute() -> AppResult<()> {
let loader = ScriptLoader::new();
let test_script = loader.load::<TestScript>()?;
test_script /// Sets up user accounts
.execute(TestScriptArgs { #[tracing::instrument(level = "debug", skip(self))]
msg: "'Hello World'".to_string(), pub async fn setup_users(&self, users_cfg: UsersConfig) -> AppResult<()> {
}) self.loader
.load::<SetupUsersScript>()?
.execute(JSONArgs(users_cfg))
.await .await
} }
}

@ -1,5 +1,28 @@
use tourmaline::{
tasks::{User, UsersConfig},
TaskExecutor,
};
#[tokio::main(flavor = "current_thread")] #[tokio::main(flavor = "current_thread")]
async fn main() { async fn main() {
color_eyre::install().unwrap(); color_eyre::install().unwrap();
tourmaline::test_execute().await.unwrap(); dotenv::dotenv().unwrap();
let executor = TaskExecutor::new();
let user_cfg = UsersConfig {
users: vec![
User {
name: String::from("test"),
password: String::from("password"),
sudoer: false,
shell: String::from("/bin/zsh"),
},
User {
name: String::from("test2"),
password: String::from("superpassword"),
sudoer: true,
shell: String::from("/bin/nu"),
},
],
};
executor.setup_users(user_cfg).await.unwrap();
} }

@ -99,15 +99,20 @@ impl NuExecutor {
tokio::task::spawn_blocking(move || { tokio::task::spawn_blocking(move || {
// TODO: Create the AST for the call here instead of parsing it from a string // TODO: Create the AST for the call here instead of parsing it from a string
let args = format!("main {}", args.join(" ")); let args = format!("main {}", args.join(" "));
nu_cli::eval_source( if !nu_cli::eval_source(
&mut engine_state, &mut engine_state,
&mut stack, &mut stack,
args.as_bytes(), args.as_bytes(),
"<commandline>", "<commandline>",
PipelineData::new(Span::new(0, 0)), PipelineData::new(Span::new(0, 0)),
); ) {
Err(AppError::FailedToExecuteScript)
} else {
Ok(())
}
}) })
.await; .await
.unwrap()?;
Ok(()) Ok(())
} }

@ -1,3 +1,4 @@
use serde::Serialize;
use std::{marker::PhantomData, path::PathBuf}; use std::{marker::PhantomData, path::PathBuf};
use crate::error::AppResult; use crate::error::AppResult;
@ -48,3 +49,17 @@ impl<S: Script> NuScript<S> {
.await .await
} }
} }
pub struct JSONArgs<T: Serialize>(pub T);
impl<T: Serialize> ScriptArgs for JSONArgs<T> {
fn get_args(self) -> Vec<String> {
// TODO: Make this lesss... weird
// Maybe try providing the value directly in the executor
// instead of parsing and wrapping it
vec![format!(
"('{}' | from json)",
serde_json::to_string(&self.0).unwrap()
)]
}
}

@ -0,0 +1,15 @@
mod configure_locale;
mod configure_network;
mod create_partitions;
mod install_base;
mod install_bootloader;
mod install_desktop;
mod setup_users;
pub use configure_locale::*;
pub use configure_network::*;
pub use create_partitions::*;
pub use install_base::*;
pub use install_bootloader::*;
pub use install_desktop::*;
pub use setup_users::*;

@ -0,0 +1,26 @@
use serde::Serialize;
use crate::scripting::script::{JSONArgs, Script};
pub struct SetupUsersScript;
#[derive(Clone, Debug, Serialize)]
pub struct UsersConfig {
pub users: Vec<User>,
}
#[derive(Clone, Debug, Serialize)]
pub struct User {
pub name: String,
pub password: String,
pub sudoer: bool,
pub shell: String,
}
impl Script for SetupUsersScript {
type Args = JSONArgs<UsersConfig>;
fn get_name() -> &'static str {
"setup-users.nu"
}
}

@ -1,8 +1,8 @@
use std::path::PathBuf; use std::{env, path::PathBuf};
const CONFIG_DIR: &str = "/etc"; const DEFAULT_CONFIG_DIR: &str = "/etc";
lazy_static::lazy_static! { lazy_static::lazy_static! {
pub static ref CFG_PATH: PathBuf = PathBuf::from(CONFIG_DIR).join("tourmaline"); pub static ref CFG_PATH: PathBuf = env::var("TRM_CFG_PATH").map(PathBuf::from).unwrap_or_else(|_| PathBuf::from(DEFAULT_CONFIG_DIR).join("tourmaline"));
pub static ref SCRIPT_PATH: PathBuf = CFG_PATH.join("scripts"); pub static ref SCRIPT_PATH: PathBuf = CFG_PATH.join("scripts");
} }

Loading…
Cancel
Save