Skip to content
Open
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
5 changes: 4 additions & 1 deletion crates/cli/src/cli/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -189,9 +189,12 @@ pub struct StartSimnet {
/// List of keypair paths to airdrop (eg. surfpool start --airdrop-keypair-path ~/.config/solana/id.json --airdrop-keypair-path ~/.config/solana/id2.json)
#[arg(long = "airdrop-keypair-path", short = 'k', default_value = DEFAULT_SOLANA_KEYPAIR_PATH.as_str())]
pub airdrop_keypair_path: Vec<String>,
/// Watch programs in your `target/deploy` folder, and automatically re-execute the deployment runbook when the `.so` files change. (eg. surfpool start --watch)
/// Watch programs in your artifacts folder (default: `target/deploy`), and automatically re-execute the deployment runbook when the `.so` files change. (eg. surfpool start --watch)
#[clap(long = "watch", action=ArgAction::SetTrue, default_value = "false")]
pub watch: bool,
/// Override the path where .so program artifacts are loaded from (default: target/deploy). (eg. surfpool start --artifacts-path ./target/deploy/debug)
#[arg(long = "artifacts-path")]
pub artifacts_path: Option<String>,
/// List of geyser plugins to load (eg. surfpool start --geyser-plugin-config plugin1.json --geyser-plugin-config plugin2.json)
#[arg(long = "geyser-plugin-config", short = 'g')]
pub plugin_config_path: Vec<String>,
Expand Down
28 changes: 21 additions & 7 deletions crates/cli/src/cli/simnet/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -512,15 +512,22 @@ async fn write_and_execute_iac(
// If there were existing on-disk runbooks, we'll execute those instead of in-memory ones
// If there were no existing runbooks and the user requested autopilot, we'll generate and execute in-memory runbooks
// If there were no existing runbooks and the user did not request autopilot, we'll generate and execute on-disk runbooks
let do_execute_in_memory_runbooks = cmd.anchor_compat && !txtx_manifest_exists;
if !cmd.anchor_compat && txtx_manifest_exists {
// When --artifacts-path is set, always use in-memory runbooks so the custom bin_path is injected
let has_custom_artifacts_path = cmd.artifacts_path.is_some();
let do_execute_in_memory_runbooks =
has_custom_artifacts_path || (cmd.anchor_compat && !txtx_manifest_exists);
if !has_custom_artifacts_path && !cmd.anchor_compat && txtx_manifest_exists {
let runbooks_ids_to_execute = cmd.runbooks.clone();
on_disk_runbook_data = Some((txtx_manifest_location.clone(), runbooks_ids_to_execute));
};

// Are we in a project directory?
if let Ok(deployment) =
detect_program_frameworks(&cmd.manifest_path, &cmd.anchor_test_config_paths).await
if let Ok(deployment) = detect_program_frameworks(
&cmd.manifest_path,
&cmd.anchor_test_config_paths,
cmd.artifacts_path.as_deref(),
)
.await
{
if let Some(ProgramFrameworkData {
framework,
Expand Down Expand Up @@ -549,7 +556,8 @@ async fn write_and_execute_iac(
}

// Is infrastructure-as-code (IaC) already setup?
let do_write_scaffold = !cmd.anchor_compat && !txtx_manifest_exists;
let do_write_scaffold =
!has_custom_artifacts_path && !cmd.anchor_compat && !txtx_manifest_exists;
if do_write_scaffold {
// Scaffold IaC
scaffold_iac_layout(
Expand All @@ -572,6 +580,7 @@ async fn write_and_execute_iac(
&accounts,
&accounts_dir,
generate_subgraphs,
cmd.artifacts_path.as_deref(),
)?);
}
}
Expand All @@ -593,11 +602,16 @@ async fn write_and_execute_iac(
.map_err(|e| format!("Thread to execute runbooks exited: {}", e))?;

if cmd.watch {
let artifacts_path_for_watch = cmd.artifacts_path.clone();
let _handle = hiro_system_kit::thread_named("Watch Filesystem")
.spawn(move || {
let mut target_path = base_location.clone();
let _ = target_path.append_path("target");
let _ = target_path.append_path("deploy");
if let Some(ref path) = artifacts_path_for_watch {
let _ = target_path.append_path(path);
} else {
let _ = target_path.append_path("target");
let _ = target_path.append_path("deploy");
}
let (tx, rx) = mpsc::channel::<NotifyResult<Event>>();
let mut watcher = notify::recommended_watcher(tx).map_err(|e| e.to_string())?;
watcher
Expand Down
15 changes: 11 additions & 4 deletions crates/cli/src/scaffold/anchor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ fn should_generate_subgraphs(anchor_version: &Option<String>) -> bool {
pub fn try_get_programs_from_project(
base_location: FileLocation,
test_suite_paths: &[String],
artifacts_path: Option<&str>,
) -> Result<Option<ProgramFrameworkData>, String> {
let mut manifest_location = base_location.clone();
manifest_location.append_path("Anchor.toml")?;
Expand All @@ -60,10 +61,16 @@ pub fn try_get_programs_from_project(
if let Some((_, deployments)) = manifest.programs.iter().next() {
for (program_name, deployment) in deployments.iter() {
let so_exists = {
let mut so_path = target_location.clone();
so_path.append_path("deploy")?;
so_path.append_path(&format!("{}.so", program_name))?;
so_path.exists()
if let Some(artifacts) = artifacts_path {
let mut so_path = base_location.clone();
so_path.append_path(&format!("{}/{}.so", artifacts, program_name))?;
so_path.exists()
} else {
let mut so_path = target_location.clone();
so_path.append_path("deploy")?;
so_path.append_path(&format!("{}.so", program_name))?;
so_path.exists()
}
};
programs.push(ProgramMetadata::new(
program_name,
Expand Down
28 changes: 18 additions & 10 deletions crates/cli/src/scaffold/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -76,20 +76,23 @@ impl ProgramFrameworkData {
pub async fn detect_program_frameworks(
manifest_path: &str,
test_paths: &[String],
artifacts_path: Option<&str>,
) -> Result<Option<ProgramFrameworkData>, String> {
let manifest_location = FileLocation::from_path_string(manifest_path)?;
let base_dir = manifest_location.get_parent_location()?;
// Look for Anchor project layout
// Note: Poseidon projects generate Anchor.toml files, so they will also be identified here
if let Some(res) = anchor::try_get_programs_from_project(base_dir.clone(), test_paths)
.map_err(|e| format!("Invalid Anchor project: {e}"))?
if let Some(res) =
anchor::try_get_programs_from_project(base_dir.clone(), test_paths, artifacts_path)
.map_err(|e| format!("Invalid Anchor project: {e}"))?
{
return Ok(Some(res));
}

// Look for Steel project layout
if let Some((framework, programs)) = steel::try_get_programs_from_project(base_dir.clone())
.map_err(|e| format!("Invalid Steel project: {e}"))?
if let Some((framework, programs)) =
steel::try_get_programs_from_project(base_dir.clone(), artifacts_path)
.map_err(|e| format!("Invalid Steel project: {e}"))?
{
return Ok(Some(ProgramFrameworkData::partial(framework, programs)));
}
Expand All @@ -102,15 +105,17 @@ pub async fn detect_program_frameworks(
}

// Look for Pinocchio project layout
if let Some((framework, programs)) = pinocchio::try_get_programs_from_project(base_dir.clone())
.map_err(|e| format!("Invalid Pinocchio project: {e}"))?
if let Some((framework, programs)) =
pinocchio::try_get_programs_from_project(base_dir.clone(), artifacts_path)
.map_err(|e| format!("Invalid Pinocchio project: {e}"))?
{
return Ok(Some(ProgramFrameworkData::partial(framework, programs)));
}

// Look for Native project layout
if let Some((framework, programs)) = native::try_get_programs_from_project(base_dir.clone())
.map_err(|e| format!("Invalid Native project: {e}"))?
if let Some((framework, programs)) =
native::try_get_programs_from_project(base_dir.clone(), artifacts_path)
.map_err(|e| format!("Invalid Native project: {e}"))?
{
return Ok(Some(ProgramFrameworkData::partial(framework, programs)));
}
Expand Down Expand Up @@ -142,6 +147,7 @@ pub fn scaffold_in_memory_iac(
accounts: &Option<Vec<AccountEntry>>,
accounts_dir: &Option<Vec<AccountDirEntry>>,
generate_subgraphs: bool,
artifacts_path: Option<&str>,
) -> Result<(String, RunbookSources, WorkspaceManifest), String> {
let mut deployment_runbook_src: String = String::new();

Expand All @@ -157,8 +163,10 @@ pub fn scaffold_in_memory_iac(
for program_metadata in programs.iter() {
if program_metadata.so_exists {
deployment_runbook_src.push_str(
&framework
.get_in_memory_interpolated_program_deployment_template(&program_metadata.name),
&framework.get_in_memory_interpolated_program_deployment_template(
&program_metadata.name,
artifacts_path,
),
);

if generate_subgraphs {
Expand Down
2 changes: 2 additions & 0 deletions crates/cli/src/scaffold/native.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ use crate::types::Framework;
/// it is considered a native project.
pub fn try_get_programs_from_project(
base_location: FileLocation,
artifacts_path: Option<&str>,
) -> Result<Option<(Framework, Vec<ProgramMetadata>)>> {
let mut manifest_location = base_location.clone();
manifest_location
Expand All @@ -29,6 +30,7 @@ pub fn try_get_programs_from_project(
"solana-program",
&base_location,
&manifest,
artifacts_path,
)?
else {
return Ok(None);
Expand Down
9 changes: 7 additions & 2 deletions crates/cli/src/scaffold/pinocchio.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ use crate::types::Framework;
/// it is considered a native project.
pub fn try_get_programs_from_project(
base_location: FileLocation,
artifacts_path: Option<&str>,
) -> Result<Option<(Framework, Vec<ProgramMetadata>)>> {
let mut manifest_location = base_location.clone();
manifest_location
Expand All @@ -25,8 +26,12 @@ pub fn try_get_programs_from_project(
let manifest = CargoManifestFile::from_manifest_str(&manifest)
.map_err(|e| anyhow!("unable to read Cargo.toml: {}", e))?;

let Some(program_metadata) =
get_program_metadata_from_manifest_with_dep("pinocchio", &base_location, &manifest)?
let Some(program_metadata) = get_program_metadata_from_manifest_with_dep(
"pinocchio",
&base_location,
&manifest,
artifacts_path,
)?
else {
return Ok(None);
};
Expand Down
9 changes: 7 additions & 2 deletions crates/cli/src/scaffold/steel.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ use crate::types::Framework;
/// it is considered a native project.
pub fn try_get_programs_from_project(
base_location: FileLocation,
artifacts_path: Option<&str>,
) -> Result<Option<(Framework, Vec<ProgramMetadata>)>> {
let mut manifest_location = base_location.clone();
manifest_location
Expand All @@ -25,8 +26,12 @@ pub fn try_get_programs_from_project(
let manifest = CargoManifestFile::from_manifest_str(&manifest)
.map_err(|e| anyhow!("unable to read Cargo.toml: {}", e))?;

let Some(program_metadata) =
get_program_metadata_from_manifest_with_dep("steel", &base_location, &manifest)?
let Some(program_metadata) = get_program_metadata_from_manifest_with_dep(
"steel",
&base_location,
&manifest,
artifacts_path,
)?
else {
return Ok(None);
};
Expand Down
14 changes: 9 additions & 5 deletions crates/cli/src/scaffold/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ pub fn get_program_metadata_from_manifest_with_dep(
dependency_indicator: &str,
base_location: &FileLocation,
manifest: &CargoManifestFile,
artifacts_path: Option<&str>,
) -> Result<Option<ProgramMetadata>> {
let Some(manifest) =
manifest.get_manifest_with_dependency(dependency_indicator, base_location)?
Expand Down Expand Up @@ -43,12 +44,15 @@ pub fn get_program_metadata_from_manifest_with_dep(
};

let so_exists = {
let so_path_str = if let Some(artifacts) = artifacts_path {
format!("{}/{}.so", artifacts, program_name)
} else {
format!("target/deploy/{}.so", program_name)
};
let mut so_path = base_location.clone();
so_path
.append_path(&format!("target/deploy/{}.so", program_name))
.map_err(|e| {
anyhow!("failed to construct path to program .so file for existence check: {e}")
})?;
so_path.append_path(&so_path_str).map_err(|e| {
anyhow!("failed to construct path to program .so file for existence check: {e}")
})?;
so_path.exists()
};

Expand Down
19 changes: 18 additions & 1 deletion crates/cli/src/types/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,15 +28,32 @@ impl Framework {
pub fn get_in_memory_interpolated_program_deployment_template(
&self,
program_name: &str,
artifacts_path: Option<&str>,
) -> String {
match self {
let base = match self {
Framework::Anchor => {
get_in_memory_interpolated_anchor_program_deployment_template(program_name)
}
Framework::Typhoon => todo!(),
Framework::Native | Framework::Steel | Framework::Pinocchio => {
get_in_memory_interpolated_native_program_deployment_template(program_name)
}
};
if let Some(artifacts) = artifacts_path {
let get_program_fn = match self {
Framework::Anchor => "svm::get_program_from_anchor_project",
_ => "svm::get_program_from_native_project",
};
let bin_path = format!("{}/{}.so", artifacts.trim_end_matches('/'), program_name);
// Pass bin_path as the 4th argument (program_name, keypair_path, idl_path, bin_path)
let old = format!("program = {}(\"{}\") ", get_program_fn, program_name);
let new = format!(
"program = {}(\"{}\", null, null, \"{}\") ",
get_program_fn, program_name, bin_path
);
base.replace(&old, &new)
} else {
base
}
}
pub fn get_interpolated_subgraph_template(
Expand Down
Loading