Add an option to install a specific version of sbf-tools (#29544)
This commit is contained in:
parent
71467808d2
commit
cc4e134079
|
@ -4939,6 +4939,8 @@ dependencies = [
|
||||||
"log",
|
"log",
|
||||||
"predicates",
|
"predicates",
|
||||||
"regex",
|
"regex",
|
||||||
|
"reqwest",
|
||||||
|
"semver 1.0.14",
|
||||||
"serial_test",
|
"serial_test",
|
||||||
"solana-download-utils",
|
"solana-download-utils",
|
||||||
"solana-logger 1.15.0",
|
"solana-logger 1.15.0",
|
||||||
|
|
|
@ -11,7 +11,7 @@ SBF_TOOLS_VERSION=unknown
|
||||||
|
|
||||||
cargo_build_sbf_main="${here}/../sdk/cargo-build-sbf/src/main.rs"
|
cargo_build_sbf_main="${here}/../sdk/cargo-build-sbf/src/main.rs"
|
||||||
if [[ -f "${cargo_build_sbf_main}" ]]; then
|
if [[ -f "${cargo_build_sbf_main}" ]]; then
|
||||||
version=$(sed -e 's/^.*sbf_tools_version\s*=\s*"\(v[0-9.]\+\)".*/\1/;t;d' "${cargo_build_sbf_main}")
|
version=$(sed -e 's/^.*sbf_tools_version\s*=\s*String::from("\(v[0-9.]\+\)").*/\1/;t;d' "${cargo_build_sbf_main}")
|
||||||
if [[ ${version} != '' ]]; then
|
if [[ ${version} != '' ]]; then
|
||||||
SBF_TOOLS_VERSION="${version}"
|
SBF_TOOLS_VERSION="${version}"
|
||||||
else
|
else
|
||||||
|
|
|
@ -15,6 +15,8 @@ cargo_metadata = "0.15.0"
|
||||||
clap = { version = "3.1.5", features = ["cargo", "env"] }
|
clap = { version = "3.1.5", features = ["cargo", "env"] }
|
||||||
log = { version = "0.4.14", features = ["std"] }
|
log = { version = "0.4.14", features = ["std"] }
|
||||||
regex = "1.6.0"
|
regex = "1.6.0"
|
||||||
|
reqwest = { version = "0.11", features = ["blocking"] }
|
||||||
|
semver = "1.0"
|
||||||
solana-download-utils = { path = "../../download-utils", version = "=1.15.0" }
|
solana-download-utils = { path = "../../download-utils", version = "=1.15.0" }
|
||||||
solana-logger = { path = "../../logger", version = "=1.15.0" }
|
solana-logger = { path = "../../logger", version = "=1.15.0" }
|
||||||
solana-sdk = { path = "..", version = "=1.15.0" }
|
solana-sdk = { path = "..", version = "=1.15.0" }
|
||||||
|
|
|
@ -124,6 +124,106 @@ where
|
||||||
.collect::<String>()
|
.collect::<String>()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn is_version_string(arg: &str) -> Result<(), String> {
|
||||||
|
let semver_re = Regex::new(r"^v[0-9]+\.[0-9]+(\.[0-9]+)?").unwrap();
|
||||||
|
if semver_re.is_match(arg) {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
Err("a version string starts with 'v' and contains major and minor version numbers separated by a dot, e.g. v1.32".to_string())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn find_installed_sbf_tools(arch: &str) -> Vec<String> {
|
||||||
|
let home_dir = PathBuf::from(env::var("HOME").unwrap_or_else(|err| {
|
||||||
|
error!("Can't get home directory path: {}", err);
|
||||||
|
exit(1);
|
||||||
|
}));
|
||||||
|
let solana = home_dir.join(".cache").join("solana");
|
||||||
|
let package = if arch == "bpf" {
|
||||||
|
"bpf-tools"
|
||||||
|
} else {
|
||||||
|
"sbf-tools"
|
||||||
|
};
|
||||||
|
std::fs::read_dir(solana)
|
||||||
|
.unwrap()
|
||||||
|
.filter_map(|e| match e {
|
||||||
|
Err(_) => None,
|
||||||
|
Ok(e) => {
|
||||||
|
if e.path().join(package).is_dir() {
|
||||||
|
Some(e.path().file_name().unwrap().to_string_lossy().to_string())
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.collect::<Vec<_>>()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_latest_sbf_tools_version() -> Result<String, String> {
|
||||||
|
let url = "https://github.com/solana-labs/sbf-tools/releases/latest";
|
||||||
|
let resp =
|
||||||
|
reqwest::blocking::get(url).map_err(|err| format!("Failed to GET {}: {}", url, err))?;
|
||||||
|
let path = std::path::Path::new(resp.url().path());
|
||||||
|
let version = path.file_name().unwrap().to_string_lossy().to_string();
|
||||||
|
Ok(version)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn normalize_version(version: String) -> String {
|
||||||
|
let dots = version.as_bytes().iter().fold(
|
||||||
|
0,
|
||||||
|
|n: u32, c| if *c == b'.' { n.saturating_add(1) } else { n },
|
||||||
|
);
|
||||||
|
if dots == 1 {
|
||||||
|
format!("{}.0", version)
|
||||||
|
} else {
|
||||||
|
version
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn validate_sbf_tools_version(
|
||||||
|
arch: &str,
|
||||||
|
requested_version: &str,
|
||||||
|
builtin_version: String,
|
||||||
|
) -> String {
|
||||||
|
let normalized_requested = normalize_version(requested_version.to_string());
|
||||||
|
let requested_semver = semver::Version::parse(&normalized_requested[1..]).unwrap();
|
||||||
|
let installed_versions = find_installed_sbf_tools(arch);
|
||||||
|
for v in installed_versions {
|
||||||
|
if requested_semver <= semver::Version::parse(&normalize_version(v)[1..]).unwrap() {
|
||||||
|
return requested_version.to_string();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let latest_version = get_latest_sbf_tools_version().unwrap_or_else(|err| {
|
||||||
|
debug!(
|
||||||
|
"Can't get the latest version of sbf-tools: {}. Using built-in version {}.",
|
||||||
|
err, &builtin_version,
|
||||||
|
);
|
||||||
|
builtin_version.clone()
|
||||||
|
});
|
||||||
|
let normalized_latest = normalize_version(latest_version.clone());
|
||||||
|
let latest_semver = semver::Version::parse(&normalized_latest[1..]).unwrap();
|
||||||
|
if requested_semver <= latest_semver {
|
||||||
|
requested_version.to_string()
|
||||||
|
} else {
|
||||||
|
warn!(
|
||||||
|
"Version {} is not valid, latest version is {}. Using the built-in version {}",
|
||||||
|
requested_version, latest_version, &builtin_version,
|
||||||
|
);
|
||||||
|
builtin_version
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn make_sbf_tools_path_for_version(package: &str, version: &str) -> PathBuf {
|
||||||
|
let home_dir = PathBuf::from(env::var("HOME").unwrap_or_else(|err| {
|
||||||
|
error!("Can't get home directory path: {}", err);
|
||||||
|
exit(1);
|
||||||
|
}));
|
||||||
|
home_dir
|
||||||
|
.join(".cache")
|
||||||
|
.join("solana")
|
||||||
|
.join(version)
|
||||||
|
.join(package)
|
||||||
|
}
|
||||||
|
|
||||||
// Check whether a package is installed and install it if missing.
|
// Check whether a package is installed and install it if missing.
|
||||||
fn install_if_missing(
|
fn install_if_missing(
|
||||||
config: &Config,
|
config: &Config,
|
||||||
|
@ -524,21 +624,12 @@ fn build_sbf_package(config: &Config, target_directory: &Path, package: &cargo_m
|
||||||
} else {
|
} else {
|
||||||
"solana-sbf-tools-linux.tar.bz2"
|
"solana-sbf-tools-linux.tar.bz2"
|
||||||
};
|
};
|
||||||
|
|
||||||
let home_dir = PathBuf::from(env::var("HOME").unwrap_or_else(|err| {
|
|
||||||
error!("Can't get home directory path: {}", err);
|
|
||||||
exit(1);
|
|
||||||
}));
|
|
||||||
let package = if config.arch == "bpf" {
|
let package = if config.arch == "bpf" {
|
||||||
"bpf-tools"
|
"bpf-tools"
|
||||||
} else {
|
} else {
|
||||||
"sbf-tools"
|
"sbf-tools"
|
||||||
};
|
};
|
||||||
let target_path = home_dir
|
let target_path = make_sbf_tools_path_for_version(package, config.sbf_tools_version);
|
||||||
.join(".cache")
|
|
||||||
.join("solana")
|
|
||||||
.join(config.sbf_tools_version)
|
|
||||||
.join(package);
|
|
||||||
install_if_missing(
|
install_if_missing(
|
||||||
config,
|
config,
|
||||||
package,
|
package,
|
||||||
|
@ -846,7 +937,7 @@ fn main() {
|
||||||
|
|
||||||
// The following line is scanned by CI configuration script to
|
// The following line is scanned by CI configuration script to
|
||||||
// separate cargo caches according to the version of sbf-tools.
|
// separate cargo caches according to the version of sbf-tools.
|
||||||
let sbf_tools_version = "v1.32";
|
let sbf_tools_version = String::from("v1.32");
|
||||||
let version = format!("{}\nsbf-tools {}", crate_version!(), sbf_tools_version);
|
let version = format!("{}\nsbf-tools {}", crate_version!(), sbf_tools_version);
|
||||||
let matches = clap::Command::new(crate_name!())
|
let matches = clap::Command::new(crate_name!())
|
||||||
.about(crate_description!())
|
.about(crate_description!())
|
||||||
|
@ -933,6 +1024,14 @@ fn main() {
|
||||||
.takes_value(false)
|
.takes_value(false)
|
||||||
.help("Run without accessing the network"),
|
.help("Run without accessing the network"),
|
||||||
)
|
)
|
||||||
|
.arg(
|
||||||
|
Arg::new("tools_version")
|
||||||
|
.long("tools-version")
|
||||||
|
.value_name("STRING")
|
||||||
|
.takes_value(true)
|
||||||
|
.validator(is_version_string)
|
||||||
|
.help("sbf-tools version to use or to install, a version string, e.g. \"v1.32\""),
|
||||||
|
)
|
||||||
.arg(
|
.arg(
|
||||||
Arg::new("verbose")
|
Arg::new("verbose")
|
||||||
.short('v')
|
.short('v')
|
||||||
|
@ -968,6 +1067,15 @@ fn main() {
|
||||||
let sbf_sdk: PathBuf = matches.value_of_t_or_exit("sbf_sdk");
|
let sbf_sdk: PathBuf = matches.value_of_t_or_exit("sbf_sdk");
|
||||||
let sbf_out_dir: Option<PathBuf> = matches.value_of_t("sbf_out_dir").ok();
|
let sbf_out_dir: Option<PathBuf> = matches.value_of_t("sbf_out_dir").ok();
|
||||||
|
|
||||||
|
let sbf_tools_version = if let Some(tools_version) = matches.value_of("tools_version") {
|
||||||
|
validate_sbf_tools_version(
|
||||||
|
matches.value_of("arch").unwrap(),
|
||||||
|
tools_version,
|
||||||
|
sbf_tools_version,
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
sbf_tools_version
|
||||||
|
};
|
||||||
let config = Config {
|
let config = Config {
|
||||||
cargo_args: matches
|
cargo_args: matches
|
||||||
.values_of("cargo_args")
|
.values_of("cargo_args")
|
||||||
|
@ -989,7 +1097,7 @@ fn main() {
|
||||||
.join(sbf_out_dir)
|
.join(sbf_out_dir)
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
sbf_tools_version,
|
sbf_tools_version: sbf_tools_version.as_str(),
|
||||||
dump: matches.is_present("dump"),
|
dump: matches.is_present("dump"),
|
||||||
features: matches.values_of_t("features").ok().unwrap_or_default(),
|
features: matches.values_of_t("features").ok().unwrap_or_default(),
|
||||||
force_tools_install: matches.is_present("force_tools_install"),
|
force_tools_install: matches.is_present("force_tools_install"),
|
||||||
|
|
Loading…
Reference in New Issue