add bare cli
This commit is contained in:
parent
ba0ad9239d
commit
5da6b35ead
@ -1,8 +1,8 @@
|
||||
use std::{
|
||||
io::{BufRead, BufReader},
|
||||
process::{Command, Stdio},
|
||||
};
|
||||
use std::process::Command;
|
||||
|
||||
use crate::cli::CuddleVariable;
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub struct ShellAction {
|
||||
path: String,
|
||||
name: String,
|
||||
@ -13,7 +13,7 @@ impl ShellAction {
|
||||
Self { path, name }
|
||||
}
|
||||
|
||||
pub fn execute(self) -> anyhow::Result<()> {
|
||||
pub fn execute(self, variables: Vec<CuddleVariable>) -> anyhow::Result<()> {
|
||||
log::debug!("executing shell action: {}", self.path.clone());
|
||||
|
||||
log::info!(
|
||||
@ -28,18 +28,12 @@ Starting running shell action: {}
|
||||
|
||||
let mut process = Command::new(self.path)
|
||||
.current_dir(".")
|
||||
//.stdout(Stdio::piped())
|
||||
//.stderr(Stdio::piped())
|
||||
.spawn()?;
|
||||
.envs(variables.iter().map(|v| {
|
||||
log::trace!("{:?}", v);
|
||||
|
||||
//{
|
||||
// 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() {
|
||||
// log::info!("{}", line);
|
||||
// }
|
||||
//}
|
||||
(v.name.to_uppercase(), v.value.clone())
|
||||
}))
|
||||
.spawn()?;
|
||||
|
||||
process.wait()?;
|
||||
|
||||
|
@ -1,12 +1,18 @@
|
||||
use std::{
|
||||
env::current_dir,
|
||||
path::PathBuf,
|
||||
sync::{Arc, Mutex},
|
||||
};
|
||||
|
||||
use anyhow::anyhow;
|
||||
use clap::Command;
|
||||
use git2::Repository;
|
||||
|
||||
use crate::{actions, context::CuddleContext, model::CuddleScript};
|
||||
use crate::{
|
||||
actions,
|
||||
context::{CuddleContext, CuddleTreeType},
|
||||
model::CuddleScript,
|
||||
};
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
#[allow(dead_code)]
|
||||
@ -21,7 +27,7 @@ impl CuddleAction {
|
||||
Self { script, path, name }
|
||||
}
|
||||
|
||||
pub fn execute(self) {
|
||||
pub fn execute(self, variables: Vec<CuddleVariable>) {
|
||||
match self.script {
|
||||
CuddleScript::Shell(_s) => {
|
||||
match actions::shell::ShellAction::new(
|
||||
@ -34,7 +40,7 @@ impl CuddleAction {
|
||||
self.name
|
||||
),
|
||||
)
|
||||
.execute()
|
||||
.execute(variables)
|
||||
{
|
||||
Ok(()) => {}
|
||||
Err(e) => {
|
||||
@ -47,26 +53,112 @@ impl CuddleAction {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
#[allow(dead_code)]
|
||||
pub struct CuddleVariable {
|
||||
pub name: String,
|
||||
pub value: String,
|
||||
}
|
||||
|
||||
impl CuddleVariable {
|
||||
pub fn new(name: String, value: String) -> Self {
|
||||
Self { name, value }
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct GitCommit {
|
||||
commit_sha: String,
|
||||
}
|
||||
|
||||
impl GitCommit {
|
||||
fn new() -> anyhow::Result<GitCommit> {
|
||||
let repo = Repository::open(current_dir().expect("having current_dir available")).map_err(
|
||||
|e| {
|
||||
log::debug!("{}", e);
|
||||
anyhow::anyhow!("could not open repository")
|
||||
},
|
||||
)?;
|
||||
let head_ref = repo
|
||||
.head()
|
||||
.map_err(|e| {
|
||||
log::warn!("{}", e);
|
||||
anyhow::anyhow!("could not get HEAD")
|
||||
})?
|
||||
.target()
|
||||
.ok_or(anyhow::anyhow!(
|
||||
"could not extract head -> target to commit_sha"
|
||||
))?;
|
||||
|
||||
Ok(Self {
|
||||
commit_sha: head_ref.to_string(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct CuddleCli<'a> {
|
||||
scripts: Vec<CuddleAction>,
|
||||
variables: Vec<CuddleVariable>,
|
||||
context: Arc<Mutex<Vec<CuddleContext>>>,
|
||||
command: Option<Command<'a>>,
|
||||
tmp_dir: Option<PathBuf>,
|
||||
}
|
||||
|
||||
impl<'a> CuddleCli<'a> {
|
||||
pub fn new(context: Arc<Mutex<Vec<CuddleContext>>>) -> anyhow::Result<CuddleCli<'a>> {
|
||||
let mut cli = CuddleCli {
|
||||
scripts: vec![],
|
||||
variables: vec![],
|
||||
context: context.clone(),
|
||||
command: None,
|
||||
tmp_dir: None,
|
||||
};
|
||||
|
||||
cli = cli.process_scripts().build_cli();
|
||||
cli = cli
|
||||
.process_variables()
|
||||
.process_scripts()
|
||||
.process_templates()?
|
||||
.build_cli();
|
||||
|
||||
Ok(cli)
|
||||
}
|
||||
|
||||
fn process_variables(mut self) -> Self {
|
||||
if let Ok(context_iter) = self.context.clone().lock() {
|
||||
for ctx in context_iter.iter() {
|
||||
if let Some(variables) = ctx.plan.vars.clone() {
|
||||
for (name, var) in variables {
|
||||
self.variables.push(CuddleVariable::new(name, var))
|
||||
}
|
||||
}
|
||||
if let CuddleTreeType::Root = ctx.node_type {
|
||||
let mut temp_path = ctx.path.clone();
|
||||
temp_path.push(".cuddle/tmp/");
|
||||
|
||||
self.variables.push(CuddleVariable::new(
|
||||
"tmp".into(),
|
||||
temp_path.clone().to_string_lossy().to_string(),
|
||||
));
|
||||
|
||||
self.tmp_dir = Some(temp_path);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
match GitCommit::new() {
|
||||
Ok(commit) => self.variables.push(CuddleVariable::new(
|
||||
"commit_sha".into(),
|
||||
commit.commit_sha.clone(),
|
||||
)),
|
||||
Err(e) => {
|
||||
log::debug!("{}", e);
|
||||
}
|
||||
}
|
||||
|
||||
self
|
||||
}
|
||||
|
||||
fn process_scripts(mut self) -> Self {
|
||||
if let Ok(context_iter) = self.context.clone().lock() {
|
||||
for ctx in context_iter.iter() {
|
||||
@ -82,25 +174,70 @@ impl<'a> CuddleCli<'a> {
|
||||
self
|
||||
}
|
||||
|
||||
fn process_templates(self) -> anyhow::Result<Self> {
|
||||
if let None = self.tmp_dir {
|
||||
log::debug!("cannot process template as bare bones cli");
|
||||
return Ok(self);
|
||||
}
|
||||
|
||||
// Make sure tmp_dir exists and clean it up first
|
||||
let tmp_dir = self
|
||||
.tmp_dir
|
||||
.clone()
|
||||
.ok_or(anyhow::anyhow!("tmp_dir does not exist aborting"))?;
|
||||
if tmp_dir.exists() && tmp_dir.ends_with("tmp") {
|
||||
std::fs::remove_dir_all(tmp_dir.clone())?;
|
||||
}
|
||||
std::fs::create_dir_all(tmp_dir.clone())?;
|
||||
// Handle all templating with variables and such.
|
||||
// TODO: use actual templating engine, for new we just copy templates to the final folder
|
||||
|
||||
if let Ok(context_iter) = self.context.clone().lock() {
|
||||
for ctx in context_iter.iter() {
|
||||
let mut template_path = ctx.path.clone();
|
||||
template_path.push("templates");
|
||||
|
||||
log::trace!("template path: {}", template_path.clone().to_string_lossy());
|
||||
|
||||
if !template_path.exists() {
|
||||
continue;
|
||||
}
|
||||
|
||||
for file in std::fs::read_dir(template_path)?.into_iter() {
|
||||
let f = file?;
|
||||
let mut dest_file = tmp_dir.clone();
|
||||
dest_file.push(f.file_name());
|
||||
|
||||
std::fs::copy(f.path(), dest_file)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(self)
|
||||
}
|
||||
|
||||
fn build_cli(mut self) -> Self {
|
||||
let mut root_cmd = Command::new("cuddle")
|
||||
.version("1.0")
|
||||
.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")
|
||||
.subcommand_required(true)
|
||||
.propagate_version(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");
|
||||
if self.scripts.len() > 0 {
|
||||
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").subcommand_required(true);
|
||||
|
||||
for script in self.scripts.iter() {
|
||||
let action_cmd = Command::new(script.name.clone());
|
||||
for script in self.scripts.iter() {
|
||||
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);
|
||||
}
|
||||
|
||||
root_cmd = root_cmd.subcommand(execute_cmd);
|
||||
}
|
||||
|
||||
root_cmd = root_cmd.subcommand(execute_cmd);
|
||||
|
||||
self.command = Some(root_cmd);
|
||||
|
||||
self
|
||||
@ -119,7 +256,7 @@ impl<'a> CuddleCli<'a> {
|
||||
log::trace!(action=name; "running action");
|
||||
match self.scripts.iter().find(|ele| ele.name == name) {
|
||||
Some(script) => {
|
||||
script.clone().execute();
|
||||
script.clone().execute(self.variables.clone());
|
||||
Ok(())
|
||||
}
|
||||
_ => (Err(anyhow!("could not find a match"))),
|
||||
|
@ -12,10 +12,17 @@ use crate::{
|
||||
model::{CuddleBase, CuddlePlan},
|
||||
};
|
||||
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub enum CuddleTreeType {
|
||||
Root,
|
||||
Leaf,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct CuddleContext {
|
||||
pub plan: CuddlePlan,
|
||||
pub path: PathBuf,
|
||||
pub node_type: CuddleTreeType,
|
||||
}
|
||||
|
||||
pub fn extract_cuddle(config: CuddleConfig) -> anyhow::Result<Arc<Mutex<Vec<CuddleContext>>>> {
|
||||
@ -41,6 +48,7 @@ pub fn extract_cuddle(config: CuddleConfig) -> anyhow::Result<Arc<Mutex<Vec<Cudd
|
||||
context.lock().unwrap().push(CuddleContext {
|
||||
plan: cuddle_plan.clone(),
|
||||
path: current_dir()?,
|
||||
node_type: CuddleTreeType::Root,
|
||||
});
|
||||
|
||||
// pull parent plan and execute recursive descent
|
||||
@ -131,6 +139,7 @@ fn recurse_parent(path: PathBuf, context: Arc<Mutex<Vec<CuddleContext>>>) -> any
|
||||
ctxs.push(CuddleContext {
|
||||
plan: cuddle_plan.clone(),
|
||||
path: path.clone(),
|
||||
node_type: CuddleTreeType::Leaf,
|
||||
});
|
||||
} else {
|
||||
return Err(anyhow::anyhow!("Could not acquire lock, aborting"));
|
||||
|
@ -1,3 +1,8 @@
|
||||
use std::{
|
||||
env::current_dir,
|
||||
sync::{Arc, Mutex},
|
||||
};
|
||||
|
||||
use config::CuddleConfig;
|
||||
|
||||
mod actions;
|
||||
@ -11,8 +16,16 @@ fn main() -> anyhow::Result<()> {
|
||||
|
||||
let config = CuddleConfig::from_env()?;
|
||||
|
||||
let context = context::extract_cuddle(config.clone())?;
|
||||
_ = cli::CuddleCli::new(context)?.execute()?;
|
||||
match git2::Repository::open(current_dir()?) {
|
||||
Ok(_) => {
|
||||
let context = context::extract_cuddle(config.clone())?;
|
||||
_ = cli::CuddleCli::new(context)?.execute()?;
|
||||
}
|
||||
Err(_) => {
|
||||
// Only build bare bones cli
|
||||
_ = cli::CuddleCli::new(Arc::new(Mutex::new(vec![])))?.execute()?;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
@ -30,5 +30,6 @@ pub enum CuddleScript {
|
||||
#[derive(Debug, Clone, PartialEq, Deserialize)]
|
||||
pub struct CuddlePlan {
|
||||
pub base: CuddleBase,
|
||||
pub vars: Option<HashMap<String, String>>,
|
||||
pub scripts: Option<HashMap<String, CuddleScript>>,
|
||||
}
|
||||
|
@ -59,14 +59,7 @@
|
||||
"title": "your collection of variables to be available to cuddle",
|
||||
"patternProperties": {
|
||||
"^.*$": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"type": "object"
|
||||
}
|
||||
]
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
|
Loading…
Reference in New Issue
Block a user