add bare cli
This commit is contained in:
parent
ba0ad9239d
commit
5da6b35ead
@ -1,8 +1,8 @@
|
|||||||
use std::{
|
use std::process::Command;
|
||||||
io::{BufRead, BufReader},
|
|
||||||
process::{Command, Stdio},
|
|
||||||
};
|
|
||||||
|
|
||||||
|
use crate::cli::CuddleVariable;
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
pub struct ShellAction {
|
pub struct ShellAction {
|
||||||
path: String,
|
path: String,
|
||||||
name: String,
|
name: String,
|
||||||
@ -13,7 +13,7 @@ impl ShellAction {
|
|||||||
Self { path, name }
|
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::debug!("executing shell action: {}", self.path.clone());
|
||||||
|
|
||||||
log::info!(
|
log::info!(
|
||||||
@ -28,18 +28,12 @@ Starting running shell action: {}
|
|||||||
|
|
||||||
let mut process = Command::new(self.path)
|
let mut process = Command::new(self.path)
|
||||||
.current_dir(".")
|
.current_dir(".")
|
||||||
//.stdout(Stdio::piped())
|
.envs(variables.iter().map(|v| {
|
||||||
//.stderr(Stdio::piped())
|
log::trace!("{:?}", v);
|
||||||
.spawn()?;
|
|
||||||
|
|
||||||
//{
|
(v.name.to_uppercase(), v.value.clone())
|
||||||
// let stdout = process.stdout.as_mut().unwrap();
|
}))
|
||||||
// let stdout_reader = BufReader::new(stdout);
|
.spawn()?;
|
||||||
// let mut stdout_lines = stdout_reader.lines();
|
|
||||||
// while let Some(Ok(line)) = stdout_lines.next() {
|
|
||||||
// log::info!("{}", line);
|
|
||||||
// }
|
|
||||||
//}
|
|
||||||
|
|
||||||
process.wait()?;
|
process.wait()?;
|
||||||
|
|
||||||
|
@ -1,12 +1,18 @@
|
|||||||
use std::{
|
use std::{
|
||||||
|
env::current_dir,
|
||||||
path::PathBuf,
|
path::PathBuf,
|
||||||
sync::{Arc, Mutex},
|
sync::{Arc, Mutex},
|
||||||
};
|
};
|
||||||
|
|
||||||
use anyhow::anyhow;
|
use anyhow::anyhow;
|
||||||
use clap::Command;
|
use clap::Command;
|
||||||
|
use git2::Repository;
|
||||||
|
|
||||||
use crate::{actions, context::CuddleContext, model::CuddleScript};
|
use crate::{
|
||||||
|
actions,
|
||||||
|
context::{CuddleContext, CuddleTreeType},
|
||||||
|
model::CuddleScript,
|
||||||
|
};
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
@ -21,7 +27,7 @@ impl CuddleAction {
|
|||||||
Self { script, path, name }
|
Self { script, path, name }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn execute(self) {
|
pub fn execute(self, variables: Vec<CuddleVariable>) {
|
||||||
match self.script {
|
match self.script {
|
||||||
CuddleScript::Shell(_s) => {
|
CuddleScript::Shell(_s) => {
|
||||||
match actions::shell::ShellAction::new(
|
match actions::shell::ShellAction::new(
|
||||||
@ -34,7 +40,7 @@ impl CuddleAction {
|
|||||||
self.name
|
self.name
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
.execute()
|
.execute(variables)
|
||||||
{
|
{
|
||||||
Ok(()) => {}
|
Ok(()) => {}
|
||||||
Err(e) => {
|
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)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct CuddleCli<'a> {
|
pub struct CuddleCli<'a> {
|
||||||
scripts: Vec<CuddleAction>,
|
scripts: Vec<CuddleAction>,
|
||||||
|
variables: Vec<CuddleVariable>,
|
||||||
context: Arc<Mutex<Vec<CuddleContext>>>,
|
context: Arc<Mutex<Vec<CuddleContext>>>,
|
||||||
command: Option<Command<'a>>,
|
command: Option<Command<'a>>,
|
||||||
|
tmp_dir: Option<PathBuf>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> CuddleCli<'a> {
|
impl<'a> CuddleCli<'a> {
|
||||||
pub fn new(context: Arc<Mutex<Vec<CuddleContext>>>) -> anyhow::Result<CuddleCli<'a>> {
|
pub fn new(context: Arc<Mutex<Vec<CuddleContext>>>) -> anyhow::Result<CuddleCli<'a>> {
|
||||||
let mut cli = CuddleCli {
|
let mut cli = CuddleCli {
|
||||||
scripts: vec![],
|
scripts: vec![],
|
||||||
|
variables: vec![],
|
||||||
context: context.clone(),
|
context: context.clone(),
|
||||||
command: None,
|
command: None,
|
||||||
|
tmp_dir: None,
|
||||||
};
|
};
|
||||||
|
|
||||||
cli = cli.process_scripts().build_cli();
|
cli = cli
|
||||||
|
.process_variables()
|
||||||
|
.process_scripts()
|
||||||
|
.process_templates()?
|
||||||
|
.build_cli();
|
||||||
|
|
||||||
Ok(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 {
|
fn process_scripts(mut self) -> Self {
|
||||||
if let Ok(context_iter) = self.context.clone().lock() {
|
if let Ok(context_iter) = self.context.clone().lock() {
|
||||||
for ctx in context_iter.iter() {
|
for ctx in context_iter.iter() {
|
||||||
@ -82,25 +174,70 @@ impl<'a> CuddleCli<'a> {
|
|||||||
self
|
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 {
|
fn build_cli(mut self) -> Self {
|
||||||
let mut root_cmd = Command::new("cuddle")
|
let mut root_cmd = Command::new("cuddle")
|
||||||
.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")
|
||||||
|
.subcommand_required(true)
|
||||||
.propagate_version(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() {
|
for script in self.scripts.iter() {
|
||||||
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
root_cmd = root_cmd.subcommand(execute_cmd);
|
||||||
}
|
}
|
||||||
|
|
||||||
root_cmd = root_cmd.subcommand(execute_cmd);
|
|
||||||
|
|
||||||
self.command = Some(root_cmd);
|
self.command = Some(root_cmd);
|
||||||
|
|
||||||
self
|
self
|
||||||
@ -119,7 +256,7 @@ impl<'a> CuddleCli<'a> {
|
|||||||
log::trace!(action=name; "running action");
|
log::trace!(action=name; "running action");
|
||||||
match self.scripts.iter().find(|ele| ele.name == name) {
|
match self.scripts.iter().find(|ele| ele.name == name) {
|
||||||
Some(script) => {
|
Some(script) => {
|
||||||
script.clone().execute();
|
script.clone().execute(self.variables.clone());
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
_ => (Err(anyhow!("could not find a match"))),
|
_ => (Err(anyhow!("could not find a match"))),
|
||||||
|
@ -12,10 +12,17 @@ use crate::{
|
|||||||
model::{CuddleBase, CuddlePlan},
|
model::{CuddleBase, CuddlePlan},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
|
pub enum CuddleTreeType {
|
||||||
|
Root,
|
||||||
|
Leaf,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct CuddleContext {
|
pub struct CuddleContext {
|
||||||
pub plan: CuddlePlan,
|
pub plan: CuddlePlan,
|
||||||
pub path: PathBuf,
|
pub path: PathBuf,
|
||||||
|
pub node_type: CuddleTreeType,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn extract_cuddle(config: CuddleConfig) -> anyhow::Result<Arc<Mutex<Vec<CuddleContext>>>> {
|
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 {
|
context.lock().unwrap().push(CuddleContext {
|
||||||
plan: cuddle_plan.clone(),
|
plan: cuddle_plan.clone(),
|
||||||
path: current_dir()?,
|
path: current_dir()?,
|
||||||
|
node_type: CuddleTreeType::Root,
|
||||||
});
|
});
|
||||||
|
|
||||||
// pull parent plan and execute recursive descent
|
// 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 {
|
ctxs.push(CuddleContext {
|
||||||
plan: cuddle_plan.clone(),
|
plan: cuddle_plan.clone(),
|
||||||
path: path.clone(),
|
path: path.clone(),
|
||||||
|
node_type: CuddleTreeType::Leaf,
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
return Err(anyhow::anyhow!("Could not acquire lock, aborting"));
|
return Err(anyhow::anyhow!("Could not acquire lock, aborting"));
|
||||||
|
@ -1,3 +1,8 @@
|
|||||||
|
use std::{
|
||||||
|
env::current_dir,
|
||||||
|
sync::{Arc, Mutex},
|
||||||
|
};
|
||||||
|
|
||||||
use config::CuddleConfig;
|
use config::CuddleConfig;
|
||||||
|
|
||||||
mod actions;
|
mod actions;
|
||||||
@ -11,8 +16,16 @@ fn main() -> anyhow::Result<()> {
|
|||||||
|
|
||||||
let config = CuddleConfig::from_env()?;
|
let config = CuddleConfig::from_env()?;
|
||||||
|
|
||||||
let context = context::extract_cuddle(config.clone())?;
|
match git2::Repository::open(current_dir()?) {
|
||||||
_ = cli::CuddleCli::new(context)?.execute()?;
|
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(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -30,5 +30,6 @@ pub enum CuddleScript {
|
|||||||
#[derive(Debug, Clone, PartialEq, Deserialize)]
|
#[derive(Debug, Clone, PartialEq, Deserialize)]
|
||||||
pub struct CuddlePlan {
|
pub struct CuddlePlan {
|
||||||
pub base: CuddleBase,
|
pub base: CuddleBase,
|
||||||
|
pub vars: Option<HashMap<String, String>>,
|
||||||
pub scripts: Option<HashMap<String, CuddleScript>>,
|
pub scripts: Option<HashMap<String, CuddleScript>>,
|
||||||
}
|
}
|
||||||
|
@ -59,14 +59,7 @@
|
|||||||
"title": "your collection of variables to be available to cuddle",
|
"title": "your collection of variables to be available to cuddle",
|
||||||
"patternProperties": {
|
"patternProperties": {
|
||||||
"^.*$": {
|
"^.*$": {
|
||||||
"anyOf": [
|
"type": "string"
|
||||||
{
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "object"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"additionalProperties": false
|
"additionalProperties": false
|
||||||
|
Loading…
Reference in New Issue
Block a user