Skip to content

Commit

Permalink
Merge branch 'coral-xyz:master' into fix/spl-token-upgrade
Browse files Browse the repository at this point in the history
  • Loading branch information
yanCode committed Dec 23, 2024
2 parents 7dbe334 + 6ff6655 commit 6117822
Show file tree
Hide file tree
Showing 7 changed files with 217 additions and 87 deletions.
88 changes: 88 additions & 0 deletions .github/workflows/release.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
name: Release

on:
push:
tags:
- "v[0-9]+.[0-9]+.[0-9]+"

pull_request:
branches:
- master
paths:
- VERSION

env:
DIST: dist-${{ github.ref_name }}

jobs:
build:
name: Build
runs-on: ${{ matrix.os }}
strategy:
matrix:
target:
- aarch64-apple-darwin
- x86_64-unknown-linux-gnu
- x86_64-apple-darwin
- x86_64-pc-windows-msvc
include:
- target: aarch64-apple-darwin
os: macos-latest

- target: x86_64-unknown-linux-gnu
os: ubuntu-latest

- target: x86_64-apple-darwin
os: macos-latest

- target: x86_64-pc-windows-msvc
os: windows-latest

steps:
- uses: actions/checkout@v4

- uses: dtolnay/rust-toolchain@master
with:
toolchain: stable
target: ${{ matrix.target }}

- name: Build release binary
run: cargo build --package anchor-cli --release --locked --target ${{ matrix.target }}

- name: Prepare
if: startsWith(github.ref, 'refs/tags/')
id: prepare
shell: bash
run: |
version=$(echo $GITHUB_REF_NAME | cut -dv -f2)
ext=""
[[ "${{ matrix.os }}" == windows-latest ]] && ext=".exe"
mkdir $DIST
mv "target/${{ matrix.target }}/release/anchor$ext" $DIST/anchor-$version-${{ matrix.target }}$ext
echo "version=$version" >> $GITHUB_OUTPUT
- uses: actions/upload-artifact@v4
if: startsWith(github.ref, 'refs/tags/')
with:
name: anchor-${{ steps.prepare.outputs.version }}-${{ matrix.target }}
path: ${{ env.DIST }}
overwrite: true
retention-days: 1

upload:
name: Upload binaries to release
if: startsWith(github.ref, 'refs/tags/')
needs: [build]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

- uses: actions/download-artifact@v4
with:
path: ${{ env.DIST }}

- name: Upload
shell: bash
run: GH_TOKEN=${{ secrets.GITHUB_TOKEN }} gh release upload $GITHUB_REF_NAME $DIST/*/* --clobber
4 changes: 2 additions & 2 deletions .github/workflows/tests.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@ name: Tests
on:
push:
branches:
- fix/spl-token-upgrade
- master
pull_request:
branches:
- fix/spl-token-upgrade
- master

jobs:
tests:
Expand Down
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ The minor version will be incremented upon a breaking change and the patch versi
- cli: Add test template for [Mollusk](https://github.com/buffalojoec/mollusk) ([#3352](https://github.com/coral-xyz/anchor/pull/3352)).
- idl: Disallow account discriminators that can conflict with the `zero` constraint ([#3365](https://github.com/coral-xyz/anchor/pull/3365)).
- cli: Include recommended solana args by default and add new `--max-retries` option to the `deploy` command ([#3354](https://github.com/coral-xyz/anchor/pull/3354)).
- avm: Make installation download binaries by default ([#3445](https://github.com/coral-xyz/anchor/pull/3445)).

### Fixes

Expand Down Expand Up @@ -103,6 +104,7 @@ The minor version will be incremented upon a breaking change and the patch versi
- lang: Require `zero` accounts to be unique ([#3409](https://github.com/coral-xyz/anchor/pull/3409)).
- lang: Deduplicate `zero` accounts against `init` accounts ([#3422](https://github.com/coral-xyz/anchor/pull/3422)).
- cli: Fix custom `provider.cluster` ([#3428](https://github.com/coral-xyz/anchor/pull/3428)).
- cli: Ignore non semver solana/agave releases to avoid panic ([#3432](https://github.com/coral-xyz/anchor/pull/3432)).

### Breaking

Expand Down
175 changes: 105 additions & 70 deletions avm/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ pub fn use_version(opt_version: Option<Version>) -> Result<()> {
.next()
.expect("Expected input")?;
match input.as_str() {
"y" | "yes" => return install_version(InstallTarget::Version(version), false),
"y" | "yes" => return install_version(InstallTarget::Version(version), false, false),
_ => return Err(anyhow!("Installation rejected.")),
};
}
Expand All @@ -107,7 +107,7 @@ pub enum InstallTarget {
/// Update to the latest version
pub fn update() -> Result<()> {
let latest_version = get_latest_version()?;
install_version(InstallTarget::Version(latest_version), false)
install_version(InstallTarget::Version(latest_version), false, false)
}

/// The commit sha provided can be shortened,
Expand Down Expand Up @@ -165,84 +165,119 @@ fn get_anchor_version_from_commit(commit: &str) -> Result<Version> {
}

/// Install a version of anchor-cli
pub fn install_version(install_target: InstallTarget, force: bool) -> Result<()> {
let mut args: Vec<String> = vec![
"install".into(),
"--git".into(),
"https://github.com/coral-xyz/anchor".into(),
"anchor-cli".into(),
"--locked".into(),
"--root".into(),
AVM_HOME.to_str().unwrap().into(),
];
let version = match install_target {
InstallTarget::Version(version) => {
args.extend(["--tag".into(), format!("v{}", version), "anchor-cli".into()]);
version
}
InstallTarget::Commit(commit) => {
args.extend(["--rev".into(), commit.clone()]);
get_anchor_version_from_commit(&commit)?
}
pub fn install_version(
install_target: InstallTarget,
force: bool,
from_source: bool,
) -> Result<()> {
let version = match &install_target {
InstallTarget::Version(version) => version.to_owned(),
InstallTarget::Commit(commit) => get_anchor_version_from_commit(commit)?,
};

// If version is already installed we ignore the request.
let installed_versions = read_installed_versions()?;
if installed_versions.contains(&version) && !force {
println!("Version {version} is already installed");
// Return early if version is already installed
if !force && read_installed_versions()?.contains(&version) {
eprintln!("Version `{version}` is already installed");
return Ok(());
}

// If the version is older than v0.31, install using `rustc 1.79.0` to get around the problem
// explained in https://github.com/coral-xyz/anchor/pull/3143
if version < Version::parse("0.31.0")? {
const REQUIRED_VERSION: &str = "1.79.0";
let is_installed = Command::new("rustup")
.args(["toolchain", "list"])
.output()
.map(|output| String::from_utf8(output.stdout))??
.lines()
.any(|line| line.starts_with(REQUIRED_VERSION));
if !is_installed {
let exit_status = Command::new("rustup")
.args(["toolchain", "install", REQUIRED_VERSION])
.spawn()?
.wait()?;
if !exit_status.success() {
return Err(anyhow!(
"Installation of `rustc {REQUIRED_VERSION}` failed. \
let is_older_than_v0_31_0 = version < Version::parse("0.31.0")?;
if from_source || is_older_than_v0_31_0 {
// Build from source using `cargo install --git`
let mut args: Vec<String> = vec![
"install".into(),
"anchor-cli".into(),
"--git".into(),
"https://github.com/coral-xyz/anchor".into(),
"--locked".into(),
"--root".into(),
AVM_HOME.to_str().unwrap().into(),
];
let conditional_args = match install_target {
InstallTarget::Version(version) => ["--tag".into(), format!("v{}", version)],
InstallTarget::Commit(commit) => ["--rev".into(), commit],
};
args.extend_from_slice(&conditional_args);

// If the version is older than v0.31, install using `rustc 1.79.0` to get around the problem
// explained in https://github.com/coral-xyz/anchor/pull/3143
if is_older_than_v0_31_0 {
const REQUIRED_VERSION: &str = "1.79.0";
let is_installed = Command::new("rustup")
.args(["toolchain", "list"])
.output()
.map(|output| String::from_utf8(output.stdout))??
.lines()
.any(|line| line.starts_with(REQUIRED_VERSION));
if !is_installed {
let exit_status = Command::new("rustup")
.args(["toolchain", "install", REQUIRED_VERSION])
.spawn()?
.wait()?;
if !exit_status.success() {
return Err(anyhow!(
"Installation of `rustc {REQUIRED_VERSION}` failed. \
`rustc <1.80` is required to install Anchor v{version} from source. \
See https://github.com/coral-xyz/anchor/pull/3143 for more information."
));
));
}
}
}

// Prepend the toolchain to use with the `cargo install` command
args.insert(0, format!("+{REQUIRED_VERSION}"));
}
// Prepend the toolchain to use with the `cargo install` command
args.insert(0, format!("+{REQUIRED_VERSION}"));
}

let output = Command::new("cargo")
.args(args)
.stdout(Stdio::inherit())
.stderr(Stdio::inherit())
.output()
.map_err(|e| anyhow!("Cargo install for {version} failed: {e}"))?;
if !output.status.success() {
return Err(anyhow!(
"Failed to install {version}, is it a valid version?"
));
}
let output = Command::new("cargo")
.args(args)
.stdout(Stdio::inherit())
.stderr(Stdio::inherit())
.output()
.map_err(|e| anyhow!("`cargo install` for version `{version}` failed: {e}"))?;
if !output.status.success() {
return Err(anyhow!(
"Failed to install {version}, is it a valid version?"
));
}

let bin_dir = get_bin_dir_path();
let bin_name = if cfg!(target_os = "windows") {
"anchor.exe"
let bin_dir = get_bin_dir_path();
let bin_name = if cfg!(target_os = "windows") {
"anchor.exe"
} else {
"anchor"
};
fs::rename(bin_dir.join(bin_name), version_binary_path(&version))?;
} else {
"anchor"
};
fs::rename(
bin_dir.join(bin_name),
bin_dir.join(format!("anchor-{version}")),
)?;
let output = Command::new("rustc").arg("-vV").output()?;
let target = core::str::from_utf8(&output.stdout)?
.lines()
.find(|line| line.starts_with("host:"))
.and_then(|line| line.split(':').last())
.ok_or_else(|| anyhow!("`host` not found from `rustc -vV` output"))?
.trim();
let ext = if cfg!(target_os = "windows") {
".exe"
} else {
""
};
let res = reqwest::blocking::get(format!(
"https://github.com/coral-xyz/anchor/releases/download/v{version}/anchor-{version}-{target}{ext}"
))?;
if !res.status().is_success() {
return Err(anyhow!(
"Failed to download the binary for version `{version}` (status code: {})",
res.status()
));
}

let bin_path = version_binary_path(&version);
fs::write(&bin_path, res.bytes()?)?;

// Set file to executable on UNIX
#[cfg(not(target_os = "windows"))]
fs::set_permissions(
bin_path,
<fs::Permissions as std::os::unix::fs::PermissionsExt>::from_mode(0o775),
)?;
}

// If .version file is empty or not parseable, write the newly installed version to it
if current_version().is_err() {
Expand All @@ -255,7 +290,7 @@ pub fn install_version(install_target: InstallTarget, force: bool) -> Result<()>

/// Remove an installed version of anchor-cli
pub fn uninstall_version(version: &Version) -> Result<()> {
let version_path = get_bin_dir_path().join(format!("anchor-{version}"));
let version_path = version_binary_path(version);
if !version_path.exists() {
return Err(anyhow!("anchor-cli {} is not installed", version));
}
Expand Down
6 changes: 5 additions & 1 deletion avm/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,9 @@ pub enum Commands {
/// Flag to force installation even if the version
/// is already installed
force: bool,
#[clap(long)]
/// Build from source code rather than downloading prebuilt binaries
from_source: bool,
},
#[clap(about = "Uninstall a version of Anchor")]
Uninstall {
Expand Down Expand Up @@ -77,7 +80,8 @@ pub fn entry(opts: Cli) -> Result<()> {
Commands::Install {
version_or_commit,
force,
} => avm::install_version(version_or_commit, force),
from_source,
} => avm::install_version(version_or_commit, force, from_source),
Commands::Uninstall { version } => avm::uninstall_version(&version),
Commands::List {} => avm::list_versions(),
Commands::Update {} => avm::update(),
Expand Down
27 changes: 14 additions & 13 deletions cli/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -556,16 +556,16 @@ fn override_toolchain(cfg_override: &ConfigOverride) -> Result<RestoreToolchainC

let cfg = Config::discover(cfg_override)?;
if let Some(cfg) = cfg {
fn parse_version(text: &str) -> String {
Regex::new(r"(\d+\.\d+\.\S+)")
.unwrap()
.captures_iter(text)
.next()
.unwrap()
.get(0)
.unwrap()
.as_str()
.to_string()
fn parse_version(text: &str) -> Option<String> {
Some(
Regex::new(r"(\d+\.\d+\.\S+)")
.unwrap()
.captures_iter(text)
.next()?
.get(0)?
.as_str()
.to_string(),
)
}

fn get_current_version(cmd_name: &str) -> Result<String> {
Expand All @@ -577,8 +577,8 @@ fn override_toolchain(cfg_override: &ConfigOverride) -> Result<RestoreToolchainC
}

let output_version = std::str::from_utf8(&output.stdout)?;
let version = parse_version(output_version);
Ok(version)
parse_version(output_version)
.ok_or_else(|| anyhow!("Failed to parse the version of `{cmd_name}`"))
}

if let Some(solana_version) = &cfg.toolchain.solana_version {
Expand Down Expand Up @@ -635,7 +635,8 @@ fn override_toolchain(cfg_override: &ConfigOverride) -> Result<RestoreToolchainC
// Hide the installation progress if the version is already installed
let is_installed = std::str::from_utf8(&output.stdout)?
.lines()
.any(|line| parse_version(line) == version);
.filter_map(parse_version)
.any(|line_version| line_version == version);
let (stderr, stdout) = if is_installed {
(Stdio::null(), Stdio::null())
} else {
Expand Down
Loading

0 comments on commit 6117822

Please sign in to comment.