This commit is contained in:
Joe Bellus 2021-11-13 01:53:44 -05:00
parent b624dc3b34
commit 39399f93db
4 changed files with 151 additions and 56 deletions

2
Cargo.lock generated
View File

@ -60,7 +60,7 @@ dependencies = [
[[package]] [[package]]
name = "arkham" name = "arkham"
version = "0.1.1" version = "0.1.0"
dependencies = [ dependencies = [
"console", "console",
] ]

View File

@ -5,7 +5,7 @@ use std::collections::HashMap;
#[derive(Serialize, Deserialize, Default)] #[derive(Serialize, Deserialize, Default)]
#[serde(default)] #[serde(default)]
pub struct Project { pub struct Project {
pub components: Vec<Component>, pub components: HashMap<String, Component>,
pub groups: Vec<Group>, pub groups: Vec<Group>,
pub env: HashMap<String, String>, pub env: HashMap<String, String>,
pub tasks: Vec<TaskDefinition>, pub tasks: Vec<TaskDefinition>,
@ -30,13 +30,13 @@ impl Project {
Jobs::new(jobs) Jobs::new(jobs)
}) })
.or_else(|| { .or_else(|| {
self.components.iter().find_map(|component| { self.components.iter().find_map(|(c_name, component)| {
component component
.tasks .tasks
.iter() .iter()
.find(|t| format!("{}:{}", component.name, t.name) == name) .find(|t| format!("{}:{}", c_name, t.name) == name)
.map(|task| { .map(|task| {
let job = self.build_component_task_job(component, task); let job = self.build_component_task_job(c_name, component, task);
let mut jobs = task let mut jobs = task
.before .before
.iter() .iter()
@ -53,13 +53,13 @@ impl Project {
} }
fn get_relative_task(&self, task_name: &str, component_name: &str) -> Option<Jobs> { fn get_relative_task(&self, task_name: &str, component_name: &str) -> Option<Jobs> {
if let Some(component) = self.components.iter().find(|c| c.name == component_name) { if let Some(component) = self.components.get(component_name) {
component component
.tasks .tasks
.iter() .iter()
.find(|t| t.name == task_name) .find(|t| t.name == task_name)
.map(|task| { .map(|task| {
let job = self.build_component_task_job(component, task); let job = self.build_component_task_job(component_name, component, task);
let mut jobs = task let mut jobs = task
.before .before
.iter() .iter()
@ -76,9 +76,9 @@ impl Project {
} }
} }
fn get_component(&self, name: &str) -> Option<Jobs> { fn get_component(&self, component_name: &str) -> Option<Jobs> {
self.components.iter().find(|c| c.name == name).map(|c| { self.components.get(component_name).map(|c| {
let component_job = self.build_component_job(c); let component_job = self.build_component_job(component_name, c);
let mut absolute_tasks = c let mut absolute_tasks = c
.before .before
.iter() .iter()
@ -90,7 +90,7 @@ impl Project {
let mut relative_tasks = c let mut relative_tasks = c
.before .before
.iter() .iter()
.map(|name| self.get_relative_task(name, &c.name)) .map(|task_name| self.get_relative_task(task_name, &component_name))
.flatten() .flatten()
.map(|jobs| jobs.to_vec()) .map(|jobs| jobs.to_vec())
.flatten() .flatten()
@ -102,11 +102,22 @@ impl Project {
}) })
} }
fn build_component_job(&self, c: &Component) -> Job { fn get_group(&self, name: &str) -> Option<Vec<Jobs>> {
self.groups.iter().find(|g| g.name == name).map(|group| {
group
.components
.iter()
.map(|name| self.get_by_name(&name))
.flatten()
.collect()
})
}
fn build_component_job(&self, name: &str, c: &Component) -> Job {
let mut env = self.env.clone(); let mut env = self.env.clone();
env.extend(c.env.clone()); env.extend(c.env.clone());
Job { Job {
name: c.name.clone(), name: name.to_string(),
env, env,
..Job::default() ..Job::default()
} }
@ -121,12 +132,17 @@ impl Project {
} }
} }
fn build_component_task_job(&self, component: &Component, task: &TaskDefinition) -> Job { fn build_component_task_job(
&self,
cmp_name: &str,
component: &Component,
task: &TaskDefinition,
) -> Job {
let mut env = self.env.clone(); let mut env = self.env.clone();
env.extend(component.env.clone()); env.extend(component.env.clone());
env.extend(task.env.clone()); env.extend(task.env.clone());
Job { Job {
name: format!("{}:{}", component.name.clone(), task.name.clone()), name: format!("{}:{}", cmp_name.to_string(), task.name.clone()),
env, env,
..Job::default() ..Job::default()
} }
@ -135,6 +151,15 @@ impl Project {
pub fn get_by_name(&self, name: &str) -> Option<Jobs> { pub fn get_by_name(&self, name: &str) -> Option<Jobs> {
self.get_component(name) self.get_component(name)
.or_else(|| self.get_absolute_task(name)) .or_else(|| self.get_absolute_task(name))
.or_else(|| {
self.get_group(name).map(|v| {
v.iter()
.map(|jobs| jobs.to_vec())
.flatten()
.collect::<Vec<_>>()
.into()
})
})
} }
pub fn from_str(s: &str) -> Self { pub fn from_str(s: &str) -> Self {
@ -146,15 +171,13 @@ impl Project {
#[serde(default)] #[serde(default)]
pub struct Group { pub struct Group {
name: String, name: String,
components: Vec<Component>, components: Vec<String>,
env: HashMap<String, String>,
} }
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize)]
#[serde(default)] #[serde(default)]
pub struct Component { pub struct Component {
pub env: HashMap<String, String>, pub env: HashMap<String, String>,
pub name: String,
pub command: String, pub command: String,
pub path: Option<String>, pub path: Option<String>,
pub retry: bool, pub retry: bool,
@ -168,7 +191,6 @@ impl Default for Component {
fn default() -> Self { fn default() -> Self {
Self { Self {
env: HashMap::new(), env: HashMap::new(),
name: "UNNAMED".to_string(),
command: String::new(), command: String::new(),
path: None, path: None,
retry: false, retry: false,
@ -202,7 +224,7 @@ mod tests {
let project = Project::from_str( let project = Project::from_str(
r#" r#"
components: components:
- name: test-component test-component: {}
"#, "#,
); );
@ -228,9 +250,9 @@ mod tests {
let project = Project::from_str( let project = Project::from_str(
r#" r#"
components: components:
- name: c1 c1:
tasks: tasks:
- name: task1 - name: task1
"#, "#,
); );
@ -243,11 +265,11 @@ mod tests {
let project = Project::from_str( let project = Project::from_str(
r#" r#"
components: components:
- name: main-cmp main-cmp:
before: before:
- main-cmp:sub-task - main-cmp:sub-task
tasks: tasks:
- name: sub-task - name: sub-task
"#, "#,
); );
@ -257,15 +279,15 @@ mod tests {
} }
#[test] #[test]
fn component_dependent_relative_component_task() { fn component_dependent_relative() {
let project = Project::from_str( let project = Project::from_str(
r#" r#"
components: components:
- name: main-cmp main-cmp:
before: before:
- sub-task - sub-task
tasks: tasks:
- name: sub-task - name: sub-task
"#, "#,
); );
@ -279,19 +301,19 @@ mod tests {
let project = Project::from_str( let project = Project::from_str(
r#" r#"
components: components:
- name: ui ui:
before:
- build-ui
tasks:
- name: build-ui
- name: server
before:
- setup
tasks:
- name: setup
- name: build
before: before:
- server:setup - build-ui
tasks:
- name: build-ui
server:
before:
- setup
tasks:
- name: setup
- name: build
before:
- server:setup
tasks: tasks:
- name: build - name: build
before: before:
@ -316,9 +338,9 @@ mod tests {
foo: one foo: one
sub: two sub: two
components: components:
- name: main-cmp main-cmp:
env: env:
sub: three sub: three
"#, "#,
); );
@ -337,13 +359,13 @@ mod tests {
foo: one foo: one
sub: two sub: two
components: components:
- name: main-cmp main-cmp:
env: env:
sub: three sub: three
tasks: tasks:
- name: t - name: t
env: env:
foo: four foo: four
"#, "#,
); );
@ -353,4 +375,43 @@ mod tests {
assert_eq!(job.env.get("sub"), Some(&String::from("three"))); assert_eq!(job.env.get("sub"), Some(&String::from("three")));
assert_eq!(job.env.get("root"), Some(&String::from("ten"))); assert_eq!(job.env.get("root"), Some(&String::from("ten")));
} }
#[test]
fn group() {
let project = Project::from_str(
r#"
groups:
- name: all
components:
- ui
- server
components:
ui:
before:
- build-ui
tasks:
- name: build-ui
server:
before:
- setup
tasks:
- name: setup
- name: build
before:
- server:setup
tasks:
- name: build
before:
- ui:build-ui
- server:build
"#,
);
let jobs = project.get_by_name("all").unwrap();
println!("{:?}", jobs);
assert_eq!(jobs.get(0).unwrap().name, "ui:build-ui");
assert_eq!(jobs.get(1).unwrap().name, "ui");
assert_eq!(jobs.get(2).unwrap().name, "server:setup");
assert_eq!(jobs.get(3).unwrap().name, "server");
assert_eq!(jobs.len(), 4);
}
} }

View File

@ -39,6 +39,12 @@ impl DerefMut for Jobs {
} }
} }
impl From<Vec<Job>> for Jobs {
fn from(fr: Vec<Job>) -> Self {
Jobs::new(fr)
}
}
#[derive(Clone, Debug, Message)] #[derive(Clone, Debug, Message)]
#[rtype(result = "()")] #[rtype(result = "()")]
pub struct Job { pub struct Job {

View File

@ -1,6 +1,9 @@
use crate::definition::Project; use crate::definition::Project;
use actix::prelude::*; use actix::prelude::*;
use arkham::{App, Command};
use runner::Manager; use runner::Manager;
use std::env;
use std::path::{Path, PathBuf};
mod definition; mod definition;
mod job; mod job;
@ -23,7 +26,32 @@ async fn main() {
let manager = Manager::new().start(); let manager = Manager::new().start();
manager.do_send(jobs); manager.do_send(jobs);
find_config("conductor.yml");
actix_rt::signal::ctrl_c() actix_rt::signal::ctrl_c()
.await .await
.expect("failed to listen for event"); .expect("failed to listen for event");
} }
fn find_config(config: &str) -> Option<PathBuf> {
env::current_dir()
.map(|dir| find_file(&dir, config))
.unwrap_or(None)
}
fn find_file(starting_directory: &Path, filename: &str) -> Option<PathBuf> {
let mut path: PathBuf = starting_directory.into();
let file = Path::new(&filename);
loop {
path.push(file);
if path.is_file() {
break Some(path);
}
if !(path.pop() && path.pop()) {
break None;
}
}
}