Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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