diff --git a/CHANGELOG.md b/CHANGELOG.md index a999c5de6f..e73326b249 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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 diff --git a/cli/src/config.rs b/cli/src/config.rs index 1b4ae8a4d4..03c6b81884 100644 --- a/cli/src/config.rs +++ b/cli/src/config.rs @@ -263,6 +263,33 @@ impl WithPath { 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) -> Result> { + 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 { + self.get_programs(Some(name.to_owned()))? + .into_iter() + .next() + .ok_or_else(|| anyhow!("Expected a program")) + } + pub fn canonicalize_workspace(&self) -> Result<(Vec, Vec)> { let members = self .workspace @@ -296,29 +323,6 @@ impl WithPath { .collect(); Ok((members, exclude)) } - - pub fn get_program(&self, name: &str) -> Result>> { - 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 std::ops::Deref for WithPath { diff --git a/cli/src/lib.rs b/cli/src/lib.rs index 8d6d5ba592..228fd36e22 100644 --- a/cli/src/lib.rs +++ b/cli/src/lib.rs @@ -3076,7 +3076,7 @@ fn clean(cfg_override: &ConfigOverride) -> Result<()> { fn deploy( cfg_override: &ConfigOverride, - program_str: Option, + program_name: Option, program_keypair: Option, ) -> Result<()> { // Execute the code within the workspace @@ -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(()) }) @@ -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"))?; @@ -3789,21 +3758,12 @@ fn keys_list(cfg_override: &ConfigOverride) -> Result<()> { /// Sync the program's `declare_id!` pubkey with the pubkey from `target/deploy/.json`. fn keys_sync(cfg_override: &ConfigOverride, program_name: Option) -> 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();