Teach solana-install about release channels (#5372)
$ solana-install init edge # <-- setup an install using the edge channel $ solana-install update # <-- update to the latest edge channel release
This commit is contained in:
parent
c2fc0f2418
commit
937f9ad049
|
@ -1,4 +1,4 @@
|
||||||
use crate::config::Config;
|
use crate::config::{Config, ExplicitRelease};
|
||||||
use crate::stop_process::stop_process;
|
use crate::stop_process::stop_process;
|
||||||
use crate::update_manifest::{SignedUpdateManifest, UpdateManifest};
|
use crate::update_manifest::{SignedUpdateManifest, UpdateManifest};
|
||||||
use chrono::{Local, TimeZone};
|
use chrono::{Local, TimeZone};
|
||||||
|
@ -492,7 +492,7 @@ pub fn init(
|
||||||
json_rpc_url: &str,
|
json_rpc_url: &str,
|
||||||
update_manifest_pubkey: &Pubkey,
|
update_manifest_pubkey: &Pubkey,
|
||||||
no_modify_path: bool,
|
no_modify_path: bool,
|
||||||
release_semver: Option<&str>,
|
explicit_release: Option<ExplicitRelease>,
|
||||||
) -> Result<(), String> {
|
) -> Result<(), String> {
|
||||||
let config = {
|
let config = {
|
||||||
// Write new config file only if different, so that running |solana-install init|
|
// Write new config file only if different, so that running |solana-install init|
|
||||||
|
@ -503,7 +503,7 @@ pub fn init(
|
||||||
data_dir,
|
data_dir,
|
||||||
json_rpc_url,
|
json_rpc_url,
|
||||||
update_manifest_pubkey,
|
update_manifest_pubkey,
|
||||||
release_semver,
|
explicit_release,
|
||||||
);
|
);
|
||||||
if current_config != config {
|
if current_config != config {
|
||||||
config.save(config_file)?;
|
config.save(config_file)?;
|
||||||
|
@ -525,7 +525,7 @@ pub fn init(
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn github_download_url(release_semver: &str) -> String {
|
fn github_release_download_url(release_semver: &str) -> String {
|
||||||
format!(
|
format!(
|
||||||
"https://github.com/solana-labs/solana/releases/download/v{}/solana-release-{}.tar.bz2",
|
"https://github.com/solana-labs/solana/releases/download/v{}/solana-release-{}.tar.bz2",
|
||||||
release_semver,
|
release_semver,
|
||||||
|
@ -533,6 +533,14 @@ fn github_download_url(release_semver: &str) -> String {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn release_channel_download_url(release_channel: &str) -> String {
|
||||||
|
format!(
|
||||||
|
"http://release.solana.com/{}/solana-release-{}.tar.bz2",
|
||||||
|
release_channel,
|
||||||
|
crate::build_env::TARGET
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn info(config_file: &str, local_info_only: bool) -> Result<Option<UpdateManifest>, String> {
|
pub fn info(config_file: &str, local_info_only: bool) -> Result<Option<UpdateManifest>, String> {
|
||||||
let config = Config::load(config_file)?;
|
let config = Config::load(config_file)?;
|
||||||
|
|
||||||
|
@ -541,12 +549,24 @@ pub fn info(config_file: &str, local_info_only: bool) -> Result<Option<UpdateMan
|
||||||
"Active release directory:",
|
"Active release directory:",
|
||||||
&config.active_release_dir().to_str().unwrap_or("?"),
|
&config.active_release_dir().to_str().unwrap_or("?"),
|
||||||
);
|
);
|
||||||
if let Some(release_semver) = &config.release_semver {
|
|
||||||
|
if let Some(explicit_release) = &config.explicit_release {
|
||||||
|
match explicit_release {
|
||||||
|
ExplicitRelease::Semver(release_semver) => {
|
||||||
println_name_value(&format!("{}Release version:", BULLET), &release_semver);
|
println_name_value(&format!("{}Release version:", BULLET), &release_semver);
|
||||||
println_name_value(
|
println_name_value(
|
||||||
&format!("{}Release URL:", BULLET),
|
&format!("{}Release URL:", BULLET),
|
||||||
&github_download_url(release_semver),
|
&github_release_download_url(release_semver),
|
||||||
);
|
);
|
||||||
|
}
|
||||||
|
ExplicitRelease::Channel(release_channel) => {
|
||||||
|
println_name_value(&format!("{}Release channel:", BULLET), &release_channel);
|
||||||
|
println_name_value(
|
||||||
|
&format!("{}Release URL:", BULLET),
|
||||||
|
&release_channel_download_url(release_channel),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
return Ok(None);
|
return Ok(None);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -696,13 +716,27 @@ pub fn update(config_file: &str) -> Result<bool, String> {
|
||||||
let mut config = Config::load(config_file)?;
|
let mut config = Config::load(config_file)?;
|
||||||
let update_manifest = info(config_file, false)?;
|
let update_manifest = info(config_file, false)?;
|
||||||
|
|
||||||
let release_dir = if let Some(release_semver) = &config.release_semver {
|
let release_dir = if let Some(explicit_release) = &config.explicit_release {
|
||||||
let download_url = github_download_url(release_semver);
|
let (download_url, release_dir) = match explicit_release {
|
||||||
|
ExplicitRelease::Semver(release_semver) => {
|
||||||
|
let download_url = github_release_download_url(release_semver);
|
||||||
let release_dir = config.release_dir(&release_semver);
|
let release_dir = config.release_dir(&release_semver);
|
||||||
let ok_dir = release_dir.join(".ok");
|
if release_dir.join(".ok").exists() {
|
||||||
if ok_dir.exists() {
|
// If this release_semver has already been successfully downloaded, no update
|
||||||
|
// needed
|
||||||
return Ok(false);
|
return Ok(false);
|
||||||
}
|
}
|
||||||
|
(download_url, release_dir)
|
||||||
|
}
|
||||||
|
ExplicitRelease::Channel(release_channel) => {
|
||||||
|
let download_url = release_channel_download_url(release_channel);
|
||||||
|
let release_dir = config.release_dir(&release_channel);
|
||||||
|
// Note: There's currently no mechanism to check for an updated binary for a release
|
||||||
|
// channel so a download always occurs.
|
||||||
|
(download_url, release_dir)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
let (_temp_dir, temp_archive, _temp_archive_sha256) =
|
let (_temp_dir, temp_archive, _temp_archive_sha256) =
|
||||||
download_to_temp_archive(&download_url, None)
|
download_to_temp_archive(&download_url, None)
|
||||||
.map_err(|err| format!("Unable to download {}: {}", download_url, err))?;
|
.map_err(|err| format!("Unable to download {}: {}", download_url, err))?;
|
||||||
|
@ -712,7 +746,7 @@ pub fn update(config_file: &str) -> Result<bool, String> {
|
||||||
temp_archive, release_dir, err
|
temp_archive, release_dir, err
|
||||||
)
|
)
|
||||||
})?;
|
})?;
|
||||||
let _ = fs::create_dir_all(ok_dir);
|
let _ = fs::create_dir_all(release_dir.join(".ok"));
|
||||||
|
|
||||||
release_dir
|
release_dir
|
||||||
} else {
|
} else {
|
||||||
|
@ -843,7 +877,7 @@ pub fn run(
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
if 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) {
|
||||||
Ok(true) => {
|
Ok(true) => {
|
||||||
// Update successful, kill current process so it will be restart
|
// Update successful, kill current process so it will be restart
|
||||||
|
|
|
@ -5,13 +5,19 @@ use std::fs::{create_dir_all, File};
|
||||||
use std::io::{self, Write};
|
use std::io::{self, Write};
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, Debug, PartialEq)]
|
||||||
|
pub enum ExplicitRelease {
|
||||||
|
Semver(String),
|
||||||
|
Channel(String),
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Default, Debug, PartialEq)]
|
#[derive(Serialize, Deserialize, Default, Debug, PartialEq)]
|
||||||
pub struct Config {
|
pub struct Config {
|
||||||
pub json_rpc_url: String,
|
pub json_rpc_url: String,
|
||||||
pub update_manifest_pubkey: Pubkey,
|
pub update_manifest_pubkey: Pubkey,
|
||||||
pub current_update_manifest: Option<UpdateManifest>,
|
pub current_update_manifest: Option<UpdateManifest>,
|
||||||
pub update_poll_secs: u64,
|
pub update_poll_secs: u64,
|
||||||
pub release_semver: Option<String>,
|
pub explicit_release: Option<ExplicitRelease>,
|
||||||
releases_dir: PathBuf,
|
releases_dir: PathBuf,
|
||||||
active_release_dir: PathBuf,
|
active_release_dir: PathBuf,
|
||||||
}
|
}
|
||||||
|
@ -21,14 +27,14 @@ impl Config {
|
||||||
data_dir: &str,
|
data_dir: &str,
|
||||||
json_rpc_url: &str,
|
json_rpc_url: &str,
|
||||||
update_manifest_pubkey: &Pubkey,
|
update_manifest_pubkey: &Pubkey,
|
||||||
release_semver: Option<&str>,
|
explicit_release: Option<ExplicitRelease>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
json_rpc_url: json_rpc_url.to_string(),
|
json_rpc_url: json_rpc_url.to_string(),
|
||||||
update_manifest_pubkey: *update_manifest_pubkey,
|
update_manifest_pubkey: *update_manifest_pubkey,
|
||||||
current_update_manifest: None,
|
current_update_manifest: None,
|
||||||
update_poll_secs: 60, // check for updates once a minute
|
update_poll_secs: 60, // check for updates once a minute
|
||||||
release_semver: release_semver.map(|s| s.to_string()),
|
explicit_release,
|
||||||
releases_dir: PathBuf::from(data_dir).join("releases"),
|
releases_dir: PathBuf::from(data_dir).join("releases"),
|
||||||
active_release_dir: PathBuf::from(data_dir).join("active_release"),
|
active_release_dir: PathBuf::from(data_dir).join("active_release"),
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,13 +33,20 @@ fn is_pubkey(string: String) -> Result<(), String> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_semver(string: String) -> Result<(), String> {
|
fn is_semver(semver: &str) -> Result<(), String> {
|
||||||
match semver::Version::parse(&string) {
|
match semver::Version::parse(&semver) {
|
||||||
Ok(_) => Ok(()),
|
Ok(_) => Ok(()),
|
||||||
Err(err) => Err(format!("{:?}", err)),
|
Err(err) => Err(format!("{:?}", err)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn is_release_channel(channel: &str) -> Result<(), String> {
|
||||||
|
match channel {
|
||||||
|
"edge" | "beta" | "stable" => Ok(()),
|
||||||
|
_ => Err(format!("Invalid release channel {}", channel)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn main() -> Result<(), String> {
|
pub fn main() -> Result<(), String> {
|
||||||
solana_logger::setup();
|
solana_logger::setup();
|
||||||
|
|
||||||
|
@ -107,12 +114,12 @@ pub fn main() -> Result<(), String> {
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.arg(
|
.arg(
|
||||||
Arg::with_name("release_semver")
|
Arg::with_name("explicit_release")
|
||||||
.value_name("release-semver")
|
.value_name("release")
|
||||||
.index(1)
|
.index(1)
|
||||||
.conflicts_with_all(&["json_rpc_url", "update_manifest_pubkey"])
|
.conflicts_with_all(&["json_rpc_url", "update_manifest_pubkey"])
|
||||||
.validator(is_semver)
|
.validator(|string| is_semver(&string).or_else(|_| is_release_channel(&string)))
|
||||||
.help("The exact version to install. Updates will not be available if this argument is used"),
|
.help("The exact version to install. Either a semver or release channel name"),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
.subcommand(
|
.subcommand(
|
||||||
|
@ -206,7 +213,9 @@ pub fn main() -> Result<(), String> {
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let data_dir = matches.value_of("data_dir").unwrap();
|
let data_dir = matches.value_of("data_dir").unwrap();
|
||||||
let no_modify_path = matches.is_present("no_modify_path");
|
let no_modify_path = matches.is_present("no_modify_path");
|
||||||
let release_semver = matches.value_of("release_semver");
|
let explicit_release = matches
|
||||||
|
.value_of("explicit_release")
|
||||||
|
.map(ToString::to_string);
|
||||||
|
|
||||||
command::init(
|
command::init(
|
||||||
config_file,
|
config_file,
|
||||||
|
@ -214,7 +223,13 @@ pub fn main() -> Result<(), String> {
|
||||||
json_rpc_url,
|
json_rpc_url,
|
||||||
&update_manifest_pubkey,
|
&update_manifest_pubkey,
|
||||||
no_modify_path,
|
no_modify_path,
|
||||||
release_semver,
|
explicit_release.map(|explicit_release| {
|
||||||
|
if is_semver(&explicit_release).is_ok() {
|
||||||
|
config::ExplicitRelease::Semver(explicit_release)
|
||||||
|
} else {
|
||||||
|
config::ExplicitRelease::Channel(explicit_release)
|
||||||
|
}
|
||||||
|
}),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
("info", Some(matches)) => {
|
("info", Some(matches)) => {
|
||||||
|
@ -310,11 +325,11 @@ pub fn main_init() -> Result<(), String> {
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.arg(
|
.arg(
|
||||||
Arg::with_name("release_semver")
|
Arg::with_name("explicit_release")
|
||||||
.value_name("release-semver")
|
.value_name("release")
|
||||||
.index(1)
|
.index(1)
|
||||||
.conflicts_with_all(&["json_rpc_url", "update_manifest_pubkey"])
|
.conflicts_with_all(&["json_rpc_url", "update_manifest_pubkey"])
|
||||||
.validator(is_semver)
|
.validator(|string| is_semver(&string).or_else(|_| is_release_channel(&string)))
|
||||||
.help("The exact version to install. Updates will not be available if this argument is used"),
|
.help("The exact version to install. Updates will not be available if this argument is used"),
|
||||||
)
|
)
|
||||||
.get_matches();
|
.get_matches();
|
||||||
|
@ -329,7 +344,9 @@ pub fn main_init() -> Result<(), String> {
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let data_dir = matches.value_of("data_dir").unwrap();
|
let data_dir = matches.value_of("data_dir").unwrap();
|
||||||
let no_modify_path = matches.is_present("no_modify_path");
|
let no_modify_path = matches.is_present("no_modify_path");
|
||||||
let release_semver = matches.value_of("release_semver");
|
let explicit_release = matches
|
||||||
|
.value_of("explicit_release")
|
||||||
|
.map(ToString::to_string);
|
||||||
|
|
||||||
command::init(
|
command::init(
|
||||||
config_file,
|
config_file,
|
||||||
|
@ -337,6 +354,12 @@ pub fn main_init() -> Result<(), String> {
|
||||||
json_rpc_url,
|
json_rpc_url,
|
||||||
&update_manifest_pubkey,
|
&update_manifest_pubkey,
|
||||||
no_modify_path,
|
no_modify_path,
|
||||||
release_semver,
|
explicit_release.map(|explicit_release| {
|
||||||
|
if is_semver(&explicit_release).is_ok() {
|
||||||
|
config::ExplicitRelease::Semver(explicit_release)
|
||||||
|
} else {
|
||||||
|
config::ExplicitRelease::Channel(explicit_release)
|
||||||
|
}
|
||||||
|
}),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue