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
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
itself if it was upgraded
* Try to self-upgrade if compiled with this feature. Topgrade will respawn itself if it was upgraded.
* **Linux**: Run the system package manager:
* **Arch based**: Run [yay](https://github.com/Jguer/yay) or fall back to pacman
* **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")]
SkipStep,
#[cfg(all(windows, feature = "self-update"))]
#[fail(display = "Topgrade Upgraded")]
Upgraded(ExitStatus),
}
impl Fail for Error {
@@ -66,6 +70,15 @@ 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 {

View File

@@ -88,7 +88,20 @@ fn run() -> Result<(), Error> {
{
openssl_probe::init_ssl_cert_env_vars();
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));
if let Some(cause) = e.cause() {
print_warning(format!("Caused by: {}", cause));
@@ -466,6 +479,13 @@ fn main() {
exit(0);
}
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() {
ErrorKind::StepFailed => false,
ErrorKind::Retry => error

View File

@@ -3,16 +3,13 @@ use super::terminal::*;
use failure::ResultExt;
use self_update_crate;
use self_update_crate::backends::github::{GitHubUpdateStatus, Update};
#[cfg(unix)]
use std::env;
#[cfg(unix)]
use std::os::unix::process::CommandExt;
#[cfg(unix)]
use std::process::Command;
pub fn self_update() -> Result<(), Error> {
print_separator("Self update");
#[cfg(unix)]
let current_exe = env::current_exe();
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");
}
#[cfg(unix)]
{
if result.updated() {
print_warning("Respawning...");
let err = Command::new(current_exe.context(ErrorKind::SelfUpdate)?)
.args(env::args().skip(1))
.env("TOPGRADE_NO_SELF_UPGRADE", "")
.exec();
Err(err).context(ErrorKind::SelfUpdate)?
let mut command = Command::new(current_exe.context(ErrorKind::SelfUpdate)?);
command.args(env::args().skip(1)).env("TOPGRADE_NO_SELF_UPGRADE", "");
#[cfg(unix)]
{
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))?
}
}
}