Skip to content

Commit

Permalink
Merge pull request #354 from r0gue-io/daan/feat-production_build
Browse files Browse the repository at this point in the history
feat: production build
  • Loading branch information
Daanvdplas authored Dec 4, 2024
2 parents d84487c + d80f9e7 commit 6ba8d0f
Show file tree
Hide file tree
Showing 10 changed files with 472 additions and 188 deletions.
10 changes: 10 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 @@ -36,6 +36,7 @@ tar = "0.4.40"
tempfile = "3.10"
thiserror = "1.0.58"
tokio-test = "0.4.4"
toml = "0.5.0"

# networking
reqwest = { version = "0.12", features = ["json"] }
Expand Down
80 changes: 49 additions & 31 deletions crates/pop-cli/src/commands/build/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ use clap::{Args, Subcommand};
#[cfg(feature = "contract")]
use contract::BuildContractCommand;
use duct::cmd;
use pop_common::Profile;
use std::path::PathBuf;
#[cfg(feature = "parachain")]
use {parachain::BuildParachainCommand, spec::BuildSpecCommand};
Expand All @@ -29,8 +30,11 @@ pub(crate) struct BuildArgs {
#[arg(short = 'p', long)]
pub(crate) package: Option<String>,
/// For production, always build in release mode to exclude debug features.
#[clap(short, long)]
#[clap(short, long, conflicts_with = "profile")]
pub(crate) release: bool,
/// Build profile [default: debug].
#[clap(long, value_enum)]
pub(crate) profile: Option<Profile>,
/// Parachain ID to be used when generating the chain spec files.
#[arg(short = 'i', long = "id")]
#[cfg(feature = "parachain")]
Expand Down Expand Up @@ -62,19 +66,26 @@ impl Command {
#[cfg(feature = "contract")]
if pop_contracts::is_supported(args.path.as_deref())? {
// All commands originating from root command are valid
BuildContractCommand { path: args.path, release: args.release, valid: true }
.execute()?;
let release = match args.profile {
Some(profile) => profile.into(),
None => args.release,
};
BuildContractCommand { path: args.path, release, valid: true }.execute()?;
return Ok("contract");
}

// If only parachain feature enabled, build as parachain
#[cfg(feature = "parachain")]
if pop_parachains::is_supported(args.path.as_deref())? {
let profile = match args.profile {
Some(profile) => profile,
None => args.release.into(),
};
// All commands originating from root command are valid
BuildParachainCommand {
path: args.path,
package: args.package,
release: args.release,
profile: Some(profile),
id: args.id,
valid: true,
}
Expand All @@ -101,13 +112,15 @@ impl Command {
_args.push("--package");
_args.push(package)
}
if args.release {
let profile = args.profile.unwrap_or(Profile::Debug);
if profile == Profile::Release {
_args.push("--release");
} else if profile == Profile::Production {
_args.push("--profile=production");
}
cmd("cargo", _args).dir(args.path.unwrap_or_else(|| "./".into())).run()?;

let mode = if args.release { "RELEASE" } else { "DEBUG" };
cli.info(format!("The {project} was built in {mode} mode."))?;
cli.info(format!("The {project} was built in {} mode.", profile))?;
cli.outro("Build completed successfully!")?;
Ok(project)
}
Expand All @@ -117,41 +130,46 @@ impl Command {
mod tests {
use super::*;
use cli::MockCli;
use pop_common::manifest::add_production_profile;
use strum::VariantArray;

#[test]
fn build_works() -> anyhow::Result<()> {
let name = "hello_world";
let temp_dir = tempfile::tempdir()?;
let path = temp_dir.path();
let project_path = path.join(name);
cmd("cargo", ["new", name, "--bin"]).dir(&path).run()?;
add_production_profile(&project_path)?;

for package in [None, Some(name.to_string())] {
for release in [false, true] {
let project = if package.is_some() { "package" } else { "project" };
let mode = if release { "RELEASE" } else { "DEBUG" };
let mut cli = MockCli::new()
.expect_intro(format!("Building your {project}"))
.expect_info(format!("The {project} was built in {mode} mode."))
.expect_outro("Build completed successfully!");

assert_eq!(
Command::build(
BuildArgs {
command: None,
path: Some(path.join(name)),
package: package.clone(),
release,
id: None,
},
&mut cli,
)?,
project
);

cli.verify()?;
for release in [true, false] {
for profile in Profile::VARIANTS {
let profile = if release { Profile::Release } else { profile.clone() };
let project = if package.is_some() { "package" } else { "project" };
let mut cli = MockCli::new()
.expect_intro(format!("Building your {project}"))
.expect_info(format!("The {project} was built in {profile} mode."))
.expect_outro("Build completed successfully!");

assert_eq!(
Command::build(
BuildArgs {
command: None,
path: Some(project_path.clone()),
package: package.clone(),
release,
profile: Some(profile.clone()),
id: None,
},
&mut cli,
)?,
project
);
cli.verify()?;
}
}
}

Ok(())
}
}
31 changes: 17 additions & 14 deletions crates/pop-cli/src/commands/build/parachain.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,9 @@ pub struct BuildParachainCommand {
/// The package to be built.
#[arg(short = 'p', long)]
pub(crate) package: Option<String>,
/// For production, always build in release mode to exclude debug features.
#[clap(short, long, default_value = "true")]
pub(crate) release: bool,
/// Build profile [default: debug].
#[clap(long, value_enum)]
pub(crate) profile: Option<Profile>,
/// Parachain ID to be used when generating the chain spec files.
#[arg(short = 'i', long = "id")]
pub(crate) id: Option<u32>,
Expand All @@ -41,12 +41,13 @@ impl BuildParachainCommand {
let project = if self.package.is_some() { "package" } else { "parachain" };
cli.intro(format!("Building your {project}"))?;

let profile = self.profile.unwrap_or(Profile::Debug);
// Show warning if specified as deprecated.
if !self.valid {
cli.warning("NOTE: this command is deprecated. Please use `pop build` (or simply `pop b`) in future...")?;
#[cfg(not(test))]
sleep(Duration::from_secs(3))
} else if !self.release {
} else if profile == Profile::Debug {
cli.warning("NOTE: this command now defaults to DEBUG builds. Please use `--release` (or simply `-r`) for a release build...")?;
#[cfg(not(test))]
sleep(Duration::from_secs(3))
Expand All @@ -55,9 +56,8 @@ impl BuildParachainCommand {
// Build parachain.
cli.warning("NOTE: this may take some time...")?;
let project_path = self.path.unwrap_or_else(|| PathBuf::from("./"));
let mode: Profile = self.release.into();
let binary = build_parachain(&project_path, self.package, &mode, None)?;
cli.info(format!("The {project} was built in {mode} mode."))?;
let binary = build_parachain(&project_path, self.package, &profile, None)?;
cli.info(format!("The {project} was built in {} mode.", profile))?;
cli.outro("Build completed successfully!")?;
let generated_files = [format!("Binary generated at: {}", binary.display())];
let generated_files: Vec<_> = generated_files
Expand All @@ -79,7 +79,9 @@ mod tests {
use super::*;
use cli::MockCli;
use duct::cmd;
use pop_common::manifest::add_production_profile;
use std::{fs, io::Write, path::Path};
use strum::VariantArray;

// Function that generates a Cargo.toml inside node directory for testing.
fn generate_mock_node(temp_dir: &Path) -> anyhow::Result<()> {
Expand All @@ -106,33 +108,34 @@ mod tests {
let name = "hello_world";
let temp_dir = tempfile::tempdir()?;
let path = temp_dir.path();
let project_path = path.join(name);
cmd("cargo", ["new", name, "--bin"]).dir(&path).run()?;
generate_mock_node(&temp_dir.path().join(name))?;
add_production_profile(&project_path)?;
generate_mock_node(&project_path)?;

for package in [None, Some(name.to_string())] {
for release in [false, true] {
for profile in Profile::VARIANTS {
for valid in [false, true] {
let project = if package.is_some() { "package" } else { "parachain" };
let mode = if release { Profile::Release } else { Profile::Debug };
let mut cli = MockCli::new()
.expect_intro(format!("Building your {project}"))
.expect_warning("NOTE: this may take some time...")
.expect_info(format!("The {project} was built in {mode} mode."))
.expect_info(format!("The {project} was built in {profile} mode."))
.expect_outro("Build completed successfully!");

if !valid {
cli = cli.expect_warning("NOTE: this command is deprecated. Please use `pop build` (or simply `pop b`) in future...");
} else {
if !release {
if profile == &Profile::Debug {
cli = cli.expect_warning("NOTE: this command now defaults to DEBUG builds. Please use `--release` (or simply `-r`) for a release build...");
}
}

assert_eq!(
BuildParachainCommand {
path: Some(path.join(name)),
path: Some(project_path.clone()),
package: package.clone(),
release,
profile: Some(profile.clone()),
id: None,
valid,
}
Expand Down
Loading

0 comments on commit 6ba8d0f

Please sign in to comment.