2018-06-28 12:16:54 +03:00
|
|
|
mod config;
|
2018-10-17 14:07:58 +03:00
|
|
|
mod ctrlc;
|
2018-12-11 16:43:26 +02:00
|
|
|
mod error;
|
2018-08-26 16:12:59 +03:00
|
|
|
mod executor;
|
2018-06-03 18:04:58 +03:00
|
|
|
mod report;
|
2018-11-26 14:27:19 +02:00
|
|
|
#[cfg(feature = "self-update")]
|
|
|
|
|
mod self_update;
|
2018-12-15 21:52:21 +02:00
|
|
|
mod steps;
|
2018-05-31 16:00:01 +03:00
|
|
|
mod terminal;
|
2018-06-17 11:43:25 +03:00
|
|
|
mod utils;
|
2018-05-30 07:53:19 +03:00
|
|
|
|
2018-08-22 10:43:32 +03:00
|
|
|
use self::config::Config;
|
2018-12-11 16:43:26 +02:00
|
|
|
use self::error::{Error, ErrorKind};
|
2018-08-24 21:52:17 +03:00
|
|
|
use self::report::Report;
|
2018-12-15 21:52:21 +02:00
|
|
|
use self::steps::*;
|
2018-12-09 10:30:41 +02:00
|
|
|
use self::terminal::*;
|
2018-12-11 16:43:26 +02:00
|
|
|
use failure::{Fail, ResultExt};
|
2018-08-25 22:19:38 +03:00
|
|
|
use std::borrow::Cow;
|
2018-06-20 21:05:49 +03:00
|
|
|
use std::env;
|
2018-12-11 16:43:26 +02:00
|
|
|
use std::io;
|
2018-06-17 11:43:25 +03:00
|
|
|
use std::process::exit;
|
2018-09-06 14:42:56 +03:00
|
|
|
use structopt::StructOpt;
|
2018-05-29 23:48:30 +03:00
|
|
|
|
2018-12-05 13:38:18 +02:00
|
|
|
fn execute<'a, F, M>(func: F, no_retry: bool) -> Result<Option<(M, bool)>, Error>
|
2018-08-25 22:19:38 +03:00
|
|
|
where
|
|
|
|
|
M: Into<Cow<'a, str>>,
|
2018-12-05 11:34:08 +02:00
|
|
|
F: Fn() -> Option<(M, bool)>,
|
2018-08-25 22:19:38 +03:00
|
|
|
{
|
2018-12-05 11:34:08 +02:00
|
|
|
while let Some((key, success)) = func() {
|
2018-08-25 22:19:38 +03:00
|
|
|
if success {
|
2018-10-17 14:07:58 +03:00
|
|
|
return Ok(Some((key, success)));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
let running = ctrlc::running();
|
|
|
|
|
if !running {
|
|
|
|
|
ctrlc::set_running(true);
|
2018-08-25 22:19:38 +03:00
|
|
|
}
|
|
|
|
|
|
2018-12-05 13:38:18 +02:00
|
|
|
let should_ask = !running || !no_retry;
|
2018-12-11 16:43:26 +02:00
|
|
|
let should_retry = should_ask && should_retry(running).context(ErrorKind::Retry)?;
|
2018-10-17 14:07:58 +03:00
|
|
|
|
|
|
|
|
if !should_retry {
|
|
|
|
|
return Ok(Some((key, success)));
|
2018-08-25 22:19:38 +03:00
|
|
|
}
|
|
|
|
|
}
|
2018-10-17 14:07:58 +03:00
|
|
|
|
|
|
|
|
Ok(None)
|
2018-08-25 22:19:38 +03:00
|
|
|
}
|
|
|
|
|
|
2018-06-11 08:57:55 +03:00
|
|
|
fn run() -> Result<(), Error> {
|
2018-10-17 14:07:58 +03:00
|
|
|
ctrlc::set_handler();
|
|
|
|
|
|
2018-09-06 14:42:56 +03:00
|
|
|
let opt = config::Opt::from_args();
|
|
|
|
|
|
|
|
|
|
if opt.run_in_tmux && env::var("TMUX").is_err() {
|
2018-06-27 23:04:39 +03:00
|
|
|
#[cfg(unix)]
|
|
|
|
|
{
|
2018-09-04 11:05:54 +03:00
|
|
|
tmux::run_in_tmux();
|
2018-06-20 21:05:49 +03:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2018-06-17 14:17:36 +03:00
|
|
|
env_logger::init();
|
2018-10-17 14:07:58 +03:00
|
|
|
|
2018-12-11 16:43:26 +02:00
|
|
|
let base_dirs = directories::BaseDirs::new().ok_or(ErrorKind::NoBaseDirectories)?;
|
2018-12-15 21:52:21 +02:00
|
|
|
let git = git::Git::new();
|
|
|
|
|
let mut git_repos = git::Repositories::new(&git);
|
2018-11-07 14:31:44 +02:00
|
|
|
|
2018-07-07 02:18:19 +03:00
|
|
|
let config = Config::read(&base_dirs)?;
|
2018-08-24 21:52:17 +03:00
|
|
|
let mut report = Report::new();
|
2018-05-30 07:53:19 +03:00
|
|
|
|
2018-11-12 11:13:43 +02:00
|
|
|
#[cfg(any(target_os = "freebsd", target_os = "linux"))]
|
2018-06-27 23:04:39 +03:00
|
|
|
let sudo = utils::which("sudo");
|
2018-06-11 08:29:40 +03:00
|
|
|
|
2018-11-12 21:27:49 +02:00
|
|
|
#[cfg(feature = "self-update")]
|
|
|
|
|
{
|
2018-12-31 13:26:17 +02:00
|
|
|
if !opt.run_type.dry() && env::var("TOPGRADE_NO_SELF_UPGRADE").is_err() {
|
2018-12-05 11:34:08 +02:00
|
|
|
if let Err(e) = self_update::self_update() {
|
|
|
|
|
print_warning(format!("Self update error: {}", e));
|
2018-12-23 13:17:53 +02:00
|
|
|
if let Some(cause) = e.cause() {
|
|
|
|
|
print_warning(format!("Caused by: {}", cause));
|
|
|
|
|
}
|
2018-11-12 21:27:49 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2018-11-07 14:31:44 +02:00
|
|
|
|
2018-06-20 20:26:08 +03:00
|
|
|
if let Some(commands) = config.pre_commands() {
|
|
|
|
|
for (name, command) in commands {
|
2018-12-31 13:26:17 +02:00
|
|
|
generic::run_custom_command(&name, &command, opt.run_type).context(ErrorKind::PreCommand)?;
|
2018-06-20 20:26:08 +03:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2018-08-22 22:01:06 +03:00
|
|
|
#[cfg(windows)]
|
|
|
|
|
let powershell = windows::Powershell::new();
|
|
|
|
|
|
|
|
|
|
#[cfg(windows)]
|
2018-12-31 13:26:17 +02:00
|
|
|
report.push_result(execute(|| powershell.update_modules(opt.run_type), opt.no_retry)?);
|
2018-08-22 22:01:06 +03:00
|
|
|
|
2018-10-02 10:46:38 +03:00
|
|
|
#[cfg(target_os = "linux")]
|
|
|
|
|
let distribution = linux::Distribution::detect();
|
|
|
|
|
|
2018-08-22 22:18:48 +03:00
|
|
|
#[cfg(target_os = "linux")]
|
|
|
|
|
{
|
2018-09-06 15:14:59 +03:00
|
|
|
if !opt.no_system {
|
2018-10-02 11:36:10 +03:00
|
|
|
match &distribution {
|
2018-10-02 10:46:38 +03:00
|
|
|
Ok(distribution) => {
|
2018-12-16 23:22:59 -08:00
|
|
|
report.push_result(execute(
|
2018-12-31 13:26:17 +02:00
|
|
|
|| distribution.upgrade(&sudo, opt.cleanup, opt.run_type),
|
2018-12-16 23:22:59 -08:00
|
|
|
opt.no_retry,
|
|
|
|
|
)?);
|
2018-10-02 10:46:38 +03:00
|
|
|
}
|
|
|
|
|
Err(e) => {
|
|
|
|
|
println!("Error detecting current distribution: {}", e);
|
|
|
|
|
}
|
|
|
|
|
}
|
2018-12-31 13:26:17 +02:00
|
|
|
report.push_result(execute(|| linux::run_etc_update(&sudo, opt.run_type), opt.no_retry)?);
|
2018-08-22 22:18:48 +03:00
|
|
|
}
|
2018-06-28 07:47:51 +03:00
|
|
|
}
|
|
|
|
|
|
2018-08-22 22:18:48 +03:00
|
|
|
#[cfg(windows)]
|
2018-12-31 13:26:17 +02:00
|
|
|
report.push_result(execute(|| windows::run_chocolatey(opt.run_type), opt.no_retry)?);
|
2018-08-22 22:18:48 +03:00
|
|
|
|
2018-10-17 13:57:30 +03:00
|
|
|
#[cfg(windows)]
|
2018-12-31 13:26:17 +02:00
|
|
|
report.push_result(execute(|| windows::run_scoop(opt.run_type), opt.no_retry)?);
|
2018-10-17 13:57:30 +03:00
|
|
|
|
2018-08-19 14:45:23 +03:00
|
|
|
#[cfg(unix)]
|
2018-12-31 13:26:17 +02:00
|
|
|
report.push_result(execute(|| unix::run_homebrew(opt.cleanup, opt.run_type), opt.no_retry)?);
|
2018-11-12 11:13:43 +02:00
|
|
|
#[cfg(target_os = "freebsd")]
|
2018-12-31 13:34:56 +02:00
|
|
|
report.push_result(execute(
|
|
|
|
|
|| freebsd::upgrade_packages(&sudo, opt.run_type),
|
|
|
|
|
opt.no_retry,
|
|
|
|
|
)?);
|
2018-10-21 13:05:49 +03:00
|
|
|
#[cfg(unix)]
|
2018-12-31 13:26:17 +02:00
|
|
|
report.push_result(execute(|| unix::run_nix(opt.run_type), opt.no_retry)?);
|
2018-08-19 14:45:23 +03:00
|
|
|
|
2018-09-06 15:14:59 +03:00
|
|
|
if !opt.no_emacs {
|
2018-09-05 11:17:15 +03:00
|
|
|
git_repos.insert(base_dirs.home_dir().join(".emacs.d"));
|
|
|
|
|
}
|
|
|
|
|
|
2018-12-09 16:58:13 +09:00
|
|
|
if !opt.no_vim {
|
|
|
|
|
git_repos.insert(base_dirs.home_dir().join(".vim"));
|
|
|
|
|
git_repos.insert(base_dirs.home_dir().join(".config/nvim"));
|
|
|
|
|
}
|
2018-05-30 07:53:19 +03:00
|
|
|
|
2018-06-27 23:04:39 +03:00
|
|
|
#[cfg(unix)]
|
|
|
|
|
{
|
2018-07-07 02:18:19 +03:00
|
|
|
git_repos.insert(base_dirs.home_dir().join(".zshrc"));
|
|
|
|
|
git_repos.insert(base_dirs.home_dir().join(".oh-my-zsh"));
|
|
|
|
|
git_repos.insert(base_dirs.home_dir().join(".tmux"));
|
|
|
|
|
git_repos.insert(base_dirs.home_dir().join(".config/fish"));
|
2018-08-27 15:22:44 +03:00
|
|
|
git_repos.insert(base_dirs.config_dir().join("openbox"));
|
2018-06-08 18:19:07 +03:00
|
|
|
}
|
2018-05-30 07:53:19 +03:00
|
|
|
|
2018-08-23 22:08:04 +03:00
|
|
|
#[cfg(windows)]
|
|
|
|
|
{
|
|
|
|
|
if let Some(profile) = powershell.profile() {
|
|
|
|
|
git_repos.insert(profile);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2018-09-06 15:14:59 +03:00
|
|
|
if !opt.no_git_repos {
|
2018-09-03 11:51:09 -04:00
|
|
|
if let Some(custom_git_repos) = config.git_repos() {
|
|
|
|
|
for git_repo in custom_git_repos {
|
|
|
|
|
git_repos.insert(git_repo);
|
|
|
|
|
}
|
2018-05-30 07:53:19 +03:00
|
|
|
}
|
|
|
|
|
}
|
2018-06-11 08:21:39 +03:00
|
|
|
for repo in git_repos.repositories() {
|
2018-12-31 13:26:17 +02:00
|
|
|
report.push_result(execute(|| git.pull(&repo, opt.run_type), opt.no_retry)?);
|
2018-05-31 15:59:45 +03:00
|
|
|
}
|
|
|
|
|
|
2018-06-27 23:04:39 +03:00
|
|
|
#[cfg(unix)]
|
|
|
|
|
{
|
2018-12-31 13:26:17 +02:00
|
|
|
report.push_result(execute(|| unix::run_zplug(&base_dirs, opt.run_type), opt.no_retry)?);
|
|
|
|
|
report.push_result(execute(|| unix::run_fisher(&base_dirs, opt.run_type), opt.no_retry)?);
|
|
|
|
|
report.push_result(execute(|| tmux::run_tpm(&base_dirs, opt.run_type), opt.no_retry)?);
|
2018-05-31 16:17:22 +03:00
|
|
|
}
|
|
|
|
|
|
2018-12-31 13:26:17 +02:00
|
|
|
report.push_result(execute(|| generic::run_rustup(&base_dirs, opt.run_type), opt.no_retry)?);
|
|
|
|
|
report.push_result(execute(|| generic::run_cargo_update(opt.run_type), opt.no_retry)?);
|
2018-09-05 11:17:15 +03:00
|
|
|
|
2018-09-06 15:14:59 +03:00
|
|
|
if !opt.no_emacs {
|
2018-12-31 13:26:17 +02:00
|
|
|
report.push_result(execute(|| generic::run_emacs(&base_dirs, opt.run_type), opt.no_retry)?);
|
2018-09-05 11:17:15 +03:00
|
|
|
}
|
|
|
|
|
|
2018-12-31 13:26:17 +02:00
|
|
|
report.push_result(execute(|| generic::run_opam_update(opt.run_type), opt.no_retry)?);
|
|
|
|
|
report.push_result(execute(|| generic::run_vcpkg_update(opt.run_type), opt.no_retry)?);
|
|
|
|
|
report.push_result(execute(|| generic::run_pipx_update(opt.run_type), opt.no_retry)?);
|
|
|
|
|
report.push_result(execute(|| generic::run_jetpack(opt.run_type), opt.no_retry)?);
|
2018-12-09 16:58:13 +09:00
|
|
|
|
|
|
|
|
if !opt.no_vim {
|
2018-12-31 13:26:17 +02:00
|
|
|
report.push_result(execute(|| vim::upgrade_vim(&base_dirs, opt.run_type), opt.no_retry)?);
|
|
|
|
|
report.push_result(execute(|| vim::upgrade_neovim(&base_dirs, opt.run_type), opt.no_retry)?);
|
2018-12-09 16:58:13 +09:00
|
|
|
}
|
|
|
|
|
|
2018-12-05 13:38:18 +02:00
|
|
|
report.push_result(execute(
|
2018-12-31 13:26:17 +02:00
|
|
|
|| node::run_npm_upgrade(&base_dirs, opt.run_type),
|
2018-12-05 13:38:18 +02:00
|
|
|
opt.no_retry,
|
|
|
|
|
)?);
|
|
|
|
|
report.push_result(execute(
|
2018-12-31 13:26:17 +02:00
|
|
|
|| generic::run_composer_update(&base_dirs, opt.run_type),
|
2018-12-05 13:38:18 +02:00
|
|
|
opt.no_retry,
|
|
|
|
|
)?);
|
2018-12-31 13:26:17 +02:00
|
|
|
report.push_result(execute(|| node::yarn_global_update(opt.run_type), opt.no_retry)?);
|
2018-10-04 11:26:51 +03:00
|
|
|
|
2018-10-29 14:32:33 +02:00
|
|
|
#[cfg(not(any(
|
|
|
|
|
target_os = "freebsd",
|
|
|
|
|
target_os = "openbsd",
|
|
|
|
|
target_os = "netbsd",
|
|
|
|
|
target_os = "dragonfly"
|
|
|
|
|
)))]
|
2018-12-31 13:26:17 +02:00
|
|
|
report.push_result(execute(|| generic::run_apm(opt.run_type), opt.no_retry)?);
|
|
|
|
|
report.push_result(execute(|| generic::run_gem(&base_dirs, opt.run_type), opt.no_retry)?);
|
2018-06-06 11:27:43 +03:00
|
|
|
|
2018-06-27 23:04:39 +03:00
|
|
|
#[cfg(target_os = "linux")]
|
|
|
|
|
{
|
2018-12-31 13:26:17 +02:00
|
|
|
report.push_result(execute(|| linux::flatpak_user_update(opt.run_type), opt.no_retry)?);
|
2018-12-05 13:38:18 +02:00
|
|
|
report.push_result(execute(
|
2018-12-31 13:26:17 +02:00
|
|
|
|| linux::flatpak_global_update(&sudo, opt.run_type),
|
2018-12-05 13:38:18 +02:00
|
|
|
opt.no_retry,
|
|
|
|
|
)?);
|
2018-12-31 13:26:17 +02:00
|
|
|
report.push_result(execute(|| linux::run_snap(&sudo, opt.run_type), opt.no_retry)?);
|
2018-06-14 13:24:52 +03:00
|
|
|
}
|
|
|
|
|
|
2018-06-11 08:38:29 +03:00
|
|
|
if let Some(commands) = config.commands() {
|
|
|
|
|
for (name, command) in commands {
|
2018-12-05 13:38:18 +02:00
|
|
|
report.push_result(execute(
|
2018-12-31 13:26:17 +02:00
|
|
|
|| Some((name, generic::run_custom_command(&name, &command, opt.run_type).is_ok())),
|
2018-12-05 13:38:18 +02:00
|
|
|
opt.no_retry,
|
|
|
|
|
)?);
|
2018-06-11 08:38:29 +03:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2018-06-27 23:04:39 +03:00
|
|
|
#[cfg(target_os = "linux")]
|
|
|
|
|
{
|
2018-12-31 13:26:17 +02:00
|
|
|
report.push_result(execute(|| linux::run_fwupdmgr(opt.run_type), opt.no_retry)?);
|
|
|
|
|
report.push_result(execute(|| linux::run_needrestart(&sudo, opt.run_type), opt.no_retry)?);
|
2018-05-31 09:19:27 +03:00
|
|
|
}
|
|
|
|
|
|
2018-06-27 23:04:39 +03:00
|
|
|
#[cfg(target_os = "macos")]
|
|
|
|
|
{
|
2018-09-06 15:14:59 +03:00
|
|
|
if !opt.no_system {
|
2018-12-31 13:26:17 +02:00
|
|
|
report.push_result(execute(|| macos::upgrade_macos(opt.run_type), opt.no_retry)?);
|
2018-08-13 14:39:29 +03:00
|
|
|
}
|
2018-06-03 18:04:58 +03:00
|
|
|
}
|
|
|
|
|
|
2018-11-12 11:13:43 +02:00
|
|
|
#[cfg(target_os = "freebsd")]
|
|
|
|
|
{
|
|
|
|
|
if !opt.no_system {
|
2018-12-31 13:26:17 +02:00
|
|
|
report.push_result(execute(|| freebsd::upgrade_freebsd(&sudo, opt.run_type), opt.no_retry)?);
|
2018-11-12 11:13:43 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2018-08-22 22:18:48 +03:00
|
|
|
#[cfg(windows)]
|
|
|
|
|
{
|
2018-09-06 15:14:59 +03:00
|
|
|
if !opt.no_system {
|
2018-12-31 13:26:17 +02:00
|
|
|
report.push_result(execute(|| powershell.windows_update(opt.run_type), opt.no_retry)?);
|
2018-08-22 22:18:48 +03:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2018-08-24 21:52:17 +03:00
|
|
|
if !report.data().is_empty() {
|
2018-12-05 11:34:08 +02:00
|
|
|
print_separator("Summary");
|
2018-06-03 18:04:58 +03:00
|
|
|
|
2018-08-24 21:52:17 +03:00
|
|
|
for (key, succeeded) in report.data() {
|
2018-12-05 11:34:08 +02:00
|
|
|
print_result(key, *succeeded);
|
2018-06-03 18:04:58 +03:00
|
|
|
}
|
2018-10-02 11:36:10 +03:00
|
|
|
|
|
|
|
|
#[cfg(target_os = "linux")]
|
|
|
|
|
{
|
|
|
|
|
if let Ok(distribution) = &distribution {
|
|
|
|
|
distribution.show_summary();
|
|
|
|
|
}
|
|
|
|
|
}
|
2018-11-15 11:37:08 +02:00
|
|
|
|
|
|
|
|
#[cfg(target_os = "freebsd")]
|
2018-11-15 15:54:24 +02:00
|
|
|
freebsd::audit_packages(&sudo).ok();
|
2018-05-29 23:48:30 +03:00
|
|
|
}
|
|
|
|
|
|
2018-08-24 21:52:17 +03:00
|
|
|
if report.data().iter().all(|(_, succeeded)| *succeeded) {
|
2018-06-11 08:57:55 +03:00
|
|
|
Ok(())
|
|
|
|
|
} else {
|
2018-12-11 16:43:26 +02:00
|
|
|
Err(ErrorKind::StepFailed)?
|
2018-06-11 08:57:55 +03:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn main() {
|
|
|
|
|
match run() {
|
|
|
|
|
Ok(()) => {
|
|
|
|
|
exit(0);
|
|
|
|
|
}
|
|
|
|
|
Err(error) => {
|
2018-12-11 16:43:26 +02:00
|
|
|
let should_print = match error.kind() {
|
|
|
|
|
ErrorKind::StepFailed => false,
|
|
|
|
|
ErrorKind::Retry => error
|
|
|
|
|
.cause()
|
|
|
|
|
.and_then(|cause| cause.downcast_ref::<io::Error>())
|
|
|
|
|
.filter(|io_error| io_error.kind() == io::ErrorKind::Interrupted)
|
|
|
|
|
.is_none(),
|
|
|
|
|
_ => true,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
if should_print {
|
|
|
|
|
println!("Error: {}", error);
|
|
|
|
|
if let Some(cause) = error.cause() {
|
|
|
|
|
println!("Caused by: {}", cause);
|
|
|
|
|
}
|
2018-10-17 14:07:58 +03:00
|
|
|
}
|
2018-06-11 08:57:55 +03:00
|
|
|
exit(1);
|
|
|
|
|
}
|
|
|
|
|
}
|
2018-05-29 23:48:30 +03:00
|
|
|
}
|