Better error handling (fixes #15)

This commit is contained in:
Roey Darwish Dror
2018-06-06 15:32:38 +03:00
parent 3897b2ac76
commit ef69dc01ba
4 changed files with 254 additions and 142 deletions

View File

@@ -1,3 +1,4 @@
use super::Check;
use failure::Error;
use std::path::{Path, PathBuf};
use std::process::Command;
@@ -38,17 +39,18 @@ impl Git {
None
}
pub fn pull<P: AsRef<Path>>(&self, path: P) -> Result<Option<bool>, Error> {
pub fn pull<P: AsRef<Path>>(&self, path: P) -> Result<Option<()>, Error> {
if let Some(git) = &self.git {
if let Ok(mut command) = Command::new(&git)
Command::new(&git)
.arg("pull")
.arg("--rebase")
.arg("--autostash")
.current_dir(path)
.spawn()
{
return Ok(Some(command.wait()?.success()));
}
.spawn()?
.wait()?
.check()?;
return Ok(Some(()));
}
Ok(None)

View File

@@ -7,6 +7,7 @@ extern crate termion;
mod git;
mod report;
mod steps;
mod terminal;
use failure::Error;
@@ -16,7 +17,8 @@ use report::{Report, Reporter};
use std::collections::HashSet;
use std::env::home_dir;
use std::path::PathBuf;
use std::process::{Command, ExitStatus};
use std::process::ExitStatus;
use steps::*;
use terminal::Terminal;
use which::which;
@@ -38,8 +40,6 @@ impl Check for ExitStatus {
}
}
const EMACS_UPGRADE: &str = include_str!("emacs.el");
fn home_path(p: &str) -> PathBuf {
let mut path = home_dir().unwrap();
path.push(p);
@@ -88,79 +88,45 @@ fn main() -> Result<(), Error> {
if cfg!(unix) {
if let Ok(zsh) = which("zsh") {
terminal.print_separator("zplug");
if home_path(".zplug").exists() {
Command::new(&zsh)
.args(&["-c", "source ~/.zshrc && zplug update"])
.spawn()?
.wait()?
.report("zplug", &mut reports);
terminal.print_separator("zplug");
run_zplug(&zsh).report("zplug", &mut reports);
}
}
if let Some(tpm) = tpm() {
terminal.print_separator("tmux plugins");
Command::new(&tpm)
.arg("all")
.spawn()?
.wait()?
.report("tmux", &mut reports);
run_tpm(&tpm).report("tmux", &mut reports);
}
}
let cargo_upgrade = home_path(".cargo/bin/cargo-install-update");
if cargo_upgrade.exists() {
terminal.print_separator("Cargo");
Command::new(&cargo_upgrade)
.args(&["install-update", "--all"])
.spawn()?
.wait()?
.report("Cargo", &mut reports);
run_cargo_update(&cargo_upgrade).report("Cargo", &mut reports);
}
if let Ok(emacs) = which("emacs") {
if home_path(".emacs.d").exists() {
let init_file = home_path(".emacs.d/init.el");
if init_file.exists() {
terminal.print_separator("Emacs");
Command::new(&emacs)
.args(&[
"--batch",
"-l",
home_path(".emacs.d/init.el").to_str().unwrap(),
"--eval",
EMACS_UPGRADE,
])
.spawn()?
.wait()?
.report("Emacs", &mut reports);
run_emacs(&emacs, &home_path(".emacs.d/init.el")).report("Emacs", &mut reports);
}
}
if let Ok(gem) = which("gem") {
terminal.print_separator("RubyGems");
Command::new(&gem)
.args(&["update"])
.spawn()?
.wait()?
.report("RubyGems", &mut reports);
run_gem(&gem).report("RubyGems", &mut reports);
}
if let Ok(npm) = which("npm") {
terminal.print_separator("Node Package Manager");
Command::new(&npm)
.args(&["update", "-g"])
.spawn()?
.wait()?
.report("Node Package Manager", &mut reports);
run_npm(&npm).report("Node Package Manager", &mut reports);
}
if let Ok(apm) = which("apm") {
terminal.print_separator("Atom Package Manager");
Command::new(&apm)
.args(&["upgrade", "--confirm=false"])
.spawn()?
.wait()
.map_err(Error::from)?
.report("Atom Package Manager", &mut reports);
run_apm(&apm).report("Atom Package Manager", &mut reports);
}
if cfg!(target_os = "linux") {
@@ -168,87 +134,29 @@ fn main() -> Result<(), Error> {
terminal.print_separator("System update");
match os_type::current_platform().os_type {
OSType::Arch => {
if let Ok(yay) = which("yay") {
Command::new(yay)
.spawn()?
.wait()?
.report("System upgrade", &mut reports);
} else {
if let Ok(sudo) = &sudo {
Command::new(&sudo)
.args(&["pacman", "-Syu"])
.spawn()?
.wait()?
.report("System upgrade", &mut reports);
} else {
terminal.print_warning("No sudo or yay detected. Skipping system upgrade");
}
}
}
OSType::CentOS | OSType::Redhat => {
if let Ok(sudo) = &sudo {
Command::new(&sudo)
.args(&["yum", "upgrade"])
.spawn()?
.wait()?
.report("System upgrade", &mut reports);;
}
}
OSType::Ubuntu | OSType::Debian => {
if let Ok(sudo) = &sudo {
Command::new(&sudo)
.args(&["apt", "update"])
.spawn()?
.wait()?
.check()
.and_then(|()| {
Command::new(&sudo)
.args(&["apt", "dist-upgrade"])
.spawn()?
.wait()
.map_err(Error::from)
})?
.report("System upgrade", &mut reports);;
}
}
OSType::Arch => Some(upgrade_arch_linux(&sudo, &terminal)),
OSType::CentOS | OSType::Redhat => Some(upgrade_redhat(&sudo, &terminal)),
OSType::Ubuntu | OSType::Debian => Some(upgrade_debian(&sudo, &terminal)),
OSType::Unknown => {
terminal.print_warning(
"Could not detect your Linux distribution. Do you have lsb-release installed?",
);
None
}
_ => (),
}
_ => None,
}.report("System upgrade", &mut reports);
if let Ok(fwupdmgr) = which("fwupdmgr") {
terminal.print_separator("Firmware upgrades");
Command::new(&fwupdmgr)
.arg("refresh")
.spawn()?
.wait()?
.check()
.and_then(|()| {
Command::new(&fwupdmgr)
.arg("get-updates")
.spawn()?
.wait()
.map_err(Error::from)
})?
.report("Firmware upgrade", &mut reports);
run_fwupdmgr(&fwupdmgr).report("Firmware upgrade", &mut reports);
}
if let Ok(sudo) = &sudo {
if let Ok(needrestart) = which("needrestart") {
if let Ok(_) = which("needrestart") {
terminal.print_separator("Check for needed restarts");
Command::new(&sudo)
.arg(&needrestart)
.spawn()?
.wait()?
.report("Restarts", &mut reports);
run_needrestart(&sudo).report("Restarts", &mut reports);
}
}
}
@@ -256,27 +164,11 @@ fn main() -> Result<(), Error> {
if cfg!(target_os = "macos") {
if let Ok(brew) = which("brew") {
terminal.print_separator("Homebrew");
Command::new(&brew)
.arg("update")
.spawn()?
.wait()?
.check()
.and_then(|()| {
Command::new(&brew)
.arg("upgrade")
.spawn()?
.wait()
.map_err(Error::from)
})?
.report("Homebrew", &mut reports);
run_homebrew(&brew).report("Homebrew", &mut reports);
}
terminal.print_separator("System update");
Command::new("softwareupdate")
.args(&["--install", "--all"])
.spawn()?
.wait()?
.report("System upgrade", &mut reports);;
upgrade_macos().report("System upgrade", &mut reports);;
}
let mut reports: Vec<_> = reports.into_iter().collect();

View File

@@ -1,6 +1,5 @@
use std::borrow::Cow;
use std::collections::HashMap;
use std::process::ExitStatus;
pub type Report = HashMap<String, bool>;
@@ -8,9 +7,30 @@ pub trait Reporter {
fn report<'a, M: Into<Cow<'a, str>>>(&self, key: M, report: &mut Report);
}
impl Reporter for ExitStatus {
impl<T, E> Reporter for Result<T, E>
where
T: Reporter,
{
fn report<'a, M: Into<Cow<'a, str>>>(&self, key: M, report: &mut Report) {
report.insert(key.into().into_owned(), self.success());
match self {
Err(_) => {
report.insert(key.into().into_owned(), false);
}
Ok(item) => {
item.report(key, report);
}
}
}
}
impl<T> Reporter for Option<T>
where
T: Reporter,
{
fn report<'a, M: Into<Cow<'a, str>>>(&self, key: M, report: &mut Report) {
if let Some(item) = self {
item.report(key, report);
}
}
}
@@ -19,3 +39,9 @@ impl Reporter for bool {
report.insert(key.into().into_owned(), *self);
}
}
impl Reporter for () {
fn report<'a, M: Into<Cow<'a, str>>>(&self, key: M, report: &mut Report) {
report.insert(key.into().into_owned(), true);
}
}

192
src/steps.rs Normal file
View File

@@ -0,0 +1,192 @@
use super::terminal::Terminal;
use super::{which, Check};
use failure;
use std::path::PathBuf;
use std::process::Command;
const EMACS_UPGRADE: &str = include_str!("emacs.el");
pub fn run_zplug(zsh: &PathBuf) -> Result<(), failure::Error> {
Command::new(zsh)
.args(&["-c", "source ~/.zshrc && zplug update"])
.spawn()?
.wait()?
.check()?;
Ok(())
}
pub fn run_tpm(tpm: &PathBuf) -> Result<(), failure::Error> {
Command::new(&tpm).arg("all").spawn()?.wait()?.check()?;
Ok(())
}
pub fn run_cargo_update(cargo_update: &PathBuf) -> Result<(), failure::Error> {
Command::new(&cargo_update)
.args(&["install-update", "--all"])
.spawn()?
.wait()?
.check()?;
Ok(())
}
pub fn run_emacs(emacs: &PathBuf, init: &PathBuf) -> Result<(), failure::Error> {
Command::new(&emacs)
.args(&[
"--batch",
"-l",
init.to_str().unwrap(),
"--eval",
EMACS_UPGRADE,
])
.spawn()?
.wait()?
.check()?;
Ok(())
}
pub fn run_gem(gem: &PathBuf) -> Result<(), failure::Error> {
Command::new(&gem)
.args(&["update"])
.spawn()?
.wait()?
.check()?;
Ok(())
}
pub fn run_npm(npm: &PathBuf) -> Result<(), failure::Error> {
Command::new(&npm)
.args(&["update", "-g"])
.spawn()?
.wait()?
.check()?;
Ok(())
}
pub fn run_apm(apm: &PathBuf) -> Result<(), failure::Error> {
Command::new(&apm)
.args(&["upgrade", "--confirm=false"])
.spawn()?
.wait()?
.check()?;
Ok(())
}
pub fn run_needrestart(sudo: &PathBuf) -> Result<(), failure::Error> {
Command::new(&sudo)
.arg("needrestart")
.spawn()?
.wait()?
.check()?;
Ok(())
}
pub fn run_fwupdmgr(fwupdmgr: &PathBuf) -> Result<(), failure::Error> {
Command::new(&fwupdmgr)
.arg("refresh")
.spawn()?
.wait()?
.check()?;
Command::new(&fwupdmgr)
.arg("get-updates")
.spawn()?
.wait()?
.check()?;
Ok(())
}
pub fn upgrade_macos() -> Result<(), failure::Error> {
Command::new("softwareupdate")
.args(&["--install", "--all"])
.spawn()?
.wait()?
.check()?;
Ok(())
}
pub fn run_homebrew(homebrew: &PathBuf) -> Result<(), failure::Error> {
Command::new(&homebrew)
.arg("update")
.spawn()?
.wait()?
.check()?;
Command::new(&homebrew)
.arg("upgrade")
.spawn()?
.wait()?
.check()?;
Ok(())
}
pub fn upgrade_arch_linux(
sudo: &Result<PathBuf, which::Error>,
terminal: &Terminal,
) -> Result<(), failure::Error> {
if let Ok(yay) = which("yay") {
Command::new(yay).spawn()?.wait()?.check()?;
} else {
if let Ok(sudo) = &sudo {
Command::new(&sudo)
.args(&["pacman", "-Syu"])
.spawn()?
.wait()?
.check()?;
} else {
terminal.print_warning("No sudo or yay detected. Skipping system upgrade");
}
}
Ok(())
}
pub fn upgrade_redhat(
sudo: &Result<PathBuf, which::Error>,
terminal: &Terminal,
) -> Result<(), failure::Error> {
if let Ok(sudo) = &sudo {
Command::new(&sudo)
.args(&["yum", "upgrade"])
.spawn()?
.wait()?
.check()?;
} else {
terminal.print_warning("No sudo detected. Skipping system upgrade");
}
Ok(())
}
pub fn upgrade_debian(
sudo: &Result<PathBuf, which::Error>,
terminal: &Terminal,
) -> Result<(), failure::Error> {
if let Ok(sudo) = &sudo {
Command::new(&sudo)
.args(&["apt", "update"])
.spawn()?
.wait()?
.check()?;
Command::new(&sudo)
.args(&["apt", "upgrade"])
.spawn()?
.wait()?
.check()?;
} else {
terminal.print_warning("No sudo detected. Skipping system upgrade");
}
Ok(())
}