summaryrefslogtreecommitdiff
path: root/src/map.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/map.rs')
-rw-r--r--src/map.rs40
1 files changed, 28 insertions, 12 deletions
diff --git a/src/map.rs b/src/map.rs
index be81216..671318e 100644
--- a/src/map.rs
+++ b/src/map.rs
@@ -1,12 +1,12 @@
-use std::error::Error;
use textwrap::fill;
pub use crate::from_yaml;
+pub use crate::RoadmapError;
pub use crate::Status;
pub use crate::Step;
/// Error in Roadmap, from parsing or otherwise.
-pub type RoadmapResult<T> = Result<T, Box<dyn Error>>;
+pub type RoadmapResult<T> = Result<T, RoadmapError>;
/// Represent a full project roadmap.
///
@@ -25,9 +25,17 @@ impl Roadmap {
Roadmap { steps: vec![] }
}
+ // Find steps that nothing depends on.
+ fn goals(&self) -> Vec<&Step> {
+ self.steps
+ .iter()
+ .filter(|step| self.is_goal(step))
+ .collect()
+ }
+
/// Count number of steps that nothing depends on.
pub fn count_goals(&self) -> usize {
- self.steps.iter().filter(|step| self.is_goal(step)).count()
+ self.goals().len()
}
/// Iterate over step names.
@@ -120,21 +128,29 @@ impl Roadmap {
// Validate that the parsed, constructed roadmap is valid.
pub fn validate(&self) -> RoadmapResult<()> {
// Is there exactly one goal?
- match self.count_goals() {
- 0 => return Err(format!("the roadmap doesn't have a goal").into()),
+ let goals = self.goals();
+ let n = goals.len();
+ match n {
+ 0 => return Err(RoadmapError::NoGoals),
1 => (),
- _ => return Err(format!("must have exactly one goal for roadmap").into()),
+ _ => {
+ let names: Vec<String> = goals.iter().map(|s| s.name().into()).collect();
+ return Err(RoadmapError::ManyGoals {
+ count: n,
+ names: names,
+ });
+ }
}
// Does every dependency exist?
for step in self.iter() {
for depname in step.dependencies() {
match self.get_step(depname) {
- None => {
- return Err(
- format!("step {} depends on missing {}", step.name(), depname).into(),
- )
- }
+ None =>
+ return Err(RoadmapError::MissingDep {
+ name: step.name().into(),
+ missing: depname.into(),
+ }),
Some(_) => (),
}
}
@@ -191,7 +207,7 @@ impl Roadmap {
fn get_status_shape(step: &Step) -> &str {
match step.status() {
Status::Blocked => "rectangle",
- Status::Finished => "circle",
+ Status::Finished => "octagon",
Status::Ready => "ellipse",
Status::Next => "ellipse",
Status::Goal => "diamond",