Skip to content

Commit

Permalink
cli: Accept program lib name for anchor deploy --program-name (#2519)
Browse files Browse the repository at this point in the history
  • Loading branch information
acheroncrypto authored Jun 6, 2023
1 parent a88be42 commit 3d7c97b
Show file tree
Hide file tree
Showing 3 changed files with 80 additions and 115 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ The minor version will be incremented upon a breaking change and the patch versi
- cli: Add `keys sync` command to sync program id declarations ([#2505](https://github.com/coral-xyz/anchor/pull/2505)).
- cli: Create new programs with correct program ids ([#2509](https://github.com/coral-xyz/anchor/pull/2509)).
- cli, client, lang, spl: Update Solana toolchain and dependencies to `1.16.0` and specify maximum version of `<1.17.0` ([#2512](https://github.com/coral-xyz/anchor/pull/2512)).
- cli: `anchor deploy` command's `--program-name` argument accepts program lib names ([#2519](https://github.com/coral-xyz/anchor/pull/2519)).

### Fixes

Expand Down
50 changes: 27 additions & 23 deletions cli/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -263,6 +263,33 @@ impl WithPath<Config> {
Ok(r)
}

/// Read and get all the programs from the workspace.
///
/// This method will only return the given program if `name` exists.
pub fn get_programs(&self, name: Option<String>) -> Result<Vec<Program>> {
let programs = self.read_all_programs()?;
let programs = match name {
Some(name) => vec![programs
.into_iter()
.find(|program| {
name == program.lib_name
|| name == program.path.file_name().unwrap().to_str().unwrap()
})
.ok_or_else(|| anyhow!("Program {name} not found"))?],
None => programs,
};

Ok(programs)
}

/// Get the specified program from the workspace.
pub fn get_program(&self, name: &str) -> Result<Program> {
self.get_programs(Some(name.to_owned()))?
.into_iter()
.next()
.ok_or_else(|| anyhow!("Expected a program"))
}

pub fn canonicalize_workspace(&self) -> Result<(Vec<PathBuf>, Vec<PathBuf>)> {
let members = self
.workspace
Expand Down Expand Up @@ -296,29 +323,6 @@ impl WithPath<Config> {
.collect();
Ok((members, exclude))
}

pub fn get_program(&self, name: &str) -> Result<Option<WithPath<Program>>> {
for program in self.read_all_programs()? {
let cargo_toml = program.path.join("Cargo.toml");
if !cargo_toml.exists() {
return Err(anyhow!(
"Did not find Cargo.toml at the path: {}",
program.path.display()
));
}
let p_lib_name = Manifest::from_path(&cargo_toml)?.lib_name()?;
if name == p_lib_name {
let path = self
.path()
.parent()
.unwrap()
.canonicalize()?
.join(&program.path);
return Ok(Some(WithPath::new(program, path)));
}
}
Ok(None)
}
}

impl<T> std::ops::Deref for WithPath<T> {
Expand Down
144 changes: 52 additions & 92 deletions cli/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3076,7 +3076,7 @@ fn clean(cfg_override: &ConfigOverride) -> Result<()> {

fn deploy(
cfg_override: &ConfigOverride,
program_str: Option<String>,
program_name: Option<String>,
program_keypair: Option<String>,
) -> Result<()> {
// Execute the code within the workspace
Expand All @@ -3088,91 +3088,62 @@ fn deploy(
println!("Deploying cluster: {}", url);
println!("Upgrade authority: {}", keypair);

let mut program_found = true; // Flag to track if the specified program is found
for mut program in cfg.get_programs(program_name)? {
let binary_path = program.binary_path().display().to_string();

println!("Deploying program {:?}...", program.lib_name);
println!("Program path: {}...", binary_path);

let (program_keypair_filepath, program_id) = match &program_keypair {
Some(path) => (
path.clone(),
solana_sdk::signature::read_keypair_file(path)
.map_err(|_| anyhow!("Unable to read keypair file"))?
.pubkey(),
),
None => (
program.keypair_file()?.path().display().to_string(),
program.pubkey()?,
),
};

for mut program in cfg.read_all_programs()? {
// If a program string is provided
if let Some(single_prog_str) = &program_str {
let program_name = program.path.file_name().unwrap().to_str().unwrap();
// Send deploy transactions using the Solana CLI
let exit = std::process::Command::new("solana")
.arg("program")
.arg("deploy")
.arg("--url")
.arg(&url)
.arg("--keypair")
.arg(&keypair)
.arg("--program-id")
.arg(strip_workspace_prefix(program_keypair_filepath))
.arg(strip_workspace_prefix(binary_path))
.stdout(Stdio::inherit())
.stderr(Stdio::inherit())
.output()
.expect("Must deploy");

// Check if the provided program string matches the program name
if single_prog_str.as_str() != program_name {
program_found = false;
} else {
program_found = true;
}
// Check if deployment was successful
if !exit.status.success() {
println!("There was a problem deploying: {exit:?}.");
std::process::exit(exit.status.code().unwrap_or(1));
}

if program_found {
let binary_path = program.binary_path().display().to_string();
if let Some(mut idl) = program.idl.as_mut() {
// Add program address to the IDL.
idl.metadata = Some(serde_json::to_value(IdlTestMetadata {
address: program_id.to_string(),
})?);

println!(
"Deploying program {:?}...",
program.path.file_name().unwrap().to_str().unwrap()
);
println!("Program path: {}...", binary_path);

let (program_keypair_filepath, program_id) = match &program_keypair {
Some(path) => (
path.clone(),
solana_sdk::signature::read_keypair_file(path)
.map_err(|_| anyhow!("Unable to read keypair file"))?
.pubkey(),
),
None => (
program.keypair_file()?.path().display().to_string(),
program.pubkey()?,
),
};

// Send deploy transactions using the Solana CLI
let exit = std::process::Command::new("solana")
.arg("program")
.arg("deploy")
.arg("--url")
.arg(&url)
.arg("--keypair")
.arg(&keypair)
.arg("--program-id")
.arg(strip_workspace_prefix(program_keypair_filepath))
.arg(strip_workspace_prefix(binary_path))
.stdout(Stdio::inherit())
.stderr(Stdio::inherit())
.output()
.expect("Must deploy");

// Check if deployment was successful
if !exit.status.success() {
println!("There was a problem deploying: {exit:?}.");
std::process::exit(exit.status.code().unwrap_or(1));
}

if let Some(mut idl) = program.idl.as_mut() {
// Add program address to the IDL.
idl.metadata = Some(serde_json::to_value(IdlTestMetadata {
address: program_id.to_string(),
})?);

// Persist it.
let idl_out = PathBuf::from("target/idl")
.join(&idl.name)
.with_extension("json");
write_idl(idl, OutFile::File(idl_out))?;
}
}

// Break the loop if a specific programme is discovered and program_str is not None.
if program_str.is_some() && program_found {
break;
// Persist it.
let idl_out = PathBuf::from("target/idl")
.join(&idl.name)
.with_extension("json");
write_idl(idl, OutFile::File(idl_out))?;
}
}

// If a program string is provided but not found
if program_str.is_some() && !program_found {
println!("Specified program not found");
} else {
println!("Deploy success");
}
println!("Deploy success");

Ok(())
})
Expand Down Expand Up @@ -3582,12 +3553,10 @@ fn publish(
// Discover the various workspace configs.
let cfg = Config::discover(cfg_override)?.expect("Not in workspace.");

let program = cfg
.get_program(&program_name)?
.ok_or_else(|| anyhow!("Workspace member not found"))?;
let program = cfg.get_program(&program_name)?;

let program_cargo_lock = pathdiff::diff_paths(
program.path().join("Cargo.lock"),
program.path.join("Cargo.lock"),
cfg.path().parent().unwrap(),
)
.ok_or_else(|| anyhow!("Unable to diff Cargo.lock path"))?;
Expand Down Expand Up @@ -3789,21 +3758,12 @@ fn keys_list(cfg_override: &ConfigOverride) -> Result<()> {
/// Sync the program's `declare_id!` pubkey with the pubkey from `target/deploy/<KEYPAIR>.json`.
fn keys_sync(cfg_override: &ConfigOverride, program_name: Option<String>) -> Result<()> {
with_workspace(cfg_override, |cfg| {
let programs = cfg.read_all_programs()?;
let programs = match program_name {
Some(program_name) => vec![programs
.into_iter()
.find(|program| program.lib_name == program_name)
.ok_or_else(|| anyhow!("`{program_name}` is not found"))?],
None => programs,
};

let declare_id_regex = RegexBuilder::new(r#"^(([\w]+::)*)declare_id!\("(\w*)"\)"#)
.multi_line(true)
.build()
.unwrap();

for program in programs {
for program in cfg.get_programs(program_name)? {
// Get the pubkey from the keypair file
let actual_program_id = program.pubkey()?.to_string();

Expand Down

1 comment on commit 3d7c97b

@vercel
Copy link

@vercel vercel bot commented on 3d7c97b Jun 6, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Successfully deployed to the following URLs:

anchor-docs – ./

anchor-docs-git-master-200ms.vercel.app
www.anchor-lang.com
anchor-lang.com
anchor-docs-200ms.vercel.app

Please sign in to comment.