Use file contents instead of symlink.

This commit is contained in:
Gav Wood 2016-12-11 03:33:10 +01:00
parent 7a1539cfb5
commit 2865cbaf70
No known key found for this signature in database
GPG Key ID: C49C1ACA1CC9B252
2 changed files with 31 additions and 37 deletions

View File

@ -117,7 +117,7 @@ mod stratum;
use std::{process, env};
use std::collections::HashMap;
use std::io::{self as stdio, BufReader, Write};
use std::io::{self as stdio, BufReader, Read, Write};
use std::fs::File;
use std::path::PathBuf;
use util::sha3::sha3;
@ -190,21 +190,26 @@ fn sync_main(alt_mains: &mut HashMap<String, fn()>) {
}
// TODO: merge with version in Updater.
fn updates_latest() -> PathBuf {
fn updates_path(name: &str) -> PathBuf {
let mut dest = PathBuf::from(env::home_dir().unwrap().to_str().expect("env filesystem paths really should be valid; qed"));
dest.push(".parity-updates");
dest.push("parity");
dest.push(name);
dest
}
fn latest_exe_path() -> Option<PathBuf> {
File::open(updates_path("latest")).ok()
.and_then(|mut f| { let mut exe = String::new(); f.read_to_string(&mut exe).ok().map(|_| updates_path(&exe)) })
}
// Starts ~/.parity-updates/parity and returns the code it exits with.
fn run_parity() -> Option<i32> {
let exe = updates_latest();
process::Command::new(exe)
.args(&env::args_os().collect::<Vec<_>>())
.status()
.map(|es| es.code().unwrap_or(128))
.ok()
latest_exe_path().and_then(|exe| process::Command::new(exe)
.args(&env::args_os().collect::<Vec<_>>())
.status()
.map(|es| es.code().unwrap_or(128))
.ok()
)
}
const PLEASE_RESTART_EXIT_CODE: i32 = 69;
@ -254,16 +259,17 @@ fn main() {
let force_direct = std::env::args().any(|arg| arg == "--force-direct");
let exe = std::env::current_exe().ok();
let development = exe.as_ref().and_then(|p| p.parent().and_then(|p| p.parent()).and_then(|p| p.file_name()).map(|n| n == "target")).unwrap_or(false);
let same_name = exe.as_ref().and_then(|p| p.file_stem().map(|s| s == "parity")).unwrap_or(false);
let have_update = updates_latest().exists();
let is_non_updated_current = exe.map_or(false, |p| p.canonicalize().ok() != updates_latest().canonicalize().ok());
let same_name = exe.as_ref().map(|p| p.file_stem().map_or(false, |s| s == "parity") && p.extension().map_or(true, |x| x == "exe")).unwrap_or(false);
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.map_or(false, |exe| latest_exe.as_ref().map_or(false, |lexe| exe.canonicalize().ok() != lexe.canonicalize().ok()));
trace_main!("Starting up {} (force-direct: {}, development: {}, same-name: {}, have-update: {}, non-updated-current: {})", std::env::current_exe().map(|x| format!("{}", x.display())).unwrap_or("<unknown>".to_owned()), force_direct, development, same_name, have_update, is_non_updated_current);
if !force_direct && !development && same_name && have_update && is_non_updated_current {
// looks like we're not running ~/.parity-updates/parity when the user is expecting otherwise.
// Everything run inside a loop, so we'll be able to restart from the child into a new version seamlessly.
loop {
// If we fail to run the updated parity then fallback to local version.
trace_main!("Attempting to run latest update...");
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());
let exit_code = run_parity().unwrap_or_else(|| { trace_main!("Falling back to local..."); main_direct() });
trace_main!("Latest exited with {}", exit_code);
if exit_code != PLEASE_RESTART_EXIT_CODE {

View File

@ -15,8 +15,9 @@
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
use std::sync::{Arc, Weak};
use std::{io, os, fs, env};
use std::path::{Path, PathBuf};
use std::{fs, env};
use std::io::Write;
use std::path::{PathBuf};
use util::misc::{VersionInfo, ReleaseTrack/*, platform*/};
use util::{Address, H160, H256, FixedHash, Mutex, Bytes};
use super::operations::Operations;
@ -113,16 +114,6 @@ fn platform() -> String {
"test".to_owned()
}
#[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)
}
impl Updater {
pub fn new(client: Weak<BlockChainClient>, update_policy: UpdatePolicy) -> Arc<Self> {
let mut u = Updater {
@ -170,10 +161,10 @@ impl Updater {
(|| -> Result<bool, String> {
let mut s = self.state.lock();
if let Some(r) = s.ready.take() {
let p = Self::update_file_path(&r.version);
let n = Self::updates_latest();
let _ = fs::remove_file(&n);
match symlink(p, n) {
let p = Self::update_file_name(&r.version);
let n = Self::updates_path("latest");
// TODO: creating then writing is a bit fragile. would be nice to make it atomic.
match fs::File::create(&n).and_then(|mut f| f.write_all(p.as_bytes())) {
Ok(_) => {
info!("Completed upgrade to {}", &r.version);
s.installed = Some(r);
@ -249,17 +240,14 @@ impl Updater {
}
}
fn update_file_path(v: &VersionInfo) -> PathBuf {
let mut dest = PathBuf::from(env::home_dir().unwrap().to_str().expect("env filesystem paths really should be valid; qed"));
dest.push(".parity-updates");
dest.push(format!("parity-{}.{}.{}-{:?}", v.version.major, v.version.minor, v.version.patch, v.hash));
dest
fn update_file_name(v: &VersionInfo) -> String {
format!("parity-{}.{}.{}-{:?}", v.version.major, v.version.minor, v.version.patch, v.hash)
}
fn updates_latest() -> PathBuf {
fn updates_path(name: &str) -> PathBuf {
let mut dest = PathBuf::from(env::home_dir().unwrap().to_str().expect("env filesystem paths really should be valid; qed"));
dest.push(".parity-updates");
dest.push("parity");
dest.push(name);
dest
}
@ -270,7 +258,7 @@ impl Updater {
let fetched = s.fetching.take().unwrap();
let b = result.map_err(|e| format!("Unable to fetch update ({}): {:?}", fetched.version, e))?;
info!("Fetched latest version ({}) OK to {}", fetched.version, b.display());
let dest = Self::update_file_path(&fetched.version);
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))?;
fs::copy(&b, &dest).map_err(|e| format!("Unable to copy update: {:?}", e))?;
info!("Copied file to {}", dest.display());