Added cli for subcommands
This commit is contained in:
parent
6f1f21f710
commit
f5e1e3027a
72
Cargo.lock
generated
72
Cargo.lock
generated
@ -8,6 +8,17 @@ version = "1.0.60"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "c794e162a5eff65c72ef524dfe393eb923c354e350bb78b9c7383df13f3bc142"
|
checksum = "c794e162a5eff65c72ef524dfe393eb923c354e350bb78b9c7383df13f3bc142"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "atty"
|
||||||
|
version = "0.2.14"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8"
|
||||||
|
dependencies = [
|
||||||
|
"hermit-abi",
|
||||||
|
"libc",
|
||||||
|
"winapi",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "autocfg"
|
name = "autocfg"
|
||||||
version = "1.1.0"
|
version = "1.1.0"
|
||||||
@ -39,11 +50,36 @@ version = "1.0.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "clap"
|
||||||
|
version = "3.2.16"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a3dbbb6653e7c55cc8595ad3e1f7be8f32aba4eb7ff7f0fd1163d4f3d137c0a9"
|
||||||
|
dependencies = [
|
||||||
|
"atty",
|
||||||
|
"bitflags",
|
||||||
|
"clap_lex",
|
||||||
|
"indexmap",
|
||||||
|
"strsim",
|
||||||
|
"termcolor",
|
||||||
|
"textwrap",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "clap_lex"
|
||||||
|
version = "0.2.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "2850f2f5a82cbf437dd5af4d49848fbdfc27c157c3d010345776f952765261c5"
|
||||||
|
dependencies = [
|
||||||
|
"os_str_bytes",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cuddle_cli"
|
name = "cuddle_cli"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
|
"clap",
|
||||||
"git2",
|
"git2",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_yaml",
|
"serde_yaml",
|
||||||
@ -81,6 +117,15 @@ version = "0.12.3"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888"
|
checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "hermit-abi"
|
||||||
|
version = "0.1.19"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "idna"
|
name = "idna"
|
||||||
version = "0.2.3"
|
version = "0.2.3"
|
||||||
@ -197,6 +242,12 @@ dependencies = [
|
|||||||
"vcpkg",
|
"vcpkg",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "os_str_bytes"
|
||||||
|
version = "6.2.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "648001efe5d5c0102d8cea768e348da85d90af8ba91f0bea908f157951493cd4"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "percent-encoding"
|
name = "percent-encoding"
|
||||||
version = "2.1.0"
|
version = "2.1.0"
|
||||||
@ -275,6 +326,12 @@ dependencies = [
|
|||||||
"unsafe-libyaml",
|
"unsafe-libyaml",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "strsim"
|
||||||
|
version = "0.10.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "syn"
|
name = "syn"
|
||||||
version = "1.0.99"
|
version = "1.0.99"
|
||||||
@ -286,6 +343,21 @@ dependencies = [
|
|||||||
"unicode-ident",
|
"unicode-ident",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "termcolor"
|
||||||
|
version = "1.1.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "bab24d30b911b2376f3a13cc2cd443142f0c81dda04c118693e35b3835757755"
|
||||||
|
dependencies = [
|
||||||
|
"winapi-util",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "textwrap"
|
||||||
|
version = "0.15.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b1141d4d61095b28419e22cb0bbf02755f5e54e0526f97f1e3d1d160e60885fb"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tinyvec"
|
name = "tinyvec"
|
||||||
version = "1.6.0"
|
version = "1.6.0"
|
||||||
|
5
\
Normal file
5
\
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
#[derive(Debug)]
|
||||||
|
pub struct CuddleContext {
|
||||||
|
pub plan: CuddlePlan,
|
||||||
|
pub path: PathBuf,
|
||||||
|
}
|
@ -11,3 +11,4 @@ serde = { version = "1.0.143", features = ["derive"] }
|
|||||||
serde_yaml = "0.9.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"
|
||||||
|
97
cuddle_cli/src/cli.rs
Normal file
97
cuddle_cli/src/cli.rs
Normal file
@ -0,0 +1,97 @@
|
|||||||
|
use std::{
|
||||||
|
path::PathBuf,
|
||||||
|
sync::{Arc, Mutex},
|
||||||
|
};
|
||||||
|
|
||||||
|
use clap::Command;
|
||||||
|
|
||||||
|
use crate::{context::CuddleContext, model::CuddleScript};
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
#[allow(dead_code)]
|
||||||
|
struct CuddleAction {
|
||||||
|
script: CuddleScript,
|
||||||
|
path: PathBuf,
|
||||||
|
name: String,
|
||||||
|
}
|
||||||
|
#[allow(dead_code)]
|
||||||
|
impl CuddleAction {
|
||||||
|
pub fn new(script: CuddleScript, path: PathBuf, name: String) -> Self {
|
||||||
|
Self { script, path, name }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn execute(self) {
|
||||||
|
match self.script {
|
||||||
|
CuddleScript::Shell(s) => {}
|
||||||
|
CuddleScript::Dagger(d) => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct CuddleCli<'a> {
|
||||||
|
scripts: Vec<CuddleAction>,
|
||||||
|
context: Arc<Mutex<Vec<CuddleContext>>>,
|
||||||
|
command: Option<Command<'a>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> CuddleCli<'a> {
|
||||||
|
pub fn new(context: Arc<Mutex<Vec<CuddleContext>>>) -> anyhow::Result<CuddleCli<'a>> {
|
||||||
|
let mut cli = CuddleCli {
|
||||||
|
scripts: vec![],
|
||||||
|
context: context.clone(),
|
||||||
|
command: None,
|
||||||
|
};
|
||||||
|
|
||||||
|
cli = cli.process_scripts().build_cli();
|
||||||
|
|
||||||
|
Ok(cli)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn process_scripts(mut self) -> Self {
|
||||||
|
if let Ok(context_iter) = self.context.clone().lock() {
|
||||||
|
for ctx in context_iter.iter() {
|
||||||
|
if let Some(scripts) = ctx.plan.scripts.clone() {
|
||||||
|
for (name, script) in scripts {
|
||||||
|
self.scripts
|
||||||
|
.push(CuddleAction::new(script.clone(), ctx.path.clone(), name))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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")
|
||||||
|
.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");
|
||||||
|
|
||||||
|
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
|
||||||
|
execute_cmd = execute_cmd.subcommand(action_cmd);
|
||||||
|
}
|
||||||
|
|
||||||
|
root_cmd = root_cmd.subcommand(execute_cmd);
|
||||||
|
|
||||||
|
self.command = Some(root_cmd);
|
||||||
|
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn execute(self) -> Self {
|
||||||
|
if let Some(cli) = self.command.clone() {
|
||||||
|
let _ = cli.get_matches();
|
||||||
|
}
|
||||||
|
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
179
cuddle_cli/src/context.rs
Normal file
179
cuddle_cli/src/context.rs
Normal file
@ -0,0 +1,179 @@
|
|||||||
|
use std::{
|
||||||
|
env::{self, current_dir},
|
||||||
|
ffi::OsStr,
|
||||||
|
path::{Path, PathBuf},
|
||||||
|
sync::{Arc, Mutex},
|
||||||
|
};
|
||||||
|
|
||||||
|
use git2::{build::RepoBuilder, FetchOptions, RemoteCallbacks};
|
||||||
|
|
||||||
|
use crate::model::{CuddleBase, CuddlePlan};
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct CuddleContext {
|
||||||
|
pub plan: CuddlePlan,
|
||||||
|
pub path: PathBuf,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn extract_cuddle() -> anyhow::Result<Arc<Mutex<Vec<CuddleContext>>>> {
|
||||||
|
let mut curr_dir = current_dir()?;
|
||||||
|
curr_dir.push(".cuddle/");
|
||||||
|
if let Err(res) = std::fs::remove_dir_all(curr_dir) {
|
||||||
|
println!("{}", res);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Load main cuddle file
|
||||||
|
let cuddle_yaml = find_root_cuddle()?;
|
||||||
|
// TODO: Set trace
|
||||||
|
println!("{}", cuddle_yaml);
|
||||||
|
let cuddle_plan = serde_yaml::from_str::<CuddlePlan>(cuddle_yaml.as_str())?;
|
||||||
|
|
||||||
|
// TODO: Set debug
|
||||||
|
println!("{:?}", cuddle_plan);
|
||||||
|
|
||||||
|
let context: Arc<Mutex<Vec<CuddleContext>>> = Arc::new(Mutex::new(Vec::new()));
|
||||||
|
context.lock().unwrap().push(CuddleContext {
|
||||||
|
plan: cuddle_plan.clone(),
|
||||||
|
path: current_dir()?,
|
||||||
|
});
|
||||||
|
|
||||||
|
// pull parent plan and execute recursive descent
|
||||||
|
match cuddle_plan.base {
|
||||||
|
CuddleBase::Bool(true) => {
|
||||||
|
return Err(anyhow::anyhow!(
|
||||||
|
"plan cannot be enabled without specifying a plan"
|
||||||
|
))
|
||||||
|
}
|
||||||
|
CuddleBase::Bool(false) => {
|
||||||
|
println!("plan is root skipping")
|
||||||
|
}
|
||||||
|
CuddleBase::String(parent_plan) => {
|
||||||
|
let destination_path = create_cuddle_local()?;
|
||||||
|
let mut cuddle_dest = destination_path.clone();
|
||||||
|
cuddle_dest.push("base");
|
||||||
|
|
||||||
|
pull_parent_cuddle_into_local(parent_plan, cuddle_dest.clone())?;
|
||||||
|
recurse_parent(cuddle_dest, context.clone())?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Ok(ctx) = context.clone().lock() {
|
||||||
|
// TODO: set trace
|
||||||
|
println!("{:?}", ctx)
|
||||||
|
} else {
|
||||||
|
return Err(anyhow::anyhow!("could not acquire lock"));
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(context)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn create_cuddle_local() -> anyhow::Result<PathBuf> {
|
||||||
|
let mut curr_dir = current_dir()?;
|
||||||
|
curr_dir.push(".cuddle/");
|
||||||
|
|
||||||
|
if curr_dir.exists() {
|
||||||
|
println!(".cuddle already exists skipping");
|
||||||
|
return Ok(curr_dir);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::fs::create_dir(curr_dir.clone())?;
|
||||||
|
|
||||||
|
Ok(curr_dir)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn create_cuddle(path: PathBuf) -> anyhow::Result<PathBuf> {
|
||||||
|
let mut curr_dir = path.clone();
|
||||||
|
curr_dir.push(".cuddle/");
|
||||||
|
|
||||||
|
if curr_dir.exists() {
|
||||||
|
println!(".cuddle already exists skipping");
|
||||||
|
return Ok(curr_dir);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::fs::create_dir(curr_dir.clone())?;
|
||||||
|
|
||||||
|
Ok(curr_dir)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn pull_parent_cuddle_into_local(
|
||||||
|
parent_cuddle: String,
|
||||||
|
destination: PathBuf,
|
||||||
|
) -> anyhow::Result<()> {
|
||||||
|
let mut rc = RemoteCallbacks::new();
|
||||||
|
rc.credentials(|_url, username_from_url, _allowed_types| {
|
||||||
|
git2::Cred::ssh_key(
|
||||||
|
username_from_url.unwrap(),
|
||||||
|
None,
|
||||||
|
Path::new(&format!("{}/.ssh/id_ed25519", env::var("HOME").unwrap())),
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
});
|
||||||
|
|
||||||
|
let mut fo = FetchOptions::new();
|
||||||
|
fo.remote_callbacks(rc);
|
||||||
|
|
||||||
|
RepoBuilder::new()
|
||||||
|
.fetch_options(fo)
|
||||||
|
.clone(&parent_cuddle, &destination)?;
|
||||||
|
|
||||||
|
println!("pulled: {}", parent_cuddle);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn recurse_parent(path: PathBuf, context: Arc<Mutex<Vec<CuddleContext>>>) -> anyhow::Result<()> {
|
||||||
|
let cuddle_contents = find_cuddle(path.clone())?;
|
||||||
|
let cuddle_plan = serde_yaml::from_str::<CuddlePlan>(&cuddle_contents)?;
|
||||||
|
|
||||||
|
let ctx = context.clone();
|
||||||
|
if let Ok(mut ctxs) = ctx.lock() {
|
||||||
|
ctxs.push(CuddleContext {
|
||||||
|
plan: cuddle_plan.clone(),
|
||||||
|
path: path.clone(),
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
return Err(anyhow::anyhow!("Could not acquire lock, aborting"));
|
||||||
|
}
|
||||||
|
|
||||||
|
match cuddle_plan.base {
|
||||||
|
CuddleBase::Bool(true) => {
|
||||||
|
return Err(anyhow::anyhow!(
|
||||||
|
"plan cannot be enabled without specifying a plan"
|
||||||
|
))
|
||||||
|
}
|
||||||
|
CuddleBase::Bool(false) => {
|
||||||
|
println!("plan is root, finishing up");
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
CuddleBase::String(parent_plan) => {
|
||||||
|
let destination_path = create_cuddle(path.clone())?;
|
||||||
|
let mut cuddle_dest = destination_path.clone();
|
||||||
|
cuddle_dest.push("base");
|
||||||
|
|
||||||
|
pull_parent_cuddle_into_local(parent_plan, cuddle_dest.clone())?;
|
||||||
|
return recurse_parent(cuddle_dest, context.clone());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn find_root_cuddle() -> anyhow::Result<String> {
|
||||||
|
// TODO: Make recursive towards root
|
||||||
|
let current_dir = env::current_dir()?;
|
||||||
|
find_cuddle(current_dir)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn find_cuddle(path: PathBuf) -> anyhow::Result<String> {
|
||||||
|
for entry in std::fs::read_dir(path)? {
|
||||||
|
let entry = entry?;
|
||||||
|
let path = entry.path();
|
||||||
|
|
||||||
|
let metadata = std::fs::metadata(&path)?;
|
||||||
|
if metadata.is_file() && path.file_name().unwrap() == OsStr::new("cuddle.yaml") {
|
||||||
|
return Ok(std::fs::read_to_string(path)?);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Err(anyhow::anyhow!(
|
||||||
|
"Could not find 'cuddle.yaml' in the current directory"
|
||||||
|
))
|
||||||
|
}
|
@ -1,205 +1,13 @@
|
|||||||
use std::{
|
mod cli;
|
||||||
collections::HashMap,
|
mod context;
|
||||||
env::{self, current_dir},
|
mod model;
|
||||||
ffi::OsStr,
|
|
||||||
path::{Path, PathBuf},
|
|
||||||
sync::{Arc, Mutex},
|
|
||||||
};
|
|
||||||
|
|
||||||
use git2::{build::RepoBuilder, FetchOptions, RemoteCallbacks};
|
|
||||||
use serde::Deserialize;
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Deserialize)]
|
|
||||||
#[serde(untagged)]
|
|
||||||
enum CuddleBase {
|
|
||||||
Bool(bool),
|
|
||||||
String(String),
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Deserialize)]
|
|
||||||
struct CuddleShellScript {}
|
|
||||||
#[derive(Debug, Clone, PartialEq, Deserialize)]
|
|
||||||
struct CuddleDaggerScript {}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Deserialize)]
|
|
||||||
#[serde(tag = "type")]
|
|
||||||
enum CuddleScript {
|
|
||||||
#[serde(alias = "shell")]
|
|
||||||
Shell(CuddleShellScript),
|
|
||||||
#[serde(alias = "dagger")]
|
|
||||||
Dagger(CuddleDaggerScript),
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Deserialize)]
|
|
||||||
struct CuddlePlan {
|
|
||||||
pub base: CuddleBase,
|
|
||||||
pub scripts: Option<HashMap<String, CuddleScript>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
struct CuddleContext {
|
|
||||||
pub plan: CuddlePlan,
|
|
||||||
pub path: PathBuf,
|
|
||||||
}
|
|
||||||
|
|
||||||
fn main() -> anyhow::Result<()> {
|
fn main() -> anyhow::Result<()> {
|
||||||
let mut curr_dir = current_dir()?;
|
let context = context::extract_cuddle()?;
|
||||||
curr_dir.push(".cuddle/");
|
let mut cuddle_cli = cli::CuddleCli::new(context.clone())?;
|
||||||
if let Err(res) = std::fs::remove_dir_all(curr_dir) {
|
cuddle_cli = cuddle_cli.execute();
|
||||||
println!("{}", res);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Load main cuddle file
|
println!("{:?}", cuddle_cli);
|
||||||
let cuddle_yaml = find_root_cuddle()?;
|
|
||||||
// TODO: Set trace
|
|
||||||
println!("{}", cuddle_yaml);
|
|
||||||
let cuddle_plan = serde_yaml::from_str::<CuddlePlan>(cuddle_yaml.as_str())?;
|
|
||||||
|
|
||||||
// TODO: Set debug
|
|
||||||
println!("{:?}", cuddle_plan);
|
|
||||||
|
|
||||||
let context: Arc<Mutex<Vec<CuddleContext>>> = Arc::new(Mutex::new(Vec::new()));
|
|
||||||
context.lock().unwrap().push(CuddleContext {
|
|
||||||
plan: cuddle_plan.clone(),
|
|
||||||
path: current_dir()?,
|
|
||||||
});
|
|
||||||
|
|
||||||
// pull parent plan and execute recursive descent
|
|
||||||
match cuddle_plan.base {
|
|
||||||
CuddleBase::Bool(true) => {
|
|
||||||
return Err(anyhow::anyhow!(
|
|
||||||
"plan cannot be enabled without specifying a plan"
|
|
||||||
))
|
|
||||||
}
|
|
||||||
CuddleBase::Bool(false) => {
|
|
||||||
println!("plan is root skipping")
|
|
||||||
}
|
|
||||||
CuddleBase::String(parent_plan) => {
|
|
||||||
let destination_path = create_cuddle_local()?;
|
|
||||||
let mut cuddle_dest = destination_path.clone();
|
|
||||||
cuddle_dest.push("base");
|
|
||||||
|
|
||||||
pull_parent_cuddle_into_local(parent_plan, cuddle_dest.clone())?;
|
|
||||||
recurse_parent(cuddle_dest, context.clone())?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Ok(ctx) = context.lock() {
|
|
||||||
println!("{:?}", ctx)
|
|
||||||
} else {
|
|
||||||
return Err(anyhow::anyhow!("could not acquire lock"));
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn create_cuddle_local() -> anyhow::Result<PathBuf> {
|
|
||||||
let mut curr_dir = current_dir()?;
|
|
||||||
curr_dir.push(".cuddle/");
|
|
||||||
|
|
||||||
if curr_dir.exists() {
|
|
||||||
println!(".cuddle already exists skipping");
|
|
||||||
return Ok(curr_dir);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::fs::create_dir(curr_dir.clone())?;
|
|
||||||
|
|
||||||
Ok(curr_dir)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn create_cuddle(path: PathBuf) -> anyhow::Result<PathBuf> {
|
|
||||||
let mut curr_dir = path.clone();
|
|
||||||
curr_dir.push(".cuddle/");
|
|
||||||
|
|
||||||
if curr_dir.exists() {
|
|
||||||
println!(".cuddle already exists skipping");
|
|
||||||
return Ok(curr_dir);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::fs::create_dir(curr_dir.clone())?;
|
|
||||||
|
|
||||||
Ok(curr_dir)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn pull_parent_cuddle_into_local(
|
|
||||||
parent_cuddle: String,
|
|
||||||
destination: PathBuf,
|
|
||||||
) -> anyhow::Result<()> {
|
|
||||||
let mut rc = RemoteCallbacks::new();
|
|
||||||
rc.credentials(|_url, username_from_url, _allowed_types| {
|
|
||||||
git2::Cred::ssh_key(
|
|
||||||
username_from_url.unwrap(),
|
|
||||||
None,
|
|
||||||
Path::new(&format!("{}/.ssh/id_ed25519", env::var("HOME").unwrap())),
|
|
||||||
None,
|
|
||||||
)
|
|
||||||
});
|
|
||||||
|
|
||||||
let mut fo = FetchOptions::new();
|
|
||||||
fo.remote_callbacks(rc);
|
|
||||||
|
|
||||||
RepoBuilder::new()
|
|
||||||
.fetch_options(fo)
|
|
||||||
.clone(&parent_cuddle, &destination)?;
|
|
||||||
|
|
||||||
println!("pulled: {}", parent_cuddle);
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn recurse_parent(path: PathBuf, context: Arc<Mutex<Vec<CuddleContext>>>) -> anyhow::Result<()> {
|
|
||||||
let cuddle_contents = find_cuddle(path.clone())?;
|
|
||||||
let cuddle_plan = serde_yaml::from_str::<CuddlePlan>(&cuddle_contents)?;
|
|
||||||
|
|
||||||
let ctx = context.clone();
|
|
||||||
if let Ok(mut ctxs) = ctx.lock() {
|
|
||||||
ctxs.push(CuddleContext {
|
|
||||||
plan: cuddle_plan.clone(),
|
|
||||||
path: path.clone(),
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
return Err(anyhow::anyhow!("Could not acquire lock, aborting"));
|
|
||||||
}
|
|
||||||
|
|
||||||
match cuddle_plan.base {
|
|
||||||
CuddleBase::Bool(true) => {
|
|
||||||
return Err(anyhow::anyhow!(
|
|
||||||
"plan cannot be enabled without specifying a plan"
|
|
||||||
))
|
|
||||||
}
|
|
||||||
CuddleBase::Bool(false) => {
|
|
||||||
println!("plan is root, finishing up");
|
|
||||||
return Ok(());
|
|
||||||
}
|
|
||||||
CuddleBase::String(parent_plan) => {
|
|
||||||
let destination_path = create_cuddle(path.clone())?;
|
|
||||||
let mut cuddle_dest = destination_path.clone();
|
|
||||||
cuddle_dest.push("base");
|
|
||||||
|
|
||||||
pull_parent_cuddle_into_local(parent_plan, cuddle_dest.clone())?;
|
|
||||||
return recurse_parent(cuddle_dest, context.clone());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn find_root_cuddle() -> anyhow::Result<String> {
|
|
||||||
// TODO: Make recursive towards root
|
|
||||||
let current_dir = env::current_dir()?;
|
|
||||||
find_cuddle(current_dir)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn find_cuddle(path: PathBuf) -> anyhow::Result<String> {
|
|
||||||
for entry in std::fs::read_dir(path)? {
|
|
||||||
let entry = entry?;
|
|
||||||
let path = entry.path();
|
|
||||||
|
|
||||||
let metadata = std::fs::metadata(&path)?;
|
|
||||||
if metadata.is_file() && path.file_name().unwrap() == OsStr::new("cuddle.yaml") {
|
|
||||||
return Ok(std::fs::read_to_string(path)?);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Err(anyhow::anyhow!(
|
|
||||||
"Could not find 'cuddle.yaml' in the current directory"
|
|
||||||
))
|
|
||||||
}
|
|
||||||
|
34
cuddle_cli/src/model.rs
Normal file
34
cuddle_cli/src/model.rs
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
|
use serde::Deserialize;
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq, Deserialize)]
|
||||||
|
#[serde(untagged)]
|
||||||
|
pub enum CuddleBase {
|
||||||
|
Bool(bool),
|
||||||
|
String(String),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq, Deserialize)]
|
||||||
|
pub struct CuddleShellScript {
|
||||||
|
pub description: Option<String>,
|
||||||
|
}
|
||||||
|
#[derive(Debug, Clone, PartialEq, Deserialize)]
|
||||||
|
pub struct CuddleDaggerScript {
|
||||||
|
pub description: Option<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq, Deserialize)]
|
||||||
|
#[serde(tag = "type")]
|
||||||
|
pub enum CuddleScript {
|
||||||
|
#[serde(alias = "shell")]
|
||||||
|
Shell(CuddleShellScript),
|
||||||
|
#[serde(alias = "dagger")]
|
||||||
|
Dagger(CuddleDaggerScript),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq, Deserialize)]
|
||||||
|
pub struct CuddlePlan {
|
||||||
|
pub base: CuddleBase,
|
||||||
|
pub scripts: Option<HashMap<String, CuddleScript>>,
|
||||||
|
}
|
@ -5,3 +5,4 @@ base: "git@git.front.kjuulh.io:kjuulh/cuddle-rust-plan.git"
|
|||||||
scripts:
|
scripts:
|
||||||
build:
|
build:
|
||||||
type: shell
|
type: shell
|
||||||
|
description: "build rust plan"
|
||||||
|
@ -31,6 +31,9 @@
|
|||||||
"shell",
|
"shell",
|
||||||
"dagger"
|
"dagger"
|
||||||
]
|
]
|
||||||
|
},
|
||||||
|
"description": {
|
||||||
|
"type": "string"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user