Implement respawn after upgrade in Windows

This commit is contained in:
Roey Darwish Dror
2019-06-03 09:41:25 +03:00
parent 693935816a
commit 50a0563bb4
4 changed files with 52 additions and 12 deletions

View File

@@ -43,8 +43,7 @@ distribution which ships the latest version of Rust, such as Arch Linux.
## Usage ## Usage
Just run `topgrade`. It will run the following steps: Just run `topgrade`. It will run the following steps:
* Try to self-upgrade if compiled with this feature. On Unix systems Topgrade will also respawn * Try to self-upgrade if compiled with this feature. Topgrade will respawn itself if it was upgraded.
itself if it was upgraded
* **Linux**: Run the system package manager: * **Linux**: Run the system package manager:
* **Arch based**: Run [yay](https://github.com/Jguer/yay) or fall back to pacman * **Arch based**: Run [yay](https://github.com/Jguer/yay) or fall back to pacman
* **Redhat based**: Run `yum upgrade` (or `dnf` if present) * **Redhat based**: Run `yum upgrade` (or `dnf` if present)

View File

@@ -44,6 +44,10 @@ pub enum ErrorKind {
#[fail(display = "A step should be skipped")] #[fail(display = "A step should be skipped")]
SkipStep, SkipStep,
#[cfg(all(windows, feature = "self-update"))]
#[fail(display = "Topgrade Upgraded")]
Upgraded(ExitStatus),
} }
impl Fail for Error { impl Fail for Error {
@@ -66,6 +70,15 @@ impl Error {
pub fn kind(&self) -> ErrorKind { pub fn kind(&self) -> ErrorKind {
*self.inner.get_context() *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 { impl From<ErrorKind> for Error {

View File

@@ -88,7 +88,20 @@ fn run() -> Result<(), Error> {
{ {
openssl_probe::init_ssl_cert_env_vars(); openssl_probe::init_ssl_cert_env_vars();
if !run_type.dry() && env::var("TOPGRADE_NO_SELF_UPGRADE").is_err() { if !run_type.dry() && env::var("TOPGRADE_NO_SELF_UPGRADE").is_err() {
if let Err(e) = self_update::self_update() { 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 {
print_warning(format!("Self update error: {}", e)); print_warning(format!("Self update error: {}", e));
if let Some(cause) = e.cause() { if let Some(cause) = e.cause() {
print_warning(format!("Caused by: {}", cause)); print_warning(format!("Caused by: {}", cause));
@@ -466,6 +479,13 @@ fn main() {
exit(0); exit(0);
} }
Err(error) => { Err(error) => {
#[cfg(all(windows, feature = "self-update"))]
{
if let ErrorKind::Upgraded(status) = error.kind() {
exit(status.code().unwrap());
}
}
let should_print = match error.kind() { let should_print = match error.kind() {
ErrorKind::StepFailed => false, ErrorKind::StepFailed => false,
ErrorKind::Retry => error ErrorKind::Retry => error

View File

@@ -3,16 +3,13 @@ use super::terminal::*;
use failure::ResultExt; use failure::ResultExt;
use self_update_crate; use self_update_crate;
use self_update_crate::backends::github::{GitHubUpdateStatus, Update}; use self_update_crate::backends::github::{GitHubUpdateStatus, Update};
#[cfg(unix)]
use std::env; use std::env;
#[cfg(unix)] #[cfg(unix)]
use std::os::unix::process::CommandExt; use std::os::unix::process::CommandExt;
#[cfg(unix)]
use std::process::Command; use std::process::Command;
pub fn self_update() -> Result<(), Error> { pub fn self_update() -> Result<(), Error> {
print_separator("Self update"); print_separator("Self update");
#[cfg(unix)]
let current_exe = env::current_exe(); let current_exe = env::current_exe();
let target = self_update_crate::get_target().context(ErrorKind::SelfUpdate)?; let target = self_update_crate::get_target().context(ErrorKind::SelfUpdate)?;
@@ -38,15 +35,26 @@ pub fn self_update() -> Result<(), Error> {
println!("Topgrade is up-to-date"); println!("Topgrade is up-to-date");
} }
#[cfg(unix)]
{ {
if result.updated() { if result.updated() {
print_warning("Respawning..."); print_warning("Respawning...");
let err = Command::new(current_exe.context(ErrorKind::SelfUpdate)?) let mut command = Command::new(current_exe.context(ErrorKind::SelfUpdate)?);
.args(env::args().skip(1)) command.args(env::args().skip(1)).env("TOPGRADE_NO_SELF_UPGRADE", "");
.env("TOPGRADE_NO_SELF_UPGRADE", "")
.exec(); #[cfg(unix)]
Err(err).context(ErrorKind::SelfUpdate)? {
let err = command.exec();
Err(err).context(ErrorKind::SelfUpdate)?
}
#[cfg(windows)]
{
let status = command
.spawn()
.and_then(|mut c| c.wait())
.context(ErrorKind::SelfUpdate)?;
Err(ErrorKind::Upgraded(status))?
}
} }
} }