Migrate from failure to anyhow/thiserror (#273)

This commit is contained in:
Roey Darwish Dror
2019-12-11 23:05:38 +02:00
committed by GitHub
parent 1ea9b91e11
commit ba516aa1dd
22 changed files with 259 additions and 335 deletions

46
Cargo.lock generated
View File

@@ -21,6 +21,11 @@ dependencies = [
"winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "anyhow"
version = "1.0.25"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "arc-swap"
version = "0.4.4"
@@ -392,7 +397,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)",
"quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
"syn 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)",
"syn 1.0.11 (registry+https://github.com/rust-lang/crates.io-index)",
"synstructure 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)",
]
@@ -996,7 +1001,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)",
"quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
"syn 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)",
"syn 1.0.11 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@@ -1382,7 +1387,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)",
"quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
"syn 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)",
"syn 1.0.11 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@@ -1489,7 +1494,7 @@ dependencies = [
"proc-macro-error 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
"proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)",
"quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
"syn 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)",
"syn 1.0.11 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@@ -1508,12 +1513,12 @@ dependencies = [
"heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
"proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)",
"quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
"syn 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)",
"syn 1.0.11 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "syn"
version = "1.0.8"
version = "1.0.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -1528,7 +1533,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)",
"quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
"syn 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)",
"syn 1.0.11 (registry+https://github.com/rust-lang/crates.io-index)",
"unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
@@ -1589,6 +1594,24 @@ dependencies = [
"unicode-width 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "thiserror"
version = "1.0.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"thiserror-impl 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "thiserror-impl"
version = "1.0.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)",
"quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
"syn 1.0.11 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "thread_local"
version = "0.3.6"
@@ -1832,11 +1855,10 @@ dependencies = [
name = "topgrade"
version = "3.5.0"
dependencies = [
"anyhow 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)",
"chrono 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)",
"console 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)",
"directories 2.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
"failure 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
"failure_derive 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
"futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)",
"glob 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -1850,6 +1872,7 @@ dependencies = [
"shellexpand 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
"structopt 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
"strum 0.16.0 (registry+https://github.com/rust-lang/crates.io-index)",
"thiserror 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)",
"tokio 0.1.22 (registry+https://github.com/rust-lang/crates.io-index)",
"tokio-process 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)",
"toml 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -2083,6 +2106,7 @@ dependencies = [
"checksum adler32 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "5d2e7343e7fc9de883d1b0341e0b13970f764c14101234857d2ddafa1cb1cac2"
"checksum aho-corasick 0.7.6 (registry+https://github.com/rust-lang/crates.io-index)" = "58fb5e95d83b38284460a5fda7d6470aa0b8844d283a0b614b8535e880800d2d"
"checksum ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b"
"checksum anyhow 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)" = "9267dff192e68f3399525901e709a48c1d3982c9c072fa32f2127a0cb0babf14"
"checksum arc-swap 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "d7b8a9123b8027467bce0099fe556c628a53c8d83df0507084c31e9ba2e39aff"
"checksum arrayref 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "0d382e583f07208808f6b1249e60848879ba3543f57c32277bf52d69c2f0f0ee"
"checksum arrayvec 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cff77d8686867eceff3105329d4698d96c2391c176d5d03adc90c7389162b5b8"
@@ -2251,7 +2275,7 @@ dependencies = [
"checksum structopt-derive 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "ea692d40005b3ceba90a9fe7a78fa8d4b82b0ce627eebbffc329aab850f3410e"
"checksum strum 0.16.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6138f8f88a16d90134763314e3fc76fa3ed6a7db4725d6acf9a3ef95a3188d22"
"checksum strum_macros 0.16.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0054a7df764039a6cd8592b9de84be4bec368ff081d203a7d5371cbfa8e65c81"
"checksum syn 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)" = "661641ea2aa15845cddeb97dad000d22070bb5c1fb456b96c1cba883ec691e92"
"checksum syn 1.0.11 (registry+https://github.com/rust-lang/crates.io-index)" = "dff0acdb207ae2fe6d5976617f887eb1e35a2ba52c13c7234c790960cdad9238"
"checksum synstructure 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)" = "67656ea1dc1b41b1451851562ea232ec2e5a80242139f7e679ceccfb5d61f545"
"checksum tar 0.4.26 (registry+https://github.com/rust-lang/crates.io-index)" = "b3196bfbffbba3e57481b6ea32249fbaf590396a52505a2615adbb79d9d826d3"
"checksum tempdir 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)" = "15f2b5fb00ccdf689e0149d1b1b3c03fead81c2b37735d812fa8bddbbf41b6d8"
@@ -2259,6 +2283,8 @@ dependencies = [
"checksum termcolor 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "96d6098003bde162e4277c70665bd87c326f5a0c3f3fbfb285787fa482d54e6e"
"checksum termios 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "72b620c5ea021d75a735c943269bb07d30c9b77d6ac6b236bc8b5c496ef05625"
"checksum textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060"
"checksum thiserror 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)" = "6f357d1814b33bc2dc221243f8424104bfe72dbe911d5b71b3816a2dff1c977e"
"checksum thiserror-impl 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)" = "eb2e25d25307eb8436894f727aba8f65d07adf02e5b35a13cebed48bd282bfef"
"checksum thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c6b53e329000edc2b34dbe8545fd20e55a333362d0a321909685a19bd28c3f1b"
"checksum time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)" = "db8dcfca086c1143c9270ac42a2bbd8a7ee477b78ac8e45b19abfb0cbede4b6f"
"checksum tokio 0.1.22 (registry+https://github.com/rust-lang/crates.io-index)" = "5a09c0b5bb588872ab2f09afa13ee6e9dac11e10a0ec9e8e3ba39a5a5d530af6"

View File

@@ -13,8 +13,6 @@ readme = "README.md"
[dependencies]
directories = "2.0.1"
failure = "0.1.5"
failure_derive = "0.1.5"
serde = { version = "1.0.92", features = ["derive"] }
toml = "0.5.1"
which_crate = { version = "2.0.1", package = "which" }
@@ -34,6 +32,8 @@ openssl-probe = { version = "0.1.2", optional = true }
pretty_env_logger = "0.3.0"
glob = "0.3.0"
strum = { version = "0.16.0", features = ["derive"]}
thiserror = "1.0.9"
anyhow = "1.0.25"
[target.'cfg(unix)'.dependencies]
nix = "0.15.0"

View File

@@ -1,9 +1,6 @@
use super::error::{Error, ErrorKind};
use super::utils::editor;
use anyhow::Result;
use directories::BaseDirs;
use failure::ResultExt;
use strum::{EnumIter, EnumString, EnumVariantNames, IntoEnumIterator};
use log::{debug, LevelFilter};
use pretty_env_logger::formatted_timed_builder;
use serde::Deserialize;
@@ -14,6 +11,7 @@ use std::path::PathBuf;
use std::process::Command;
use std::{env, fs};
use structopt::StructOpt;
use strum::{EnumIter, EnumString, EnumVariantNames, IntoEnumIterator};
use toml;
type Commands = BTreeMap<String, String>;
@@ -70,20 +68,18 @@ pub struct ConfigFile {
}
impl ConfigFile {
fn ensure(base_dirs: &BaseDirs) -> Result<PathBuf, Error> {
fn ensure(base_dirs: &BaseDirs) -> Result<PathBuf> {
let config_path = base_dirs.config_dir().join("topgrade.toml");
if !config_path.exists() {
write(&config_path, include_str!("../config.example.toml"))
.map_err(|e| {
debug!(
"Unable to write the example configuration file to {}: {}. Using blank config.",
config_path.display(),
e
);
e
})
.context(ErrorKind::Configuration)?;
debug!("No configuration exists");
write(&config_path, include_str!("../config.example.toml")).map_err(|e| {
debug!(
"Unable to write the example configuration file to {}: {}. Using blank config.",
config_path.display(),
e
);
e
})?;
}
Ok(config_path)
@@ -92,22 +88,18 @@ impl ConfigFile {
/// Read the configuration file.
///
/// If the configuration file does not exist the function returns the default ConfigFile.
fn read(base_dirs: &BaseDirs) -> Result<ConfigFile, Error> {
fn read(base_dirs: &BaseDirs) -> Result<ConfigFile> {
let config_path = Self::ensure(base_dirs)?;
let contents = fs::read_to_string(&config_path)
.map_err(|e| {
log::error!("Unable to read {}", config_path.display());
e
})
.context(ErrorKind::Configuration)?;
let contents = fs::read_to_string(&config_path).map_err(|e| {
log::error!("Unable to read {}", config_path.display());
e
})?;
let mut result: Self = toml::from_str(&contents)
.map_err(|e| {
log::error!("Failed to deserialize {}", config_path.display());
e
})
.context(ErrorKind::Configuration)?;
let mut result: Self = toml::from_str(&contents).map_err(|e| {
log::error!("Failed to deserialize {}", config_path.display());
e
})?;
if let Some(ref mut paths) = &mut result.git_repos {
for path in paths.iter_mut() {
@@ -120,7 +112,7 @@ impl ConfigFile {
Ok(result)
}
fn edit(base_dirs: &BaseDirs) -> Result<(), Error> {
fn edit(base_dirs: &BaseDirs) -> Result<()> {
let config_path = Self::ensure(base_dirs)?;
let editor = editor();
@@ -128,8 +120,7 @@ impl ConfigFile {
Command::new(editor)
.arg(config_path)
.spawn()
.and_then(|mut p| p.wait())
.context(ErrorKind::Configuration)?;
.and_then(|mut p| p.wait())?;
Ok(())
}
}
@@ -200,7 +191,7 @@ impl Config {
/// Load the configuration.
///
/// The function parses the command line arguments and reading the configuration file.
pub fn load(base_dirs: &BaseDirs, opt: CommandLineArgs) -> Result<Self, Error> {
pub fn load(base_dirs: &BaseDirs, opt: CommandLineArgs) -> Result<Self> {
let mut builder = formatted_timed_builder();
if opt.verbose {
@@ -210,18 +201,9 @@ impl Config {
builder.init();
let config_file = ConfigFile::read(base_dirs).unwrap_or_else(|e| {
use failure::Fail;
// Inform the user about errors when loading the configuration,
// but fallback to the default config to at least attempt to do something
log::error!("failed to load configuration: {}", e);
let mut err = e.cause();
while let Some(e) = err {
log::error!("{}", e);
err = e.cause();
}
ConfigFile::default()
});
@@ -235,7 +217,7 @@ impl Config {
}
/// Launch an editor to edit the configuration
pub fn edit(base_dirs: &BaseDirs) -> Result<(), Error> {
pub fn edit(base_dirs: &BaseDirs) -> Result<()> {
ConfigFile::edit(base_dirs)
}

View File

@@ -1,92 +1,28 @@
use failure::{Backtrace, Context, Fail};
use std::fmt::{self, Display};
use std::process::ExitStatus;
use thiserror::Error;
#[derive(Debug)]
pub struct Error {
inner: Context<ErrorKind>,
}
#[derive(Copy, Clone, Eq, PartialEq, Debug, Fail)]
pub enum ErrorKind {
#[fail(display = "Error asking the user for retry")]
Retry,
#[fail(display = "Cannot find the user base directories")]
NoBaseDirectories,
#[fail(display = "A step failed")]
StepFailed,
#[fail(display = "Error reading the configuration")]
Configuration,
#[fail(display = "A custom pre-command failed")]
PreCommand,
#[fail(display = "{}", _0)]
#[derive(Error, Debug, PartialEq)]
pub enum TopgradeError {
#[error("{0}")]
ProcessFailed(ExitStatus),
#[fail(display = "Unknown Linux Distribution")]
#[error("Unknown Linux Distribution")]
#[cfg(target_os = "linux")]
UnknownLinuxDistribution,
#[fail(display = "Process execution failure")]
ProcessExecution,
#[fail(display = "Self-update failure")]
#[cfg(feature = "self-update")]
SelfUpdate,
#[fail(display = "A step should be skipped")]
SkipStep,
#[cfg(all(windows, feature = "self-update"))]
#[fail(display = "Topgrade Upgraded")]
Upgraded(ExitStatus),
#[error("A pull action was failed")]
PullFailed,
}
impl Fail for Error {
fn cause(&self) -> Option<&dyn Fail> {
self.inner.cause()
}
#[derive(Error, Debug)]
#[error("A step failed")]
pub struct StepFailed;
fn backtrace(&self) -> Option<&Backtrace> {
self.inner.backtrace()
}
}
#[derive(Error, Debug)]
#[error("A step should be skipped")]
pub struct SkipStep;
impl Display for Error {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
Display::fmt(&self.inner, f)
}
}
impl Error {
pub fn kind(&self) -> ErrorKind {
*self.inner.get_context()
}
#[cfg(all(windows, feature = "self-update"))]
pub fn upgraded(&self) -> bool {
if let ErrorKind::Upgraded(_) = self.kind() {
true
} else {
false
}
}
}
impl From<ErrorKind> for Error {
fn from(kind: ErrorKind) -> Error {
Error {
inner: Context::new(kind),
}
}
}
impl From<Context<ErrorKind>> for Error {
fn from(inner: Context<ErrorKind>) -> Error {
Error { inner }
}
}
#[cfg(all(windows, feature = "self-update"))]
#[derive(Error, Debug)]
#[error("Topgrade Upgraded")]
pub struct Upgraded(pub ExitStatus);

View File

@@ -1,7 +1,7 @@
//! Utilities for command execution
use super::error::{Error, ErrorKind};
use super::utils::Check;
use failure::ResultExt;
use crate::error::TopgradeError;
use crate::utils::Check;
use anyhow::Result;
use log::trace;
use std::ffi::{OsStr, OsString};
use std::path::Path;
@@ -119,9 +119,9 @@ impl Executor {
}
/// See `std::process::Command::spawn`
pub fn spawn(&mut self) -> Result<ExecutorChild, Error> {
pub fn spawn(&mut self) -> Result<ExecutorChild> {
let result = match self {
Executor::Wet(c) => c.spawn().context(ErrorKind::ProcessExecution).map(ExecutorChild::Wet)?,
Executor::Wet(c) => c.spawn().map(ExecutorChild::Wet)?,
Executor::Dry(c) => {
c.dry_run();
ExecutorChild::Dry
@@ -132,9 +132,9 @@ impl Executor {
}
/// See `std::process::Command::output`
pub fn output(&mut self) -> Result<ExecutorOutput, Error> {
pub fn output(&mut self) -> Result<ExecutorOutput> {
match self {
Executor::Wet(c) => Ok(ExecutorOutput::Wet(c.output().context(ErrorKind::ProcessExecution)?)),
Executor::Wet(c) => Ok(ExecutorOutput::Wet(c.output()?)),
Executor::Dry(c) => {
c.dry_run();
Ok(ExecutorOutput::Dry)
@@ -145,7 +145,7 @@ impl Executor {
/// A convinence method for `spawn().wait().check()`.
/// Returns an error if something went wrong during the execution or if the
/// process exited with failure.
pub fn check_run(&mut self) -> Result<(), Error> {
pub fn check_run(&mut self) -> Result<()> {
self.spawn()?.wait()?.check()
}
}
@@ -189,12 +189,9 @@ pub enum ExecutorChild {
impl ExecutorChild {
/// See `std::process::Child::wait`
pub fn wait(&mut self) -> Result<ExecutorExitStatus, Error> {
pub fn wait(&mut self) -> Result<ExecutorExitStatus> {
let result = match self {
ExecutorChild::Wet(c) => c
.wait()
.context(ErrorKind::ProcessExecution)
.map(ExecutorExitStatus::Wet)?,
ExecutorChild::Wet(c) => c.wait().map(ExecutorExitStatus::Wet)?,
ExecutorChild::Dry => ExecutorExitStatus::Dry,
};
@@ -209,7 +206,7 @@ pub enum ExecutorExitStatus {
}
impl Check for ExecutorExitStatus {
fn check(self) -> Result<(), Error> {
fn check(self) -> Result<()> {
match self {
ExecutorExitStatus::Wet(e) => e.check(),
ExecutorExitStatus::Dry => Ok(()),
@@ -220,17 +217,17 @@ impl Check for ExecutorExitStatus {
/// Extension methods for `std::process::Command`
pub trait CommandExt {
/// Run the command, wait for it to complete, check the return code and decode the output as UTF-8.
fn check_output(&mut self) -> Result<String, Error>;
fn check_output(&mut self) -> Result<String>;
}
impl CommandExt for Command {
fn check_output(&mut self) -> Result<String, Error> {
let output = self.output().context(ErrorKind::ProcessExecution)?;
fn check_output(&mut self) -> Result<String> {
let output = self.output()?;
trace!("Output of {:?}: {:?}", self, output);
let status = output.status;
if !status.success() {
return Err(ErrorKind::ProcessFailed(status).into());
return Err(TopgradeError::ProcessFailed(status).into());
}
Ok(String::from_utf8(output.stdout).context(ErrorKind::ProcessExecution)?)
Ok(String::from_utf8(output.stdout)?)
}
}

View File

@@ -11,11 +11,13 @@ mod terminal;
mod utils;
use self::config::{CommandLineArgs, Config, Step};
use self::error::{Error, ErrorKind};
#[cfg(all(windows, feature = "self-update"))]
use self::error::Upgraded;
use self::error::{SkipStep, StepFailed};
use self::report::Report;
use self::steps::*;
use self::terminal::*;
use failure::{Fail, ResultExt};
use anyhow::{anyhow, Result};
use log::debug;
#[cfg(feature = "self-update")]
use openssl_probe;
@@ -26,9 +28,9 @@ use std::io;
use std::process::exit;
use structopt::StructOpt;
fn execute<'a, F, M>(report: &mut Report<'a>, key: M, func: F, no_retry: bool) -> Result<(), Error>
fn execute<'a, F, M>(report: &mut Report<'a>, key: M, func: F, no_retry: bool) -> Result<()>
where
F: Fn() -> Result<(), Error>,
F: Fn() -> Result<()>,
M: Into<Cow<'a, str>> + Debug,
{
debug!("Step {:?}", key);
@@ -39,7 +41,7 @@ where
report.push_result(Some((key, true)));
break;
}
Err(ref e) if e.kind() == ErrorKind::SkipStep => {
Err(e) if e.downcast_ref::<SkipStep>().is_some() => {
break;
}
Err(_) => {
@@ -49,7 +51,7 @@ where
}
let should_ask = interrupted || !no_retry;
let should_retry = should_ask && should_retry(interrupted).context(ErrorKind::Retry)?;
let should_retry = should_ask && should_retry(interrupted)?;
if !should_retry {
report.push_result(Some((key, false)));
@@ -62,10 +64,10 @@ where
Ok(())
}
fn run() -> Result<(), Error> {
fn run() -> Result<()> {
ctrlc::set_handler();
let base_dirs = directories::BaseDirs::new().ok_or(ErrorKind::NoBaseDirectories)?;
let base_dirs = directories::BaseDirs::new().ok_or_else(|| anyhow!("No base directories"))?;
let opt = CommandLineArgs::from_args();
if opt.edit_config() {
@@ -98,29 +100,21 @@ fn run() -> Result<(), Error> {
if !run_type.dry() && env::var("TOPGRADE_NO_SELF_UPGRADE").is_err() {
let result = self_update::self_update();
#[cfg(windows)]
{
let upgraded = match &result {
Ok(()) => false,
Err(e) => e.upgraded(),
};
if upgraded {
return result;
if let Err(e) = &result {
#[cfg(windows)]
{
if e.downcast_ref::<Upgraded>().is_some() {
return result;
}
}
}
if let Err(e) = result {
print_warning(format!("Self update error: {}", e));
if let Some(cause) = e.cause() {
print_warning(format!("Caused by: {}", cause));
}
}
}
}
if let Some(commands) = config.pre_commands() {
for (name, command) in commands {
generic::run_custom_command(&name, &command, run_type).context(ErrorKind::PreCommand)?;
generic::run_custom_command(&name, &command, run_type)?;
}
}
@@ -661,7 +655,7 @@ fn run() -> Result<(), Error> {
if report.data().iter().all(|(_, succeeded)| *succeeded) {
Ok(())
} else {
Err(ErrorKind::StepFailed.into())
Err(StepFailed.into())
}
}
@@ -673,26 +667,19 @@ fn main() {
Err(error) => {
#[cfg(all(windows, feature = "self-update"))]
{
if let ErrorKind::Upgraded(status) = error.kind() {
if let Some(Upgraded(status)) = error.downcast_ref::<Upgraded>() {
exit(status.code().unwrap());
}
}
let should_print = match error.kind() {
ErrorKind::StepFailed => false,
ErrorKind::Retry => error
.cause()
.and_then(|cause| cause.downcast_ref::<io::Error>())
let skip_print = (error.downcast_ref::<StepFailed>().is_some())
|| (error
.downcast_ref::<io::Error>()
.filter(|io_error| io_error.kind() == io::ErrorKind::Interrupted)
.is_none(),
_ => true,
};
.is_some());
if should_print {
if !skip_print {
println!("Error: {}", error);
if let Some(cause) = error.cause() {
println!("Caused by: {}", cause);
}
}
exit(1);
}

View File

@@ -1,6 +1,7 @@
use super::error::{Error, ErrorKind};
use super::terminal::*;
use failure::ResultExt;
#[cfg(windows)]
use crate::error::Upgraded;
use anyhow::{bail, Result};
use self_update_crate;
use self_update_crate::backends::github::{GitHubUpdateStatus, Update};
use std::env;
@@ -8,7 +9,7 @@ use std::env;
use std::os::unix::process::CommandExt;
use std::process::Command;
pub fn self_update() -> Result<(), Error> {
pub fn self_update() -> Result<()> {
print_separator("Self update");
let current_exe = env::current_exe();
@@ -23,8 +24,7 @@ pub fn self_update() -> Result<(), Error> {
.current_version(self_update_crate::cargo_crate_version!())
.no_confirm(true)
.build()
.and_then(Update::update_extended)
.context(ErrorKind::SelfUpdate)?;
.and_then(Update::update_extended)?;
if let GitHubUpdateStatus::Updated(release) = &result {
println!("\nTopgrade upgraded to {}:\n", release.version());
@@ -36,22 +36,19 @@ pub fn self_update() -> Result<(), Error> {
{
if result.updated() {
print_warning("Respawning...");
let mut command = Command::new(current_exe.context(ErrorKind::SelfUpdate)?);
let mut command = Command::new(current_exe?);
command.args(env::args().skip(1)).env("TOPGRADE_NO_SELF_UPGRADE", "");
#[cfg(unix)]
{
let err = command.exec();
Err(err).context(ErrorKind::SelfUpdate)?
bail!(err);
}
#[cfg(windows)]
{
let status = command
.spawn()
.and_then(|mut c| c.wait())
.context(ErrorKind::SelfUpdate)?;
return Err(ErrorKind::Upgraded(status).into());
let status = command.spawn().and_then(|mut c| c.wait())?;
bail!(Upgraded(status));
}
}
}

View File

@@ -1,7 +1,7 @@
use crate::error::Error;
use crate::executor::RunType;
use crate::terminal::print_separator;
use crate::utils::{require, require_option, PathExt};
use anyhow::Result;
use directories::BaseDirs;
#[cfg(windows)]
use std::env;
@@ -35,7 +35,7 @@ impl Emacs {
self.directory.as_ref()
}
pub fn upgrade(&self, run_type: RunType) -> Result<(), Error> {
pub fn upgrade(&self, run_type: RunType) -> Result<()> {
let emacs = require("emacs")?;
let init_file = require_option(self.directory.as_ref())?.join("init.el").require()?;

View File

@@ -1,14 +1,14 @@
use crate::error::{Error, ErrorKind};
use crate::error::SkipStep;
use crate::executor::{CommandExt, RunType};
use crate::terminal::{print_separator, shell};
use crate::utils::{self, PathExt};
use anyhow::Result;
use directories::BaseDirs;
use failure::ResultExt;
use std::env;
use std::path::PathBuf;
use std::process::Command;
pub fn run_cargo_update(run_type: RunType) -> Result<(), Error> {
pub fn run_cargo_update(run_type: RunType) -> Result<()> {
let cargo_update = utils::require("cargo-install-update")?;
print_separator("Cargo");
@@ -19,14 +19,14 @@ pub fn run_cargo_update(run_type: RunType) -> Result<(), Error> {
.check_run()
}
pub fn run_flutter_upgrade(run_type: RunType) -> Result<(), Error> {
pub fn run_flutter_upgrade(run_type: RunType) -> Result<()> {
let flutter = utils::require("flutter")?;
print_separator("Flutter");
run_type.execute(&flutter).arg("upgrade").check_run()
}
pub fn run_go(base_dirs: &BaseDirs, run_type: RunType) -> Result<(), Error> {
pub fn run_go(base_dirs: &BaseDirs, run_type: RunType) -> Result<()> {
let go = utils::require("go")?;
env::var("GOPATH")
.unwrap_or_else(|_| base_dirs.home_dir().join("go").to_str().unwrap().to_string())
@@ -36,7 +36,7 @@ pub fn run_go(base_dirs: &BaseDirs, run_type: RunType) -> Result<(), Error> {
run_type.execute(&go).arg("get").arg("-u").arg("all").check_run()
}
pub fn run_gem(base_dirs: &BaseDirs, run_type: RunType) -> Result<(), Error> {
pub fn run_gem(base_dirs: &BaseDirs, run_type: RunType) -> Result<()> {
let gem = utils::require("gem")?;
base_dirs.home_dir().join(".gem").require()?;
@@ -51,7 +51,7 @@ pub fn run_gem(base_dirs: &BaseDirs, run_type: RunType) -> Result<(), Error> {
target_os = "netbsd",
target_os = "dragonfly"
)))]
pub fn run_apm(run_type: RunType) -> Result<(), Error> {
pub fn run_apm(run_type: RunType) -> Result<()> {
let apm = utils::require("apm")?;
print_separator("Atom Package Manager");
@@ -59,23 +59,19 @@ pub fn run_apm(run_type: RunType) -> Result<(), Error> {
run_type.execute(&apm).args(&["upgrade", "--confirm=false"]).check_run()
}
pub fn run_rustup(base_dirs: &BaseDirs, run_type: RunType) -> Result<(), Error> {
pub fn run_rustup(base_dirs: &BaseDirs, run_type: RunType) -> Result<()> {
let rustup = utils::require("rustup")?;
print_separator("rustup");
if rustup
.canonicalize()
.context(ErrorKind::StepFailed)?
.is_descendant_of(base_dirs.home_dir())
{
if rustup.canonicalize()?.is_descendant_of(base_dirs.home_dir()) {
run_type.execute(&rustup).args(&["self", "update"]).check_run()?;
}
run_type.execute(&rustup).arg("update").check_run()
}
pub fn run_jetpack(run_type: RunType) -> Result<(), Error> {
pub fn run_jetpack(run_type: RunType) -> Result<()> {
let jetpack = utils::require("jetpack")?;
print_separator("Jetpack");
@@ -83,7 +79,7 @@ pub fn run_jetpack(run_type: RunType) -> Result<(), Error> {
run_type.execute(&jetpack).args(&["global", "update"]).check_run()
}
pub fn run_opam_update(run_type: RunType) -> Result<(), Error> {
pub fn run_opam_update(run_type: RunType) -> Result<()> {
let opam = utils::require("opam")?;
print_separator("OCaml Package Manager");
@@ -92,28 +88,28 @@ pub fn run_opam_update(run_type: RunType) -> Result<(), Error> {
run_type.execute(&opam).arg("upgrade").check_run()
}
pub fn run_vcpkg_update(run_type: RunType) -> Result<(), Error> {
pub fn run_vcpkg_update(run_type: RunType) -> Result<()> {
let vcpkg = utils::require("vcpkg")?;
print_separator("vcpkg");
run_type.execute(&vcpkg).args(&["upgrade", "--no-dry-run"]).check_run()
}
pub fn run_pipx_update(run_type: RunType) -> Result<(), Error> {
pub fn run_pipx_update(run_type: RunType) -> Result<()> {
let pipx = utils::require("pipx")?;
print_separator("pipx");
run_type.execute(&pipx).arg("upgrade-all").check_run()
}
pub fn run_stack_update(run_type: RunType) -> Result<(), Error> {
pub fn run_stack_update(run_type: RunType) -> Result<()> {
let stack = utils::require("stack")?;
print_separator("stack");
run_type.execute(&stack).arg("upgrade").check_run()
}
pub fn run_myrepos_update(base_dirs: &BaseDirs, run_type: RunType) -> Result<(), Error> {
pub fn run_myrepos_update(base_dirs: &BaseDirs, run_type: RunType) -> Result<()> {
let myrepos = utils::require("mr")?;
base_dirs.home_dir().join(".mrconfig").require()?;
@@ -133,22 +129,22 @@ pub fn run_myrepos_update(base_dirs: &BaseDirs, run_type: RunType) -> Result<(),
.check_run()
}
pub fn run_custom_command(name: &str, command: &str, run_type: RunType) -> Result<(), Error> {
pub fn run_custom_command(name: &str, command: &str, run_type: RunType) -> Result<()> {
print_separator(name);
run_type.execute(shell()).arg("-c").arg(command).check_run()
}
pub fn run_composer_update(base_dirs: &BaseDirs, run_type: RunType) -> Result<(), Error> {
pub fn run_composer_update(base_dirs: &BaseDirs, run_type: RunType) -> Result<()> {
let composer = utils::require("composer")?;
let composer_home = Command::new(&composer)
.args(&["global", "config", "--absolute", "--quiet", "home"])
.check_output()
.map_err(|_| Error::from(ErrorKind::SkipStep))
.map(|s| PathBuf::from(s.trim()))
.and_then(PathExt::require)?;
.map_err(|_| (SkipStep))
.map(|s| PathBuf::from(s.trim()))?
.require()?;
if !composer_home.is_descendant_of(base_dirs.home_dir()) {
return Err(ErrorKind::SkipStep.into());
return Err(SkipStep.into());
}
print_separator("Composer");
@@ -168,14 +164,14 @@ pub fn run_remote_topgrade(
ssh_arguments: &Option<String>,
run_in_tmux: bool,
_tmux_arguments: &Option<String>,
) -> Result<(), Error> {
) -> Result<()> {
let ssh = utils::require("ssh")?;
if run_in_tmux && !run_type.dry() {
#[cfg(unix)]
{
crate::tmux::run_remote_topgrade(hostname, &ssh, _tmux_arguments)?;
Err(ErrorKind::SkipStep.into())
Err(SkipStep.into())
}
#[cfg(not(unix))]

View File

@@ -1,7 +1,8 @@
use crate::error::{Error, ErrorKind};
use crate::error::TopgradeError;
use crate::executor::{CommandExt, RunType};
use crate::terminal::print_separator;
use crate::utils::{which, HumanizedPath};
use anyhow::Result;
use console::style;
use futures::future::{join_all, Future};
use glob::{glob_with, MatchOptions};
@@ -79,7 +80,7 @@ impl Git {
repositories: &Repositories,
run_type: RunType,
extra_arguments: &Option<String>,
) -> Result<(), Error> {
) -> Result<()> {
if repositories.repositories.is_empty() {
return Ok(());
}
@@ -143,7 +144,7 @@ impl Git {
println!("{} {}", style("Up-to-date").green().bold(), path);
}
}
Ok(true) as Result<bool, Error>
Ok(true) as Result<bool>
} else {
println!("{} pulling {}", style("Failed").red().bold(), path);
if let Ok(text) = std::str::from_utf8(&output.stderr) {
@@ -163,7 +164,7 @@ impl Git {
let mut runtime = Runtime::new().unwrap();
let results: Vec<bool> = runtime.block_on(join_all(futures))?;
if results.into_iter().any(|success| !success) {
Err(ErrorKind::StepFailed.into())
Err(TopgradeError::PullFailed.into())
} else {
Ok(())
}

View File

@@ -1,7 +1,9 @@
use crate::error::{Error, ErrorKind};
use crate::error::SkipStep;
use crate::executor::{CommandExt, RunType};
use crate::terminal::print_separator;
use crate::utils::{require, PathExt};
use anyhow::Result;
use directories::BaseDirs;
use std::path::PathBuf;
use std::process::Command;
@@ -15,32 +17,32 @@ impl NPM {
Self { command }
}
fn root(&self) -> Result<PathBuf, Error> {
fn root(&self) -> Result<PathBuf> {
Command::new(&self.command)
.args(&["root", "-g"])
.check_output()
.map(PathBuf::from)
}
fn upgrade(&self, run_type: RunType) -> Result<(), Error> {
fn upgrade(&self, run_type: RunType) -> Result<()> {
run_type.execute(&self.command).args(&["update", "-g"]).check_run()?;
Ok(())
}
}
pub fn run_npm_upgrade(base_dirs: &BaseDirs, run_type: RunType) -> Result<(), Error> {
pub fn run_npm_upgrade(base_dirs: &BaseDirs, run_type: RunType) -> Result<()> {
let npm = require("npm").map(NPM::new)?;
let npm_root = npm.root()?;
if !npm_root.is_descendant_of(base_dirs.home_dir()) {
return Err(ErrorKind::SkipStep.into());
return Err(SkipStep.into());
}
print_separator("Node Package Manager");
npm.upgrade(run_type)
}
pub fn yarn_global_update(run_type: RunType) -> Result<(), Error> {
pub fn yarn_global_update(run_type: RunType) -> Result<()> {
let yarn = require("yarn")?;
print_separator("Yarn");

View File

@@ -1,4 +1,4 @@
use crate::error::{Error, ErrorKind};
use crate::error::TopgradeError;
use crate::executor::RunType;
use crate::terminal::print_separator;
use crate::utils::require_option;
@@ -6,7 +6,7 @@ use failure::ResultExt;
use std::path::PathBuf;
use std::process::Command;
pub fn upgrade_packages(sudo: Option<&PathBuf>, run_type: RunType) -> Result<(), Error> {
pub fn upgrade_packages(sudo: Option<&PathBuf>, run_type: RunType) -> Result<()> {
let sudo = require_option(sudo)?;
print_separator("DrgaonFly BSD Packages");
run_type
@@ -15,7 +15,7 @@ pub fn upgrade_packages(sudo: Option<&PathBuf>, run_type: RunType) -> Result<(),
.check_run()
}
pub fn audit_packages(sudo: &Option<PathBuf>) -> Result<(), Error> {
pub fn audit_packages(sudo: &Option<PathBuf>) -> Result<()> {
if let Some(sudo) = sudo {
println!();
Command::new(sudo)

View File

@@ -1,4 +1,4 @@
use crate::error::{Error, ErrorKind};
use crate::error::TopgradeError;
use crate::executor::RunType;
use crate::terminal::print_separator;
use crate::utils::require_option;
@@ -6,7 +6,7 @@ use failure::ResultExt;
use std::path::PathBuf;
use std::process::Command;
pub fn upgrade_freebsd(sudo: Option<&PathBuf>, run_type: RunType) -> Result<(), Error> {
pub fn upgrade_freebsd(sudo: Option<&PathBuf>, run_type: RunType) -> Result<()> {
let sudo = require_option(sudo)?;
print_separator("FreeBSD Update");
run_type
@@ -15,13 +15,13 @@ pub fn upgrade_freebsd(sudo: Option<&PathBuf>, run_type: RunType) -> Result<(),
.check_run()
}
pub fn upgrade_packages(sudo: Option<&PathBuf>, run_type: RunType) -> Result<(), Error> {
pub fn upgrade_packages(sudo: Option<&PathBuf>, run_type: RunType) -> Result<()> {
let sudo = require_option(sudo)?;
print_separator("FreeBSD Packages");
run_type.execute(sudo).args(&["/usr/sbin/pkg", "upgrade"]).check_run()
}
pub fn audit_packages(sudo: &Option<PathBuf>) -> Result<(), Error> {
pub fn audit_packages(sudo: &Option<PathBuf>) -> Result<()> {
if let Some(sudo) = sudo {
println!();
Command::new(sudo)

View File

@@ -1,9 +1,9 @@
use crate::config::Config;
use crate::error::{Error, ErrorKind};
use crate::error::{SkipStep, TopgradeError};
use crate::executor::{ExecutorExitStatus, RunType};
use crate::terminal::{print_separator, print_warning};
use crate::utils::{require, require_option, which, PathExt};
use failure::ResultExt;
use anyhow::Result;
use ini::Ini;
use log::debug;
use serde::Deserialize;
@@ -37,7 +37,7 @@ pub enum Distribution {
}
impl Distribution {
fn parse_os_release(os_release: &ini::Ini) -> Result<Self, Error> {
fn parse_os_release(os_release: &ini::Ini) -> Result<Self> {
let section = os_release.general_section();
let id = section.get("ID").map(String::as_str);
let id_like: Option<Vec<&str>> = section
@@ -65,22 +65,22 @@ impl Distribution {
Some("gentoo") => Distribution::Gentoo,
Some("exherbo") => Distribution::Exherbo,
Some("nixos") => Distribution::NixOS,
_ => return Err(ErrorKind::UnknownLinuxDistribution.into()),
_ => return Err(TopgradeError::UnknownLinuxDistribution.into()),
})
}
pub fn detect() -> Result<Self, Error> {
pub fn detect() -> Result<Self> {
if PathBuf::from(OS_RELEASE_PATH).exists() {
let os_release = Ini::load_from_file(OS_RELEASE_PATH).context(ErrorKind::UnknownLinuxDistribution)?;
let os_release = Ini::load_from_file(OS_RELEASE_PATH)?;
return Self::parse_os_release(&os_release);
}
Err(ErrorKind::UnknownLinuxDistribution.into())
Err(TopgradeError::UnknownLinuxDistribution.into())
}
#[must_use]
pub fn upgrade(self, sudo: &Option<PathBuf>, run_type: RunType, config: &Config) -> Result<(), Error> {
pub fn upgrade(self, sudo: &Option<PathBuf>, run_type: RunType, config: &Config) -> Result<()> {
print_separator("System update");
let yes = config.yes();
@@ -134,7 +134,7 @@ fn upgrade_arch_linux(
run_type: RunType,
yes: bool,
yay_arguments: &str,
) -> Result<(), Error> {
) -> Result<()> {
let pacman = which("powerpill").unwrap_or_else(|| PathBuf::from("/usr/bin/pacman"));
let path = {
@@ -197,7 +197,7 @@ fn upgrade_arch_linux(
Ok(())
}
fn upgrade_redhat(sudo: &Option<PathBuf>, run_type: RunType, yes: bool) -> Result<(), Error> {
fn upgrade_redhat(sudo: &Option<PathBuf>, run_type: RunType, yes: bool) -> Result<()> {
if let Some(sudo) = &sudo {
let mut command = run_type.execute(&sudo);
command
@@ -219,7 +219,7 @@ fn upgrade_redhat(sudo: &Option<PathBuf>, run_type: RunType, yes: bool) -> Resul
Ok(())
}
fn upgrade_suse(sudo: &Option<PathBuf>, run_type: RunType) -> Result<(), Error> {
fn upgrade_suse(sudo: &Option<PathBuf>, run_type: RunType) -> Result<()> {
if let Some(sudo) = &sudo {
run_type
.execute(&sudo)
@@ -237,7 +237,7 @@ fn upgrade_suse(sudo: &Option<PathBuf>, run_type: RunType) -> Result<(), Error>
Ok(())
}
fn upgrade_void(sudo: &Option<PathBuf>, run_type: RunType) -> Result<(), Error> {
fn upgrade_void(sudo: &Option<PathBuf>, run_type: RunType) -> Result<()> {
if let Some(sudo) = &sudo {
for _ in 0..2 {
run_type
@@ -252,7 +252,7 @@ fn upgrade_void(sudo: &Option<PathBuf>, run_type: RunType) -> Result<(), Error>
Ok(())
}
fn upgrade_gentoo(sudo: &Option<PathBuf>, run_type: RunType) -> Result<(), Error> {
fn upgrade_gentoo(sudo: &Option<PathBuf>, run_type: RunType) -> Result<()> {
if let Some(sudo) = &sudo {
if let Some(layman) = which("layman") {
run_type.execute(&sudo).arg(layman).args(&["-s", "ALL"]).check_run()?;
@@ -281,7 +281,7 @@ fn upgrade_gentoo(sudo: &Option<PathBuf>, run_type: RunType) -> Result<(), Error
Ok(())
}
fn upgrade_debian(sudo: &Option<PathBuf>, cleanup: bool, run_type: RunType, yes: bool) -> Result<(), Error> {
fn upgrade_debian(sudo: &Option<PathBuf>, cleanup: bool, run_type: RunType, yes: bool) -> Result<()> {
if let Some(sudo) = &sudo {
let apt = which("apt-fast").unwrap_or_else(|| PathBuf::from("/usr/bin/apt"));
run_type.execute(&sudo).arg(&apt).arg("update").check_run()?;
@@ -310,7 +310,7 @@ fn upgrade_debian(sudo: &Option<PathBuf>, cleanup: bool, run_type: RunType, yes:
Ok(())
}
fn upgrade_solus(sudo: &Option<PathBuf>, run_type: RunType) -> Result<(), Error> {
fn upgrade_solus(sudo: &Option<PathBuf>, run_type: RunType) -> Result<()> {
if let Some(sudo) = &sudo {
run_type
.execute(&sudo)
@@ -323,7 +323,7 @@ fn upgrade_solus(sudo: &Option<PathBuf>, run_type: RunType) -> Result<(), Error>
Ok(())
}
fn upgrade_clearlinux(sudo: &Option<PathBuf>, run_type: RunType) -> Result<(), Error> {
fn upgrade_clearlinux(sudo: &Option<PathBuf>, run_type: RunType) -> Result<()> {
if let Some(sudo) = &sudo {
run_type
.execute(&sudo)
@@ -336,7 +336,7 @@ fn upgrade_clearlinux(sudo: &Option<PathBuf>, run_type: RunType) -> Result<(), E
Ok(())
}
fn upgrade_exherbo(sudo: &Option<PathBuf>, cleanup: bool, run_type: RunType) -> Result<(), Error> {
fn upgrade_exherbo(sudo: &Option<PathBuf>, cleanup: bool, run_type: RunType) -> Result<()> {
if let Some(sudo) = &sudo {
run_type.execute(&sudo).args(&["/usr/bin/cave", "sync"]).check_run()?;
@@ -368,7 +368,7 @@ fn upgrade_exherbo(sudo: &Option<PathBuf>, cleanup: bool, run_type: RunType) ->
Ok(())
}
fn upgrade_nixos(sudo: &Option<PathBuf>, cleanup: bool, run_type: RunType) -> Result<(), Error> {
fn upgrade_nixos(sudo: &Option<PathBuf>, cleanup: bool, run_type: RunType) -> Result<()> {
if let Some(sudo) = &sudo {
run_type
.execute(&sudo)
@@ -388,7 +388,7 @@ fn upgrade_nixos(sudo: &Option<PathBuf>, cleanup: bool, run_type: RunType) -> Re
Ok(())
}
pub fn run_needrestart(sudo: Option<&PathBuf>, run_type: RunType) -> Result<(), Error> {
pub fn run_needrestart(sudo: Option<&PathBuf>, run_type: RunType) -> Result<()> {
let sudo = require_option(sudo)?;
let needrestart = require("needrestart")?;
@@ -400,7 +400,7 @@ pub fn run_needrestart(sudo: Option<&PathBuf>, run_type: RunType) -> Result<(),
}
#[must_use]
pub fn run_fwupdmgr(run_type: RunType) -> Result<(), Error> {
pub fn run_fwupdmgr(run_type: RunType) -> Result<()> {
let fwupdmgr = require("fwupdmgr")?;
print_separator("Firmware upgrades");
@@ -410,7 +410,7 @@ pub fn run_fwupdmgr(run_type: RunType) -> Result<(), Error> {
if let ExecutorExitStatus::Wet(e) = exit_status {
if !(e.success() || e.code().map(|c| c == 2).unwrap_or(false)) {
return Err(ErrorKind::ProcessFailed(e).into());
return Err(TopgradeError::ProcessFailed(e).into());
}
}
@@ -418,7 +418,7 @@ pub fn run_fwupdmgr(run_type: RunType) -> Result<(), Error> {
}
#[must_use]
pub fn flatpak_update(run_type: RunType) -> Result<(), Error> {
pub fn flatpak_update(run_type: RunType) -> Result<()> {
let flatpak = require("flatpak")?;
print_separator("Flatpak User Packages");
@@ -433,12 +433,12 @@ pub fn flatpak_update(run_type: RunType) -> Result<(), Error> {
}
#[must_use]
pub fn run_snap(sudo: Option<&PathBuf>, run_type: RunType) -> Result<(), Error> {
pub fn run_snap(sudo: Option<&PathBuf>, run_type: RunType) -> Result<()> {
let sudo = require_option(sudo)?;
let snap = require("snap")?;
if !PathBuf::from("/var/snapd.socket").exists() && !PathBuf::from("/run/snapd.socket").exists() {
return Err(ErrorKind::SkipStep.into());
return Err(SkipStep.into());
}
print_separator("snap");
@@ -446,7 +446,7 @@ pub fn run_snap(sudo: Option<&PathBuf>, run_type: RunType) -> Result<(), Error>
}
#[must_use]
pub fn run_rpi_update(sudo: Option<&PathBuf>, run_type: RunType) -> Result<(), Error> {
pub fn run_rpi_update(sudo: Option<&PathBuf>, run_type: RunType) -> Result<()> {
let sudo = require_option(sudo)?;
let rpi_update = require("rpi-update")?;
@@ -456,7 +456,7 @@ pub fn run_rpi_update(sudo: Option<&PathBuf>, run_type: RunType) -> Result<(), E
}
#[must_use]
pub fn run_pihole_update(sudo: Option<&PathBuf>, run_type: RunType) -> Result<(), Error> {
pub fn run_pihole_update(sudo: Option<&PathBuf>, run_type: RunType) -> Result<()> {
let sudo = require_option(sudo)?;
let pihole = require("pihole")?;
@@ -466,7 +466,7 @@ pub fn run_pihole_update(sudo: Option<&PathBuf>, run_type: RunType) -> Result<()
}
#[must_use]
pub fn run_etc_update(sudo: Option<&PathBuf>, run_type: RunType) -> Result<(), Error> {
pub fn run_etc_update(sudo: Option<&PathBuf>, run_type: RunType) -> Result<()> {
let sudo = require_option(sudo)?;
let etc_update = require("etc-update")?;
print_separator("etc-update");

View File

@@ -1,9 +1,9 @@
use crate::error::Error;
use crate::executor::RunType;
use crate::terminal::print_separator;
use anyhow::Result;
#[must_use]
pub fn upgrade_macos(run_type: RunType) -> Result<(), Error> {
pub fn upgrade_macos(run_type: RunType) -> Result<()> {
print_separator("App Store");
run_type

View File

@@ -1,15 +1,15 @@
use crate::error::Error;
#[cfg(target_os = "linux")]
use crate::error::ErrorKind;
use crate::error::SkipStep;
use crate::executor::{CommandExt, RunType};
use crate::terminal::print_separator;
use crate::utils::{require, PathExt};
use anyhow::Result;
use directories::BaseDirs;
use std::env;
use std::path::{Path, PathBuf};
use std::process::Command;
pub fn run_fisher(base_dirs: &BaseDirs, run_type: RunType) -> Result<(), Error> {
pub fn run_fisher(base_dirs: &BaseDirs, run_type: RunType) -> Result<()> {
let fish = require("fish")?;
base_dirs
.home_dir()
@@ -26,7 +26,7 @@ pub fn run_fisher(base_dirs: &BaseDirs, run_type: RunType) -> Result<(), Error>
}
#[must_use]
pub fn run_homebrew(cleanup: bool, run_type: RunType) -> Result<(), Error> {
pub fn run_homebrew(cleanup: bool, run_type: RunType) -> Result<()> {
let brew = require("brew")?;
print_separator("Brew");
@@ -52,7 +52,7 @@ pub fn run_homebrew(cleanup: bool, run_type: RunType) -> Result<(), Error> {
}
#[must_use]
pub fn run_nix(run_type: RunType) -> Result<(), Error> {
pub fn run_nix(run_type: RunType) -> Result<()> {
let nix = require("nix")?;
let nix_channel = require("nix-channel")?;
let nix_env = require("nix-env")?;
@@ -65,7 +65,7 @@ pub fn run_nix(run_type: RunType) -> Result<(), Error> {
if let Ok(Distribution::NixOS) = Distribution::detect() {
debug!("Nix on NixOS must be upgraded via 'nixos-rebuild switch', skipping.");
return Err(ErrorKind::SkipStep.into());
return Err(SkipStep.into());
}
}
@@ -74,21 +74,21 @@ pub fn run_nix(run_type: RunType) -> Result<(), Error> {
run_type.execute(&nix_env).arg("--upgrade").check_run()
}
pub fn run_home_manager(run_type: RunType) -> Result<(), Error> {
pub fn run_home_manager(run_type: RunType) -> Result<()> {
let home_manager = require("home-manager")?;
print_separator("home-manager");
run_type.execute(&home_manager).arg("switch").check_run()
}
pub fn run_pearl(run_type: RunType) -> Result<(), Error> {
pub fn run_pearl(run_type: RunType) -> Result<()> {
let pearl = require("pearl")?;
print_separator("pearl");
run_type.execute(&pearl).arg("update").check_run()
}
pub fn run_sdkman(base_dirs: &BaseDirs, cleanup: bool, run_type: RunType) -> Result<(), Error> {
pub fn run_sdkman(base_dirs: &BaseDirs, cleanup: bool, run_type: RunType) -> Result<()> {
let bash = require("bash")?;
let sdkman_init_path = env::var("SDKMAN_DIR")

View File

@@ -1,17 +1,18 @@
use crate::error::{Error, ErrorKind};
use crate::error::SkipStep;
use crate::executor::{CommandExt, RunType};
use crate::terminal::print_separator;
use crate::utils::require;
use anyhow::Result;
use std::process::Command;
pub fn run_chocolatey(run_type: RunType) -> Result<(), Error> {
pub fn run_chocolatey(run_type: RunType) -> Result<()> {
let choco = require("choco")?;
print_separator("Chocolatey");
run_type.execute(&choco).args(&["upgrade", "all"]).check_run()
}
pub fn run_scoop(run_type: RunType) -> Result<(), Error> {
pub fn run_scoop(run_type: RunType) -> Result<()> {
let scoop = require("scoop")?;
print_separator("Scoop");
@@ -20,12 +21,12 @@ pub fn run_scoop(run_type: RunType) -> Result<(), Error> {
run_type.execute(&scoop).args(&["update", "*"]).check_run()
}
pub fn run_wsl_topgrade(run_type: RunType) -> Result<(), Error> {
pub fn run_wsl_topgrade(run_type: RunType) -> Result<()> {
let wsl = require("wsl")?;
let topgrade = Command::new(&wsl)
.args(&["bash", "-l", "which", "topgrade"])
.check_output()
.map_err(|_| ErrorKind::SkipStep)?;
.map_err(|_| SkipStep)?;
run_type
.execute(&wsl)

View File

@@ -1,9 +1,9 @@
use crate::error::Error;
#[cfg(windows)]
use crate::error::ErrorKind;
use crate::error::SkipStep;
use crate::executor::{CommandExt, RunType};
use crate::terminal::{is_dumb, print_separator};
use crate::utils::{require_option, which, PathExt};
use anyhow::Result;
use std::path::PathBuf;
use std::process::Command;
@@ -53,7 +53,7 @@ impl Powershell {
self.profile.as_ref()
}
pub fn update_modules(&self, run_type: RunType) -> Result<(), Error> {
pub fn update_modules(&self, run_type: RunType) -> Result<()> {
let powershell = require_option(self.path.as_ref())?;
print_separator("Powershell Modules Update");
@@ -65,11 +65,11 @@ impl Powershell {
}
#[cfg(windows)]
pub fn windows_update(&self, run_type: RunType) -> Result<(), Error> {
pub fn windows_update(&self, run_type: RunType) -> Result<()> {
let powershell = require_option(self.path.as_ref())?;
if !Self::has_module(&powershell, "PSWindowsUpdate") {
return Err(ErrorKind::SkipStep.into());
return Err(SkipStep.into());
}
print_separator("Windows Update");

View File

@@ -1,16 +1,15 @@
use crate::error::{Error, ErrorKind};
use crate::executor::RunType;
use crate::terminal::print_separator;
use crate::utils::{which, Check, PathExt};
use anyhow::Result;
use directories::BaseDirs;
use failure::ResultExt;
use std::env;
use std::io;
use std::os::unix::process::CommandExt;
use std::path::{Path, PathBuf};
use std::process::{exit, Command};
pub fn run_tpm(base_dirs: &BaseDirs, run_type: RunType) -> Result<(), Error> {
pub fn run_tpm(base_dirs: &BaseDirs, run_type: RunType) -> Result<()> {
let tpm = base_dirs
.home_dir()
.join(".tmux/plugins/tpm/bin/update_plugins")
@@ -62,13 +61,11 @@ impl Tmux {
.success())
}
fn run_in_session(&self, command: &str) -> Result<(), Error> {
fn run_in_session(&self, command: &str) -> Result<()> {
self.build()
.args(&["new-window", "-a", "-t", "topgrade:1", command])
.spawn()
.context(ErrorKind::ProcessExecution)?
.wait()
.context(ErrorKind::ProcessExecution)?
.spawn()?
.wait()?
.check()?;
Ok(())
@@ -107,7 +104,7 @@ pub fn run_in_tmux(args: &Option<String>) -> ! {
}
}
pub fn run_remote_topgrade(hostname: &str, ssh: &Path, tmux_args: &Option<String>) -> Result<(), Error> {
pub fn run_remote_topgrade(hostname: &str, ssh: &Path, tmux_args: &Option<String>) -> Result<()> {
let command = format!(
"{ssh} -t {hostname} env TOPGRADE_PREFIX={hostname} TOPGRADE_KEEP_END=1 topgrade",
ssh = ssh.display(),
@@ -117,9 +114,7 @@ pub fn run_remote_topgrade(hostname: &str, ssh: &Path, tmux_args: &Option<String
.build()
.args(&["new-window", "-a", "-t", "topgrade:1", &command])
.env_remove("TMUX")
.spawn()
.context(ErrorKind::ProcessExecution)?
.wait()
.context(ErrorKind::ProcessExecution)?
.spawn()?
.wait()?
.check()
}

View File

@@ -1,4 +1,6 @@
use crate::error::{Error, ErrorKind};
use crate::error::{SkipStep, TopgradeError};
use anyhow::Result;
use crate::executor::{CommandExt, ExecutorOutput, RunType};
use crate::terminal::print_separator;
use crate::utils::{require, require_option, PathExt};
@@ -74,7 +76,7 @@ fn upgrade(
plugin_framework: PluginFramework,
run_type: RunType,
cleanup: bool,
) -> Result<(), Error> {
) -> Result<()> {
let output = run_type
.execute(&vim)
.args(&["-N", "-u"])
@@ -95,7 +97,7 @@ fn upgrade(
if !status.success() {
io::stdout().write(&output.stdout).ok();
io::stderr().write(&output.stderr).ok();
return Err(ErrorKind::ProcessFailed(status).into());
return Err(TopgradeError::ProcessFailed(status).into());
} else {
println!("Plugins upgraded")
}
@@ -105,12 +107,12 @@ fn upgrade(
}
#[must_use]
pub fn upgrade_vim(base_dirs: &BaseDirs, run_type: RunType, cleanup: bool) -> Result<(), Error> {
pub fn upgrade_vim(base_dirs: &BaseDirs, run_type: RunType, cleanup: bool) -> Result<()> {
let vim = require("vim")?;
let output = Command::new(&vim).arg("--version").check_output()?;
if !output.starts_with("VIM") {
return Err(ErrorKind::SkipStep.into());
return Err(SkipStep.into());
}
let vimrc = require_option(vimrc(&base_dirs))?;
@@ -121,7 +123,7 @@ pub fn upgrade_vim(base_dirs: &BaseDirs, run_type: RunType, cleanup: bool) -> Re
}
#[must_use]
pub fn upgrade_neovim(base_dirs: &BaseDirs, run_type: RunType, cleanup: bool) -> Result<(), Error> {
pub fn upgrade_neovim(base_dirs: &BaseDirs, run_type: RunType, cleanup: bool) -> Result<()> {
let nvim = require("nvim")?;
let nvimrc = require_option(nvimrc(&base_dirs))?;
let plugin_framework = require_option(PluginFramework::detect(&nvimrc))?;
@@ -130,7 +132,7 @@ pub fn upgrade_neovim(base_dirs: &BaseDirs, run_type: RunType, cleanup: bool) ->
upgrade(&nvim, &nvimrc, plugin_framework, run_type, cleanup)
}
pub fn run_voom(_base_dirs: &BaseDirs, run_type: RunType) -> Result<(), Error> {
pub fn run_voom(_base_dirs: &BaseDirs, run_type: RunType) -> Result<()> {
let voom = require("voom")?;
print_separator("voom");

View File

@@ -1,12 +1,12 @@
use crate::error::Error;
use crate::executor::RunType;
use crate::terminal::print_separator;
use crate::utils::{require, PathExt};
use anyhow::Result;
use directories::BaseDirs;
use std::env;
use std::path::{Path, PathBuf};
pub fn run_zr(base_dirs: &BaseDirs, run_type: RunType) -> Result<(), Error> {
pub fn run_zr(base_dirs: &BaseDirs, run_type: RunType) -> Result<()> {
let zsh = require("zsh")?;
env::var("ZR_HOME")
@@ -26,7 +26,7 @@ pub fn zshrc(base_dirs: &BaseDirs) -> PathBuf {
.unwrap_or_else(|_| base_dirs.home_dir().join(".zshrc"))
}
pub fn run_antigen(base_dirs: &BaseDirs, run_type: RunType) -> Result<(), Error> {
pub fn run_antigen(base_dirs: &BaseDirs, run_type: RunType) -> Result<()> {
let zsh = require("zsh")?;
let zshrc = zshrc(base_dirs).require()?;
env::var("ADOTDIR")
@@ -40,7 +40,7 @@ pub fn run_antigen(base_dirs: &BaseDirs, run_type: RunType) -> Result<(), Error>
run_type.execute(zsh).args(&["-c", cmd.as_str()]).check_run()
}
pub fn run_zplug(base_dirs: &BaseDirs, run_type: RunType) -> Result<(), Error> {
pub fn run_zplug(base_dirs: &BaseDirs, run_type: RunType) -> Result<()> {
let zsh = require("zsh")?;
let zshrc = zshrc(base_dirs).require()?;
@@ -55,7 +55,7 @@ pub fn run_zplug(base_dirs: &BaseDirs, run_type: RunType) -> Result<(), Error> {
run_type.execute(zsh).args(&["-c", cmd.as_str()]).check_run()
}
pub fn run_zplugin(base_dirs: &BaseDirs, run_type: RunType) -> Result<(), Error> {
pub fn run_zplugin(base_dirs: &BaseDirs, run_type: RunType) -> Result<()> {
let zsh = require("zsh")?;
let zshrc = zshrc(base_dirs).require()?;
@@ -73,7 +73,7 @@ pub fn run_zplugin(base_dirs: &BaseDirs, run_type: RunType) -> Result<(), Error>
run_type.execute(zsh).args(&["-c", cmd.as_str()]).check_run()
}
pub fn run_oh_my_zsh(base_dirs: &BaseDirs, run_type: RunType) -> Result<(), Error> {
pub fn run_oh_my_zsh(base_dirs: &BaseDirs, run_type: RunType) -> Result<()> {
let zsh = require("zsh")?;
let zshrc = zshrc(base_dirs).require()?;
base_dirs.home_dir().join(".oh-my-zsh").require()?;

View File

@@ -1,4 +1,6 @@
use super::error::{Error, ErrorKind};
use crate::error::{SkipStep, TopgradeError};
use anyhow::Result;
use log::{debug, error};
use std::env;
use std::ffi::OsStr;
@@ -8,21 +10,21 @@ use std::process::{ExitStatus, Output};
use which_crate;
pub trait Check {
fn check(self) -> Result<(), Error>;
fn check(self) -> Result<()>;
}
impl Check for ExitStatus {
fn check(self) -> Result<(), Error> {
fn check(self) -> Result<()> {
if self.success() {
Ok(())
} else {
Err(ErrorKind::ProcessFailed(self).into())
Err(TopgradeError::ProcessFailed(self).into())
}
}
}
impl Check for Output {
fn check(self) -> Result<(), Error> {
fn check(self) -> Result<()> {
self.status.check()
}
}
@@ -35,7 +37,7 @@ where
fn is_descendant_of(&self, ancestor: &Path) -> bool;
/// Returns the path if it exists or ErrorKind::SkipStep otherwise
fn require(self) -> Result<Self, Error>;
fn require(self) -> Result<Self>;
}
impl<T> PathExt for T
@@ -54,13 +56,13 @@ where
self.as_ref().iter().zip(ancestor.iter()).all(|(a, b)| a == b)
}
fn require(self) -> Result<Self, Error> {
fn require(self) -> Result<Self> {
if self.as_ref().exists() {
debug!("Path {:?} exists", self.as_ref());
Ok(self)
} else {
debug!("Path {:?} doesn't exist", self.as_ref());
Err(ErrorKind::SkipStep.into())
Err(SkipStep.into())
}
}
}
@@ -178,7 +180,7 @@ mod tests {
}
}
pub fn require<T: AsRef<OsStr> + Debug>(binary_name: T) -> Result<PathBuf, Error> {
pub fn require<T: AsRef<OsStr> + Debug>(binary_name: T) -> Result<PathBuf> {
match which_crate::which(&binary_name) {
Ok(path) => {
debug!("Detected {:?} as {:?}", &path, &binary_name);
@@ -187,7 +189,7 @@ pub fn require<T: AsRef<OsStr> + Debug>(binary_name: T) -> Result<PathBuf, Error
Err(e) => match e.kind() {
which_crate::ErrorKind::CannotFindBinaryPath => {
debug!("Cannot find {:?}", &binary_name);
Err(ErrorKind::SkipStep.into())
Err(SkipStep.into())
}
_ => {
panic!("Detecting {:?} failed: {}", &binary_name, e);
@@ -197,10 +199,10 @@ pub fn require<T: AsRef<OsStr> + Debug>(binary_name: T) -> Result<PathBuf, Error
}
#[allow(dead_code)]
pub fn require_option<T>(option: Option<T>) -> Result<T, Error> {
pub fn require_option<T>(option: Option<T>) -> Result<T> {
if let Some(value) = option {
Ok(value)
} else {
Err(ErrorKind::SkipStep.into())
Err(SkipStep.into())
}
}