|
|
@ -9,20 +9,20 @@ use symbols::{Symbol, SymbolRunner}; |
|
|
|
#[derive(Debug)]
|
|
|
|
pub enum SymbolRunError {
|
|
|
|
Symbol(Box<dyn Error>),
|
|
|
|
ExecuteDidNotReach(())
|
|
|
|
ExecuteDidNotReach(()),
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Error for SymbolRunError {
|
|
|
|
fn description(&self) -> &str {
|
|
|
|
match self {
|
|
|
|
SymbolRunError::Symbol(_) => "Symbol execution error",
|
|
|
|
SymbolRunError::ExecuteDidNotReach(_) => "Target not reached after executing symbol"
|
|
|
|
SymbolRunError::ExecuteDidNotReach(_) => "Target not reached after executing symbol",
|
|
|
|
}
|
|
|
|
}
|
|
|
|
fn cause(&self) -> Option<&dyn Error> {
|
|
|
|
match self {
|
|
|
|
SymbolRunError::Symbol(ref e) => Some(&**e),
|
|
|
|
SymbolRunError::ExecuteDidNotReach(_) => None
|
|
|
|
SymbolRunError::ExecuteDidNotReach(_) => None,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
@ -31,24 +31,25 @@ impl fmt::Display for SymbolRunError { |
|
|
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
|
|
match self {
|
|
|
|
SymbolRunError::Symbol(ref e) => write!(f, "{}", e),
|
|
|
|
SymbolRunError::ExecuteDidNotReach(_) => write!(f, "{}", self.description())
|
|
|
|
SymbolRunError::ExecuteDidNotReach(_) => write!(f, "{}", self.description()),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub struct InitializingSymbolRunner<L: Logger> {
|
|
|
|
logger: RefCell<L>
|
|
|
|
logger: RefCell<L>,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<L: Logger> InitializingSymbolRunner<L> {
|
|
|
|
pub fn new(logger: L) -> Self {
|
|
|
|
Self { logger: RefCell::new(logger) }
|
|
|
|
Self {
|
|
|
|
logger: RefCell::new(logger),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<L: Logger> SymbolRunner for InitializingSymbolRunner<L> {
|
|
|
|
fn run_symbol(&self, symbol: &dyn Symbol) -> Result<(), Box<dyn Error>>
|
|
|
|
{
|
|
|
|
fn run_symbol(&self, symbol: &dyn Symbol) -> Result<(), Box<dyn Error>> {
|
|
|
|
let mut logger = self.logger.borrow_mut();
|
|
|
|
let target_reached = try!(symbol.target_reached());
|
|
|
|
if target_reached {
|
|
|
@ -58,7 +59,13 @@ impl<L: Logger> SymbolRunner for InitializingSymbolRunner<L> { |
|
|
|
logger.write(format!("Executing {}", symbol).as_str());
|
|
|
|
try!(symbol.execute());
|
|
|
|
let target_reached = try!(symbol.target_reached());
|
|
|
|
logger.debug(format!("Symbol reports target_reached: {:?} (should be true)", target_reached).as_str());
|
|
|
|
logger.debug(
|
|
|
|
format!(
|
|
|
|
"Symbol reports target_reached: {:?} (should be true)",
|
|
|
|
target_reached
|
|
|
|
)
|
|
|
|
.as_str(),
|
|
|
|
);
|
|
|
|
if !target_reached {
|
|
|
|
return Err(Box::new(SymbolRunError::ExecuteDidNotReach(())));
|
|
|
|
}
|
|
|
@ -68,18 +75,19 @@ impl<L: Logger> SymbolRunner for InitializingSymbolRunner<L> { |
|
|
|
}
|
|
|
|
|
|
|
|
pub struct DrySymbolRunner<L: Logger> {
|
|
|
|
logger: RefCell<L>
|
|
|
|
logger: RefCell<L>,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<L: Logger> DrySymbolRunner<L> {
|
|
|
|
pub fn new(logger: L) -> Self {
|
|
|
|
Self { logger: RefCell::new(logger) }
|
|
|
|
Self {
|
|
|
|
logger: RefCell::new(logger),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<L: Logger> SymbolRunner for DrySymbolRunner<L> {
|
|
|
|
fn run_symbol(&self, symbol: &dyn Symbol) -> Result<(), Box<dyn Error>>
|
|
|
|
{
|
|
|
|
fn run_symbol(&self, symbol: &dyn Symbol) -> Result<(), Box<dyn Error>> {
|
|
|
|
let mut logger = self.logger.borrow_mut();
|
|
|
|
let target_reached = try!(symbol.target_reached());
|
|
|
|
logger.debug(format!("Symbol reports target_reached: {:?}", target_reached).as_str());
|
|
|
@ -92,22 +100,29 @@ impl<L: Logger> SymbolRunner for DrySymbolRunner<L> { |
|
|
|
|
|
|
|
pub struct ReportingSymbolRunner<'a, R: 'a + SymbolRunner, L: Logger>(&'a R, RefCell<L>);
|
|
|
|
|
|
|
|
impl<'a, R, L> ReportingSymbolRunner<'a, R, L> where R: SymbolRunner, L: Logger {
|
|
|
|
impl<'a, R, L> ReportingSymbolRunner<'a, R, L>
|
|
|
|
where
|
|
|
|
R: SymbolRunner,
|
|
|
|
L: Logger,
|
|
|
|
{
|
|
|
|
pub fn new(symbol_runner: &'a R, logger: L) -> Self {
|
|
|
|
ReportingSymbolRunner(symbol_runner, RefCell::new(logger))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<'a, R, L> SymbolRunner for ReportingSymbolRunner<'a, R, L> where R: SymbolRunner, L: Logger {
|
|
|
|
fn run_symbol(&self, symbol: &dyn Symbol) -> Result<(), Box<dyn Error>>
|
|
|
|
{
|
|
|
|
impl<'a, R, L> SymbolRunner for ReportingSymbolRunner<'a, R, L>
|
|
|
|
where
|
|
|
|
R: SymbolRunner,
|
|
|
|
L: Logger,
|
|
|
|
{
|
|
|
|
fn run_symbol(&self, symbol: &dyn Symbol) -> Result<(), Box<dyn Error>> {
|
|
|
|
let mut logger = self.1.borrow_mut();
|
|
|
|
logger.debug(format!("Running symbol {}", symbol).as_str());
|
|
|
|
let res = self.0.run_symbol(symbol);
|
|
|
|
match res {
|
|
|
|
Err(ref e) => {
|
|
|
|
logger.write(format!("Failed on {} with {}, aborting.", symbol, e).as_str());
|
|
|
|
},
|
|
|
|
}
|
|
|
|
Ok(_) => {
|
|
|
|
logger.debug(format!("Successfully finished {}", symbol).as_str());
|
|
|
|
}
|
|
|
@ -116,23 +131,28 @@ impl<'a, R, L> SymbolRunner for ReportingSymbolRunner<'a, R, L> where R: SymbolR |
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
use std::collections::HashSet;
|
|
|
|
use resources::Resource;
|
|
|
|
use std::collections::HashSet;
|
|
|
|
|
|
|
|
pub struct NonRepeatingSymbolRunner<R: SymbolRunner> {
|
|
|
|
upstream: R,
|
|
|
|
done: RefCell<HashSet<Resource>>
|
|
|
|
done: RefCell<HashSet<Resource>>,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<R> NonRepeatingSymbolRunner<R> where R: SymbolRunner {
|
|
|
|
impl<R> NonRepeatingSymbolRunner<R>
|
|
|
|
where
|
|
|
|
R: SymbolRunner,
|
|
|
|
{
|
|
|
|
pub fn new(symbol_runner: R) -> Self {
|
|
|
|
NonRepeatingSymbolRunner{ upstream: symbol_runner, done: RefCell::new(HashSet::new()) }
|
|
|
|
NonRepeatingSymbolRunner {
|
|
|
|
upstream: symbol_runner,
|
|
|
|
done: RefCell::new(HashSet::new()),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<R: SymbolRunner> SymbolRunner for NonRepeatingSymbolRunner<R> {
|
|
|
|
fn run_symbol(&self, symbol: &dyn Symbol) -> Result<(), Box<dyn Error>>
|
|
|
|
{
|
|
|
|
fn run_symbol(&self, symbol: &dyn Symbol) -> Result<(), Box<dyn Error>> {
|
|
|
|
if let Some(resources) = symbol.provides() {
|
|
|
|
let mut done = self.done.borrow_mut();
|
|
|
|
let mut has_to_run = false;
|
|
|
@ -151,17 +171,29 @@ impl<R: SymbolRunner> SymbolRunner for NonRepeatingSymbolRunner<R> { |
|
|
|
}
|
|
|
|
use std::marker::PhantomData;
|
|
|
|
|
|
|
|
pub struct RequirementsResolvingSymbolRunner<'a, 's, R: 'a + SymbolRunner, G: 'a + SymbolRepository<'s>>(R, &'a G, PhantomData<Box<dyn Symbol + 's>>);
|
|
|
|
|
|
|
|
impl<'s, 'a: 's, R, G> RequirementsResolvingSymbolRunner<'a, 's, R, G> where R: SymbolRunner, G: SymbolRepository<'s> {
|
|
|
|
pub struct RequirementsResolvingSymbolRunner<
|
|
|
|
'a,
|
|
|
|
's,
|
|
|
|
R: 'a + SymbolRunner,
|
|
|
|
G: 'a + SymbolRepository<'s>,
|
|
|
|
>(R, &'a G, PhantomData<Box<dyn Symbol + 's>>);
|
|
|
|
|
|
|
|
impl<'s, 'a: 's, R, G> RequirementsResolvingSymbolRunner<'a, 's, R, G>
|
|
|
|
where
|
|
|
|
R: SymbolRunner,
|
|
|
|
G: SymbolRepository<'s>,
|
|
|
|
{
|
|
|
|
pub fn new(symbol_runner: R, symbol_repo: &'a G) -> Self {
|
|
|
|
RequirementsResolvingSymbolRunner(symbol_runner, symbol_repo, PhantomData)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<'s, 'a: 's, R, G> SymbolRunner for RequirementsResolvingSymbolRunner<'a, 's, R, G> where R: SymbolRunner, G: SymbolRepository<'s> {
|
|
|
|
fn run_symbol(&self, symbol: &dyn Symbol) -> Result<(), Box<dyn Error>>
|
|
|
|
{
|
|
|
|
impl<'s, 'a: 's, R, G> SymbolRunner for RequirementsResolvingSymbolRunner<'a, 's, R, G>
|
|
|
|
where
|
|
|
|
R: SymbolRunner,
|
|
|
|
G: SymbolRepository<'s>,
|
|
|
|
{
|
|
|
|
fn run_symbol(&self, symbol: &dyn Symbol) -> Result<(), Box<dyn Error>> {
|
|
|
|
for resource in symbol.get_prerequisites() {
|
|
|
|
if let Some(dep) = self.1.get_symbol(&resource) {
|
|
|
|
try!(dep.as_action(self).run());
|
|
|
@ -180,13 +212,13 @@ mod test { |
|
|
|
use std::fmt;
|
|
|
|
|
|
|
|
use loggers::Logger;
|
|
|
|
use symbols::{Action, OwnedSymbolAction, Symbol, SymbolAction};
|
|
|
|
use schema::SymbolRunner;
|
|
|
|
use schema::InitializingSymbolRunner;
|
|
|
|
use schema::SymbolRunner;
|
|
|
|
use symbols::{Action, OwnedSymbolAction, Symbol, SymbolAction};
|
|
|
|
|
|
|
|
#[derive(Debug, PartialEq, Clone)]
|
|
|
|
enum DummySymbolError {
|
|
|
|
Error(())
|
|
|
|
Error(()),
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Error for DummySymbolError {
|
|
|
@ -203,7 +235,7 @@ mod test { |
|
|
|
|
|
|
|
struct DummySymbol<'a> {
|
|
|
|
_execute: &'a dyn Fn() -> Result<(), Box<dyn Error>>,
|
|
|
|
_target_reached: &'a dyn Fn() -> Result<bool, Box<dyn Error>>
|
|
|
|
_target_reached: &'a dyn Fn() -> Result<bool, Box<dyn Error>>,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<'b> Symbol for DummySymbol<'b> {
|
|
|
@ -218,7 +250,10 @@ mod test { |
|
|
|
Box::new(SymbolAction::new(runner, self))
|
|
|
|
}
|
|
|
|
|
|
|
|
fn into_action<'a>(self: Box<Self>, runner: &'a dyn SymbolRunner) -> Box<dyn Action + 'a> where Self: 'a {
|
|
|
|
fn into_action<'a>(self: Box<Self>, runner: &'a dyn SymbolRunner) -> Box<dyn Action + 'a>
|
|
|
|
where
|
|
|
|
Self: 'a,
|
|
|
|
{
|
|
|
|
Box::new(OwnedSymbolAction::new(runner, *self))
|
|
|
|
}
|
|
|
|
}
|
|
|
@ -230,13 +265,19 @@ mod test { |
|
|
|
}
|
|
|
|
|
|
|
|
impl<'a> DummySymbol<'a> {
|
|
|
|
fn new(target_reached: &'a dyn Fn() -> Result<bool, Box<dyn Error>>, execute: &'a dyn Fn() -> Result<(), Box<dyn Error>>) -> DummySymbol<'a> {
|
|
|
|
DummySymbol { _target_reached: target_reached, _execute: execute }
|
|
|
|
fn new(
|
|
|
|
target_reached: &'a dyn Fn() -> Result<bool, Box<dyn Error>>,
|
|
|
|
execute: &'a dyn Fn() -> Result<(), Box<dyn Error>>,
|
|
|
|
) -> DummySymbol<'a> {
|
|
|
|
DummySymbol {
|
|
|
|
_target_reached: target_reached,
|
|
|
|
_execute: execute,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
struct DummyLogger {
|
|
|
|
log: Vec<String>
|
|
|
|
log: Vec<String>,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl DummyLogger {
|
|
|
@ -256,28 +297,33 @@ mod test { |
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn nothing_needed_to_be_done() {
|
|
|
|
let result = InitializingSymbolRunner::new(DummyLogger::new()).run_symbol(&DummySymbol::new(&|| Ok(true), &|| Ok(())));
|
|
|
|
let result = InitializingSymbolRunner::new(DummyLogger::new())
|
|
|
|
.run_symbol(&DummySymbol::new(&|| Ok(true), &|| Ok(())));
|
|
|
|
assert!(result.is_ok());
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn everything_is_ok() {
|
|
|
|
let first = RefCell::new(true);
|
|
|
|
let result = InitializingSymbolRunner::new(DummyLogger::new()).run_symbol(&DummySymbol::new(&|| {
|
|
|
|
let mut _first = first.borrow_mut();
|
|
|
|
Ok(if *_first {
|
|
|
|
*_first = false;
|
|
|
|
true
|
|
|
|
} else {
|
|
|
|
false
|
|
|
|
})
|
|
|
|
}, &|| Ok(())));
|
|
|
|
let result = InitializingSymbolRunner::new(DummyLogger::new()).run_symbol(&DummySymbol::new(
|
|
|
|
&|| {
|
|
|
|
let mut _first = first.borrow_mut();
|
|
|
|
Ok(if *_first {
|
|
|
|
*_first = false;
|
|
|
|
true
|
|
|
|
} else {
|
|
|
|
false
|
|
|
|
})
|
|
|
|
},
|
|
|
|
&|| Ok(()),
|
|
|
|
));
|
|
|
|
assert!(result.is_ok());
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn executing_did_not_change_state() {
|
|
|
|
let result = InitializingSymbolRunner::new(DummyLogger::new()).run_symbol(&DummySymbol::new(&|| Ok(false), &|| Ok(())));
|
|
|
|
let result = InitializingSymbolRunner::new(DummyLogger::new())
|
|
|
|
.run_symbol(&DummySymbol::new(&|| Ok(false), &|| Ok(())));
|
|
|
|
assert_eq!(
|
|
|
|
result.unwrap_err().description(),
|
|
|
|
"Target not reached after executing symbol"
|
|
|
@ -286,7 +332,11 @@ mod test { |
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn executing_did_not_work() {
|
|
|
|
let err = InitializingSymbolRunner::new(DummyLogger::new()).run_symbol(&DummySymbol::new(&|| Ok(false), &|| Err(Box::new(DummySymbolError::Error(()))))).unwrap_err();
|
|
|
|
let err = InitializingSymbolRunner::new(DummyLogger::new())
|
|
|
|
.run_symbol(&DummySymbol::new(&|| Ok(false), &|| {
|
|
|
|
Err(Box::new(DummySymbolError::Error(())))
|
|
|
|
}))
|
|
|
|
.unwrap_err();
|
|
|
|
assert_eq!(err.description(), "Description");
|
|
|
|
}
|
|
|
|
}
|