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:
		| @@ -1,4 +1,4 @@ | ||||
| use crate::config::Config; | ||||
| use crate::config::{Config, ExplicitRelease}; | ||||
| use crate::stop_process::stop_process; | ||||
| use crate::update_manifest::{SignedUpdateManifest, UpdateManifest}; | ||||
| use chrono::{Local, TimeZone}; | ||||
| @@ -492,7 +492,7 @@ pub fn init( | ||||
|     json_rpc_url: &str, | ||||
|     update_manifest_pubkey: &Pubkey, | ||||
|     no_modify_path: bool, | ||||
|     release_semver: Option<&str>, | ||||
|     explicit_release: Option<ExplicitRelease>, | ||||
| ) -> Result<(), String> { | ||||
|     let config = { | ||||
|         // Write new config file only if different, so that running |solana-install init| | ||||
| @@ -503,7 +503,7 @@ pub fn init( | ||||
|             data_dir, | ||||
|             json_rpc_url, | ||||
|             update_manifest_pubkey, | ||||
|             release_semver, | ||||
|             explicit_release, | ||||
|         ); | ||||
|         if current_config != config { | ||||
|             config.save(config_file)?; | ||||
| @@ -525,7 +525,7 @@ pub fn init( | ||||
|     Ok(()) | ||||
| } | ||||
|  | ||||
| fn github_download_url(release_semver: &str) -> String { | ||||
| fn github_release_download_url(release_semver: &str) -> String { | ||||
|     format!( | ||||
|         "https://github.com/solana-labs/solana/releases/download/v{}/solana-release-{}.tar.bz2", | ||||
|         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> { | ||||
|     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:", | ||||
|         &config.active_release_dir().to_str().unwrap_or("?"), | ||||
|     ); | ||||
|     if let Some(release_semver) = &config.release_semver { | ||||
|         println_name_value(&format!("{}Release version:", BULLET), &release_semver); | ||||
|         println_name_value( | ||||
|             &format!("{}Release URL:", BULLET), | ||||
|             &github_download_url(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 URL:", BULLET), | ||||
|                     &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); | ||||
|     } | ||||
|  | ||||
| @@ -696,13 +716,27 @@ pub fn update(config_file: &str) -> Result<bool, String> { | ||||
|     let mut config = Config::load(config_file)?; | ||||
|     let update_manifest = info(config_file, false)?; | ||||
|  | ||||
|     let release_dir = if let Some(release_semver) = &config.release_semver { | ||||
|         let download_url = github_download_url(release_semver); | ||||
|         let release_dir = config.release_dir(&release_semver); | ||||
|         let ok_dir = release_dir.join(".ok"); | ||||
|         if ok_dir.exists() { | ||||
|             return Ok(false); | ||||
|         } | ||||
|     let release_dir = if let Some(explicit_release) = &config.explicit_release { | ||||
|         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); | ||||
|                 if release_dir.join(".ok").exists() { | ||||
|                     // If this release_semver has already been successfully downloaded, no update | ||||
|                     // needed | ||||
|                     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) = | ||||
|             download_to_temp_archive(&download_url, None) | ||||
|                 .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 | ||||
|             ) | ||||
|         })?; | ||||
|         let _ = fs::create_dir_all(ok_dir); | ||||
|         let _ = fs::create_dir_all(release_dir.join(".ok")); | ||||
|  | ||||
|         release_dir | ||||
|     } 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) { | ||||
|                 Ok(true) => { | ||||
|                     // 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::path::{Path, PathBuf}; | ||||
|  | ||||
| #[derive(Serialize, Deserialize, Debug, PartialEq)] | ||||
| pub enum ExplicitRelease { | ||||
|     Semver(String), | ||||
|     Channel(String), | ||||
| } | ||||
|  | ||||
| #[derive(Serialize, Deserialize, Default, Debug, PartialEq)] | ||||
| pub struct Config { | ||||
|     pub json_rpc_url: String, | ||||
|     pub update_manifest_pubkey: Pubkey, | ||||
|     pub current_update_manifest: Option<UpdateManifest>, | ||||
|     pub update_poll_secs: u64, | ||||
|     pub release_semver: Option<String>, | ||||
|     pub explicit_release: Option<ExplicitRelease>, | ||||
|     releases_dir: PathBuf, | ||||
|     active_release_dir: PathBuf, | ||||
| } | ||||
| @@ -21,14 +27,14 @@ impl Config { | ||||
|         data_dir: &str, | ||||
|         json_rpc_url: &str, | ||||
|         update_manifest_pubkey: &Pubkey, | ||||
|         release_semver: Option<&str>, | ||||
|         explicit_release: Option<ExplicitRelease>, | ||||
|     ) -> Self { | ||||
|         Self { | ||||
|             json_rpc_url: json_rpc_url.to_string(), | ||||
|             update_manifest_pubkey: *update_manifest_pubkey, | ||||
|             current_update_manifest: None, | ||||
|             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"), | ||||
|             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> { | ||||
|     match semver::Version::parse(&string) { | ||||
| fn is_semver(semver: &str) -> Result<(), String> { | ||||
|     match semver::Version::parse(&semver) { | ||||
|         Ok(_) => Ok(()), | ||||
|         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> { | ||||
|     solana_logger::setup(); | ||||
|  | ||||
| @@ -107,12 +114,12 @@ pub fn main() -> Result<(), String> { | ||||
|                     } | ||||
|                 }) | ||||
|                 .arg( | ||||
|                     Arg::with_name("release_semver") | ||||
|                         .value_name("release-semver") | ||||
|                     Arg::with_name("explicit_release") | ||||
|                         .value_name("release") | ||||
|                         .index(1) | ||||
|                         .conflicts_with_all(&["json_rpc_url", "update_manifest_pubkey"]) | ||||
|                         .validator(is_semver) | ||||
|                         .help("The exact version to install.  Updates will not be available if this argument is used"), | ||||
|                 .validator(|string| is_semver(&string).or_else(|_| is_release_channel(&string))) | ||||
|                         .help("The exact version to install.  Either a semver or release channel name"), | ||||
|                 ), | ||||
|         ) | ||||
|         .subcommand( | ||||
| @@ -206,7 +213,9 @@ pub fn main() -> Result<(), String> { | ||||
|                 .unwrap(); | ||||
|             let data_dir = matches.value_of("data_dir").unwrap(); | ||||
|             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( | ||||
|                 config_file, | ||||
| @@ -214,7 +223,13 @@ pub fn main() -> Result<(), String> { | ||||
|                 json_rpc_url, | ||||
|                 &update_manifest_pubkey, | ||||
|                 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)) => { | ||||
| @@ -310,11 +325,11 @@ pub fn main_init() -> Result<(), String> { | ||||
|             } | ||||
|         }) | ||||
|         .arg( | ||||
|             Arg::with_name("release_semver") | ||||
|                 .value_name("release-semver") | ||||
|             Arg::with_name("explicit_release") | ||||
|                 .value_name("release") | ||||
|                 .index(1) | ||||
|                 .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"), | ||||
|         ) | ||||
|         .get_matches(); | ||||
| @@ -329,7 +344,9 @@ pub fn main_init() -> Result<(), String> { | ||||
|         .unwrap(); | ||||
|     let data_dir = matches.value_of("data_dir").unwrap(); | ||||
|     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( | ||||
|         config_file, | ||||
| @@ -337,6 +354,12 @@ pub fn main_init() -> Result<(), String> { | ||||
|         json_rpc_url, | ||||
|         &update_manifest_pubkey, | ||||
|         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) | ||||
|             } | ||||
|         }), | ||||
|     ) | ||||
| } | ||||
|   | ||||
		Reference in New Issue
	
	Block a user