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

Autogenerate abi/metadata package #58

Merged
merged 30 commits into from
Jun 24, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
4d4c549
Use into for constructing toml values
ascjones Jun 16, 2020
f625084
Promote workspace mod to directory
ascjones Jun 17, 2020
db6a487
Fix import warnings
ascjones Jun 17, 2020
47b3d36
Update license headers
ascjones Jun 17, 2020
fc6b021
Remove abi package from template, generate it instead
ascjones Jun 18, 2020
db3b9f3
Extract contract name and generate files
ascjones Jun 18, 2020
44f6426
Fix some errors
ascjones Jun 18, 2020
ab055ee
Insert ink_lang dependency
ascjones Jun 18, 2020
f91220e
Fmt
ascjones Jun 18, 2020
cbb8f6a
Merge branch 'master' into aj-abi
ascjones Jun 19, 2020
3b0368a
ink! v2 compatibility
ascjones Jun 19, 2020
cc8b14f
Use new generate_metadata extern
ascjones Jun 22, 2020
d5ece81
Warn the user if they have legacy abi_gen artifacts
ascjones Jun 23, 2020
58a2ecb
Move existing abi package check to the right place
ascjones Jun 23, 2020
2b1bc03
Remove v2 backwards compat, use ink! master in template
ascjones Jun 23, 2020
231b3b5
Remove type_metadata dependency
ascjones Jun 23, 2020
dc30077
Fix up template for working with ink! master
ascjones Jun 23, 2020
298fca3
Update template lib.rs for ink! 3
ascjones Jun 23, 2020
649e250
Fix template
ascjones Jun 23, 2020
75c9bb5
Fix template constructors
ascjones Jun 23, 2020
43942c3
Try again with template
ascjones Jun 23, 2020
e35dc74
Move template files to templates dir
ascjones Jun 24, 2020
25f3b28
Rename abi to metadata
ascjones Jun 24, 2020
72cfe7c
Rename abi constant and update warning
ascjones Jun 24, 2020
d673967
More renames from abi to metadata
ascjones Jun 24, 2020
d5e7daa
Document generate_package function
ascjones Jun 24, 2020
6a6cc2e
Fmt
ascjones Jun 24, 2020
ecb188d
More abi to metadata renames
ascjones Jun 24, 2020
b2e9433
Update template parity-scale-codec
ascjones Jun 24, 2020
80ddf09
Bump version
ascjones Jun 24, 2020
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
2 changes: 1 addition & 1 deletion Cargo.lock

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

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "cargo-contract"
version = "0.6.1"
version = "0.7.0"
authors = ["Parity Technologies <admin@parity.io>"]
build = "build.rs"
edition = "2018"
Expand Down
2 changes: 1 addition & 1 deletion build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ fn main() {
.expect("OUT_DIR should be set by cargo")
.into();

let template_dir = manifest_dir.join("template");
let template_dir = manifest_dir.join("templates").join("new");
let dst_file = out_dir.join("template.zip");

println!(
Expand Down
13 changes: 7 additions & 6 deletions src/cmd/metadata.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ pub(crate) fn execute_generate_metadata(
"run",
&[
"--package",
"abi-gen",
"metadata-gen",
&manifest_path.cargo_arg(),
&target_dir_arg,
"--release",
Expand All @@ -68,6 +68,7 @@ pub(crate) fn execute_generate_metadata(
.with_profile_release_lto(false)?;
Ok(())
})?
.with_metadata_gen_package()?
.using_temp(generate_metadata)?;
}

Expand Down Expand Up @@ -98,12 +99,12 @@ mod tests {
.expect("generate metadata failed");
println!("{}", message);

let mut abi_file = working_dir;
abi_file.push("target");
abi_file.push("metadata.json");
let mut metadata_file = working_dir;
metadata_file.push("target");
metadata_file.push("metadata.json");
assert!(
abi_file.exists(),
format!("Missing metadata file '{}'", abi_file.display())
metadata_file.exists(),
format!("Missing metadata file '{}'", metadata_file.display())
)
});
}
Expand Down
91 changes: 85 additions & 6 deletions src/workspace/manifest.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@

use anyhow::{Context, Result};

use super::Profile;
use super::{metadata, Profile};
use std::convert::{TryFrom, TryInto};
use std::{
collections::HashSet,
Expand All @@ -26,6 +26,8 @@ use std::{
use toml::value;

const MANIFEST_FILE: &str = "Cargo.toml";
const LEGACY_METADATA_PACKAGE_PATH: &str = ".ink/abi_gen";
const METADATA_PACKAGE_PATH: &str = ".ink/metadata_gen";

/// Path to a Cargo.toml file
#[derive(Clone, Debug)]
Expand Down Expand Up @@ -90,6 +92,8 @@ impl AsRef<Path> for ManifestPath {
pub struct Manifest {
path: ManifestPath,
toml: value::Table,
/// True if a metadata package should be generated for this manifest
metadata_package: bool,
}

impl Manifest {
Expand All @@ -107,9 +111,15 @@ impl Manifest {
Ok(Manifest {
path: manifest_path,
toml,
metadata_package: false,
})
}

/// Get the path of the manifest file
pub(super) fn path(&self) -> &ManifestPath {
&self.path
}

/// Get mutable reference to `[lib] crate-types = []` section
fn get_crate_types_mut(&mut self) -> Result<&mut value::Array> {
let lib = self
Expand Down Expand Up @@ -185,6 +195,40 @@ impl Manifest {
Ok(self)
}

/// Adds a metadata package to the manifest workspace for generating metadata
pub fn with_metadata_package(&mut self) -> Result<&mut Self> {
let workspace = self
.toml
.entry("workspace")
.or_insert(value::Value::Table(Default::default()));
let members = workspace
.as_table_mut()
.ok_or(anyhow::anyhow!("workspace should be a table"))?
.entry("members")
.or_insert(value::Value::Array(Default::default()))
.as_array_mut()
.ok_or(anyhow::anyhow!("members should be an array"))?;

if members.contains(&LEGACY_METADATA_PACKAGE_PATH.into()) {
// warn user if they have legacy metadata generation artifacts
use colored::Colorize;
println!(
"{} {} {} {}",
"warning:".yellow().bold(),
"please remove".bold(),
LEGACY_METADATA_PACKAGE_PATH.bold(),
"from the `[workspace]` section in the `Cargo.toml`, \
and delete that directory. These are now auto-generated."
.bold()
);
} else {
members.push(METADATA_PACKAGE_PATH.into());
}

self.metadata_package = true;
Ok(self)
}

/// Replace relative paths with absolute paths with the working directory.
///
/// Enables the use of a temporary amended copy of the manifest.
Expand Down Expand Up @@ -294,16 +338,51 @@ impl Manifest {
}

/// Writes the amended manifest to the given path.
pub fn write(&self, path: &ManifestPath) -> Result<()> {
let manifest_path = path.as_ref();
pub fn write(&self, manifest_path: &ManifestPath) -> Result<()> {
if let Some(dir) = manifest_path.directory() {
fs::create_dir_all(dir).context(format!("Creating directory '{}'", dir.display()))?;
}

if self.metadata_package {
let dir = if let Some(manifest_dir) = manifest_path.directory() {
manifest_dir.join(METADATA_PACKAGE_PATH)
} else {
METADATA_PACKAGE_PATH.into()
};

if let Some(dir) = manifest_path.parent() {
fs::create_dir_all(&dir).context(format!("Creating directory '{}'", dir.display()))?;

let name = self
.toml
.get("lib")
.ok_or(anyhow::anyhow!("lib section not found"))?
.get("name")
.ok_or(anyhow::anyhow!("[lib] name field not found"))?
.as_str()
.ok_or(anyhow::anyhow!("[lib] name should be a string"))?;

let get_dependency = |name| -> Result<&value::Table> {
self.toml
.get("dependencies")
.ok_or(anyhow::anyhow!("[dependencies] section not found"))?
.get(name)
.ok_or(anyhow::anyhow!("{} dependency not found", name))?
.as_table()
.ok_or(anyhow::anyhow!("{} dependency should be a table", name))
};

let ink_lang = get_dependency("ink_lang")?;
let ink_abi = get_dependency("ink_abi")?;

metadata::generate_package(dir, name, ink_lang.clone(), ink_abi.clone())?;
}

let updated_toml = toml::to_string(&self.toml)?;
log::debug!("Writing updated manifest to '{}'", manifest_path.display());
fs::write(&manifest_path, updated_toml)?;
log::debug!(
"Writing updated manifest to '{}'",
manifest_path.as_ref().display()
);
fs::write(manifest_path, updated_toml)?;
Ok(())
}
}
Expand Down
71 changes: 71 additions & 0 deletions src/workspace/metadata.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
// Copyright 2018-2020 Parity Technologies (UK) Ltd.
// This file is part of cargo-contract.
//
// 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 anyhow::Result;
use std::{fs, path::Path};
use toml::value;

/// Generates a cargo workspace package which will be invoked to generate contract metadata.
///
/// # Note
///
/// `ink!` dependencies are copied from the containing contract workspace to ensure the same
/// versions are utilized.
pub(super) fn generate_package<P: AsRef<Path>>(
target_dir: P,
contract_package_name: &str,
ink_lang_dependency: value::Table,
mut ink_abi_dependency: value::Table,
) -> Result<()> {
let dir = target_dir.as_ref();
log::debug!(
"Generating metadata package for {} in {}",
contract_package_name,
dir.display()
);

let cargo_toml = include_str!("../../templates/tools/generate-metadata/_Cargo.toml");
let main_rs = include_str!("../../templates/tools/generate-metadata/main.rs");

let mut cargo_toml: value::Table = toml::from_str(cargo_toml)?;
let deps = cargo_toml
.get_mut("dependencies")
.expect("[dependencies] section specified in the template")
.as_table_mut()
.expect("[dependencies] is a table specified in the template");

// initialize contract dependency
let contract = deps
.get_mut("contract")
.expect("contract dependency specified in the template")
.as_table_mut()
.expect("contract dependency is a table specified in the template");
contract.insert("package".into(), contract_package_name.into());

// make ink_abi dependency use default features
ink_abi_dependency.remove("default-features");
ink_abi_dependency.remove("features");
ink_abi_dependency.remove("optional");

// add ink dependencies copied from contract manifest
deps.insert("ink_lang".into(), ink_lang_dependency.into());
deps.insert("ink_abi".into(), ink_abi_dependency.into());
let cargo_toml = toml::to_string(&cargo_toml)?;

fs::write(dir.join("Cargo.toml"), cargo_toml)?;
fs::write(dir.join("main.rs"), main_rs)?;
Ok(())
}
32 changes: 32 additions & 0 deletions src/workspace/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
// along with ink!. If not, see <http://www.gnu.org/licenses/>.

mod manifest;
mod metadata;
mod profile;

#[doc(inline)]
Expand Down Expand Up @@ -95,6 +96,37 @@ impl Workspace {
Ok(self)
}

/// Amend the workspace manifest using the supplied function.
pub fn with_workspace_manifest<F>(&mut self, f: F) -> Result<&mut Self>
where
F: FnOnce(&mut Manifest) -> Result<()>,
{
let workspace_root = self.workspace_root.clone();
let workspace_manifest = self
.members
.iter_mut()
.find_map(|(_, (_, manifest))| {
if manifest.path().directory() == Some(&workspace_root) {
Some(manifest)
} else {
None
}
})
.ok_or(anyhow::anyhow!(
"The workspace root package should be a workspace member"
))?;
f(workspace_manifest)?;
Ok(self)
}

/// Generates a package to invoke for generating contract metadata
pub(super) fn with_metadata_gen_package(&mut self) -> Result<&mut Self> {
self.with_workspace_manifest(|manifest| {
manifest.with_metadata_package()?;
Ok(())
})
}

/// Writes the amended manifests to the `target` directory, retaining the workspace directory
/// structure, but only with the `Cargo.toml` files.
///
Expand Down
16 changes: 0 additions & 16 deletions template/.ink/abi_gen/_Cargo.toml

This file was deleted.

7 changes: 0 additions & 7 deletions template/.ink/abi_gen/main.rs

This file was deleted.

Loading