Added shell action

This commit is contained in:
Kasper Juul Hermansen 2022-08-10 16:46:56 +02:00
parent f5e1e3027a
commit faf15d1398
Signed by: kjuulh
GPG Key ID: 0F95C140730F2F23
9 changed files with 181 additions and 19 deletions

21
Cargo.lock generated
View File

@ -80,12 +80,33 @@ version = "0.1.0"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"clap", "clap",
"envconfig",
"git2", "git2",
"serde", "serde",
"serde_yaml", "serde_yaml",
"walkdir", "walkdir",
] ]
[[package]]
name = "envconfig"
version = "0.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ea81cc7e21f55a9d9b1efb6816904978d0bfbe31a50347cb24b2e75564bcac9b"
dependencies = [
"envconfig_derive",
]
[[package]]
name = "envconfig_derive"
version = "0.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7dfca278e5f84b45519acaaff758ebfa01f18e96998bc24b8f1b722dd804b9bf"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]] [[package]]
name = "form_urlencoded" name = "form_urlencoded"
version = "1.0.1" version = "1.0.1"

View File

@ -12,3 +12,4 @@ serde_yaml = "0.9.4"
walkdir = "2.3.2" walkdir = "2.3.2"
git2 = { version = "0.15.0", features = ["ssh"] } git2 = { version = "0.15.0", features = ["ssh"] }
clap = "3.2.16" clap = "3.2.16"
envconfig = "0.10.0"

View File

@ -0,0 +1 @@
pub mod shell;

View File

@ -0,0 +1,54 @@
use std::{
io::{BufRead, BufReader},
process::{Command, Stdio},
};
pub struct ShellAction {
path: String,
}
impl ShellAction {
pub fn new(path: String) -> Self {
Self { path }
}
pub fn execute(self) -> anyhow::Result<()> {
println!("executing shell action: {}", self.path.clone());
println!(
"
===
Starting running shell action: {}
===
",
self.path.clone()
);
let mut process = Command::new(self.path)
.current_dir(".")
.stdout(Stdio::piped())
.stderr(Stdio::piped())
.spawn()?;
{
let stdout = process.stdout.as_mut().unwrap();
let stdout_reader = BufReader::new(stdout);
let mut stdout_lines = stdout_reader.lines();
while let Some(Ok(line)) = stdout_lines.next() {
println!("{}", line);
}
}
process.wait()?;
println!(
"
===
Finished running shell action
===
"
);
Ok(())
}
}

View File

@ -3,9 +3,10 @@ use std::{
sync::{Arc, Mutex}, sync::{Arc, Mutex},
}; };
use anyhow::anyhow;
use clap::Command; use clap::Command;
use crate::{context::CuddleContext, model::CuddleScript}; use crate::{actions, context::CuddleContext, model::CuddleScript};
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
#[allow(dead_code)] #[allow(dead_code)]
@ -22,8 +23,23 @@ impl CuddleAction {
pub fn execute(self) { pub fn execute(self) {
match self.script { match self.script {
CuddleScript::Shell(s) => {} CuddleScript::Shell(_s) => {
CuddleScript::Dagger(d) => {} match actions::shell::ShellAction::new(format!(
"{}/scripts/{}.sh",
self.path
.to_str()
.expect("action doesn't have a name, this should never happen"),
self.name
))
.execute()
{
Ok(()) => {}
Err(e) => {
eprintln!("{}", e)
}
}
}
CuddleScript::Dagger(_d) => {}
} }
} }
} }
@ -68,8 +84,7 @@ impl<'a> CuddleCli<'a> {
.version("1.0") .version("1.0")
.author("kjuulh <contact@kasperhermansen.com>") .author("kjuulh <contact@kasperhermansen.com>")
.about("cuddle is your domain specific organization tool. It enabled widespread sharing through repositories, as well as collaborating while maintaining speed and integrity") .about("cuddle is your domain specific organization tool. It enabled widespread sharing through repositories, as well as collaborating while maintaining speed and integrity")
.propagate_version(true) .propagate_version(true);
.arg_required_else_help(true);
let mut execute_cmd = Command::new("x").about("x is your entry into your domains scripts, scripts inherited from parents will also be present here"); let mut execute_cmd = Command::new("x").about("x is your entry into your domains scripts, scripts inherited from parents will also be present here");
@ -77,6 +92,7 @@ impl<'a> CuddleCli<'a> {
let action_cmd = Command::new(script.name.clone()); let action_cmd = Command::new(script.name.clone());
// TODO: Some way to add an about for clap, requires conversion from String -> &str // TODO: Some way to add an about for clap, requires conversion from String -> &str
execute_cmd = execute_cmd.subcommand(action_cmd); execute_cmd = execute_cmd.subcommand(action_cmd);
} }
@ -87,11 +103,40 @@ impl<'a> CuddleCli<'a> {
self self
} }
pub fn execute(self) -> Self { pub fn execute(self) -> anyhow::Result<Self> {
if let Some(cli) = self.command.clone() { if let Some(mut cli) = self.command.clone() {
let _ = cli.get_matches(); let matches = cli.clone().get_matches();
let res = match matches.subcommand() {
Some(("x", exe_submatch)) => {
println!("executing: x");
match exe_submatch.subcommand() {
Some((name, _action_matches)) => {
println!("running action: {}", name);
match self.scripts.iter().find(|ele| ele.name == name) {
Some(script) => {
script.clone().execute();
Ok(())
}
_ => (Err(anyhow!("could not find a match"))),
}
}
_ => (Err(anyhow!("could not find a match"))),
}
}
_ => (Err(anyhow!("could not find a match"))),
};
match res {
Ok(()) => {}
Err(e) => {
eprintln!("{}", e);
let _ = cli.print_long_help();
}
}
} }
self Ok(self)
} }
} }

26
cuddle_cli/src/config.rs Normal file
View File

@ -0,0 +1,26 @@
use envconfig::Envconfig;
pub enum CuddleFetchPolicy {
Always,
Once,
}
#[derive(Envconfig, Clone)]
pub struct CuddleConfig {
#[envconfig(from = "CUDDLE_FETCH_POLICY", default = "once")]
fetch_policy: String,
}
impl CuddleConfig {
pub fn from_env() -> anyhow::Result<Self> {
CuddleConfig::init_from_env().map_err(|e| anyhow::Error::from(e))
}
pub fn get_fetch_policy(&self) -> anyhow::Result<CuddleFetchPolicy> {
match self.fetch_policy.clone().to_lowercase().as_str() {
"always" => Ok(CuddleFetchPolicy::Always),
"once" => Ok(CuddleFetchPolicy::Once),
_ => Err(anyhow::anyhow!("could not parse fetch policy")),
}
}
}

View File

@ -7,7 +7,10 @@ use std::{
use git2::{build::RepoBuilder, FetchOptions, RemoteCallbacks}; use git2::{build::RepoBuilder, FetchOptions, RemoteCallbacks};
use crate::model::{CuddleBase, CuddlePlan}; use crate::{
config::{CuddleConfig, CuddleFetchPolicy},
model::{CuddleBase, CuddlePlan},
};
#[derive(Debug)] #[derive(Debug)]
pub struct CuddleContext { pub struct CuddleContext {
@ -15,11 +18,14 @@ pub struct CuddleContext {
pub path: PathBuf, pub path: PathBuf,
} }
pub fn extract_cuddle() -> anyhow::Result<Arc<Mutex<Vec<CuddleContext>>>> { pub fn extract_cuddle(config: CuddleConfig) -> anyhow::Result<Arc<Mutex<Vec<CuddleContext>>>> {
let mut curr_dir = current_dir()?; let mut curr_dir = current_dir()?;
curr_dir.push(".cuddle/"); curr_dir.push(".cuddle/");
if let Err(res) = std::fs::remove_dir_all(curr_dir) { let fetch_policy = config.get_fetch_policy()?;
println!("{}", res); if let CuddleFetchPolicy::Always = fetch_policy {
if let Err(res) = std::fs::remove_dir_all(curr_dir) {
println!("{}", res);
}
} }
// Load main cuddle file // Load main cuddle file
@ -52,8 +58,10 @@ pub fn extract_cuddle() -> anyhow::Result<Arc<Mutex<Vec<CuddleContext>>>> {
let mut cuddle_dest = destination_path.clone(); let mut cuddle_dest = destination_path.clone();
cuddle_dest.push("base"); cuddle_dest.push("base");
pull_parent_cuddle_into_local(parent_plan, cuddle_dest.clone())?; if !cuddle_dest.exists() {
recurse_parent(cuddle_dest, context.clone())?; pull_parent_cuddle_into_local(parent_plan, cuddle_dest.clone())?;
recurse_parent(cuddle_dest, context.clone())?;
}
} }
} }

View File

@ -1,13 +1,16 @@
use config::CuddleConfig;
mod actions;
mod cli; mod cli;
mod config;
mod context; mod context;
mod model; mod model;
fn main() -> anyhow::Result<()> { fn main() -> anyhow::Result<()> {
let context = context::extract_cuddle()?; let config = CuddleConfig::from_env()?;
let mut cuddle_cli = cli::CuddleCli::new(context.clone())?;
cuddle_cli = cuddle_cli.execute();
println!("{:?}", cuddle_cli); let context = context::extract_cuddle(config.clone())?;
_ = cli::CuddleCli::new(context)?.execute()?;
Ok(()) Ok(())
} }

3
examples/base/scripts/build.sh Executable file
View File

@ -0,0 +1,3 @@
#!/bin/bash
echo "Ran build"