From d15372c8a6da15a004a7995b5be7f8f08e9a2dfc Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Sat, 11 Mar 2017 14:46:17 +0100 Subject: [PATCH] Fix auto-updater. (#4868) --- parity/main.rs | 17 ++++++++++++++--- updater/src/updater.rs | 36 ++++++++++++++++++++++++------------ 2 files changed, 38 insertions(+), 15 deletions(-) diff --git a/parity/main.rs b/parity/main.rs index 8e0bae0aa..1882cb6f3 100644 --- a/parity/main.rs +++ b/parity/main.rs @@ -122,7 +122,7 @@ mod stratum; use std::{process, env}; use std::collections::HashMap; use std::io::{self as stdio, BufReader, Read, Write}; -use std::fs::File; +use std::fs::{metadata, File}; use std::path::PathBuf; use util::sha3::sha3; use cli::Args; @@ -292,8 +292,19 @@ fn main() { let latest_exe = latest_exe_path(); let have_update = latest_exe.as_ref().map_or(false, |p| p.exists()); let is_non_updated_current = exe.as_ref().map_or(false, |exe| latest_exe.as_ref().map_or(false, |lexe| exe.canonicalize().ok() != lexe.canonicalize().ok())); - trace_main!("Starting... (have-update: {}, non-updated-current: {})", have_update, is_non_updated_current); - let exit_code = if have_update && is_non_updated_current { + let update_is_newer = match ( + latest_exe.as_ref() + .and_then(|p| metadata(p.as_path()).ok()) + .and_then(|m| m.modified().ok()), + exe.as_ref() + .and_then(|p| metadata(p.as_path()).ok()) + .and_then(|m| m.modified().ok()) + ) { + (Some(latest_exe_time), Some(this_exe_time)) if latest_exe_time > this_exe_time => true, + _ => false, + }; + trace_main!("Starting... (have-update: {}, non-updated-current: {})", have_update, is_non_updated_current); trace_main!("Starting... (have-update: {}, non-updated-current: {})", have_update, is_non_updated_current); + let exit_code = if have_update && is_non_updated_current && update_is_newer { trace_main!("Attempting to run latest update ({})...", latest_exe.as_ref().expect("guarded by have_update; latest_exe must exist for have_update; qed").display()); run_parity().unwrap_or_else(|| { trace_main!("Falling back to local..."); main_direct(true) }) } else { diff --git a/updater/src/updater.rs b/updater/src/updater.rs index 31c3106bd..1266258fe 100644 --- a/updater/src/updater.rs +++ b/updater/src/updater.rs @@ -210,13 +210,15 @@ impl Updater { let auto = { let mut s = self.state.lock(); let fetched = s.fetching.take().unwrap(); - let b = result.map_err(|e| (format!("Unable to fetch update ({}): {:?}", fetched.version, e), false))?; - info!(target: "updater", "Fetched latest version ({}) OK to {}", fetched.version, b.display()); let dest = self.updates_path(&Self::update_file_name(&fetched.version)); - fs::create_dir_all(dest.parent().expect("at least one thing pushed; qed")).map_err(|e| (format!("Unable to create updates path: {:?}", e), true))?; - fs::copy(&b, &dest).map_err(|e| (format!("Unable to copy update: {:?}", e), true))?; - restrict_permissions_owner(&dest, false, true).map_err(|e| (format!("Unable to update permissions: {}", e), true))?; - info!(target: "updater", "Installed updated binary to {}", dest.display()); + if !dest.exists() { + let b = result.map_err(|e| (format!("Unable to fetch update ({}): {:?}", fetched.version, e), false))?; + info!(target: "updater", "Fetched latest version ({}) OK to {}", fetched.version, b.display()); + fs::create_dir_all(dest.parent().expect("at least one thing pushed; qed")).map_err(|e| (format!("Unable to create updates path: {:?}", e), true))?; + fs::copy(&b, &dest).map_err(|e| (format!("Unable to copy update: {:?}", e), true))?; + restrict_permissions_owner(&dest, false, true).map_err(|e| (format!("Unable to update permissions: {}", e), true))?; + info!(target: "updater", "Installed updated binary to {}", dest.display()); + } let auto = match self.update_policy.filter { UpdateFilter::All => true, UpdateFilter::Critical if fetched.is_critical /* TODO: or is on a bad fork */ => true, @@ -271,15 +273,23 @@ impl Updater { let running_later = latest.track.version.version < self.version_info().version; let running_latest = latest.track.version.hash == self.version_info().hash; let already_have_latest = s.installed.as_ref().or(s.ready.as_ref()).map_or(false, |t| *t == latest.track); + if self.update_policy.enable_downloading && !running_later && !running_latest && !already_have_latest { if let Some(b) = latest.track.binary { if s.fetching.is_none() { - info!(target: "updater", "Attempting to get parity binary {}", b); - s.fetching = Some(latest.track.clone()); - drop(s); - let weak_self = self.weak_self.lock().clone(); - let f = move |r: Result| if let Some(this) = weak_self.upgrade() { this.fetch_done(r) }; - self.fetcher.lock().as_ref().expect("Created on `new`; qed").fetch(b, Box::new(f)); + if self.updates_path(&Self::update_file_name(&latest.track.version)).exists() { + info!(target: "updater", "Already fetched binary."); + s.fetching = Some(latest.track.clone()); + drop(s); + self.fetch_done(Ok(PathBuf::new())); + } else { + info!(target: "updater", "Attempting to get parity binary {}", b); + s.fetching = Some(latest.track.clone()); + drop(s); + let weak_self = self.weak_self.lock().clone(); + let f = move |r: Result| if let Some(this) = weak_self.upgrade() { this.fetch_done(r) }; + self.fetcher.lock().as_ref().expect("Created on `new`; qed").fetch(b, Box::new(f)); + } } } } @@ -356,6 +366,8 @@ impl Service for Updater { s.installed = Some(r); if let Some(ref h) = *self.exit_handler.lock() { (*h)(); + } else { + info!("Update installed; ready for restart."); } Ok(true) }