Skip to content

Commit

Permalink
feat: use anyhow as error handler
Browse files Browse the repository at this point in the history
  • Loading branch information
Joxit committed Oct 15, 2023
1 parent 2465785 commit 562e6d0
Show file tree
Hide file tree
Showing 11 changed files with 211 additions and 208 deletions.
3 changes: 2 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -25,4 +25,5 @@ regex = "^1.3"
chrono = "^0.4"
cron = "0.12"
clap_complete = "^4.4"
sha256 = "1.4"
sha256 = "^1.4"
anyhow = "^1.0"
4 changes: 3 additions & 1 deletion src/commands/completion.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use crate::Runtasktic;
use anyhow::Result;
use clap::{CommandFactory, Parser};
use clap_complete::{generate, Shell};

Expand All @@ -20,7 +21,7 @@ pub enum Completion {
}

impl Completion {
pub fn exec(&self) {
pub fn exec(&self) -> Result<()> {
let shell = match self {
Completion::Bash => Shell::Bash,
Completion::Fish => Shell::Fish,
Expand All @@ -30,5 +31,6 @@ impl Completion {
let mut cli = Runtasktic::command();
let bin_name = cli.get_name().to_string();
generate(shell, &mut cli, &bin_name, &mut std::io::stdout());
Ok(())
}
}
38 changes: 18 additions & 20 deletions src/commands/dot.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
use crate::config::Config;
use crate::fst::dot::*;
use crate::fst::*;
use anyhow::{anyhow, ensure, Context, Result};
use clap::Parser;
use std::fs;
use std::io::Cursor;
use std::path::PathBuf;
use std::process::exit;

#[derive(Parser, Debug)]
pub struct Dot {
Expand All @@ -18,23 +18,21 @@ pub struct Dot {
}

impl Dot {
pub fn exec(&self) {
if !self.config.exists() {
eprintln!("The config file {} does not exists", self.config.display());
return;
}
if let Err(e) = self.run() {
eprintln!("{}", e);
exit(1);
}
pub fn exec(&self) -> Result<()> {
ensure!(
self.config.exists(),
"The config file {} does not exists",
self.config.display()
);
self.run()
}

fn run(&self) -> Result<(), String> {
fn run(&self) -> Result<()> {
let yaml = fs::read_to_string(self.config.as_path())
.map_err(|msg| format!("Can't read the config file: {}", msg))?;
.with_context(|| anyhow!("Can't read the config file: {}", self.config.display()))?;

let mut config = Config::from_str(yaml.as_str())
.map_err(|msg| format!("Can't process the config file: {}", msg))?;
.with_context(|| anyhow!("Can't read the config file {}", self.config.display()))?;

let mut graph = TaskFst::new();
for task in config.tasks_values_mut() {
Expand All @@ -47,22 +45,22 @@ impl Dot {
} else {
for prev in task.depends_on().iter() {
let err_msg = format!("{} depends on {} but does not exists", task.id(), prev);
let prev_state = config.tasks().get(prev).ok_or(err_msg)?.state();
let prev_state = config.tasks().get(prev).ok_or(anyhow!(err_msg))?.state();
graph.add_arc(prev_state, task.state());
}
}
}

if graph.is_cyclic() {
let err_msg = "Can't execute your configuration. There is a deadlock in your tasks !";
return Err(err_msg.to_string());
}
ensure!(
!graph.is_cyclic(),
"Can't execute your configuration. There is a deadlock in your tasks !"
);

let mut buf: Vec<u8> = vec![];
dot_write_file(&graph, &mut buf).map_err(|e| format!("Can't create dot file: {}", e))?;
dot_write_file(&graph, &mut buf).with_context(|| "Can't create dot file")?;

dot_write_png(&mut Cursor::new(buf), &self.image)
.map_err(|e| format!("Can't save graph as png file: {}", e))?;
.with_context(|| "Can't save graph as png file")?;

Ok(())
}
Expand Down
35 changes: 19 additions & 16 deletions src/commands/exec.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use crate::config::Config;
use crate::utils::traits::{CommandConfig, WaitSchedule};
use anyhow::{anyhow, ensure, Context, Result};
use chrono::Local;
use clap::Parser;
use cron::Schedule;
Expand Down Expand Up @@ -31,12 +32,13 @@ pub struct Exec {
}

impl Exec {
pub fn exec(&self) {
pub fn exec(&self) -> Result<()> {
if let Some(config) = &self.config {
if config != &PathBuf::from("-") && !config.exists() {
eprintln!("The config file {} does not exists", config.display());
return;
}
ensure!(
config == &PathBuf::from("-") || config.exists(),
"The config file {} does not exists",
config.display()
);
}
let timezone = Local::now().timezone();

Expand All @@ -46,7 +48,7 @@ impl Exec {

if self.background && unsafe { fork() } != 0 {
// The main process should return
return;
return Ok(());
} else if self.background {
// Ignoring SIGHUP in background mode
unsafe { signal(SIGHUP, SIG_IGN) };
Expand All @@ -56,19 +58,19 @@ impl Exec {
self.cron.wait(timezone);

if let Err(e) = self.run() {
eprintln!("{}", e);
eprintln!("{:?}", e);
if self.cron.is_none() {
exit(1);
}
}

if self.cron.is_none() {
break;
return Ok(());
}
}
}

fn run(&self) -> Result<(), String> {
fn run(&self) -> Result<()> {
let (config, path) = if Some(PathBuf::from("-")) == self.config {
(Config::default(), format!("-"))
} else if let Some(path) = &self.config {
Expand All @@ -83,9 +85,10 @@ impl Exec {
config
.tasks()
.get(task)
.ok_or(format!(
.ok_or(anyhow!(
"The task `{}` does not exist in your config file `{}`",
task, path
task,
path
))?
.clone()
} else {
Expand All @@ -101,7 +104,7 @@ impl Exec {
.stderr_opt(config.stderr(), !self.background)?
.working_dir(config.working_dir())?
.spawn()
.map_err(|msg| format!("Can't run command `{}`: {}", cmd_line, msg))?;
.with_context(|| format!("Can't run command `{}`", cmd_line))?;

let exit = child.wait().unwrap();
if let Some(notification) = config.notification() {
Expand Down Expand Up @@ -130,12 +133,12 @@ impl Exec {
}
}

fn config_path(&self, path: &PathBuf) -> Result<(Config, String), String> {
let yaml = fs::read_to_string(path.as_path())
.map_err(|msg| format!("Can't read the config file: {}", msg))?;
fn config_path(&self, path: &PathBuf) -> Result<(Config, String)> {
let yaml = fs::read_to_string(&path)
.with_context(|| anyhow!("Can't read the config file {}", &path.display()))?;

let config = Config::from_str(yaml.as_str())
.map_err(|msg| format!("Can't process the config file: {}", msg))?;
.with_context(|| anyhow!("Can't process the config file {}", &path.display()))?;

Ok((config, format!("{}", path.display())))
}
Expand Down
3 changes: 2 additions & 1 deletion src/commands/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ use crate::commands::dot::Dot;
use crate::commands::exec::Exec;
use crate::commands::run::Run;
use crate::commands::update::Update;
use anyhow::Result;
use clap::Parser;

mod completion;
Expand Down Expand Up @@ -35,7 +36,7 @@ pub enum Command {
}

impl Command {
pub fn exec(&self) {
pub fn exec(&self) -> Result<()> {
match self {
Command::Run(executable) => executable.exec(),
Command::Exec(executable) => executable.exec(),
Expand Down
40 changes: 19 additions & 21 deletions src/commands/run.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
use crate::config::{Config, OnFailure};
use crate::fst::*;
use crate::utils::traits::{CommandConfig, WaitSchedule};
use anyhow::{anyhow, bail, ensure, Context, Result};
use chrono::Local;
use clap::Parser;
use cron::Schedule;
use libc::{fork, signal};
use libc::{SIGHUP, SIG_IGN};
use std::fs;
use std::path::{Path, PathBuf};
use std::process::{exit, Command, Stdio};
use std::process::{Command, Stdio};

#[derive(Parser, Debug)]
pub struct Run {
Expand All @@ -29,12 +30,13 @@ pub struct Run {
}

impl Run {
pub fn exec(&self) {
pub fn exec(&self) -> Result<()> {
for config in &self.config {
if !config.exists() {
eprintln!("The config file {} does not exists", config.display());
exit(1);
}
ensure!(
config.exists(),
"The config file {} does not exists",
config.display()
)
}
let timezone = Local::now().timezone();

Expand All @@ -44,7 +46,7 @@ impl Run {

if self.background && unsafe { fork() } != 0 {
// The main process should return
return;
return Ok(());
} else if self.background {
// Ignoring SIGHUP in background mode
unsafe { signal(SIGHUP, SIG_IGN) };
Expand All @@ -55,29 +57,26 @@ impl Run {

for (i, config) in self.config.iter().enumerate() {
let starts = if i == 0 { self.starts.clone() } else { vec![] };
if let Err(e) = self.run(&config.as_path(), &starts) {
eprintln!("{}", e);
exit(1);
}
self.run(&config.as_path(), &starts)?;
}
if self.cron.is_none() {
break;
return Ok(());
}
}
}

fn run(&self, config_path: &Path, starts: &Vec<String>) -> Result<(), String> {
fn run(&self, config_path: &Path, starts: &Vec<String>) -> Result<()> {
let yaml = fs::read_to_string(config_path)
.map_err(|msg| format!("Can't read the config file: {}", msg))?;
.with_context(|| format!("Can't read the config file {}", config_path.display()))?;

let mut config = Config::from_str(yaml.as_str())
.map_err(|msg| format!("Can't process the config file: {}", msg))?;
.with_context(|| format!("Can't process the config file {}", config_path.display()))?;

if config.tasks().is_empty() {
return Err(format!(
bail!(
"Need at least one task in the config file to run: `{}`",
config_path.display()
));
);
}

let mut graph = TaskFst::new();
Expand All @@ -92,16 +91,15 @@ impl Run {
graph.add_start_state(task.state());
} else {
for prev in task.depends_on().iter() {
let err_msg = format!("{} depends on {} but does not exists", task.id(), prev);
let err_msg = anyhow!("{} depends on {} but does not exists", task.id(), prev);
let prev_state = config.tasks().get(prev).ok_or(err_msg)?.state();
graph.add_arc(prev_state, task.state());
}
}
}

if graph.is_cyclic() {
let err_msg = "Can't execute your configuration. There is a deadlock in your tasks !";
return Err(err_msg.to_string());
bail!("Can't execute your configuration. There is a deadlock in your tasks !");
}

let processes: &mut Vec<Option<std::process::Child>> = &mut vec![];
Expand Down Expand Up @@ -139,7 +137,7 @@ impl Run {
.stderr_opt(config.stderr(), !self.background)?
.working_dir(config.working_dir())?
.spawn()
.map_err(|msg| format!("Can't run command `{}`: {}", cmd_line, msg))?;
.with_context(|| format!("Can't run command `{}`", cmd_line))?;
processes[task.id()] = Some(child);
} else if graph_iter.is_done() {
break;
Expand Down
Loading

0 comments on commit 562e6d0

Please sign in to comment.