|
@@ -12,6 +12,8 @@ use anchor_syn::idl::types::{
|
|
|
};
|
|
|
use anyhow::{anyhow, Context, Result};
|
|
|
use clap::Parser;
|
|
|
+use config::ToolchainConfig;
|
|
|
+use dirs::home_dir;
|
|
|
use flate2::read::GzDecoder;
|
|
|
use flate2::read::ZlibDecoder;
|
|
|
use flate2::write::{GzEncoder, ZlibEncoder};
|
|
@@ -463,6 +465,126 @@ pub enum ClusterCommand {
|
|
|
}
|
|
|
|
|
|
pub fn entry(opts: Opts) -> Result<()> {
|
|
|
+ let toolchain_config = override_toolchain(&opts.cfg_override)?;
|
|
|
+ let result = process_command(opts);
|
|
|
+ restore_toolchain(&toolchain_config)?;
|
|
|
+
|
|
|
+ result
|
|
|
+}
|
|
|
+
|
|
|
+/// Override the toolchain from `Anchor.toml`.
|
|
|
+///
|
|
|
+/// Returns the previous versions to restore back to.
|
|
|
+fn override_toolchain(cfg_override: &ConfigOverride) -> Result<ToolchainConfig> {
|
|
|
+ let mut previous_versions = ToolchainConfig::default();
|
|
|
+
|
|
|
+ let cfg = Config::discover(cfg_override)?;
|
|
|
+ if let Some(cfg) = cfg {
|
|
|
+ fn get_current_version(cmd_name: &str) -> Result<String> {
|
|
|
+ let output: std::process::Output = std::process::Command::new(cmd_name)
|
|
|
+ .arg("--version")
|
|
|
+ .output()?;
|
|
|
+ let output_version = std::str::from_utf8(&output.stdout)?;
|
|
|
+ let version = Regex::new(r"(\d+\.\d+\.\S+)")
|
|
|
+ .unwrap()
|
|
|
+ .captures_iter(output_version)
|
|
|
+ .next()
|
|
|
+ .unwrap()
|
|
|
+ .get(0)
|
|
|
+ .unwrap()
|
|
|
+ .as_str()
|
|
|
+ .to_string();
|
|
|
+
|
|
|
+ Ok(version)
|
|
|
+ }
|
|
|
+
|
|
|
+ if let Some(solana_version) = &cfg.toolchain.solana_version {
|
|
|
+ let current_version = get_current_version("solana")?;
|
|
|
+ if solana_version != ¤t_version {
|
|
|
+ // We are overriding with `solana-install` command instead of using the binaries
|
|
|
+ // from `~/.local/share/solana/install/releases` because we use multiple Solana
|
|
|
+ // binaries in various commands.
|
|
|
+ let exit_status = std::process::Command::new("solana-install")
|
|
|
+ .arg("init")
|
|
|
+ .arg(solana_version)
|
|
|
+ .stderr(Stdio::null())
|
|
|
+ .stdout(Stdio::null())
|
|
|
+ .spawn()?
|
|
|
+ .wait()?;
|
|
|
+
|
|
|
+ if !exit_status.success() {
|
|
|
+ println!(
|
|
|
+ "Failed to override `solana` version to {solana_version}, \
|
|
|
+ using {current_version} instead"
|
|
|
+ );
|
|
|
+ } else {
|
|
|
+ previous_versions.solana_version = Some(current_version);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // Anchor version override should be handled last
|
|
|
+ if let Some(anchor_version) = &cfg.toolchain.anchor_version {
|
|
|
+ let current_version = VERSION;
|
|
|
+ if anchor_version != current_version {
|
|
|
+ let binary_path = home_dir()
|
|
|
+ .unwrap()
|
|
|
+ .join(".avm")
|
|
|
+ .join("bin")
|
|
|
+ .join(format!("anchor-{anchor_version}"));
|
|
|
+
|
|
|
+ if !binary_path.exists() {
|
|
|
+ println!(
|
|
|
+ "`anchor` {anchor_version} is not installed with `avm`. Installing...\n"
|
|
|
+ );
|
|
|
+
|
|
|
+ let exit_status = std::process::Command::new("avm")
|
|
|
+ .arg("install")
|
|
|
+ .arg(anchor_version)
|
|
|
+ .spawn()?
|
|
|
+ .wait()?;
|
|
|
+
|
|
|
+ if !exit_status.success() {
|
|
|
+ println!(
|
|
|
+ "Failed to install `anchor` {anchor_version}, \
|
|
|
+ using {current_version} instead"
|
|
|
+ );
|
|
|
+
|
|
|
+ return Ok(previous_versions);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ let exit_code = std::process::Command::new(binary_path)
|
|
|
+ .args(std::env::args_os().skip(1))
|
|
|
+ .spawn()?
|
|
|
+ .wait()?
|
|
|
+ .code()
|
|
|
+ .unwrap_or(1);
|
|
|
+ restore_toolchain(&previous_versions)?;
|
|
|
+ std::process::exit(exit_code);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ Ok(previous_versions)
|
|
|
+}
|
|
|
+
|
|
|
+/// Restore toolchain to how it was before the command was run.
|
|
|
+fn restore_toolchain(toolchain_config: &ToolchainConfig) -> Result<()> {
|
|
|
+ if let Some(solana_version) = &toolchain_config.solana_version {
|
|
|
+ std::process::Command::new("solana-install")
|
|
|
+ .arg("init")
|
|
|
+ .arg(solana_version)
|
|
|
+ .stderr(Stdio::null())
|
|
|
+ .stdout(Stdio::null())
|
|
|
+ .spawn()?
|
|
|
+ .wait()?;
|
|
|
+ }
|
|
|
+
|
|
|
+ Ok(())
|
|
|
+}
|
|
|
+
|
|
|
+fn process_command(opts: Opts) -> Result<()> {
|
|
|
match opts.command {
|
|
|
Command::Init {
|
|
|
name,
|
|
@@ -1000,7 +1122,7 @@ pub fn build(
|
|
|
let cfg = Config::discover(cfg_override)?.expect("Not in workspace.");
|
|
|
let build_config = BuildConfig {
|
|
|
verifiable,
|
|
|
- solana_version: solana_version.or_else(|| cfg.solana_version.clone()),
|
|
|
+ solana_version: solana_version.or_else(|| cfg.toolchain.solana_version.clone()),
|
|
|
docker_image: docker_image.unwrap_or_else(|| cfg.docker()),
|
|
|
bootstrap,
|
|
|
};
|
|
@@ -1668,16 +1790,16 @@ fn verify(
|
|
|
if !skip_build {
|
|
|
build(
|
|
|
cfg_override,
|
|
|
- None, // idl
|
|
|
- None, // idl ts
|
|
|
- true, // verifiable
|
|
|
- true, // skip lint
|
|
|
- None, // program name
|
|
|
- solana_version.or_else(|| cfg.solana_version.clone()), // solana version
|
|
|
- docker_image, // docker image
|
|
|
- bootstrap, // bootstrap docker image
|
|
|
- None, // stdout
|
|
|
- None, // stderr
|
|
|
+ None, // idl
|
|
|
+ None, // idl ts
|
|
|
+ true, // verifiable
|
|
|
+ true, // skip lint
|
|
|
+ None, // program name
|
|
|
+ solana_version.or_else(|| cfg.toolchain.solana_version.clone()), // solana version
|
|
|
+ docker_image, // docker image
|
|
|
+ bootstrap, // bootstrap docker image
|
|
|
+ None, // stdout
|
|
|
+ None, // stderr
|
|
|
env_vars,
|
|
|
cargo_args,
|
|
|
false,
|
|
@@ -2647,9 +2769,7 @@ fn deserialize_idl_defined_type_to_json(
|
|
|
.iter()
|
|
|
.chain(idl.accounts.iter())
|
|
|
.find(|defined_type| defined_type.name == defined_type_name)
|
|
|
- .ok_or_else(|| {
|
|
|
- anyhow::anyhow!("Struct/Enum named {} not found in IDL.", defined_type_name)
|
|
|
- })?
|
|
|
+ .ok_or_else(|| anyhow!("Type `{}` not found in IDL.", defined_type_name))?
|
|
|
.ty;
|
|
|
|
|
|
let mut deserialized_fields = Map::new();
|