Commit fe093478 authored by Andrew Jones's avatar Andrew Jones Committed by Hero Bird

[cli] add generate-abi command (#209)

* [cli] add flag to `build` command to generate abi

* [cli] fix abi console output

* [cli] restore +nightly

* [cli] separate generate-abi command

* [cli] move nightly check to exec_cargo fn

* [cli] add test for generate_abi
parent c7411dac
Pipeline #56402 failed with stages
in 21 seconds
// Copyright 2018-2019 Parity Technologies (UK) Ltd.
// This file is part of ink!.
//
// ink! is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// ink! is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with ink!. If not, see <http://www.gnu.org/licenses/>.
use crate::cmd::{
Result,
};
use cargo_metadata::MetadataCommand;
use std::path::PathBuf;
/// Executes build of the smart-contract which produces a wasm binary that is ready for deploying.
///
/// It does so by invoking build by cargo and then post processing the final binary.
pub(crate) fn execute_generate_abi(dir: Option<&PathBuf>) -> Result<String> {
println!(" Generating abi");
super::exec_cargo("run", &[
"--package",
"abi-gen",
"--verbose",
], dir)?;
let metadata = MetadataCommand::new().exec()?;
let mut abi_path = metadata.target_directory.clone();
abi_path.push("abi.json");
Ok(format!(
"Your abi file is ready.\nYou can find it here:\n{}",
abi_path.display()
))
}
#[cfg(test)]
mod tests {
use crate::{
cmd::{
execute_new,
execute_generate_abi,
tests::with_tmp_dir,
},
AbstractionLayer,
};
#[test]
fn generate_abi() {
with_tmp_dir(|path| {
execute_new(AbstractionLayer::Lang, "new_project", Some(path))
.expect("new project creation failed");
let working_dir = path.join("new_project");
super::execute_generate_abi(Some(&working_dir)).expect("generate abi failed");
let mut abi_file = working_dir.clone();
abi_file.push("target");
abi_file.push("abi.json");
assert!(abi_file.exists())
});
}
}
...@@ -25,14 +25,7 @@ use parity_wasm::elements::{ ...@@ -25,14 +25,7 @@ use parity_wasm::elements::{
Module, Module,
Section, Section,
}; };
use std::{ use std::path::PathBuf;
io::{
self,
Write,
},
path::PathBuf,
process::Command,
};
/// This is the maximum number of pages available for a contract to allocate. /// This is the maximum number of pages available for a contract to allocate.
const MAX_MEMORY_PAGES: u32 = 16; const MAX_MEMORY_PAGES: u32 = 16;
...@@ -96,43 +89,12 @@ pub fn collect_crate_metadata(working_dir: Option<&PathBuf>) -> Result<CrateMeta ...@@ -96,43 +89,12 @@ pub fn collect_crate_metadata(working_dir: Option<&PathBuf>) -> Result<CrateMeta
/// ///
/// Currently it assumes that user wants to use `+nightly`. /// Currently it assumes that user wants to use `+nightly`.
fn build_cargo_project(working_dir: Option<&PathBuf>) -> Result<()> { fn build_cargo_project(working_dir: Option<&PathBuf>) -> Result<()> {
let mut cmd = Command::new("cargo"); super::exec_cargo("build", &[
let mut is_nightly_cmd = Command::new("cargo"); "--no-default-features",
if let Some(dir) = working_dir { "--release",
cmd.current_dir(dir); "--target=wasm32-unknown-unknown",
is_nightly_cmd.current_dir(dir); "--verbose",
} ], working_dir)
let is_nightly_default = is_nightly_cmd
.arg("--version")
.output()
.map_err(|_| ())
.and_then(|o| String::from_utf8(o.stdout).map_err(|_| ()))
.unwrap_or_default()
.contains("-nightly");
if !is_nightly_default {
cmd.arg("+nightly");
}
let output = cmd
.args(&[
"build",
"--no-default-features",
"--release",
"--target=wasm32-unknown-unknown",
"--verbose",
])
.output()?;
if !output.status.success() {
// Dump the output streams produced by cargo into the stdout/stderr.
io::stdout().write_all(&output.stdout)?;
io::stderr().write_all(&output.stderr)?;
return Err(Error::BuildFailed)
}
Ok(())
} }
/// Ensures the wasm memory import of a given module has the maximum number of pages. /// Ensures the wasm memory import of a given module has the maximum number of pages.
......
...@@ -14,12 +14,23 @@ ...@@ -14,12 +14,23 @@
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with ink!. If not, see <http://www.gnu.org/licenses/>. // along with ink!. If not, see <http://www.gnu.org/licenses/>.
use std::{
io::{
self,
Write,
},
path::PathBuf,
process::Command,
};
mod abi;
mod build; mod build;
mod deploy; mod deploy;
mod error; mod error;
mod new; mod new;
pub(crate) use self::{ pub(crate) use self::{
abi::execute_generate_abi,
build::execute_build, build::execute_build,
deploy::execute_deploy, deploy::execute_deploy,
error::{ error::{
...@@ -29,6 +40,41 @@ pub(crate) use self::{ ...@@ -29,6 +40,41 @@ pub(crate) use self::{
new::execute_new, new::execute_new,
}; };
fn exec_cargo(command: &str, args: &[&'static str], working_dir: Option<&PathBuf>) -> Result<()> {
let mut cmd = Command::new("cargo");
let mut is_nightly_cmd = Command::new("cargo");
if let Some(dir) = working_dir {
cmd.current_dir(dir);
is_nightly_cmd.current_dir(dir);
}
let is_nightly_default = is_nightly_cmd
.arg("--version")
.output()
.map_err(|_| ())
.and_then(|o| String::from_utf8(o.stdout).map_err(|_| ()))
.unwrap_or_default()
.contains("-nightly");
if !is_nightly_default {
cmd.arg("+nightly");
}
let output = cmd
.arg(command)
.args(args)
.output()?;
if !output.status.success() {
// Dump the output streams produced by cargo into the stdout/stderr.
io::stdout().write_all(&output.stdout)?;
io::stderr().write_all(&output.stderr)?;
return Err(error::CommandError::BuildFailed)
}
Ok(())
}
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use std::path::PathBuf; use std::path::PathBuf;
......
...@@ -94,6 +94,9 @@ enum Command { ...@@ -94,6 +94,9 @@ enum Command {
/// Builds the smart contract. /// Builds the smart contract.
#[structopt(name = "build")] #[structopt(name = "build")]
Build {}, Build {},
/// Generate abi artifacts
#[structopt(name = "generate-abi")]
GenerateAbi {},
/// Test the smart contract off-chain. /// Test the smart contract off-chain.
#[structopt(name = "test")] #[structopt(name = "test")]
Test {}, Test {},
...@@ -142,6 +145,7 @@ fn exec(cmd: Command) -> cmd::Result<String> { ...@@ -142,6 +145,7 @@ fn exec(cmd: Command) -> cmd::Result<String> {
target_dir, target_dir,
} => cmd::execute_new(*layer, name, target_dir.as_ref()), } => cmd::execute_new(*layer, name, target_dir.as_ref()),
Command::Build {} => cmd::execute_build(None), Command::Build {} => cmd::execute_build(None),
Command::GenerateAbi {} => cmd::execute_generate_abi(None),
Command::Test {} => Err(CommandError::UnimplementedCommand), Command::Test {} => Err(CommandError::UnimplementedCommand),
Command::Deploy { Command::Deploy {
url, url,
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment