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
3 changes: 3 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ icp-canister-interfaces = { path = "crates/icp-canister-interfaces" }
icp-sync-plugin = { path = "crates/icp-sync-plugin" }
ic-identity-hsm = "0.47.0"
icrc-ledger-types = "0.1.10"
indexmap = { version = "2", features = ["serde"] }
indicatif = "0.18.0"
indoc = "2.0.6"
itertools = "0.14.0"
Expand Down
2 changes: 2 additions & 0 deletions crates/icp-cli/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ base64.workspace = true
bigdecimal.workspace = true
bip32.workspace = true
byte-unit.workspace = true
camino.workspace = true
camino-tempfile.workspace = true
candid_parser = { workspace = true, features = ["assist"] }
candid.workspace = true
Expand All @@ -32,6 +33,7 @@ dunce.workspace = true
elliptic-curve.workspace = true
flate2.workspace = true
futures.workspace = true
tar.workspace = true
hex.workspace = true
httptest.workspace = true
ic-agent.workspace = true
Expand Down
47 changes: 44 additions & 3 deletions crates/icp-cli/src/commands/deploy.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use anyhow::anyhow;
use candid::{CandidType, Principal};
use candid::{CandidType, IDLArgs, Principal};
use clap::Args;
use futures::{StreamExt, future::try_join_all, stream::FuturesOrdered};
use ic_agent::Agent;
Expand All @@ -11,7 +11,8 @@ use icp::{
};
use icp_canister_interfaces::candid_ui::MAINNET_CANDID_UI_CID;
use serde::Serialize;
use std::collections::BTreeMap;
use std::collections::{BTreeMap, HashMap};
use std::sync::Arc;
use tracing::info;

use crate::{
Expand All @@ -21,6 +22,7 @@ use crate::{
build::build_many_with_progress_bar,
candid_compat::check_candid_compatibility_many,
create::{CreateOperation, CreateTarget},
customize,
install::{install_many, resolve_install_mode_and_status},
settings::sync_settings_many,
sync::sync_many,
Expand Down Expand Up @@ -119,6 +121,38 @@ pub(crate) async fn exec(ctx: &Context, args: &DeployArgs) -> Result<(), anyhow:
)
.await?;

// Collect interactive init arg customizations before the build so the user
// fills in all prompts upfront, uninterrupted by build output.
let customize_overrides: Arc<HashMap<String, IDLArgs>> = {
let project = ctx.project.load().await.map_err(|e| anyhow!(e))?;
let customize_path = project.dir.join(customize::CUSTOMIZE_FILE);
match customize::load_customize_manifest(&project.dir).map_err(|e| anyhow!(e))? {
None => Arc::new(HashMap::new()),
Some(manifest) => {
Comment on lines +124 to +131
let init_args: HashMap<String, Option<icp::InitArgs>> = cnames
.iter()
.map(|name| {
let ia = env
.get_canister_info(name)
.ok()
.and_then(|(_, info)| info.init_args.clone());
(name.clone(), ia)
})
.collect();
Arc::new(
customize::prompt_customizations(
&manifest,
&cnames,
&init_args,
args.yes,
&customize_path,
)
.map_err(|e| anyhow!(e))?,
)
}
}
};

// Build the selected canisters
info!("Building canisters:");

Expand Down Expand Up @@ -263,6 +297,7 @@ pub(crate) async fn exec(ctx: &Context, args: &DeployArgs) -> Result<(), anyhow:
let canisters = try_join_all(cnames.iter().map(|name| {
let environment_selection = environment_selection.clone();
let agent = agent.clone();
let co = customize_overrides.clone();
async move {
let cid = ctx
.get_canister_id_for_env(
Expand All @@ -279,9 +314,15 @@ pub(crate) async fn exec(ctx: &Context, args: &DeployArgs) -> Result<(), anyhow:
let (_canister_path, canister_info) =
env.get_canister_info(name).map_err(|e| anyhow!(e))?;

// CLI --args/--args-file take priority over manifest init_args
// Priority: CLI --args/--args-file > icp_customize.yaml prompts > manifest init_args
let init_args_bytes = if args.args_opt.is_some() {
args.args_opt.resolve_bytes()?
} else if let Some(customized) = co.get(name) {
Some(
customized
.to_bytes()
.map_err(|e| anyhow!("failed to serialize customized init args: {e}"))?,
)
} else {
canister_info
.init_args
Expand Down
41 changes: 41 additions & 0 deletions crates/icp-cli/src/commands/project/bundle.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
use anyhow::Context as _;
use clap::Args;
use icp::context::Context;
use icp::prelude::*;

use crate::operations::bundle::create_bundle;

/// Bundle a project into a self-contained deployable archive.
///
/// Builds all project canisters and packages them with a rewritten manifest
/// into a `.tar.gz` file. The rewritten manifest replaces all build steps
/// with pre-built steps referencing the bundled WASM files. Asset sync
/// directories are included in the archive.
///
/// Projects with script sync steps cannot be bundled.
#[derive(Args, Debug)]
pub(crate) struct BundleArgs {
/// Output path for the bundle archive (e.g. bundle.tar.gz)
#[arg(long, short)]
pub(crate) output: PathBuf,
}

pub(crate) async fn exec(ctx: &Context, args: &BundleArgs) -> Result<(), anyhow::Error> {
let project = ctx.project.load().await.context("failed to load project")?;

let canisters: Vec<_> = project.canisters.into_values().collect();

create_bundle(
&project.dir,
canisters,
ctx.builder.clone(),
ctx.artifacts.clone(),
&ctx.dirs.package_cache()?,
ctx.debug,
&args.output,
)
.await
.context("failed to create bundle")?;

Ok(())
}
5 changes: 4 additions & 1 deletion crates/icp-cli/src/commands/project/mod.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
use clap::Subcommand;

pub(crate) mod bundle;
pub(crate) mod show;

/// Display information about the current project
/// Manage the current project
#[derive(Debug, Subcommand)]
pub(crate) enum Command {
Show(show::ShowArgs),
#[command(hide = true)]
Bundle(bundle::BundleArgs),
}
3 changes: 3 additions & 0 deletions crates/icp-cli/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -406,6 +406,9 @@ async fn dispatch(ctx: &icp::context::Context, command: Command) -> Result<(), E
commands::project::Command::Show(args) => {
commands::project::show::exec(ctx, &args).await?
}
commands::project::Command::Bundle(args) => {
commands::project::bundle::exec(ctx, &args).await?
}
},

// Settings
Expand Down
Loading
Loading