Merge pull request #914 from ethcore/upgrades

Upgrade logic between versions
This commit is contained in:
Arkadiy Paronyan 2016-04-12 11:30:52 +02:00
commit 283ce13454
4 changed files with 141 additions and 1 deletions

1
Cargo.lock generated
View File

@ -22,6 +22,7 @@ dependencies = [
"rpassword 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc_version 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
"semver 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
"time 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)",
]

View File

@ -29,7 +29,7 @@ ethminer = { path = "miner" }
ethcore-devtools = { path = "devtools" }
ethcore-rpc = { path = "rpc", optional = true }
ethcore-webapp = { path = "webapp", optional = true }
semver = "0.2"
[dependencies.hyper]
version = "0.8"

View File

@ -36,6 +36,7 @@ extern crate daemonize;
extern crate time;
extern crate number_prefix;
extern crate rpassword;
extern crate semver;
// for price_info.rs
#[macro_use] extern crate hyper;
@ -71,6 +72,7 @@ use rpc::Server as RpcServer;
use webapp::Listening as WebappServer;
mod price_info;
mod upgrade;
fn die_with_message(msg: &str) -> ! {
println!("ERROR: {}", msg);
@ -785,6 +787,17 @@ fn die_with_io_error(e: std::io::Error) -> ! {
}
fn main() {
match ::upgrade::upgrade() {
Ok(upgrades_applied) => {
if upgrades_applied > 0 {
println!("Executed {} upgrade scripts - ok", upgrades_applied);
}
},
Err(e) => {
die!("Error upgrading parity data: {:?}", e);
}
}
Configuration::parse().execute();
}

126
parity/upgrade.rs Normal file
View File

@ -0,0 +1,126 @@
// Copyright 2015, 2016 Ethcore (UK) Ltd.
// This file is part of Parity.
// Parity is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Parity is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
//! Parity upgrade logic
use semver::Version;
use std::collections::*;
use std::fs::File;
use std::env;
use std::io::{Read, Write};
#[derive(Debug)]
pub enum Error {
CannotLockVersionFile,
CannotUpdateVersionFile,
}
const CURRENT_VERSION: &'static str = env!("CARGO_PKG_VERSION");
#[derive(Hash, PartialEq, Eq)]
struct UpgradeKey {
pub old_version: Version,
pub new_version: Version,
}
type UpgradeList = HashMap<UpgradeKey, fn() -> Result<(), Error>>;
impl UpgradeKey {
// given the following config exist
// ver.lock 1.1 (`previous_version`)
//
// current_version 1.4 (`current_version`)
//
//
//upgrades (set of `UpgradeKey`)
// 1.0 -> 1.1 (u1)
// 1.1 -> 1.2 (u2)
// 1.2 -> 1.3 (u3)
// 1.3 -> 1.4 (u4)
// 1.4 -> 1.5 (u5)
//
// then the following upgrades should be applied:
// u2, u3, u4
fn is_applicable(&self, previous_version: &Version, current_version: &Version) -> bool {
self.old_version >= *previous_version && self.new_version <= *current_version
}
}
// dummy upgrade (remove when the first one is in)
fn dummy_upgrade() -> Result<(), Error> {
println!("Adding ver.lock");
Ok(())
}
fn push_updrades(upgrades: &mut UpgradeList)
{
// dummy upgrade (remove when the first one is in)
upgrades.insert(
UpgradeKey { old_version: Version::parse("0.9.0").unwrap(), new_version: Version::parse("1.0.0").unwrap() },
dummy_upgrade);
}
fn upgrade_from_version(previous_version: &Version) -> Result<usize, Error> {
let mut upgrades = HashMap::new();
push_updrades(&mut upgrades);
let current_version = Version::parse(CURRENT_VERSION).unwrap();
let mut count = 0;
for upgrade_key in upgrades.keys() {
if upgrade_key.is_applicable(previous_version, &current_version) {
let upgrade_script = upgrades[upgrade_key];
try!(upgrade_script());
count = count + 1;
}
}
Ok(count)
}
fn with_locked_version<F>(script: F) -> Result<usize, Error>
where F: Fn(&Version) -> Result<usize, Error>
{
let mut path = env::home_dir().expect("Applications should have a home dir");
path.push(".parity");
path.push("ver.lock");
let version =
File::open(&path).ok().and_then(|ref mut file|
{
let mut version_string = String::new();
file.read_to_string(&mut version_string)
.ok()
.and_then(|_| Version::parse(&version_string).ok())
})
.unwrap_or_else(|| Version::parse("0.9.0").unwrap());
let script_result = {
let mut lock = try!(File::create(&path).map_err(|_| Error::CannotLockVersionFile));
let result = script(&version);
let written_version = Version::parse(CURRENT_VERSION).unwrap();
try!(lock.write_all(written_version.to_string().as_bytes()).map_err(|_| Error::CannotUpdateVersionFile));
result
};
script_result
}
pub fn upgrade() -> Result<usize, Error> {
with_locked_version(|ver| {
upgrade_from_version(ver)
})
}