Add support to install a specific Solana version directly from the Github releases (#5248)
This commit is contained in:
parent
8f646e21d7
commit
b41e8333b1
|
@ -2124,6 +2124,14 @@ dependencies = [
|
||||||
"libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)",
|
"libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "semver"
|
||||||
|
version = "0.7.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "semver"
|
name = "semver"
|
||||||
version = "0.9.0"
|
version = "0.9.0"
|
||||||
|
@ -2630,6 +2638,7 @@ dependencies = [
|
||||||
"log 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
"log 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"nix 0.14.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"nix 0.14.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"reqwest 0.9.19 (registry+https://github.com/rust-lang/crates.io-index)",
|
"reqwest 0.9.19 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"semver 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"serde 1.0.94 (registry+https://github.com/rust-lang/crates.io-index)",
|
"serde 1.0.94 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"serde_derive 1.0.94 (registry+https://github.com/rust-lang/crates.io-index)",
|
"serde_derive 1.0.94 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"serde_yaml 0.8.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
"serde_yaml 0.8.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
@ -3892,6 +3901,7 @@ dependencies = [
|
||||||
"checksum scopeguard 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b42e15e59b18a828bbf5c58ea01debb36b9b096346de35d941dcb89009f24a0d"
|
"checksum scopeguard 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b42e15e59b18a828bbf5c58ea01debb36b9b096346de35d941dcb89009f24a0d"
|
||||||
"checksum security-framework 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "bfab8dda0e7a327c696d893df9ffa19cadc4bd195797997f5223cf5831beaf05"
|
"checksum security-framework 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "bfab8dda0e7a327c696d893df9ffa19cadc4bd195797997f5223cf5831beaf05"
|
||||||
"checksum security-framework-sys 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3d6696852716b589dff9e886ff83778bb635150168e83afa8ac6b8a78cb82abc"
|
"checksum security-framework-sys 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3d6696852716b589dff9e886ff83778bb635150168e83afa8ac6b8a78cb82abc"
|
||||||
|
"checksum semver 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3fdd61b85a0fa777f7fb7c454b9189b2941b110d1385ce84d7f76efdf1606a85"
|
||||||
"checksum semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403"
|
"checksum semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403"
|
||||||
"checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3"
|
"checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3"
|
||||||
"checksum serde 1.0.94 (registry+https://github.com/rust-lang/crates.io-index)" = "076a696fdea89c19d3baed462576b8f6d663064414b5c793642da8dfeb99475b"
|
"checksum serde 1.0.94 (registry+https://github.com/rust-lang/crates.io-index)" = "076a696fdea89c19d3baed462576b8f6d663064414b5c793642da8dfeb99475b"
|
||||||
|
|
|
@ -74,8 +74,7 @@ The `solana-install` tool can be used to easily install and upgrade the cluster
|
||||||
software on Linux x86_64 and mac OS systems.
|
software on Linux x86_64 and mac OS systems.
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
$ export SOLANA_RELEASE=v0.16.0 # skip this line to install the latest release
|
$ curl -sSf https://raw.githubusercontent.com/solana-labs/solana/v0.16.5/install/solana-install-init.sh | sh -s
|
||||||
$ curl -sSf https://raw.githubusercontent.com/solana-labs/solana/v0.16.0/install/solana-install-init.sh | sh -s
|
|
||||||
```
|
```
|
||||||
|
|
||||||
Alternatively build the `solana-install` program from source and run the
|
Alternatively build the `solana-install` program from source and run the
|
||||||
|
|
|
@ -27,6 +27,7 @@ lazy_static = "1.3.0"
|
||||||
log = "0.4.7"
|
log = "0.4.7"
|
||||||
nix = "0.14.1"
|
nix = "0.14.1"
|
||||||
reqwest = "0.9.19"
|
reqwest = "0.9.19"
|
||||||
|
semver = "0.7.0"
|
||||||
serde = "1.0.94"
|
serde = "1.0.94"
|
||||||
serde_derive = "1.0.94"
|
serde_derive = "1.0.94"
|
||||||
serde_yaml = "0.8.9"
|
serde_yaml = "0.8.9"
|
||||||
|
|
|
@ -492,13 +492,19 @@ 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>,
|
||||||
) -> 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|
|
||||||
// repeatedly doesn't unnecessarily re-download
|
// repeatedly doesn't unnecessarily re-download
|
||||||
let mut current_config = Config::load(config_file).unwrap_or_default();
|
let mut current_config = Config::load(config_file).unwrap_or_default();
|
||||||
current_config.current_update_manifest = None;
|
current_config.current_update_manifest = None;
|
||||||
let config = Config::new(data_dir, json_rpc_url, update_manifest_pubkey);
|
let config = Config::new(
|
||||||
|
data_dir,
|
||||||
|
json_rpc_url,
|
||||||
|
update_manifest_pubkey,
|
||||||
|
release_semver,
|
||||||
|
);
|
||||||
if current_config != config {
|
if current_config != config {
|
||||||
config.save(config_file)?;
|
config.save(config_file)?;
|
||||||
}
|
}
|
||||||
|
@ -519,24 +525,42 @@ pub fn init(
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn github_download_url(release_semver: &str) -> String {
|
||||||
|
format!(
|
||||||
|
"https://github.com/solana-labs/solana/releases/download/v{}/solana-release-{}.tar.bz2",
|
||||||
|
release_semver,
|
||||||
|
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)?;
|
||||||
println_name_value("JSON RPC URL:", &config.json_rpc_url);
|
|
||||||
println_name_value(
|
|
||||||
"Update manifest pubkey:",
|
|
||||||
&config.update_manifest_pubkey.to_string(),
|
|
||||||
);
|
|
||||||
println_name_value("Configuration:", &config_file);
|
println_name_value("Configuration:", &config_file);
|
||||||
println_name_value(
|
println_name_value(
|
||||||
"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 {
|
||||||
|
println_name_value(&format!("{}Release version:", BULLET), &release_semver);
|
||||||
|
println_name_value(
|
||||||
|
&format!("{}Release URL:", BULLET),
|
||||||
|
&github_download_url(release_semver),
|
||||||
|
);
|
||||||
|
return Ok(None);
|
||||||
|
}
|
||||||
|
|
||||||
|
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) {
|
fn print_update_manifest(update_manifest: &UpdateManifest) {
|
||||||
let when = Local.timestamp(update_manifest.timestamp_secs as i64, 0);
|
let when = Local.timestamp(update_manifest.timestamp_secs as i64, 0);
|
||||||
println_name_value(&format!("{}release date", BULLET), &when.to_string());
|
println_name_value(&format!("{}release date:", BULLET), &when.to_string());
|
||||||
println_name_value(
|
println_name_value(
|
||||||
&format!("{}download URL", BULLET),
|
&format!("{}download URL:", BULLET),
|
||||||
&update_manifest.download_url,
|
&update_manifest.download_url,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -669,44 +693,66 @@ fn symlink_dir<P: AsRef<Path>, Q: AsRef<Path>>(src: P, dst: Q) -> std::io::Resul
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn update(config_file: &str) -> Result<bool, String> {
|
pub fn update(config_file: &str) -> Result<bool, String> {
|
||||||
let update_manifest = info(config_file, false)?;
|
|
||||||
if update_manifest.is_none() {
|
|
||||||
return Ok(false);
|
|
||||||
}
|
|
||||||
let update_manifest = update_manifest.unwrap();
|
|
||||||
|
|
||||||
if timestamp_secs()
|
|
||||||
< u64::from_str_radix(crate::build_env::BUILD_SECONDS_SINCE_UNIX_EPOCH, 10).unwrap()
|
|
||||||
{
|
|
||||||
Err("Unable to update as system time seems unreliable".to_string())?
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut config = Config::load(config_file)?;
|
let mut config = Config::load(config_file)?;
|
||||||
if let Some(ref current_update_manifest) = config.current_update_manifest {
|
let update_manifest = info(config_file, false)?;
|
||||||
if update_manifest.timestamp_secs < current_update_manifest.timestamp_secs {
|
|
||||||
Err("Unable to update to an older version".to_string())?
|
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 (_temp_dir, temp_archive, _temp_archive_sha256) =
|
||||||
|
download_to_temp_archive(&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
|
||||||
|
)
|
||||||
|
})?;
|
||||||
|
let _ = fs::create_dir_all(ok_dir);
|
||||||
|
|
||||||
let (_temp_dir, temp_archive, _temp_archive_sha256) = download_to_temp_archive(
|
release_dir
|
||||||
&update_manifest.download_url,
|
} else {
|
||||||
Some(&update_manifest.download_sha256),
|
if update_manifest.is_none() {
|
||||||
)
|
return Ok(false);
|
||||||
.map_err(|err| {
|
}
|
||||||
format!(
|
let update_manifest = update_manifest.unwrap();
|
||||||
"Unable to download {}: {}",
|
|
||||||
update_manifest.download_url, err
|
if timestamp_secs()
|
||||||
|
< u64::from_str_radix(crate::build_env::BUILD_SECONDS_SINCE_UNIX_EPOCH, 10).unwrap()
|
||||||
|
{
|
||||||
|
Err("Unable to update as system time seems unreliable".to_string())?
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(ref current_update_manifest) = config.current_update_manifest {
|
||||||
|
if update_manifest.timestamp_secs < current_update_manifest.timestamp_secs {
|
||||||
|
Err("Unable to update to an older version".to_string())?
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let release_dir = config.release_dir(&update_manifest.download_sha256);
|
||||||
|
let (_temp_dir, temp_archive, _temp_archive_sha256) = download_to_temp_archive(
|
||||||
|
&update_manifest.download_url,
|
||||||
|
Some(&update_manifest.download_sha256),
|
||||||
)
|
)
|
||||||
})?;
|
.map_err(|err| {
|
||||||
|
format!(
|
||||||
|
"Unable to download {}: {}",
|
||||||
|
update_manifest.download_url, err
|
||||||
|
)
|
||||||
|
})?;
|
||||||
|
extract_release_archive(&temp_archive, &release_dir).map_err(|err| {
|
||||||
|
format!(
|
||||||
|
"Unable to extract {:?} to {:?}: {}",
|
||||||
|
temp_archive, release_dir, err
|
||||||
|
)
|
||||||
|
})?;
|
||||||
|
|
||||||
let release_dir = config.release_dir(&update_manifest.download_sha256);
|
config.current_update_manifest = Some(update_manifest);
|
||||||
|
release_dir
|
||||||
extract_release_archive(&temp_archive, &release_dir).map_err(|err| {
|
};
|
||||||
format!(
|
|
||||||
"Unable to extract {:?} to {:?}: {}",
|
|
||||||
temp_archive, release_dir, err
|
|
||||||
)
|
|
||||||
})?;
|
|
||||||
|
|
||||||
let release_target = load_release_target(&release_dir).map_err(|err| {
|
let release_target = load_release_target(&release_dir).map_err(|err| {
|
||||||
format!(
|
format!(
|
||||||
|
@ -733,7 +779,6 @@ pub fn update(config_file: &str) -> Result<bool, String> {
|
||||||
)
|
)
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
config.current_update_manifest = Some(update_manifest);
|
|
||||||
config.save(config_file)?;
|
config.save(config_file)?;
|
||||||
|
|
||||||
println!(" {}{}", SPARKLE, style("Update successful").bold());
|
println!(" {}{}", SPARKLE, style("Update successful").bold());
|
||||||
|
|
|
@ -11,17 +11,24 @@ pub struct Config {
|
||||||
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>,
|
||||||
releases_dir: PathBuf,
|
releases_dir: PathBuf,
|
||||||
active_release_dir: PathBuf,
|
active_release_dir: PathBuf,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Config {
|
impl Config {
|
||||||
pub fn new(data_dir: &str, json_rpc_url: &str, update_manifest_pubkey: &Pubkey) -> Self {
|
pub fn new(
|
||||||
|
data_dir: &str,
|
||||||
|
json_rpc_url: &str,
|
||||||
|
update_manifest_pubkey: &Pubkey,
|
||||||
|
release_semver: Option<&str>,
|
||||||
|
) -> 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()),
|
||||||
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"),
|
||||||
}
|
}
|
||||||
|
@ -64,7 +71,7 @@ impl Config {
|
||||||
self.active_release_dir.join("bin")
|
self.active_release_dir.join("bin")
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn release_dir(&self, release_sha256: &str) -> PathBuf {
|
pub fn release_dir(&self, release_id: &str) -> PathBuf {
|
||||||
self.releases_dir.join(release_sha256)
|
self.releases_dir.join(release_id)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,6 +33,13 @@ fn is_pubkey(string: String) -> Result<(), String> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn is_semver(string: String) -> Result<(), String> {
|
||||||
|
match semver::Version::parse(&string) {
|
||||||
|
Ok(_) => Ok(()),
|
||||||
|
Err(err) => Err(format!("{:?}", err)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn main() -> Result<(), String> {
|
pub fn main() -> Result<(), String> {
|
||||||
solana_logger::setup();
|
solana_logger::setup();
|
||||||
|
|
||||||
|
@ -98,7 +105,15 @@ pub fn main() -> Result<(), String> {
|
||||||
Some(default_value) => arg.default_value(default_value),
|
Some(default_value) => arg.default_value(default_value),
|
||||||
None => arg,
|
None => arg,
|
||||||
}
|
}
|
||||||
}),
|
})
|
||||||
|
.arg(
|
||||||
|
Arg::with_name("release_semver")
|
||||||
|
.value_name("release-semver")
|
||||||
|
.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"),
|
||||||
|
),
|
||||||
)
|
)
|
||||||
.subcommand(
|
.subcommand(
|
||||||
SubCommand::with_name("info")
|
SubCommand::with_name("info")
|
||||||
|
@ -191,6 +206,7 @@ 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");
|
||||||
|
|
||||||
command::init(
|
command::init(
|
||||||
config_file,
|
config_file,
|
||||||
|
@ -198,6 +214,7 @@ 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,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
("info", Some(matches)) => {
|
("info", Some(matches)) => {
|
||||||
|
@ -292,6 +309,14 @@ pub fn main_init() -> Result<(), String> {
|
||||||
None => arg,
|
None => arg,
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
.arg(
|
||||||
|
Arg::with_name("release_semver")
|
||||||
|
.value_name("release-semver")
|
||||||
|
.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"),
|
||||||
|
)
|
||||||
.get_matches();
|
.get_matches();
|
||||||
|
|
||||||
let config_file = matches.value_of("config_file").unwrap();
|
let config_file = matches.value_of("config_file").unwrap();
|
||||||
|
@ -304,6 +329,7 @@ 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");
|
||||||
|
|
||||||
command::init(
|
command::init(
|
||||||
config_file,
|
config_file,
|
||||||
|
@ -311,5 +337,6 @@ 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,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue