`solana-install update` now updates a named release to the latest patch version
This commit is contained in:
parent
66b4124a68
commit
79280b304b
|
@ -4647,7 +4647,7 @@ dependencies = [
|
||||||
"reqwest 0.10.8",
|
"reqwest 0.10.8",
|
||||||
"semver 0.9.0",
|
"semver 0.9.0",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_derive",
|
"serde_json",
|
||||||
"serde_yaml",
|
"serde_yaml",
|
||||||
"solana-clap-utils",
|
"solana-clap-utils",
|
||||||
"solana-client",
|
"solana-client",
|
||||||
|
|
|
@ -22,8 +22,8 @@ indicatif = "0.15.0"
|
||||||
lazy_static = "1.4.0"
|
lazy_static = "1.4.0"
|
||||||
nix = "0.19.0"
|
nix = "0.19.0"
|
||||||
reqwest = { version = "0.10.8", default-features = false, features = ["blocking", "rustls-tls", "json"] }
|
reqwest = { version = "0.10.8", default-features = false, features = ["blocking", "rustls-tls", "json"] }
|
||||||
serde = "1.0.122"
|
serde = { version = "1.0.122", features = ["derive"] }
|
||||||
serde_derive = "1.0.103"
|
serde_json = "1.0.62"
|
||||||
serde_yaml = "0.8.13"
|
serde_yaml = "0.8.13"
|
||||||
solana-clap-utils = { path = "../clap-utils", version = "1.6.0" }
|
solana-clap-utils = { path = "../clap-utils", version = "1.6.0" }
|
||||||
solana-client = { path = "../client", version = "1.6.0" }
|
solana-client = { path = "../client", version = "1.6.0" }
|
||||||
|
|
|
@ -1,30 +1,32 @@
|
||||||
use crate::{
|
use {
|
||||||
config::{Config, ExplicitRelease},
|
crate::{
|
||||||
stop_process::stop_process,
|
config::{Config, ExplicitRelease},
|
||||||
update_manifest::{SignedUpdateManifest, UpdateManifest},
|
stop_process::stop_process,
|
||||||
|
update_manifest::{SignedUpdateManifest, UpdateManifest},
|
||||||
|
},
|
||||||
|
chrono::{Local, TimeZone},
|
||||||
|
console::{style, Emoji},
|
||||||
|
indicatif::{ProgressBar, ProgressStyle},
|
||||||
|
serde::{Deserialize, Serialize},
|
||||||
|
solana_client::rpc_client::RpcClient,
|
||||||
|
solana_config_program::{config_instruction, get_config_data, ConfigState},
|
||||||
|
solana_sdk::{
|
||||||
|
hash::{Hash, Hasher},
|
||||||
|
message::Message,
|
||||||
|
pubkey::Pubkey,
|
||||||
|
signature::{read_keypair_file, Keypair, Signable, Signer},
|
||||||
|
transaction::Transaction,
|
||||||
|
},
|
||||||
|
std::{
|
||||||
|
fs::{self, File},
|
||||||
|
io::{self, BufReader, Read},
|
||||||
|
path::{Path, PathBuf},
|
||||||
|
sync::mpsc,
|
||||||
|
time::{Duration, Instant, SystemTime},
|
||||||
|
},
|
||||||
|
tempfile::TempDir,
|
||||||
|
url::Url,
|
||||||
};
|
};
|
||||||
use chrono::{Local, TimeZone};
|
|
||||||
use console::{style, Emoji};
|
|
||||||
use indicatif::{ProgressBar, ProgressStyle};
|
|
||||||
use serde_derive::Deserialize;
|
|
||||||
use solana_client::rpc_client::RpcClient;
|
|
||||||
use solana_config_program::{config_instruction, get_config_data, ConfigState};
|
|
||||||
use solana_sdk::{
|
|
||||||
hash::{Hash, Hasher},
|
|
||||||
message::Message,
|
|
||||||
pubkey::Pubkey,
|
|
||||||
signature::{read_keypair_file, Keypair, Signable, Signer},
|
|
||||||
transaction::Transaction,
|
|
||||||
};
|
|
||||||
use std::{
|
|
||||||
fs::{self, File},
|
|
||||||
io::{self, BufReader, Read},
|
|
||||||
path::{Path, PathBuf},
|
|
||||||
sync::mpsc,
|
|
||||||
time::{Duration, Instant, SystemTime},
|
|
||||||
};
|
|
||||||
use tempfile::TempDir;
|
|
||||||
use url::Url;
|
|
||||||
|
|
||||||
#[derive(Deserialize, Debug)]
|
#[derive(Deserialize, Debug)]
|
||||||
pub struct ReleaseVersion {
|
pub struct ReleaseVersion {
|
||||||
|
@ -37,6 +39,7 @@ static TRUCK: Emoji = Emoji("🚚 ", "");
|
||||||
static LOOKING_GLASS: Emoji = Emoji("🔍 ", "");
|
static LOOKING_GLASS: Emoji = Emoji("🔍 ", "");
|
||||||
static BULLET: Emoji = Emoji("• ", "* ");
|
static BULLET: Emoji = Emoji("• ", "* ");
|
||||||
static SPARKLE: Emoji = Emoji("✨ ", "");
|
static SPARKLE: Emoji = Emoji("✨ ", "");
|
||||||
|
static WRAPPED_PRESENT: Emoji = Emoji("🎁 ", "");
|
||||||
static PACKAGE: Emoji = Emoji("📦 ", "");
|
static PACKAGE: Emoji = Emoji("📦 ", "");
|
||||||
static INFORMATION: Emoji = Emoji("ℹ️ ", "");
|
static INFORMATION: Emoji = Emoji("ℹ️ ", "");
|
||||||
static RECYCLING: Emoji = Emoji("♻️ ", "");
|
static RECYCLING: Emoji = Emoji("♻️ ", "");
|
||||||
|
@ -544,7 +547,7 @@ pub fn init(
|
||||||
config
|
config
|
||||||
};
|
};
|
||||||
|
|
||||||
update(config_file)?;
|
init_or_update(config_file, true, false)?;
|
||||||
|
|
||||||
let path_modified = if !no_modify_path {
|
let path_modified = if !no_modify_path {
|
||||||
add_to_path(&config.active_release_bin_dir().to_str().unwrap())
|
add_to_path(&config.active_release_bin_dir().to_str().unwrap())
|
||||||
|
@ -582,11 +585,16 @@ fn release_channel_version_url(release_channel: &str) -> String {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn info(
|
fn print_update_manifest(update_manifest: &UpdateManifest) {
|
||||||
config_file: &str,
|
let when = Local.timestamp(update_manifest.timestamp_secs as i64, 0);
|
||||||
local_info_only: bool,
|
println_name_value(&format!("{}release date:", BULLET), &when.to_string());
|
||||||
eval: bool,
|
println_name_value(
|
||||||
) -> Result<Option<UpdateManifest>, String> {
|
&format!("{}download URL:", BULLET),
|
||||||
|
&update_manifest.download_url,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn info(config_file: &str, local_info_only: bool, eval: bool) -> Result<(), String> {
|
||||||
let config = Config::load(config_file)?;
|
let config = Config::load(config_file)?;
|
||||||
|
|
||||||
if eval {
|
if eval {
|
||||||
|
@ -604,7 +612,7 @@ pub fn info(
|
||||||
println!("SOLANA_INSTALL_ACTIVE_CHANNEL={}", channel,);
|
println!("SOLANA_INSTALL_ACTIVE_CHANNEL={}", channel,);
|
||||||
Option::<String>::None
|
Option::<String>::None
|
||||||
});
|
});
|
||||||
return Ok(None);
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
println_name_value("Configuration:", &config_file);
|
println_name_value("Configuration:", &config_file);
|
||||||
|
@ -613,6 +621,17 @@ pub fn info(
|
||||||
&config.active_release_dir().to_str().unwrap_or("?"),
|
&config.active_release_dir().to_str().unwrap_or("?"),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
fn print_release_version(config: &Config) {
|
||||||
|
if let Ok(release_version) =
|
||||||
|
load_release_version(&config.active_release_dir().join("version.yml"))
|
||||||
|
{
|
||||||
|
println_name_value(
|
||||||
|
&format!("{}Release commit:", BULLET),
|
||||||
|
&release_version.commit[0..7],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if let Some(explicit_release) = &config.explicit_release {
|
if let Some(explicit_release) = &config.explicit_release {
|
||||||
match explicit_release {
|
match explicit_release {
|
||||||
ExplicitRelease::Semver(release_semver) => {
|
ExplicitRelease::Semver(release_semver) => {
|
||||||
|
@ -630,51 +649,30 @@ pub fn info(
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return Ok(None);
|
print_release_version(&config);
|
||||||
}
|
} else {
|
||||||
|
println_name_value("JSON RPC URL:", &config.json_rpc_url);
|
||||||
println_name_value("JSON RPC URL:", &config.json_rpc_url);
|
|
||||||
println_name_value(
|
|
||||||
"Update manifest pubkey:",
|
|
||||||
&config.update_manifest_pubkey.to_string(),
|
|
||||||
);
|
|
||||||
|
|
||||||
fn print_update_manifest(update_manifest: &UpdateManifest) {
|
|
||||||
let when = Local.timestamp(update_manifest.timestamp_secs as i64, 0);
|
|
||||||
println_name_value(&format!("{}release date:", BULLET), &when.to_string());
|
|
||||||
println_name_value(
|
println_name_value(
|
||||||
&format!("{}download URL:", BULLET),
|
"Update manifest pubkey:",
|
||||||
&update_manifest.download_url,
|
&config.update_manifest_pubkey.to_string(),
|
||||||
);
|
);
|
||||||
}
|
|
||||||
|
|
||||||
match config.current_update_manifest {
|
match config.current_update_manifest {
|
||||||
Some(ref update_manifest) => {
|
Some(ref update_manifest) => {
|
||||||
println_name_value("Installed version:", "");
|
println_name_value("Installed version:", "");
|
||||||
print_update_manifest(&update_manifest);
|
print_release_version(&config);
|
||||||
}
|
print_update_manifest(&update_manifest);
|
||||||
None => {
|
}
|
||||||
println_name_value("Installed version:", "None");
|
None => {
|
||||||
|
println_name_value("Installed version:", "None");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if local_info_only {
|
if local_info_only {
|
||||||
Ok(None)
|
Ok(())
|
||||||
} else {
|
} else {
|
||||||
let progress_bar = new_spinner_progress_bar();
|
update(config_file, true).map(|_| ())
|
||||||
progress_bar.set_message(&format!("{}Checking for updates...", LOOKING_GLASS));
|
|
||||||
let rpc_client = RpcClient::new(config.json_rpc_url.clone());
|
|
||||||
let manifest = get_update_manifest(&rpc_client, &config.update_manifest_pubkey)?;
|
|
||||||
progress_bar.finish_and_clear();
|
|
||||||
|
|
||||||
if Some(&manifest) == config.current_update_manifest.as_ref() {
|
|
||||||
println!("\n{}", style("Installation is up to date").italic());
|
|
||||||
Ok(None)
|
|
||||||
} else {
|
|
||||||
println!("\n{}", style("An update is available:").bold());
|
|
||||||
print_update_manifest(&manifest);
|
|
||||||
Ok(Some(manifest))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -845,24 +843,137 @@ pub fn gc(config_file: &str) -> Result<(), String> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn update(config_file: &str) -> Result<bool, String> {
|
#[derive(Debug, Deserialize, Serialize)]
|
||||||
let mut config = Config::load(config_file)?;
|
pub struct GithubRelease {
|
||||||
let update_manifest = info(config_file, false, false)?;
|
pub tag_name: String,
|
||||||
|
pub prerelease: bool,
|
||||||
|
}
|
||||||
|
|
||||||
let release_dir = if let Some(explicit_release) = &config.explicit_release {
|
#[derive(Debug, Deserialize, Serialize)]
|
||||||
let (download_url, release_dir) = match explicit_release {
|
pub struct GithubReleases(Vec<GithubRelease>);
|
||||||
ExplicitRelease::Semver(release_semver) => {
|
|
||||||
let download_url = github_release_download_url(release_semver);
|
fn semver_of(string: &str) -> Result<semver::Version, String> {
|
||||||
let release_dir = config.release_dir(&release_semver);
|
if string.starts_with('v') {
|
||||||
let download_url = if release_dir.exists() {
|
semver::Version::parse(string.split_at(1).1)
|
||||||
// If this release_semver has already been successfully downloaded, no update
|
} else {
|
||||||
// needed
|
semver::Version::parse(string)
|
||||||
println!("{} found in cache", release_semver);
|
}
|
||||||
None
|
.map_err(|err| err.to_string())
|
||||||
} else {
|
}
|
||||||
Some(download_url)
|
|
||||||
};
|
fn check_for_newer_github_release(
|
||||||
(download_url, release_dir)
|
version_filter: Option<semver::VersionReq>,
|
||||||
|
) -> reqwest::Result<Option<String>> {
|
||||||
|
let url =
|
||||||
|
reqwest::Url::parse("https://api.github.com/repos/solana-labs/solana/releases").unwrap();
|
||||||
|
let client = reqwest::blocking::Client::builder()
|
||||||
|
.user_agent("solana-install")
|
||||||
|
.build()?;
|
||||||
|
let request = client.get(url).build()?;
|
||||||
|
let response = client.execute(request)?;
|
||||||
|
|
||||||
|
let mut releases = response
|
||||||
|
.json::<GithubReleases>()?
|
||||||
|
.0
|
||||||
|
.into_iter()
|
||||||
|
.filter_map(
|
||||||
|
|GithubRelease {
|
||||||
|
tag_name,
|
||||||
|
prerelease,
|
||||||
|
}| {
|
||||||
|
if let Ok(version) = semver_of(&tag_name) {
|
||||||
|
if !prerelease
|
||||||
|
&& version_filter
|
||||||
|
.as_ref()
|
||||||
|
.map_or(true, |version_filter| version_filter.matches(&version))
|
||||||
|
{
|
||||||
|
return Some(version);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None
|
||||||
|
},
|
||||||
|
)
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
|
releases.sort();
|
||||||
|
Ok(releases.pop().map(|r| r.to_string()))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub enum SemverUpdateType {
|
||||||
|
Fixed,
|
||||||
|
Patch,
|
||||||
|
_Minor,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn update(config_file: &str, check_only: bool) -> Result<bool, String> {
|
||||||
|
init_or_update(config_file, false, check_only)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn init_or_update(config_file: &str, is_init: bool, check_only: bool) -> Result<bool, String> {
|
||||||
|
let mut config = Config::load(config_file)?;
|
||||||
|
|
||||||
|
let semver_update_type = if is_init {
|
||||||
|
SemverUpdateType::Fixed
|
||||||
|
} else {
|
||||||
|
SemverUpdateType::Patch
|
||||||
|
};
|
||||||
|
|
||||||
|
let (updated_version, download_url_and_sha256, release_dir) = if let Some(explicit_release) =
|
||||||
|
&config.explicit_release
|
||||||
|
{
|
||||||
|
match explicit_release {
|
||||||
|
ExplicitRelease::Semver(current_release_semver) => {
|
||||||
|
let progress_bar = new_spinner_progress_bar();
|
||||||
|
progress_bar.set_message(&format!("{}Checking for updates...", LOOKING_GLASS));
|
||||||
|
|
||||||
|
let github_release = check_for_newer_github_release(
|
||||||
|
semver::VersionReq::parse(&format!(
|
||||||
|
"{}{}",
|
||||||
|
match semver_update_type {
|
||||||
|
SemverUpdateType::Fixed => "=",
|
||||||
|
SemverUpdateType::Patch => "~",
|
||||||
|
SemverUpdateType::_Minor => "^",
|
||||||
|
},
|
||||||
|
current_release_semver
|
||||||
|
))
|
||||||
|
.ok(),
|
||||||
|
)
|
||||||
|
.map_err(|err| err.to_string())?;
|
||||||
|
progress_bar.finish_and_clear();
|
||||||
|
|
||||||
|
match github_release {
|
||||||
|
None => {
|
||||||
|
return Err(format!("Unknown release: {}", current_release_semver));
|
||||||
|
}
|
||||||
|
Some(release_semver) => {
|
||||||
|
if release_semver == *current_release_semver {
|
||||||
|
if let Ok(active_release_version) = load_release_version(
|
||||||
|
&config.active_release_dir().join("version.yml"),
|
||||||
|
) {
|
||||||
|
if format!("v{}", current_release_semver)
|
||||||
|
== active_release_version.channel
|
||||||
|
{
|
||||||
|
println!(
|
||||||
|
"Install is up to date. {} is the latest compatible release",
|
||||||
|
release_semver
|
||||||
|
);
|
||||||
|
return Ok(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
config.explicit_release =
|
||||||
|
Some(ExplicitRelease::Semver(release_semver.clone()));
|
||||||
|
|
||||||
|
let release_dir = config.release_dir(&release_semver);
|
||||||
|
let download_url_and_sha256 = if release_dir.exists() {
|
||||||
|
// Release already present in the cache
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
Some((github_release_download_url(&release_semver), None))
|
||||||
|
};
|
||||||
|
(release_semver, download_url_and_sha256, release_dir)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
ExplicitRelease::Channel(release_channel) => {
|
ExplicitRelease::Channel(release_channel) => {
|
||||||
let version_url = release_channel_version_url(release_channel);
|
let version_url = release_channel_version_url(release_channel);
|
||||||
|
@ -878,59 +989,73 @@ pub fn update(config_file: &str) -> Result<bool, String> {
|
||||||
let current_release_version_yml =
|
let current_release_version_yml =
|
||||||
release_dir.join("solana-release").join("version.yml");
|
release_dir.join("solana-release").join("version.yml");
|
||||||
|
|
||||||
let download_url = Some(release_channel_download_url(release_channel));
|
let download_url = release_channel_download_url(release_channel);
|
||||||
|
|
||||||
if !current_release_version_yml.exists() {
|
if !current_release_version_yml.exists() {
|
||||||
println_name_value(
|
(
|
||||||
&format!("{}Release commit:", BULLET),
|
format!(
|
||||||
&update_release_version.commit[0..7],
|
"{} commit {}",
|
||||||
);
|
release_channel,
|
||||||
(download_url, release_dir)
|
&update_release_version.commit[0..7]
|
||||||
|
),
|
||||||
|
Some((download_url, None)),
|
||||||
|
release_dir,
|
||||||
|
)
|
||||||
} else {
|
} else {
|
||||||
let current_release_version =
|
let current_release_version =
|
||||||
load_release_version(¤t_release_version_yml)?;
|
load_release_version(¤t_release_version_yml)?;
|
||||||
if update_release_version.commit == current_release_version.commit {
|
if update_release_version.commit == current_release_version.commit {
|
||||||
// Same commit, no update required
|
if let Ok(active_release_version) =
|
||||||
println!(
|
load_release_version(&config.active_release_dir().join("version.yml"))
|
||||||
"Latest {} build ({}) found in cache",
|
{
|
||||||
release_channel,
|
if current_release_version.commit == active_release_version.commit {
|
||||||
¤t_release_version.commit[0..7],
|
// Same version, no update required
|
||||||
);
|
println!(
|
||||||
(None, release_dir)
|
"Install is up to date. {} is the latest commit for {}",
|
||||||
} else {
|
&active_release_version.commit[0..7],
|
||||||
println_name_value(
|
release_channel
|
||||||
&format!("{}Release commit:", BULLET),
|
);
|
||||||
&format!(
|
return Ok(false);
|
||||||
"{} => {}:",
|
}
|
||||||
¤t_release_version.commit[0..7],
|
}
|
||||||
&update_release_version.commit[0..7],
|
|
||||||
),
|
|
||||||
);
|
|
||||||
|
|
||||||
(download_url, release_dir)
|
// Release already present in the cache
|
||||||
|
(
|
||||||
|
format!(
|
||||||
|
"{} commit {}",
|
||||||
|
release_channel,
|
||||||
|
&update_release_version.commit[0..7]
|
||||||
|
),
|
||||||
|
None,
|
||||||
|
release_dir,
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
(
|
||||||
|
format!(
|
||||||
|
"{} (from {})",
|
||||||
|
&update_release_version.commit[0..7],
|
||||||
|
¤t_release_version.commit[0..7],
|
||||||
|
),
|
||||||
|
Some((download_url, None)),
|
||||||
|
release_dir,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
|
||||||
if let Some(download_url) = download_url {
|
|
||||||
let (_temp_dir, temp_archive, _temp_archive_sha256) =
|
|
||||||
download_to_temp(&download_url, None)
|
|
||||||
.map_err(|err| format!("Unable to download {}: {}", download_url, err))?;
|
|
||||||
extract_release_archive(&temp_archive, &release_dir).map_err(|err| {
|
|
||||||
format!(
|
|
||||||
"Unable to extract {:?} to {:?}: {}",
|
|
||||||
temp_archive, release_dir, err
|
|
||||||
)
|
|
||||||
})?;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
release_dir
|
|
||||||
} else {
|
} else {
|
||||||
if update_manifest.is_none() {
|
let progress_bar = new_spinner_progress_bar();
|
||||||
|
progress_bar.set_message(&format!("{}Checking for updates...", LOOKING_GLASS));
|
||||||
|
let rpc_client = RpcClient::new(config.json_rpc_url.clone());
|
||||||
|
let update_manifest = get_update_manifest(&rpc_client, &config.update_manifest_pubkey)?;
|
||||||
|
progress_bar.finish_and_clear();
|
||||||
|
|
||||||
|
if Some(&update_manifest) == config.current_update_manifest.as_ref() {
|
||||||
|
println!("Install is up to date");
|
||||||
return Ok(false);
|
return Ok(false);
|
||||||
}
|
}
|
||||||
let update_manifest = update_manifest.unwrap();
|
println!("\n{}", style("An update is available:").bold());
|
||||||
|
print_update_manifest(&update_manifest);
|
||||||
|
|
||||||
if timestamp_secs()
|
if timestamp_secs()
|
||||||
< u64::from_str_radix(crate::build_env::BUILD_SECONDS_SINCE_UNIX_EPOCH, 10).unwrap()
|
< u64::from_str_radix(crate::build_env::BUILD_SECONDS_SINCE_UNIX_EPOCH, 10).unwrap()
|
||||||
|
@ -943,27 +1068,39 @@ pub fn update(config_file: &str) -> Result<bool, String> {
|
||||||
return Err("Unable to update to an older version".to_string());
|
return Err("Unable to update to an older version".to_string());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
config.current_update_manifest = Some(update_manifest.clone());
|
||||||
|
|
||||||
let release_dir = config.release_dir(&update_manifest.download_sha256.to_string());
|
let release_dir = config.release_dir(&update_manifest.download_sha256.to_string());
|
||||||
let (_temp_dir, temp_archive, _temp_archive_sha256) = download_to_temp(
|
|
||||||
&update_manifest.download_url,
|
let download_url = update_manifest.download_url;
|
||||||
Some(&update_manifest.download_sha256),
|
let archive_sha256 = Some(update_manifest.download_sha256);
|
||||||
|
(
|
||||||
|
"latest manifest".to_string(),
|
||||||
|
Some((download_url, archive_sha256)),
|
||||||
|
release_dir,
|
||||||
)
|
)
|
||||||
.map_err(|err| {
|
};
|
||||||
format!(
|
|
||||||
"Unable to download {}: {}",
|
if check_only {
|
||||||
update_manifest.download_url, err
|
println!(
|
||||||
)
|
" {}{}",
|
||||||
})?;
|
WRAPPED_PRESENT,
|
||||||
|
style(format!("Update available: {}", updated_version)).bold()
|
||||||
|
);
|
||||||
|
return Ok(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some((download_url, archive_sha256)) = download_url_and_sha256 {
|
||||||
|
let (_temp_dir, temp_archive, _temp_archive_sha256) =
|
||||||
|
download_to_temp(&download_url, archive_sha256.as_ref())
|
||||||
|
.map_err(|err| format!("Unable to download {}: {}", download_url, err))?;
|
||||||
extract_release_archive(&temp_archive, &release_dir).map_err(|err| {
|
extract_release_archive(&temp_archive, &release_dir).map_err(|err| {
|
||||||
format!(
|
format!(
|
||||||
"Unable to extract {:?} to {:?}: {}",
|
"Unable to extract {:?} to {:?}: {}",
|
||||||
temp_archive, release_dir, err
|
temp_archive, release_dir, err
|
||||||
)
|
)
|
||||||
})?;
|
})?;
|
||||||
|
}
|
||||||
config.current_update_manifest = Some(update_manifest);
|
|
||||||
release_dir
|
|
||||||
};
|
|
||||||
|
|
||||||
let release_target = load_release_target(&release_dir).map_err(|err| {
|
let release_target = load_release_target(&release_dir).map_err(|err| {
|
||||||
format!(
|
format!(
|
||||||
|
@ -1000,7 +1137,19 @@ pub fn update(config_file: &str) -> Result<bool, String> {
|
||||||
config.save(config_file)?;
|
config.save(config_file)?;
|
||||||
gc(config_file)?;
|
gc(config_file)?;
|
||||||
|
|
||||||
println!(" {}{}", SPARKLE, style("Update successful").bold());
|
if is_init {
|
||||||
|
println!(
|
||||||
|
" {}{}",
|
||||||
|
SPARKLE,
|
||||||
|
style(format!("{} initialized", updated_version)).bold()
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
println!(
|
||||||
|
" {}{}",
|
||||||
|
SPARKLE,
|
||||||
|
style(format!("Update successful to {}", updated_version)).bold()
|
||||||
|
);
|
||||||
|
}
|
||||||
Ok(true)
|
Ok(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1063,7 +1212,7 @@ pub fn run(
|
||||||
};
|
};
|
||||||
|
|
||||||
if config.explicit_release.is_none() && now.elapsed().as_secs() > config.update_poll_secs {
|
if config.explicit_release.is_none() && now.elapsed().as_secs() > config.update_poll_secs {
|
||||||
match update(config_file) {
|
match update(config_file, false) {
|
||||||
Ok(true) => {
|
Ok(true) => {
|
||||||
// Update successful, kill current process so it will be restart
|
// Update successful, kill current process so it will be restart
|
||||||
if let Some(ref mut child) = child_option {
|
if let Some(ref mut child) = child_option {
|
||||||
|
|
|
@ -1,9 +1,11 @@
|
||||||
use crate::update_manifest::UpdateManifest;
|
use {
|
||||||
use serde_derive::{Deserialize, Serialize};
|
crate::update_manifest::UpdateManifest,
|
||||||
use solana_sdk::pubkey::Pubkey;
|
serde::{Deserialize, Serialize},
|
||||||
use std::fs::{create_dir_all, File};
|
solana_sdk::pubkey::Pubkey,
|
||||||
use std::io::{self, Write};
|
std::fs::{create_dir_all, File},
|
||||||
use std::path::{Path, PathBuf};
|
std::io::{self, Write},
|
||||||
|
std::path::{Path, PathBuf},
|
||||||
|
};
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Debug, PartialEq)]
|
#[derive(Serialize, Deserialize, Debug, PartialEq)]
|
||||||
pub enum ExplicitRelease {
|
pub enum ExplicitRelease {
|
||||||
|
|
|
@ -2,10 +2,12 @@
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate lazy_static;
|
extern crate lazy_static;
|
||||||
|
|
||||||
use clap::{crate_description, crate_name, App, AppSettings, Arg, ArgMatches, SubCommand};
|
use {
|
||||||
use solana_clap_utils::{
|
clap::{crate_description, crate_name, App, AppSettings, Arg, ArgMatches, SubCommand},
|
||||||
input_parsers::pubkey_of,
|
solana_clap_utils::{
|
||||||
input_validators::{is_pubkey, is_url},
|
input_parsers::pubkey_of,
|
||||||
|
input_validators::{is_pubkey, is_url},
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
mod build_env;
|
mod build_env;
|
||||||
|
@ -158,9 +160,7 @@ pub fn main() -> Result<(), String> {
|
||||||
Arg::with_name("local_info_only")
|
Arg::with_name("local_info_only")
|
||||||
.short("l")
|
.short("l")
|
||||||
.long("local")
|
.long("local")
|
||||||
.help(
|
.help("only display local information, don't check for updates"),
|
||||||
"only display local information, don't check the cluster for new updates",
|
|
||||||
),
|
|
||||||
)
|
)
|
||||||
.arg(
|
.arg(
|
||||||
Arg::with_name("eval")
|
Arg::with_name("eval")
|
||||||
|
@ -262,7 +262,7 @@ pub fn main() -> Result<(), String> {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
("gc", Some(_matches)) => command::gc(config_file),
|
("gc", Some(_matches)) => command::gc(config_file),
|
||||||
("update", Some(_matches)) => command::update(config_file).map(|_| ()),
|
("update", Some(_matches)) => command::update(config_file, false).map(|_| ()),
|
||||||
("run", Some(matches)) => {
|
("run", Some(matches)) => {
|
||||||
let program_name = matches.value_of("program_name").unwrap();
|
let program_name = matches.value_of("program_name").unwrap();
|
||||||
let program_arguments = matches
|
let program_arguments = matches
|
||||||
|
|
|
@ -1,14 +1,16 @@
|
||||||
use serde_derive::{Deserialize, Serialize};
|
use {
|
||||||
use solana_config_program::ConfigState;
|
serde::{Deserialize, Serialize},
|
||||||
use solana_sdk::{
|
solana_config_program::ConfigState,
|
||||||
hash::Hash,
|
solana_sdk::{
|
||||||
pubkey::Pubkey,
|
hash::Hash,
|
||||||
signature::{Signable, Signature},
|
pubkey::Pubkey,
|
||||||
|
signature::{Signable, Signature},
|
||||||
|
},
|
||||||
|
std::{borrow::Cow, error, io},
|
||||||
};
|
};
|
||||||
use std::{borrow::Cow, error, io};
|
|
||||||
|
|
||||||
/// Information required to download and apply a given update
|
/// Information required to download and apply a given update
|
||||||
#[derive(Serialize, Deserialize, Default, Debug, PartialEq)]
|
#[derive(Serialize, Deserialize, Default, Clone, Debug, PartialEq)]
|
||||||
pub struct UpdateManifest {
|
pub struct UpdateManifest {
|
||||||
pub timestamp_secs: u64, // When the release was deployed in seconds since UNIX EPOCH
|
pub timestamp_secs: u64, // When the release was deployed in seconds since UNIX EPOCH
|
||||||
pub download_url: String, // Download URL to the release tar.bz2
|
pub download_url: String, // Download URL to the release tar.bz2
|
||||||
|
|
Loading…
Reference in New Issue