Cleanups and avoid redownloading.

This commit is contained in:
Gav Wood 2016-12-09 20:40:24 +01:00
parent c2b6be95c8
commit e5e6b77984
No known key found for this signature in database
GPG Key ID: C49C1ACA1CC9B252
2 changed files with 81 additions and 39 deletions

View File

@ -678,6 +678,9 @@ impl Client {
self.check_snooze(); self.check_snooze();
if let Some(ref mut updater) = *self.updater.lock() { if let Some(ref mut updater) = *self.updater.lock() {
updater.tick(); updater.tick();
if updater.installed.is_some() {
info!("Client should restart now.");
}
} }
} }

View File

@ -15,8 +15,8 @@
// along with Parity. If not, see <http://www.gnu.org/licenses/>. // along with Parity. If not, see <http://www.gnu.org/licenses/>.
use std::sync::{Weak}; use std::sync::{Weak};
use std::{fs, env}; use std::{io, os, fs, env};
use std::path::PathBuf; use std::path::{Path, PathBuf};
use util::misc::{VersionInfo, ReleaseTrack/*, platform*/}; use util::misc::{VersionInfo, ReleaseTrack/*, platform*/};
use util::{Address, H160, H256, FixedHash, Mutex}; use util::{Address, H160, H256, FixedHash, Mutex};
use client::operations::Operations; use client::operations::Operations;
@ -54,7 +54,8 @@ pub struct Updater {
// This does change // This does change
pub latest: Option<OperationsInfo>, pub latest: Option<OperationsInfo>,
pub ready: Option<ReleaseInfo>, pub ready: Option<ReleaseInfo>,
// If Some, client should restart itself.
pub installed: Option<ReleaseInfo>,
} }
const CLIENT_ID: &'static str = "parity"; const CLIENT_ID: &'static str = "parity";
@ -75,6 +76,7 @@ impl Updater {
this_fork: None, this_fork: None,
latest: None, latest: None,
ready: None, ready: None,
installed: None,
}; };
u.this_fork = u.operations.release(CLIENT_ID, &u.this.hash.into()).ok() u.this_fork = u.operations.release(CLIENT_ID, &u.this.hash.into()).ok()
@ -107,12 +109,40 @@ impl Updater {
self.ready.clone() self.ready.clone()
} }
#[cfg(windows)]
fn symlink<P: AsRef<Path>, Q: AsRef<Path>>(src: P, dst: Q) -> io::Result<()> {
os::windows::fs::symlink_file(src, dst)
}
#[cfg(not(windows))]
fn symlink<P: AsRef<Path>, Q: AsRef<Path>>(src: P, dst: Q) -> io::Result<()> {
os::unix::fs::symlink(src, dst)
}
/// Actually upgrades the client. Assumes that the binary has been downloaded. /// Actually upgrades the client. Assumes that the binary has been downloaded.
/// @returns `true` on success. /// @returns `true` on success.
pub fn execute_upgrade(&mut self) -> bool { pub fn execute_upgrade(&mut self) -> bool {
// TODO: link ~/.parity-updates/parity to self.ready (|| -> Result<bool, String> {
// TODO: restart parity. if let Some(r) = self.ready.take() {
unimplemented!() let p = Self::update_file_path(&r.version);
let n = Self::updates_latest();
let _ = fs::remove_file(&n);
match Self::symlink(p, n) {
Ok(_) => {
info!("Completed upgrade to {}", &r.version);
self.installed = Some(r);
Ok(true)
}
Err(e) => {
self.ready = Some(r);
Err(format!("Unable to create soft-link for update {:?}", e))
}
}
} else {
warn!("Execute upgrade called when no upgrade ready.");
Ok(false)
}
})().unwrap_or_else(|e| { warn!("{}", e); false })
} }
/// Returns true iff the current version is capable of forming consensus. /// Returns true iff the current version is capable of forming consensus.
@ -165,37 +195,40 @@ impl Updater {
}) })
} }
fn fetch_done(&mut self, _r: Result<PathBuf, fetch::Error>) { fn update_file_path(v: &VersionInfo) -> PathBuf {
let fetched = self.fetching.lock().take().unwrap(); let mut dest = PathBuf::from(env::home_dir().unwrap().to_str().expect("env filesystem paths really should be valid; qed"));
match _r { dest.push(".parity-updates");
Ok(b) => { dest.push(format!("parity-{}.{}.{}-{:?}", v.version.major, v.version.minor, v.version.patch, v.hash));
info!("Fetched latest version ({}) OK to {}", fetched.version, b.display()); dest
let mut dest = PathBuf::from(env::home_dir().unwrap().to_str().expect("env filesystem paths really should be valid; qed")); }
dest.push(".parity-updates");
match fs::create_dir_all(&dest) { fn updates_latest() -> PathBuf {
Ok(_) => { let mut dest = PathBuf::from(env::home_dir().unwrap().to_str().expect("env filesystem paths really should be valid; qed"));
dest.push(format!("parity-{}-{:?}", fetched.version, fetched.version.hash)); dest.push(".parity-updates");
match fs::copy(&b, &dest) { dest.push("parity");
Ok(_) => { dest
info!("Copied file to {}", dest.display()); }
let auto = match self.update_policy.filter {
UpdateFilter::All => true, fn fetch_done(&mut self, result: Result<PathBuf, fetch::Error>) {
UpdateFilter::Critical if fetched.is_critical /* TODO: or is on a bad fork */ => true, (|| -> Result<(), String> {
_ => false, let fetched = self.fetching.lock().take().unwrap();
}; let b = result.map_err(|e| format!("Unable to fetch update ({}): {:?}", fetched.version, e))?;
self.ready = Some(fetched); info!("Fetched latest version ({}) OK to {}", fetched.version, b.display());
if auto { let dest = Self::update_file_path(&fetched.version);
self.execute_upgrade(); fs::create_dir_all(dest.parent().expect("at least one thing pushed; qed")).map_err(|e| format!("Unable to create updates path: {:?}", e))?;
} fs::copy(&b, &dest).map_err(|e| format!("Unable to copy update: {:?}", e))?;
}, info!("Copied file to {}", dest.display());
Err(e) => warn!("Unable to copy update: {:?}", e), let auto = match self.update_policy.filter {
} UpdateFilter::All => true,
}, UpdateFilter::Critical if fetched.is_critical /* TODO: or is on a bad fork */ => true,
Err(e) => warn!("Unable to create updates path: {:?}", e), _ => false,
} };
}, self.ready = Some(fetched);
Err(e) => warn!("Unable to fetch update ({}): {:?}", fetched.version, e), if auto {
} self.execute_upgrade();
}
Ok(())
})().unwrap_or_else(|e| warn!("{}", e));
} }
pub fn tick(&mut self) { pub fn tick(&mut self) {
@ -215,13 +248,19 @@ impl Updater {
"unreleased".into() "unreleased".into()
} }
); );
if self.update_policy.enable_downloading && latest.track.version.hash != self.version_info().hash && self.ready.as_ref().map_or(true, |t| *t != latest.track) { if self.update_policy.enable_downloading && latest.track.version.hash != self.version_info().hash && self.installed.as_ref().or(self.ready.as_ref()).map_or(true, |t| *t != latest.track) {
if let Some(b) = latest.track.binary { if let Some(b) = latest.track.binary {
let mut fetching = self.fetching.lock(); let mut fetching = self.fetching.lock();
if fetching.is_none() { if fetching.is_none() {
info!("Attempting to get parity binary {}", b); info!("Attempting to get parity binary {}", b);
let c = self.client.clone(); let c = self.client.clone();
let f = move |r: Result<PathBuf, fetch::Error>| if let Some(c) = c.upgrade() { c.updater().as_mut().expect("updater exists; updater only owned by client; qed").fetch_done(r); }; let f = move |r: Result<PathBuf, fetch::Error>| {
if let Some(client) = c.upgrade() {
if let Some(updater) = client.updater().as_mut() {
updater.fetch_done(r);
}
}
};
if let Some(fetch) = self.fetch.clone().upgrade() { if let Some(fetch) = self.fetch.clone().upgrade() {
fetch.fetch(b, Box::new(f)).ok(); fetch.fetch(b, Box::new(f)).ok();
*fetching = Some(latest.track.clone()); *fetching = Some(latest.track.clone());