|
|
@ -10,12 +10,12 @@ use std::collections::HashMap; |
|
|
|
use std::process::exit; |
|
|
|
use std::process::exit; |
|
|
|
use tokio::process::Command; |
|
|
|
use tokio::process::Command; |
|
|
|
|
|
|
|
|
|
|
|
pub struct UnnamedJobsBatch { |
|
|
|
pub struct AnonymousJobBatch { |
|
|
|
waiter: Waiter, |
|
|
|
waiter: Waiter, |
|
|
|
is_running: bool, |
|
|
|
is_running: bool, |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
impl UnnamedJobsBatch { |
|
|
|
impl AnonymousJobBatch { |
|
|
|
pub fn from_meta_with_id(jobs: impl OneOrVec<(ThinJobMeta, AssignedJobById)>) -> Self { |
|
|
|
pub fn from_meta_with_id(jobs: impl OneOrVec<(ThinJobMeta, AssignedJobById)>) -> Self { |
|
|
|
let jobs = jobs.into_vec(); |
|
|
|
let jobs = jobs.into_vec(); |
|
|
|
let mut waiter = Waiter::new(); |
|
|
|
let mut waiter = Waiter::new(); |
|
|
@ -43,7 +43,7 @@ impl UnnamedJobsBatch { |
|
|
|
) |
|
|
|
) |
|
|
|
}) |
|
|
|
}) |
|
|
|
.collect(); |
|
|
|
.collect(); |
|
|
|
UnnamedJobsBatch::from_meta_with_id(jobs) |
|
|
|
AnonymousJobBatch::from_meta_with_id(jobs) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/// Spawn jobs
|
|
|
|
/// Spawn jobs
|
|
|
@ -69,6 +69,82 @@ impl UnnamedJobsBatch { |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// Store jobs and get results by name
|
|
|
|
|
|
|
|
pub struct NamedJobBatch<const FINISHED: bool = false> { |
|
|
|
|
|
|
|
runner: Option<AnonymousJobBatch>, |
|
|
|
|
|
|
|
job_names: Vec<String>, |
|
|
|
|
|
|
|
results: HashMap<String, ExecResult>, |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
impl NamedJobBatch { |
|
|
|
|
|
|
|
pub fn from_shell( |
|
|
|
|
|
|
|
named_jobs: impl OneOrVec<(&'static str, &'static str)>, |
|
|
|
|
|
|
|
) -> CombinedResult<Self> { |
|
|
|
|
|
|
|
let mut result = CombinedResult::new(); |
|
|
|
|
|
|
|
let jobs: Vec<_> = named_jobs |
|
|
|
|
|
|
|
.into_vec() |
|
|
|
|
|
|
|
.into_iter() |
|
|
|
|
|
|
|
.filter_map(|(alias, cmd)| { |
|
|
|
|
|
|
|
match FatJobMeta::builder() |
|
|
|
|
|
|
|
.with_shell(cmd) |
|
|
|
|
|
|
|
.with_alias(alias) |
|
|
|
|
|
|
|
.build() |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
Ok(fat_meta) => match fat_meta_to_thin(fat_meta) { |
|
|
|
|
|
|
|
Ok(thin_meta) => Some(thin_meta), |
|
|
|
|
|
|
|
Err(e) => { |
|
|
|
|
|
|
|
result.err(e); |
|
|
|
|
|
|
|
None |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
}, |
|
|
|
|
|
|
|
Err(e) => { |
|
|
|
|
|
|
|
result.err(e); |
|
|
|
|
|
|
|
None |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
}) |
|
|
|
|
|
|
|
.collect(); |
|
|
|
|
|
|
|
result.ok(Self::from_meta(jobs)); |
|
|
|
|
|
|
|
result |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
pub fn from_meta(named_jobs: impl OneOrVec<ThinJobMeta>) -> Self { |
|
|
|
|
|
|
|
let (job_names, job_metas): (Vec<_>, Vec<_>) = named_jobs |
|
|
|
|
|
|
|
.into_vec() |
|
|
|
|
|
|
|
.into_iter() |
|
|
|
|
|
|
|
.map(|meta| (meta.alias.clone().unwrap(), meta)) |
|
|
|
|
|
|
|
.unzip(); |
|
|
|
|
|
|
|
Self { |
|
|
|
|
|
|
|
runner: Some(AnonymousJobBatch::from_meta(job_metas)), |
|
|
|
|
|
|
|
job_names, |
|
|
|
|
|
|
|
results: HashMap::new(), |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
pub async fn wait(mut self) -> NamedJobBatch<true> { |
|
|
|
|
|
|
|
let results = self.runner.take().unwrap().wait().await; |
|
|
|
|
|
|
|
for (name, result) in self.job_names.into_iter().zip(results.into_iter()) { |
|
|
|
|
|
|
|
self.results.insert(name, result); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
NamedJobBatch::<true> { |
|
|
|
|
|
|
|
runner: None, |
|
|
|
|
|
|
|
job_names: vec![], |
|
|
|
|
|
|
|
results: self.results, |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
impl NamedJobBatch<true> { |
|
|
|
|
|
|
|
pub fn pop_opt(&mut self, name: &'static str) -> Option<ExecResult> { |
|
|
|
|
|
|
|
self.results.remove(name) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
pub fn pop(&mut self, name: &'static str) -> ExecResult { |
|
|
|
|
|
|
|
self.pop_opt(name).unwrap() |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
pub async fn run_assigned_job(meta: ThinJobMeta, ids: AssignedJobById) -> ExecResult { |
|
|
|
pub async fn run_assigned_job(meta: ThinJobMeta, ids: AssignedJobById) -> ExecResult { |
|
|
|
let mut job = AssignedJob::from((&meta, ids)); |
|
|
|
let mut job = AssignedJob::from((&meta, ids)); |
|
|
|
match meta.exec_type { |
|
|
|
match meta.exec_type { |
|
|
@ -79,7 +155,7 @@ pub async fn run_assigned_job(meta: ThinJobMeta, ids: AssignedJobById) -> ExecRe |
|
|
|
let argv_with_exec = meta.argv.replace("{}", &prep_exec_path); |
|
|
|
let argv_with_exec = meta.argv.replace("{}", &prep_exec_path); |
|
|
|
(argv_with_exec, Some(prep_exec)) |
|
|
|
(argv_with_exec, Some(prep_exec)) |
|
|
|
} else { |
|
|
|
} else { |
|
|
|
(meta.argv.clone(), None) |
|
|
|
(meta.argv, None) |
|
|
|
} |
|
|
|
} |
|
|
|
}; |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
@ -156,87 +232,11 @@ pub fn thin_meta_to_fat(meta: ThinJobMeta) -> Result<FatJobMeta<true>, ufs::Erro |
|
|
|
}) |
|
|
|
}) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/// Store jobs and get results by name
|
|
|
|
|
|
|
|
pub struct NamedJobsBatch<const FINISHED: bool = false> { |
|
|
|
|
|
|
|
runner: Option<UnnamedJobsBatch>, |
|
|
|
|
|
|
|
job_names: Vec<String>, |
|
|
|
|
|
|
|
results: HashMap<String, ExecResult>, |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
impl NamedJobsBatch { |
|
|
|
|
|
|
|
pub fn from_shell( |
|
|
|
|
|
|
|
named_jobs: impl OneOrVec<(&'static str, &'static str)>, |
|
|
|
|
|
|
|
) -> CombinedResult<Self> { |
|
|
|
|
|
|
|
let mut result = CombinedResult::new(); |
|
|
|
|
|
|
|
let jobs: Vec<_> = named_jobs |
|
|
|
|
|
|
|
.into_vec() |
|
|
|
|
|
|
|
.into_iter() |
|
|
|
|
|
|
|
.filter_map(|(alias, cmd)| { |
|
|
|
|
|
|
|
match FatJobMeta::builder() |
|
|
|
|
|
|
|
.with_shell(cmd) |
|
|
|
|
|
|
|
.with_alias(alias) |
|
|
|
|
|
|
|
.build() |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
Ok(fat_meta) => match fat_meta_to_thin(fat_meta) { |
|
|
|
|
|
|
|
Ok(thin_meta) => Some(thin_meta), |
|
|
|
|
|
|
|
Err(e) => { |
|
|
|
|
|
|
|
result.err(e); |
|
|
|
|
|
|
|
None |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
}, |
|
|
|
|
|
|
|
Err(e) => { |
|
|
|
|
|
|
|
result.err(e); |
|
|
|
|
|
|
|
None |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
}) |
|
|
|
|
|
|
|
.collect(); |
|
|
|
|
|
|
|
result.ok(Self::from_meta(jobs)); |
|
|
|
|
|
|
|
result |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
pub fn from_meta(named_jobs: impl OneOrVec<ThinJobMeta>) -> Self { |
|
|
|
|
|
|
|
let (job_names, job_metas): (Vec<_>, Vec<_>) = named_jobs |
|
|
|
|
|
|
|
.into_vec() |
|
|
|
|
|
|
|
.into_iter() |
|
|
|
|
|
|
|
.map(|meta| (meta.alias.clone().unwrap(), meta)) |
|
|
|
|
|
|
|
.unzip(); |
|
|
|
|
|
|
|
Self { |
|
|
|
|
|
|
|
runner: Some(UnnamedJobsBatch::from_meta(job_metas)), |
|
|
|
|
|
|
|
job_names, |
|
|
|
|
|
|
|
results: HashMap::new(), |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
pub async fn wait(mut self) -> NamedJobsBatch<true> { |
|
|
|
|
|
|
|
let results = self.runner.take().unwrap().wait().await; |
|
|
|
|
|
|
|
for (name, result) in self.job_names.into_iter().zip(results.into_iter()) { |
|
|
|
|
|
|
|
self.results.insert(name, result); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
NamedJobsBatch::<true> { |
|
|
|
|
|
|
|
runner: None, |
|
|
|
|
|
|
|
job_names: vec![], |
|
|
|
|
|
|
|
results: self.results, |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
impl NamedJobsBatch<true> { |
|
|
|
|
|
|
|
pub fn pop_opt(&mut self, name: &'static str) -> Option<ExecResult> { |
|
|
|
|
|
|
|
self.results.remove(name) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
pub fn pop(&mut self, name: &'static str) -> ExecResult { |
|
|
|
|
|
|
|
self.pop_opt(name).unwrap() |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#[cfg(test)] |
|
|
|
#[cfg(test)] |
|
|
|
mod tests { |
|
|
|
mod tests { |
|
|
|
use super::*; |
|
|
|
use super::*; |
|
|
|
use crate::{ |
|
|
|
use crate::{ |
|
|
|
jobs::{NamedJobsBatch, UnnamedJobsBatch}, |
|
|
|
jobs::{AnonymousJobBatch, NamedJobBatch}, |
|
|
|
models::{misc::JobType, FatJobMeta}, |
|
|
|
models::{misc::JobType, FatJobMeta}, |
|
|
|
unwrap_enum, UError, |
|
|
|
unwrap_enum, UError, |
|
|
|
}; |
|
|
|
}; |
|
|
@ -253,7 +253,7 @@ mod tests { |
|
|
|
.collect::<Vec<_>>(); |
|
|
|
.collect::<Vec<_>>(); |
|
|
|
|
|
|
|
|
|
|
|
let now = SystemTime::now(); |
|
|
|
let now = SystemTime::now(); |
|
|
|
UnnamedJobsBatch::from_meta(sleep_jobs).wait().await; |
|
|
|
AnonymousJobBatch::from_meta(sleep_jobs).wait().await; |
|
|
|
assert!(now.elapsed().unwrap().as_secs() < SLEEP_SECS + 2) |
|
|
|
assert!(now.elapsed().unwrap().as_secs() < SLEEP_SECS + 2) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
@ -292,7 +292,7 @@ mod tests { |
|
|
|
job = job.with_payload(p); |
|
|
|
job = job.with_payload(p); |
|
|
|
} |
|
|
|
} |
|
|
|
let job = fat_meta_to_thin(job.build().unwrap()).unwrap(); |
|
|
|
let job = fat_meta_to_thin(job.build().unwrap()).unwrap(); |
|
|
|
let result = UnnamedJobsBatch::from_meta(job).wait_one().await.unwrap(); |
|
|
|
let result = AnonymousJobBatch::from_meta(job).wait_one().await.unwrap(); |
|
|
|
let result = result.to_str_result(); |
|
|
|
let result = result.to_str_result(); |
|
|
|
assert_eq!(result.trim(), expected_result); |
|
|
|
assert_eq!(result.trim(), expected_result); |
|
|
|
Ok(()) |
|
|
|
Ok(()) |
|
|
@ -303,10 +303,10 @@ mod tests { |
|
|
|
const SLEEP_SECS: u64 = 1; |
|
|
|
const SLEEP_SECS: u64 = 1; |
|
|
|
let now = SystemTime::now(); |
|
|
|
let now = SystemTime::now(); |
|
|
|
let longest_job = FatJobMeta::from_shell(format!("sleep {}", SLEEP_SECS)).unwrap(); |
|
|
|
let longest_job = FatJobMeta::from_shell(format!("sleep {}", SLEEP_SECS)).unwrap(); |
|
|
|
let longest_job = UnnamedJobsBatch::from_meta(fat_meta_to_thin(longest_job).unwrap()) |
|
|
|
let longest_job = AnonymousJobBatch::from_meta(fat_meta_to_thin(longest_job).unwrap()) |
|
|
|
.spawn() |
|
|
|
.spawn() |
|
|
|
.await; |
|
|
|
.await; |
|
|
|
let ls = UnnamedJobsBatch::from_meta( |
|
|
|
let ls = AnonymousJobBatch::from_meta( |
|
|
|
fat_meta_to_thin(FatJobMeta::from_shell("ls").unwrap()).unwrap(), |
|
|
|
fat_meta_to_thin(FatJobMeta::from_shell("ls").unwrap()).unwrap(), |
|
|
|
) |
|
|
|
) |
|
|
|
.wait_one() |
|
|
|
.wait_one() |
|
|
@ -321,7 +321,7 @@ mod tests { |
|
|
|
.map(|f| fat_meta_to_thin(FatJobMeta::from_shell(format!("ls {f}")).unwrap()).unwrap()) |
|
|
|
.map(|f| fat_meta_to_thin(FatJobMeta::from_shell(format!("ls {f}")).unwrap()).unwrap()) |
|
|
|
.collect::<Vec<_>>(); |
|
|
|
.collect::<Vec<_>>(); |
|
|
|
|
|
|
|
|
|
|
|
let ls_subfolders = UnnamedJobsBatch::from_meta(subfolders_jobs).wait().await; |
|
|
|
let ls_subfolders = AnonymousJobBatch::from_meta(subfolders_jobs).wait().await; |
|
|
|
|
|
|
|
|
|
|
|
for result in ls_subfolders { |
|
|
|
for result in ls_subfolders { |
|
|
|
assert_eq!(result.unwrap().retcode.unwrap(), 0); |
|
|
|
assert_eq!(result.unwrap().retcode.unwrap(), 0); |
|
|
@ -352,7 +352,7 @@ mod tests { |
|
|
|
#[tokio::test] |
|
|
|
#[tokio::test] |
|
|
|
async fn test_failing_shell_job() -> TestResult { |
|
|
|
async fn test_failing_shell_job() -> TestResult { |
|
|
|
let job = fat_meta_to_thin(FatJobMeta::from_shell("lol_kek_puk").unwrap()).unwrap(); |
|
|
|
let job = fat_meta_to_thin(FatJobMeta::from_shell("lol_kek_puk").unwrap()).unwrap(); |
|
|
|
let job_result = UnnamedJobsBatch::from_meta(job).wait_one().await.unwrap(); |
|
|
|
let job_result = AnonymousJobBatch::from_meta(job).wait_one().await.unwrap(); |
|
|
|
let output = job_result.to_str_result(); |
|
|
|
let output = job_result.to_str_result(); |
|
|
|
assert!(output.contains("No such file")); |
|
|
|
assert!(output.contains("No such file")); |
|
|
|
assert!(job_result.retcode.is_none()); |
|
|
|
assert!(job_result.retcode.is_none()); |
|
|
@ -380,7 +380,7 @@ mod tests { |
|
|
|
|
|
|
|
|
|
|
|
#[tokio::test] |
|
|
|
#[tokio::test] |
|
|
|
async fn test_different_job_types() -> TestResult { |
|
|
|
async fn test_different_job_types() -> TestResult { |
|
|
|
let mut jobs = NamedJobsBatch::from_meta( |
|
|
|
let mut jobs = NamedJobBatch::from_meta( |
|
|
|
[ |
|
|
|
[ |
|
|
|
FatJobMeta::builder() |
|
|
|
FatJobMeta::builder() |
|
|
|
.with_shell("sleep 3") |
|
|
|
.with_shell("sleep 3") |
|
|
|