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]]
name = "arkham"
version = "0.1.1"
version = "0.1.0"
dependencies = [
"console",
]

View File

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

View File

@ -1,6 +1,9 @@
use crate::definition::Project;
use actix::prelude::*;
use arkham::{App, Command};
use runner::Manager;
use std::env;
use std::path::{Path, PathBuf};
mod definition;
mod job;
@ -23,7 +26,32 @@ async fn main() {
let manager = Manager::new().start();
manager.do_send(jobs);
find_config("conductor.yml");
actix_rt::signal::ctrl_c()
.await
.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;
}
}
}