Skip to content
Draft
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
146 changes: 97 additions & 49 deletions components/clarinet-sdk-wasm/src/core.rs
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ macro_rules! log {
}

struct DeploymentArtifacts {
artifacts: DeploymentGenerationArtifacts,
artifacts: Option<DeploymentGenerationArtifacts>,
deployment: DeploymentSpecification,
manifest: ProjectManifest,
}
Expand Down Expand Up @@ -373,7 +373,12 @@ impl SDK {
}

#[wasm_bindgen(js_name=initSession)]
pub async fn init_session(&mut self, cwd: &str, manifest_path: &str) -> Result<(), String> {
pub async fn init_session(
&mut self,
cwd: &str,
manifest_path: &str,
force_on_disk: bool,
) -> Result<(), String> {
let cwd_path = PathBuf::from(cwd);
let cwd_root = FileLocation::FileSystem { path: cwd_path };
let manifest_location = FileLocation::try_parse(manifest_path, Some(&cwd_root))
Expand All @@ -386,7 +391,10 @@ impl SDK {
accounts,
} = match self.cache.get(&manifest_location) {
Some(cache) => cache.clone(),
None => self.setup_session(cwd, manifest_path).await?,
None => {
self.setup_session(cwd, manifest_path, force_on_disk)
.await?
}
};

self.deployer = session.interpreter.get_tx_sender().to_string();
Expand All @@ -408,13 +416,14 @@ impl SDK {
&mut self,
cwd: &str,
manifest_path: &str,
force_on_disk: bool,
) -> Result<ProjectCache, String> {
let DeploymentArtifacts {
deployment,
manifest,
artifacts,
} = self
.generate_deployment_plan_internal(cwd, manifest_path)
.get_deployment_plan(cwd, manifest_path, force_on_disk)
.await?;

let mut session = initiate_session_from_manifest(&manifest);
Expand All @@ -425,7 +434,7 @@ impl SDK {
let executed_contracts = update_session_with_deployment_plan(
&mut session,
&deployment,
Some(&artifacts.asts),
artifacts.map(|a| a.asts).as_ref(),
Some(DEFAULT_EPOCH),
);

Expand Down Expand Up @@ -484,28 +493,83 @@ impl SDK {
Ok(cache)
}

async fn generate_deployment_plan_internal(
async fn get_existing_deployment_plan(
&self,
project_root: &FileLocation,
deployment_plan_location: &FileLocation,
) -> Result<Option<(String, DeploymentSpecification)>, String> {
let deployment_plan_path = deployment_plan_location.to_string();

if !self
.file_accessor
.file_exists(deployment_plan_path.clone())
.await?
{
return Ok(None);
}

let deployment_file = self.file_accessor.read_file(deployment_plan_path).await?;
let spec_file = DeploymentSpecificationFile::from_file_content(&deployment_file)?;
let deployment = DeploymentSpecification::from_specifications(
&spec_file,
&StacksNetwork::Simnet,
project_root,
None,
)?;

Ok(Some((deployment_file, deployment)))
}

async fn get_deployment_plan(
&self,
cwd: &str,
manifest_path: &str,
force_on_disk: bool,
) -> Result<DeploymentArtifacts, String> {
let cwd_path = PathBuf::from(cwd);
let cwd_root = FileLocation::FileSystem { path: cwd_path };
let cwd_root = FileLocation::FileSystem {
path: PathBuf::from(cwd),
};
let manifest_location = FileLocation::try_parse(manifest_path, Some(&cwd_root))
.ok_or("Failed to parse manifest location")?;
let manifest =
ProjectManifest::from_file_accessor(&manifest_location, true, &*self.file_accessor)
.await?;
.ok_or_else(|| format!("Failed to parse manifest location: {manifest_path}"))?;
let manifest = ProjectManifest::from_file_accessor(
&manifest_location,
true,
self.file_accessor.as_ref(),
)
.await?;
let project_root = manifest_location.get_parent_location()?;
let deployment_plan_location =
FileLocation::try_parse("deployments/default.simnet-plan.yaml", Some(&project_root))
.ok_or("Failed to parse default deployment location")?;
.ok_or_else(|| {
format!("Failed to parse deployment location relative to {project_root:?}")
})?;

// Read existing deployment plan once
let existing_deployment = self
.get_existing_deployment_plan(&project_root, &deployment_plan_location)
.await?;

// Early return if we only need the on-disk deployment plan
if force_on_disk {
let deployment = existing_deployment
.map(|(_, deployment)| deployment)
.ok_or_else(|| {
format!("Deployment plan not found at {deployment_plan_location}")
})?;

return Ok(DeploymentArtifacts {
artifacts: None,
deployment,
manifest,
});
}

// Generate a new deployment plan
let (mut deployment, artifacts) = generate_default_deployment(
&manifest,
&StacksNetwork::Simnet,
false,
Some(&*self.file_accessor),
Some(self.file_accessor.as_ref()),
Some(StacksEpochId::Epoch21),
)
.await?;
Expand All @@ -516,51 +580,36 @@ impl SDK {
return Err(diags_digest.message);
}
}
let project_root = manifest.location.get_parent_location()?;

if self
.file_accessor
.file_exists(deployment_plan_location.to_string())
.await?
// Merge with existing deployment plan if it exists
let original_deployment_file = if let Some((deployment_file, existing_deployment)) =
existing_deployment
{
let spec_file_content = self
.file_accessor
.read_file(deployment_plan_location.to_string())
.await?;

let mut spec_file = DeploymentSpecificationFile::from_file_content(&spec_file_content)?;
let mut spec_file = DeploymentSpecificationFile::from_file_content(&deployment_file)?;

// the contract publish txs are managed by the manifest
// keep the user added txs and merge them with the default deployment plan
// The contract publish txs are managed by the manifest
// Keep only the user-added txs and merge them with the default deployment plan
if let Some(ref mut plan) = spec_file.plan {
for batch in plan.batches.iter_mut() {
batch.remove_publish_transactions()
}
}

let existing_deployment = DeploymentSpecification::from_specifications(
&spec_file,
&StacksNetwork::Simnet,
&project_root,
None,
)?;

deployment.merge_batches(existing_deployment.plan.batches);

self.write_deployment_plan(
&deployment,
&project_root,
&deployment_plan_location,
Some(&spec_file_content),
)
.await?;
Some(deployment_file)
} else {
self.write_deployment_plan(&deployment, &project_root, &deployment_plan_location, None)
.await?;
}
None
};

self.write_deployment_plan(
&deployment,
&project_root,
&deployment_plan_location,
original_deployment_file.as_deref(),
)
.await?;

Ok(DeploymentArtifacts {
artifacts,
artifacts: Some(artifacts),
deployment,
manifest,
})
Expand All @@ -572,8 +621,7 @@ impl SDK {
cwd: &str,
manifest_path: &str,
) -> Result<(), String> {
self.generate_deployment_plan_internal(cwd, manifest_path)
.await?;
self.get_deployment_plan(cwd, manifest_path, false).await?;
Ok(())
}

Expand Down
18 changes: 8 additions & 10 deletions components/clarinet-sdk/node/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,13 @@ BigInt.prototype.toJSON = function () {
};

type Options = {
trackCosts: boolean;
trackCoverage: boolean;
// sdk options
trackCosts?: boolean;
trackCoverage?: boolean;
trackPerformance?: boolean;
// session options
/** Use the existing deployment plan without updating it */
forceOnDisk?: boolean;
};

export async function getSDK(options?: Options): Promise<Simnet> {
Expand Down Expand Up @@ -58,19 +62,13 @@ function memoizedInit() {
return async (
manifestPath = "./Clarinet.toml",
noCache = false,
options?: {
trackCosts: boolean;
trackCoverage: boolean;
trackPerformance?: boolean;
performanceCostField?: string;
},
options?: Options
) => {
if (noCache || !simnet) {
simnet = await getSDK(options);
}

// start a new simnet session
await simnet.initSession(process.cwd(), manifestPath);
await simnet.initSession(process.cwd(), manifestPath, !!options?.forceOnDisk);
return simnet;
};
}
Expand Down
14 changes: 13 additions & 1 deletion components/clarinet-sdk/node/tests/deployment-plan.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,9 +40,21 @@ describe("generate deployment plans test", async () => {
expect(success).toBe(true);
expect(fs.existsSync(deploymentPlanPath)).toBe(true);
})

it.only("can start a session without the existing deployment plan", async () => {
const success = await generateDeployement("tests/fixtures/Clarinet.toml");
expect(success).toBe(true);

const deployment = fs.readFileSync(deploymentPlanPath);
console.log(deployment);

const simnet = await initSimnet("tests/fixtures/Clarinet.toml", true, { forceOnDisk: true });
// make sure the simnet is running
expect(simnet.blockHeight).toBe(3);
})
});

describe("initSiment deployment plans test", async () => {
describe.skip("initSiment deployment plans test", async () => {

it("simnet deployment plan is created if it does not exist", async () => {
expect(fs.existsSync(deploymentPlanPath)).toBe(false);
Expand Down
Loading