Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add option for JSON formatted output #324

Merged
merged 20 commits into from
Aug 12, 2021
Merged
Show file tree
Hide file tree
Changes from 17 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 CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

### Added
- Add option for JSON formatted output - [#324](https://github.com/paritytech/cargo-contract/pull/324)

### Changed
- Use new dependency resolver for template contract - [#325](https://github.com/paritytech/cargo-contract/pull/325)

Expand Down
219 changes: 122 additions & 97 deletions src/cmd/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@ use crate::{
crate_metadata::CrateMetadata,
maybe_println, util, validate_wasm,
workspace::{Manifest, ManifestPath, Profile, Workspace},
BuildArtifacts, BuildMode, BuildResult, OptimizationPasses, OptimizationResult, UnstableFlags,
UnstableOptions, Verbosity, VerbosityFlags,
BuildArtifacts, BuildMode, BuildResult, OptimizationPasses, OptimizationResult, OutputType,
UnstableFlags, UnstableOptions, Verbosity, VerbosityFlags,
};
use anyhow::{Context, Result};
use colored::Colorize;
Expand All @@ -39,6 +39,20 @@ use structopt::StructOpt;
/// This is the maximum number of pages available for a contract to allocate.
const MAX_MEMORY_PAGES: u32 = 16;

/// Arguments to use when executing `build` or `check` commands.
#[derive(Default)]
pub(crate) struct ExecuteArgs {
/// The location of the Cargo manifest (`Cargo.toml`) file to use.
pub(crate) manifest_path: ManifestPath,
verbosity: Verbosity,
build_mode: BuildMode,
build_artifact: BuildArtifacts,
unstable_flags: UnstableFlags,
optimization_passes: OptimizationPasses,
keep_debug_symbols: bool,
output_type: OutputType,
}

/// Executes build of the smart-contract which produces a wasm binary that is ready for deploying.
///
/// It does so by invoking `cargo build` and then post processing the final binary.
Expand Down Expand Up @@ -102,14 +116,18 @@ pub struct BuildCommand {
/// This is useful if one wants to analyze or debug the optimized binary.
#[structopt(long)]
keep_debug_symbols: bool,

/// Export the build output in JSON format.
#[structopt(long, conflicts_with = "verbose")]
output_json: bool,
}

impl BuildCommand {
pub fn exec(&self) -> Result<BuildResult> {
let manifest_path = ManifestPath::try_from(self.manifest_path.as_ref())?;
let unstable_flags: UnstableFlags =
TryFrom::<&UnstableOptions>::try_from(&self.unstable_options)?;
let verbosity = TryFrom::<&VerbosityFlags>::try_from(&self.verbosity)?;
let mut verbosity = TryFrom::<&VerbosityFlags>::try_from(&self.verbosity)?;

// The CLI flag `optimization-passes` overwrites optimization passes which are
// potentially defined in the `Cargo.toml` profile.
Expand All @@ -130,15 +148,29 @@ impl BuildCommand {
true => BuildMode::Release,
false => BuildMode::Debug,
};
execute(
&manifest_path,

let output_type = match self.output_json {
true => OutputType::Json,
false => OutputType::HumanReadable,
};

// We want to ensure that the only thing in `STDOUT` is our JSON formatted string.
if matches!(output_type, OutputType::Json) {
verbosity = Verbosity::Quiet;
}

let args = ExecuteArgs {
manifest_path,
verbosity,
build_mode,
self.build_artifact,
build_artifact: self.build_artifact,
unstable_flags,
optimization_passes,
self.keep_debug_symbols,
)
keep_debug_symbols: self.keep_debug_symbols,
output_type,
};

execute(args)
}
}

Expand All @@ -160,15 +192,19 @@ impl CheckCommand {
let unstable_flags: UnstableFlags =
TryFrom::<&UnstableOptions>::try_from(&self.unstable_options)?;
let verbosity: Verbosity = TryFrom::<&VerbosityFlags>::try_from(&self.verbosity)?;
execute(
&manifest_path,

let args = ExecuteArgs {
manifest_path,
verbosity,
BuildMode::Debug,
BuildArtifacts::CheckOnly,
build_mode: BuildMode::Debug,
build_artifact: BuildArtifacts::CheckOnly,
unstable_flags,
OptimizationPasses::Zero,
false,
)
optimization_passes: OptimizationPasses::Zero,
keep_debug_symbols: false,
output_type: OutputType::default(),
};

execute(args)
}
}

Expand Down Expand Up @@ -582,18 +618,21 @@ pub fn assert_debug_mode_supported(ink_version: &Version) -> anyhow::Result<()>
/// Executes build of the smart-contract which produces a wasm binary that is ready for deploying.
///
/// It does so by invoking `cargo build` and then post processing the final binary.
pub(crate) fn execute(
manifest_path: &ManifestPath,
verbosity: Verbosity,
build_mode: BuildMode,
build_artifact: BuildArtifacts,
unstable_flags: UnstableFlags,
optimization_passes: OptimizationPasses,
keep_debug_symbols: bool,
) -> Result<BuildResult> {
let crate_metadata = CrateMetadata::collect(manifest_path)?;
pub(crate) fn execute(args: ExecuteArgs) -> Result<BuildResult> {
let ExecuteArgs {
manifest_path,
verbosity,
build_mode,
build_artifact,
unstable_flags,
optimization_passes,
keep_debug_symbols,
output_type,
} = args;

let crate_metadata = CrateMetadata::collect(&manifest_path)?;

assert_compatible_ink_dependencies(manifest_path, verbosity)?;
assert_compatible_ink_dependencies(&manifest_path, verbosity)?;
if build_mode == BuildMode::Debug {
assert_debug_mode_supported(&crate_metadata.ink_version)?;
}
Expand Down Expand Up @@ -662,6 +701,7 @@ pub(crate) fn execute(
}
};
let dest_wasm = opt_result.as_ref().map(|r| r.dest_wasm.clone());

Ok(BuildResult {
dest_wasm,
metadata_result,
Expand All @@ -670,6 +710,7 @@ pub(crate) fn execute(
build_mode,
build_artifact,
verbosity,
output_type,
})
}

Expand All @@ -684,8 +725,8 @@ mod tests_ci_only {
cmd::{build::load_module, BuildCommand},
util::tests::{with_new_contract_project, with_tmp_dir},
workspace::Manifest,
BuildArtifacts, BuildMode, ManifestPath, OptimizationPasses, UnstableFlags,
UnstableOptions, Verbosity, VerbosityFlags,
BuildArtifacts, BuildMode, ManifestPath, OptimizationPasses, UnstableOptions, Verbosity,
VerbosityFlags,
};
use semver::Version;
#[cfg(unix)]
Expand Down Expand Up @@ -740,16 +781,13 @@ mod tests_ci_only {
#[test]
fn build_code_only() {
with_new_contract_project(|manifest_path| {
let res = super::execute(
&manifest_path,
Verbosity::Default,
BuildMode::default(),
BuildArtifacts::CodeOnly,
UnstableFlags::default(),
OptimizationPasses::default(),
false,
)
.expect("build failed");
let args = crate::cmd::build::ExecuteArgs {
manifest_path,
build_artifact: BuildArtifacts::CodeOnly,
..Default::default()
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice 👍!

};

let res = super::execute(args).expect("build failed");

// our ci has set `CARGO_TARGET_DIR` to cache artifacts.
// this dir does not include `/target/` as a path, hence
Expand Down Expand Up @@ -783,18 +821,14 @@ mod tests_ci_only {
with_new_contract_project(|manifest_path| {
// given
let project_dir = manifest_path.directory().expect("directory must exist");
let args = crate::cmd::build::ExecuteArgs {
manifest_path: manifest_path.clone(),
build_artifact: BuildArtifacts::CheckOnly,
..Default::default()
};

// when
super::execute(
&manifest_path,
Verbosity::Default,
BuildMode::default(),
BuildArtifacts::CheckOnly,
UnstableFlags::default(),
OptimizationPasses::default(),
false,
)
.expect("build failed");
super::execute(args).expect("build failed");

// then
assert!(
Expand Down Expand Up @@ -827,6 +861,7 @@ mod tests_ci_only {
// we choose zero optimization passes as the "cli" parameter
optimization_passes: Some(OptimizationPasses::Zero),
keep_debug_symbols: false,
output_json: false,
};

// when
Expand Down Expand Up @@ -866,6 +901,7 @@ mod tests_ci_only {
// we choose no optimization passes as the "cli" parameter
optimization_passes: None,
keep_debug_symbols: false,
output_json: false,
};

// when
Expand Down Expand Up @@ -1030,6 +1066,7 @@ mod tests_ci_only {
unstable_options: UnstableOptions::default(),
optimization_passes: None,
keep_debug_symbols: false,
output_json: false,
};
let res = cmd.exec().expect("build failed");

Expand Down Expand Up @@ -1072,18 +1109,14 @@ mod tests_ci_only {
fn building_template_in_debug_mode_must_work() {
with_new_contract_project(|manifest_path| {
// given
let build_mode = BuildMode::Debug;
let args = crate::cmd::build::ExecuteArgs {
manifest_path,
build_mode: BuildMode::Debug,
..Default::default()
};

// when
let res = super::execute(
&manifest_path,
Verbosity::Default,
build_mode,
BuildArtifacts::All,
UnstableFlags::default(),
OptimizationPasses::default(),
Default::default(),
);
let res = super::execute(args);

// then
assert!(res.is_ok(), "building template in debug mode failed!");
Expand All @@ -1095,18 +1128,14 @@ mod tests_ci_only {
fn building_template_in_release_mode_must_work() {
with_new_contract_project(|manifest_path| {
// given
let build_mode = BuildMode::Release;
let args = crate::cmd::build::ExecuteArgs {
manifest_path,
build_mode: BuildMode::Release,
..Default::default()
};

// when
let res = super::execute(
&manifest_path,
Verbosity::Default,
build_mode,
BuildArtifacts::All,
UnstableFlags::default(),
OptimizationPasses::default(),
Default::default(),
);
let res = super::execute(args);

// then
assert!(res.is_ok(), "building template in release mode failed!");
Expand All @@ -1132,16 +1161,14 @@ mod tests_ci_only {
.expect("setting lib path must work");
manifest.write(&manifest_path).expect("writing must work");

let args = crate::cmd::build::ExecuteArgs {
manifest_path,
build_artifact: BuildArtifacts::CheckOnly,
..Default::default()
};

// when
let res = super::execute(
&manifest_path,
Verbosity::Default,
BuildMode::default(),
BuildArtifacts::CheckOnly,
UnstableFlags::default(),
OptimizationPasses::default(),
Default::default(),
);
let res = super::execute(args);

// then
assert!(res.is_ok(), "building contract failed!");
Expand All @@ -1152,16 +1179,15 @@ mod tests_ci_only {
#[test]
fn keep_debug_symbols_in_debug_mode() {
with_new_contract_project(|manifest_path| {
let res = super::execute(
&manifest_path,
Verbosity::Default,
BuildMode::Debug,
BuildArtifacts::CodeOnly,
UnstableFlags::default(),
OptimizationPasses::default(),
true,
)
.expect("build failed");
let args = crate::cmd::build::ExecuteArgs {
manifest_path,
build_mode: BuildMode::Debug,
build_artifact: BuildArtifacts::CodeOnly,
keep_debug_symbols: true,
..Default::default()
};

let res = super::execute(args).expect("build failed");

// we specified that debug symbols should be kept
assert!(has_debug_symbols(&res.dest_wasm.unwrap()));
Expand All @@ -1173,16 +1199,15 @@ mod tests_ci_only {
#[test]
fn keep_debug_symbols_in_release_mode() {
with_new_contract_project(|manifest_path| {
let res = super::execute(
&manifest_path,
Verbosity::Default,
BuildMode::Release,
BuildArtifacts::CodeOnly,
UnstableFlags::default(),
OptimizationPasses::default(),
true,
)
.expect("build failed");
let args = crate::cmd::build::ExecuteArgs {
manifest_path,
build_mode: BuildMode::Release,
build_artifact: BuildArtifacts::CodeOnly,
keep_debug_symbols: true,
..Default::default()
};

let res = super::execute(args).expect("build failed");

// we specified that debug symbols should be kept
assert!(has_debug_symbols(&res.dest_wasm.unwrap()));
Expand Down
Loading