diff --git a/CHANGELOG.md b/CHANGELOG.md
index 5b033d7..6371b5e 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -2,6 +2,18 @@
Changelog for `cargo-odra`.
+## [0.1.2] - 2024-XX-XX
+
+### Added
+
+- Support for defining template of a contract to grab when using `generate` command.
+- Ability to list all available templates using `list-templates` command.
+
+### Fixed
+
+- Fixed error that caused contracts to fail to be built when coming from crates with
+ hyphens in their name.
+
## [0.1.1] - 2024-02-28
### Added
diff --git a/Cargo.lock b/Cargo.lock
index 40e2ab6..f318108 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -180,15 +180,6 @@ dependencies = [
"serde",
]
-[[package]]
-name = "btoi"
-version = "0.4.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9dd6407f73a9b8b6162d8a2ef999fe6afd7cc15902ebf42c5cd296addf17e0ad"
-dependencies = [
- "num-traits",
-]
-
[[package]]
name = "bumpalo"
version = "3.16.0"
@@ -197,9 +188,9 @@ checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c"
[[package]]
name = "cargo-generate"
-version = "0.18.5"
+version = "0.21.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8a2885ae054e000b117515ab33e91c10eca90c2788a7baec1b97ada1f1f51e57"
+checksum = "9d46331ef6f27b90b9db6ac505901ccc0333421bb19ca7356669f078287c7575"
dependencies = [
"anyhow",
"auth-git2",
@@ -299,9 +290,9 @@ dependencies = [
[[package]]
name = "clap"
-version = "4.4.18"
+version = "4.5.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1e578d6ec4194633722ccf9544794b71b1385c3c027efe0c55db226fc880865c"
+checksum = "90bc066a67923782aa8515dbaea16946c5bcc5addbd668bb80af688e53e548a0"
dependencies = [
"clap_builder",
"clap_derive",
@@ -309,9 +300,9 @@ dependencies = [
[[package]]
name = "clap_builder"
-version = "4.4.18"
+version = "4.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4df4df40ec50c46000231c914968278b1eb05098cf8f1b3a518a95030e71d1c7"
+checksum = "ae129e2e766ae0ec03484e609954119f123cc1fe650337e155d03b022f24f7b4"
dependencies = [
"anstream",
"anstyle",
@@ -362,9 +353,9 @@ dependencies = [
[[package]]
name = "clap_derive"
-version = "4.4.7"
+version = "4.5.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cf9804afaaf59a91e75b022a30fb7229a7901f60c755489cc61c9b423b836442"
+checksum = "528131438037fd55894f62d6e9f068b8f45ac57ffa77517819645d10aed04f64"
dependencies = [
"heck",
"proc-macro2",
@@ -374,9 +365,9 @@ dependencies = [
[[package]]
name = "clap_lex"
-version = "0.6.0"
+version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "702fc72eb24e5a1e48ce58027a675bc24edd52096d5397d4aea7c6dd9eca0bd1"
+checksum = "98cc8fbded0c607b7ba9dd60cd98df59af97e84d24e49c8557331cfc26d301ce"
[[package]]
name = "colorchoice"
@@ -571,17 +562,27 @@ version = "0.3.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f"
+[[package]]
+name = "env_filter"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a009aa4810eb158359dda09d0c87378e4bbb89b5a801f016885a4707ba24f7ea"
+dependencies = [
+ "log",
+ "regex",
+]
+
[[package]]
name = "env_logger"
-version = "0.10.2"
+version = "0.11.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4cd405aab171cb85d6735e5c8d9db038c17d3ca007a4d2c25f337935c3d90580"
+checksum = "38b35839ba51819680ba087cd351788c9a3c476841207e0b8cee0b04722343b9"
dependencies = [
+ "anstream",
+ "anstyle",
+ "env_filter",
"humantime",
- "is-terminal",
"log",
- "regex",
- "termcolor",
]
[[package]]
@@ -605,9 +606,6 @@ name = "faster-hex"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a2a2b11eda1d40935b26cf18f6833c526845ae8c41e58d09af6adeb6f0269183"
-dependencies = [
- "serde",
-]
[[package]]
name = "fastrand"
@@ -695,23 +693,23 @@ dependencies = [
[[package]]
name = "gix-actor"
-version = "0.28.1"
+version = "0.31.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2eadca029ef716b4378f7afb19f7ee101fde9e58ba1f1445971315ac866db417"
+checksum = "45c3a3bde455ad2ee8ba8a195745241ce0b770a8a26faae59fcf409d01b28c46"
dependencies = [
"bstr",
- "btoi",
"gix-date",
+ "gix-utils",
"itoa",
"thiserror",
- "winnow 0.5.40",
+ "winnow 0.6.8",
]
[[package]]
name = "gix-config"
-version = "0.31.0"
+version = "0.36.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5cae98c6b4c66c09379bc35274b172587d6b0ac369a416c39128ad8c6454f9bb"
+checksum = "7580e05996e893347ad04e1eaceb92e1c0e6a3ffe517171af99bf6b6df0ca6e5"
dependencies = [
"bstr",
"gix-config-value",
@@ -725,7 +723,7 @@ dependencies = [
"smallvec",
"thiserror",
"unicode-bom",
- "winnow 0.5.40",
+ "winnow 0.6.8",
]
[[package]]
@@ -755,12 +753,13 @@ dependencies = [
[[package]]
name = "gix-features"
-version = "0.36.1"
+version = "0.38.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4d46a4a5c6bb5bebec9c0d18b65ada20e6517dbd7cf855b87dd4bbdce3a771b2"
+checksum = "db4254037d20a247a0367aa79333750146a369719f0c6617fec4f5752cc62b37"
dependencies = [
"gix-hash",
"gix-trace",
+ "gix-utils",
"libc",
"prodash",
"sha1_smol",
@@ -769,18 +768,19 @@ dependencies = [
[[package]]
name = "gix-fs"
-version = "0.8.1"
+version = "0.10.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "20e86eb040f5776a5ade092282e51cdcad398adb77d948b88d17583c2ae4e107"
+checksum = "e2184c40e7910529677831c8b481acf788ffd92427ed21fad65b6aa637e631b8"
dependencies = [
"gix-features",
+ "gix-utils",
]
[[package]]
name = "gix-glob"
-version = "0.14.1"
+version = "0.16.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5db19298c5eeea2961e5b3bf190767a2d1f09b8802aeb5f258e42276350aff19"
+checksum = "682bdc43cb3c00dbedfcc366de2a849b582efd8d886215dbad2ea662ec156bb5"
dependencies = [
"bitflags 2.5.0",
"bstr",
@@ -790,9 +790,9 @@ dependencies = [
[[package]]
name = "gix-hash"
-version = "0.13.3"
+version = "0.14.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1f8cf8c2266f63e582b7eb206799b63aa5fa68ee510ad349f637dfe2d0653de0"
+checksum = "f93d7df7366121b5018f947a04d37f034717e113dcf9ccd85c34b58e57a74d5e"
dependencies = [
"faster-hex",
"thiserror",
@@ -800,9 +800,9 @@ dependencies = [
[[package]]
name = "gix-lock"
-version = "11.0.1"
+version = "13.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7e5c65e6a29830a435664891ced3f3c1af010f14900226019590ee0971a22f37"
+checksum = "e7c359f81f01b8352063319bcb39789b7ea0887b406406381106e38c4a34d049"
dependencies = [
"gix-tempfile",
"gix-utils",
@@ -811,21 +811,21 @@ dependencies = [
[[package]]
name = "gix-object"
-version = "0.38.0"
+version = "0.42.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "740f2a44267f58770a1cb3a3d01d14e67b089c7136c48d4bddbb3cfd2bf86a51"
+checksum = "3d4f8efae72030df1c4a81d02dbe2348e748d9b9a11e108ed6efbd846326e051"
dependencies = [
"bstr",
- "btoi",
"gix-actor",
"gix-date",
"gix-features",
"gix-hash",
+ "gix-utils",
"gix-validate",
"itoa",
"smallvec",
"thiserror",
- "winnow 0.5.40",
+ "winnow 0.6.8",
]
[[package]]
@@ -843,9 +843,9 @@ dependencies = [
[[package]]
name = "gix-ref"
-version = "0.38.0"
+version = "0.43.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0ec2f6d07ac88d2fb8007ee3fa3e801856fb9d82e7366ec0ca332eb2c9d74a52"
+checksum = "fd4aba68b925101cb45d6df328979af0681364579db889098a0de75b36c77b65"
dependencies = [
"gix-actor",
"gix-date",
@@ -856,10 +856,11 @@ dependencies = [
"gix-object",
"gix-path",
"gix-tempfile",
+ "gix-utils",
"gix-validate",
"memmap2",
"thiserror",
- "winnow 0.5.40",
+ "winnow 0.6.8",
]
[[package]]
@@ -876,9 +877,9 @@ dependencies = [
[[package]]
name = "gix-tempfile"
-version = "11.0.1"
+version = "13.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "388dd29114a86ec69b28d1e26d6d63a662300ecf61ab3f4cc578f7d7dc9e7e23"
+checksum = "a761d76594f4443b675e85928e4902dec333273836bd386906f01e7e346a0d11"
dependencies = [
"gix-fs",
"libc",
@@ -940,15 +941,9 @@ checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1"
[[package]]
name = "heck"
-version = "0.4.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8"
-
-[[package]]
-name = "hermit-abi"
-version = "0.3.9"
+version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024"
+checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
[[package]]
name = "home"
@@ -1047,17 +1042,6 @@ dependencies = [
"cfg-if",
]
-[[package]]
-name = "is-terminal"
-version = "0.4.12"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f23ff5ef2b80d608d61efee834934d862cd92461afc0560dedf493e4c033738b"
-dependencies = [
- "hermit-abi",
- "libc",
- "windows-sys 0.52.0",
-]
-
[[package]]
name = "is_terminal_polyfill"
version = "1.70.0"
@@ -1256,9 +1240,9 @@ checksum = "6c8640c5d730cb13ebd907d8d04b52f55ac9a2eec55b440c8892f40d56c76c1d"
[[package]]
name = "memmap2"
-version = "0.7.1"
+version = "0.9.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f49388d20533534cd19360ad3d6a7dadc885944aa802ba3995040c5ec11288c6"
+checksum = "fe751422e4a8caa417e13c3ea66452215d7d63e19e604f4980461212f3ae1322"
dependencies = [
"libc",
]
@@ -1379,7 +1363,7 @@ checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8"
dependencies = [
"cfg-if",
"libc",
- "redox_syscall 0.5.1",
+ "redox_syscall",
"smallvec",
"windows-targets 0.52.5",
]
@@ -1500,9 +1484,9 @@ dependencies = [
[[package]]
name = "prodash"
-version = "26.2.2"
+version = "28.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "794b5bf8e2d19b53dcdcec3e4bba628e20f5b6062503ba89281fa7037dd7bbcf"
+checksum = "744a264d26b88a6a7e37cbad97953fa233b94d585236310bcbc88474b4092d79"
[[package]]
name = "psm"
@@ -1552,15 +1536,6 @@ dependencies = [
"getrandom",
]
-[[package]]
-name = "redox_syscall"
-version = "0.4.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa"
-dependencies = [
- "bitflags 1.3.2",
-]
-
[[package]]
name = "redox_syscall"
version = "0.5.1"
@@ -1628,9 +1603,9 @@ dependencies = [
[[package]]
name = "rhai"
-version = "1.16.3"
+version = "1.18.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e3625f343d89990133d013e39c46e350915178cf94f1bec9f49b0cbef98a3e3c"
+checksum = "7a7d88770120601ba1e548bb6bc2a05019e54ff01b51479e38e64ec3b59d4759"
dependencies = [
"ahash",
"bitflags 2.5.0",
@@ -1640,13 +1615,14 @@ dependencies = [
"rhai_codegen",
"smallvec",
"smartstring",
+ "thin-vec",
]
[[package]]
name = "rhai_codegen"
-version = "1.6.0"
+version = "2.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "853977598f084a492323fe2f7896b4100a86284ee8473612de60021ea341310f"
+checksum = "59aecf17969c04b9c0c5d21f6bc9da9fec9dd4980e64d1871443a476589d8c86"
dependencies = [
"proc-macro2",
"quote",
@@ -1874,9 +1850,9 @@ checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f"
[[package]]
name = "strsim"
-version = "0.10.0"
+version = "0.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
+checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
[[package]]
name = "subtle"
@@ -1897,24 +1873,14 @@ dependencies = [
[[package]]
name = "tempfile"
-version = "3.8.1"
+version = "3.10.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7ef1adac450ad7f4b3c28589471ade84f25f731a7a0fe30d71dfa9f60fd808e5"
+checksum = "85b77fafb263dd9d05cbeac119526425676db3784113aa9295c88498cbf8bff1"
dependencies = [
"cfg-if",
"fastrand",
- "redox_syscall 0.4.1",
"rustix",
- "windows-sys 0.48.0",
-]
-
-[[package]]
-name = "termcolor"
-version = "1.4.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755"
-dependencies = [
- "winapi-util",
+ "windows-sys 0.52.0",
]
[[package]]
@@ -1927,6 +1893,12 @@ dependencies = [
"winapi",
]
+[[package]]
+name = "thin-vec"
+version = "0.2.13"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a38c90d48152c236a3ab59271da4f4ae63d678c5d7ad6b7714d7cb9760be5e4b"
+
[[package]]
name = "thiserror"
version = "1.0.60"
@@ -2171,9 +2143,9 @@ checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
[[package]]
name = "walkdir"
-version = "2.4.0"
+version = "2.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d71d857dc86794ca4c280d616f7da00d2dbfd8cd788846559a6813e6aa4b54ee"
+checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b"
dependencies = [
"same-file",
"winapi-util",
diff --git a/Cargo.toml b/Cargo.toml
index 98896c8..b96c07e 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -19,7 +19,7 @@ convert_case = "0.6"
toml = "0.7"
serde = "1.0"
serde_derive = "1.0"
-cargo-generate = "0.18"
+cargo-generate = "0.21.0"
rm_rf = "0.6"
glob = "0.3"
cargo_toml = "0.15"
diff --git a/README.md b/README.md
index 0af4d49..c359f7a 100644
--- a/README.md
+++ b/README.md
@@ -1,9 +1,10 @@
# cargo-odra
A cargo utility that helps to create, manage and test your smart contracts
-written using Odra framework.
+written using Odra framework.
## Table of Contents
+
* [Usage](#usage)
* [Commands](#backends)
* [Links](#links)
@@ -51,10 +52,11 @@ $ cargo odra test -b casper
* `build` - builds the contracts, generates wasm files,
* `test` - runs tests,
* `generate` - generates sample contract,
+* `list-templates` - lists available templates,
* `clean` - removes temporary files (builders and wasm files),
* `completions` - generates autocomplete script for given shell
-To see exact syntax of each command, type `cargo odra command --help`.
+To see exact syntax of each command, type `cargo odra command_name --help`.
## Workspaces
@@ -74,6 +76,7 @@ $ cargo odra new --name myproject --template workspace && cd myproject
* [Odra docs](https://odra.dev/docs)
## Contact
+
Write **contact@odra.dev**
diff --git a/justfile b/justfile
index 5ca19a7..9048741 100644
--- a/justfile
+++ b/justfile
@@ -1,4 +1,4 @@
-DEVELOPMENT_ODRA_BRANCH := "release/0.9.0"
+DEVELOPMENT_ODRA_BRANCH := "release/1.0.0"
BINARYEN_VERSION := "version_116"
BINARYEN_CHECKSUM := "c55b74f3109cdae97490faf089b0286d3bba926bb6ea5ed00c8c784fc53718fd"
diff --git a/src/actions.rs b/src/actions.rs
index 3b22523..a869022 100644
--- a/src/actions.rs
+++ b/src/actions.rs
@@ -6,4 +6,5 @@ pub mod generate;
pub mod init;
pub mod schema;
pub mod test;
-mod utils;
+
+pub mod list_templates;
diff --git a/src/actions/build.rs b/src/actions/build.rs
index ee31a1b..59505da 100644
--- a/src/actions/build.rs
+++ b/src/actions/build.rs
@@ -1,7 +1,6 @@
//! Module for managing and building wasm files.
-use super::utils;
-use crate::{command, errors::Error, log, paths, project::Project};
+use crate::{command, errors::Error, log, paths, project::Project, utils};
/// BuildAction configuration.
pub struct BuildAction<'a> {
diff --git a/src/actions/generate.rs b/src/actions/generate.rs
index bb3ed88..87534cc 100644
--- a/src/actions/generate.rs
+++ b/src/actions/generate.rs
@@ -9,7 +9,7 @@ use crate::{
log,
odra_toml::Contract,
paths::{to_camel_case, to_snake_case},
- project::Project,
+ project::{OdraLocation, Project},
template::TemplateGenerator,
};
@@ -20,26 +20,40 @@ pub struct GenerateAction<'a> {
contract_module_ident: String,
module_root: PathBuf,
module_name: Option
,
+ template_name: Option,
template_generator: TemplateGenerator,
}
/// GenerateAction implementation.
impl<'a> GenerateAction<'a> {
/// Crate a new GenerateAction for a given contract.
- pub fn new(project: &'a Project, contract_name: String, module_name: Option) -> Self {
+ pub fn new(
+ project: &'a Project,
+ contract_name: String,
+ module_name: Option,
+ template_name: Option,
+ source: Option,
+ ) -> Self {
if project.is_workspace() && module_name.is_none() {
Error::CrateNotProvided.print_and_die();
}
+ let odra_location = match source {
+ None => project.project_odra_location(),
+
+ Some(_) => OdraLocation::from_source(source),
+ };
+
GenerateAction {
project,
contract_name: contract_name.clone(),
contract_module_ident: to_snake_case(contract_name),
module_root: project.module_root(module_name.clone()),
module_name,
+ template_name,
template_generator: TemplateGenerator::new(
ODRA_TEMPLATE_GH_RAW_REPO.to_string(),
- project.project_odra_location(),
+ odra_location,
),
}
}
@@ -49,7 +63,7 @@ impl GenerateAction<'_> {
/// Main function that runs the generation action.
pub fn generate_contract(&self) {
log::info(format!("Adding new contract: {} ...", self.contract_name()));
- self.add_contract_file_to_src();
+ self.add_contract_file_to_src(self.template_name.clone());
self.update_lib_rs();
self.update_odra_toml();
}
@@ -84,11 +98,11 @@ impl GenerateAction<'_> {
}
/// Crates a new module file in src directory.
- fn add_contract_file_to_src(&self) {
+ fn add_contract_file_to_src(&self, template_name: Option) {
// Rename module name.
let contract_body = self
.template_generator
- .module_template(&self.contract_struct_name())
+ .module_template(&self.contract_struct_name(), template_name)
.unwrap_or_else(|err| err.print_and_die());
// Make sure the file do not exist.
diff --git a/src/actions/init.rs b/src/actions/init.rs
index 8dcefab..d8d5c9b 100644
--- a/src/actions/init.rs
+++ b/src/actions/init.rs
@@ -5,16 +5,17 @@ use std::path::{Path, PathBuf};
use cargo_generate::{GenerateArgs, TemplatePath, Vcs};
use cargo_toml::{Dependency, DependencyDetail};
use chrono::Utc;
-use ureq::serde_json;
use crate::{
cli::InitCommand,
command::{rename_file, replace_in_file},
- consts::{ODRA_GITHUB_API_DATA, ODRA_TEMPLATE_GH_REPO},
+ consts::{ODRA_TEMPLATE_GH_RAW_REPO, ODRA_TEMPLATE_GH_REPO},
errors::Error,
log,
paths,
project::OdraLocation,
+ template::TemplateGenerator,
+ utils::odra_latest_version,
};
/// InitAction configuration.
@@ -30,36 +31,44 @@ impl InitAction {
log::info("Generating a new project...");
- let odra_location = Self::odra_location(init_command.source);
+ let odra_location = OdraLocation::from_source(init_command.source);
+
+ let template_repository_path =
+ TemplateGenerator::new(ODRA_TEMPLATE_GH_RAW_REPO.to_string(), odra_location.clone())
+ .find_template(&init_command.template)
+ .path;
let template_path = match odra_location.clone() {
OdraLocation::Local(local_path) => TemplatePath {
auto_path: Some(local_path.as_os_str().to_str().unwrap().to_string()),
- subfolder: Some(format!("templates/{}", init_command.template)),
+ subfolder: Some(template_repository_path),
test: false,
git: None,
branch: None,
tag: None,
+ revision: None,
path: None,
favorite: None,
},
OdraLocation::Remote(repo, branch) => TemplatePath {
auto_path: Some(repo),
- subfolder: Some(format!("templates/{}", init_command.template)),
+ subfolder: Some(template_repository_path),
test: false,
git: None,
branch,
tag: None,
+ revision: None,
path: None,
favorite: None,
},
OdraLocation::CratesIO(version) => TemplatePath {
auto_path: Some(ODRA_TEMPLATE_GH_REPO.to_string()),
- subfolder: Some(format!("templates/{}", init_command.template)),
+ subfolder: Some(template_repository_path),
test: false,
git: None,
branch: Some(format!("release/{}", version)),
tag: None,
+ revision: None,
path: None,
favorite: None,
},
@@ -84,6 +93,7 @@ impl InitAction {
force_git_init: false,
allow_commands: false,
overwrite: false,
+ skip_submodules: true,
other_args: None,
})
.unwrap_or_else(|e| {
@@ -111,6 +121,7 @@ impl InitAction {
"#odra_dependency",
"odra",
);
+
Self::replace_package_placeholder(
init,
&odra_location,
@@ -118,6 +129,7 @@ impl InitAction {
"#odra_test_dependency",
"odra-test",
);
+
Self::replace_package_placeholder(
init,
&odra_location,
@@ -126,6 +138,14 @@ impl InitAction {
"odra-build",
);
+ Self::replace_package_placeholder(
+ init,
+ &odra_location,
+ &cargo_toml_path,
+ "#odra_modules_dependency",
+ "modules",
+ );
+
rename_file(cargo_toml_path, "Cargo.toml");
log::info("Done!");
}
@@ -161,41 +181,6 @@ impl InitAction {
}
}
- fn odra_location(source: Option) -> OdraLocation {
- let source = if let Some(source) = source {
- source
- } else {
- Self::odra_latest_version()
- };
-
- // location on disk
- let local = PathBuf::from(&source);
- if local.exists() {
- OdraLocation::Local(local)
- } else {
- // version
- let version_regex = regex::Regex::new(r"^\d+\.\d+\.\d+$").unwrap();
- if version_regex.is_match(&source) {
- OdraLocation::CratesIO(source)
- } else {
- // branch
- OdraLocation::Remote(ODRA_TEMPLATE_GH_REPO.to_string(), Some(source))
- }
- }
- }
- fn odra_latest_version() -> String {
- let response: serde_json::Value = ureq::get(ODRA_GITHUB_API_DATA)
- .call()
- .unwrap_or_else(|_| {
- Error::FailedToFetchTemplate(ODRA_GITHUB_API_DATA.to_string()).print_and_die()
- })
- .into_json()
- .unwrap_or_else(|_| {
- Error::FailedToParseTemplate(ODRA_GITHUB_API_DATA.to_string()).print_and_die()
- });
- response["tag_name"].as_str().unwrap().to_string()
- }
-
fn odra_project_dependency(
odra_location: OdraLocation,
crate_name: &str,
@@ -216,7 +201,7 @@ impl InitAction {
(None, Some(path), None, None)
}
OdraLocation::Remote(repo, branch) => match branch {
- None => (Some(Self::odra_latest_version()), None, None, None),
+ None => (Some(odra_latest_version()), None, None, None),
Some(branch) => (None, None, Some(repo), Some(branch)),
},
OdraLocation::CratesIO(version) => (Some(version), None, None, None),
diff --git a/src/actions/list_templates.rs b/src/actions/list_templates.rs
new file mode 100644
index 0000000..6d55e92
--- /dev/null
+++ b/src/actions/list_templates.rs
@@ -0,0 +1,33 @@
+//! Module responsible for listing templates in cli.
+
+use crate::{
+ consts::ODRA_TEMPLATE_GH_RAW_REPO,
+ project::OdraLocation,
+ template::{TemplateGenerator, TemplateType},
+};
+
+/// ListTemplatesAction configuration.
+#[derive(Clone)]
+pub struct ListTemplatesAction {}
+
+impl ListTemplatesAction {
+ pub fn list(odra_location: OdraLocation) {
+ let templates =
+ TemplateGenerator::new(ODRA_TEMPLATE_GH_RAW_REPO.to_string(), odra_location)
+ .fetch_templates();
+ println!("Available contract templates:");
+ templates
+ .iter()
+ .filter(|template| template.template_type == TemplateType::Contract)
+ .for_each(|template| {
+ println!(" {:<15}{}", template.name, template.description);
+ });
+ println!("\nAvailable project templates:");
+ templates
+ .iter()
+ .filter(|template| template.template_type == TemplateType::Project)
+ .for_each(|template| {
+ println!(" {:<15}{}", template.name, template.description);
+ });
+ }
+}
diff --git a/src/actions/schema.rs b/src/actions/schema.rs
index 408bf24..1b41a84 100644
--- a/src/actions/schema.rs
+++ b/src/actions/schema.rs
@@ -1,7 +1,6 @@
//! Module for generating contracts schema.
-use super::utils;
-use crate::{command, errors::Error, log, project::Project};
+use crate::{command, errors::Error, log, project::Project, utils};
/// SchemaAction configuration.
pub struct SchemaAction<'a> {
diff --git a/src/cli.rs b/src/cli.rs
index e443e40..2a2c731 100644
--- a/src/cli.rs
+++ b/src/cli.rs
@@ -10,12 +10,14 @@ use crate::{
clean::clean_action,
generate::GenerateAction,
init::InitAction,
+ list_templates::ListTemplatesAction,
schema::SchemaAction,
test::TestAction,
},
+ cargo_toml::load_cargo_toml,
consts,
errors::Error,
- project::Project,
+ project::{OdraLocation, Project},
};
#[derive(Parser)]
@@ -59,6 +61,8 @@ pub enum OdraSubcommand {
Generate(GenerateCommand),
/// Cleans all temporary data generated by cargo odra.
Clean(CleanCommand),
+ /// Lists all available templates.
+ ListTemplates(ListTemplatesCommand),
/// Generates completions for given shell
Completions {
/// The shell to generate the completions for
@@ -80,10 +84,8 @@ pub struct InitCommand {
/// It can be a version, a branch, commit hash or a location on the filesystem.
#[clap(value_parser, long, short)]
pub source: Option,
- /// Template to use. Default is "full" - which contains a sample contract and a test.
- /// Other templates are:
- /// "blank" - which only sets up Cargo.toml and directory structure and
- /// "workspace" - which sets up a workspace with a sub crate.
+ /// Template to use.
+ /// To see all available templates, run `cargo odra list-templates`.
#[clap(value_parser, long, short, default_value = consts::ODRA_TEMPLATE_DEFAULT_TEMPLATE)]
pub template: String,
}
@@ -127,6 +129,14 @@ pub struct GenerateCommand {
/// Name of the module in which the contract will be created.
#[clap(value_parser, long, short)]
pub module: Option,
+ /// Template to use.
+ /// To see all available templates, run `cargo odra list-templates`.
+ #[clap(value_parser, long, short, default_value = consts::MODULE_TEMPLATE)]
+ pub template: Option,
+ /// Odra source to use. By default, it uses version from Cargo.toml,
+ /// but can be overriden if needed.
+ #[clap(value_parser, long, short)]
+ pub source: Option,
}
#[derive(clap::Args, Debug)]
@@ -135,10 +145,17 @@ pub struct CleanCommand {}
#[derive(clap::Args, Debug)]
/// `cargo odra update`
-pub struct UpdateCommand {
- /// If set, runs cargo update for the given builder instead of everyone.
- #[clap(value_parser, long, short, value_parser = [consts::ODRA_CASPER_BACKEND])]
- pub backend: Option,
+pub struct UpdateCommand {}
+
+#[derive(clap::Args, Debug)]
+/// `cargo odra list-templates`
+pub struct ListTemplatesCommand {
+ /// Odra source to use. By default, it uses currently used Odra version.
+ /// If ran without a project, it uses the latest release of Odra.
+ /// If passed as a parameter, it can be a version, a branch,
+ /// commit hash or a location on the filesystem.
+ #[clap(value_parser, long, short)]
+ pub source: Option,
}
/// Cargo odra main parser function.
@@ -157,8 +174,14 @@ pub fn make_action() {
}
OdraSubcommand::Generate(generate) => {
let project = Project::detect(current_dir);
- GenerateAction::new(&project, generate.contract_name, generate.module)
- .generate_contract();
+ GenerateAction::new(
+ &project,
+ generate.contract_name,
+ generate.module,
+ generate.template,
+ generate.source,
+ )
+ .generate_contract();
}
OdraSubcommand::New(init) => {
InitAction::generate_project(init, current_dir, false);
@@ -177,5 +200,17 @@ pub fn make_action() {
let project = Project::detect(current_dir);
SchemaAction::new(&project, schema.contracts_names).build();
}
+ OdraSubcommand::ListTemplates(list) => {
+ let cargo_toml = Project::find_odra_cargo_toml(current_dir.clone());
+ let odra_location = match cargo_toml {
+ None => OdraLocation::from_source(list.source),
+ Some(cargo_toml_path) => match list.source {
+ None => OdraLocation::from_project(load_cargo_toml(&cargo_toml_path)),
+ Some(source) => OdraLocation::from_source(Some(source)),
+ },
+ };
+
+ ListTemplatesAction::list(odra_location);
+ }
}
}
diff --git a/src/consts.rs b/src/consts.rs
index bc4c73a..2508983 100644
--- a/src/consts.rs
+++ b/src/consts.rs
@@ -21,7 +21,9 @@ pub const ODRA_GITHUB_API_DATA: &str = "https://api.github.com/repos/odradev/odr
pub const ODRA_TEMPLATE_DEFAULT_TEMPLATE: &str = "full";
/// Module template.
-pub const MODULE_TEMPLATE: &str = "module";
+pub const MODULE_TEMPLATE: &str = "flipper";
/// Module register snippet.
pub const MODULE_REGISTER: &str = "module_register";
+
+pub const TEMPLATES_JSON_PATH: &str = "templates/templates.json";
diff --git a/src/errors.rs b/src/errors.rs
index 1b6141d..6246a79 100644
--- a/src/errors.rs
+++ b/src/errors.rs
@@ -81,6 +81,18 @@ pub enum Error {
#[error("Crate for contract {0} not found in workspace members")]
CrateOfContractNotFound(String),
+
+ #[error("Failed to fetch templates file from {0}")]
+ FailedToFetchTemplatesFile(String),
+
+ #[error("Failed to parse templates file from {0}")]
+ FailedToParseTemplatesFile(String),
+
+ #[error("Template {0} not found in templates.json")]
+ TemplateNotFound(String),
+
+ #[error("Incorrect template type.")]
+ IncorrectTemplateType,
}
impl Error {
@@ -112,6 +124,10 @@ impl Error {
Error::WasmoptDidNotFinish => 24,
Error::CrateNotProvided => 25,
Error::CrateOfContractNotFound(_) => 26,
+ Error::FailedToFetchTemplatesFile(_) => 27,
+ Error::FailedToParseTemplatesFile(_) => 28,
+ Error::TemplateNotFound(_) => 29,
+ Error::IncorrectTemplateType => 30,
}
}
diff --git a/src/lib.rs b/src/lib.rs
index 4d2e59f..24a3d2b 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -15,3 +15,4 @@ mod odra_toml;
mod paths;
mod project;
mod template;
+mod utils;
diff --git a/src/project.rs b/src/project.rs
index 097d26d..81e6a22 100644
--- a/src/project.rs
+++ b/src/project.rs
@@ -3,9 +3,15 @@ use std::{
path::{Path, PathBuf},
};
-use cargo_toml::{Dependency, DependencyDetail};
+use cargo_toml::{Dependency, DependencyDetail, Manifest};
-use crate::{cargo_toml::load_cargo_toml, errors::Error, odra_toml::OdraToml};
+use crate::{
+ cargo_toml::load_cargo_toml,
+ consts::ODRA_TEMPLATE_GH_REPO,
+ errors::Error,
+ odra_toml::OdraToml,
+ utils::odra_latest_version,
+};
/// Struct representing the whole project.
#[derive(Debug, Clone)]
@@ -28,7 +34,7 @@ impl Project {
let odra_toml_path = Self::find_odra_toml(path.clone()).unwrap_or_else(|| {
Error::NotAnOdraProject.print_and_die();
});
- let cargo_toml_path = Self::find_cargo_toml(path).unwrap_or_else(|| {
+ let cargo_toml_path = Self::find_odra_cargo_toml(path).unwrap_or_else(|| {
Error::NotAnOdraProject.print_and_die();
});
let root = odra_toml_path.parent().unwrap().to_path_buf();
@@ -75,7 +81,7 @@ impl Project {
}
/// Name of the crate.
- /// If there is no subcrate, the project name is returned.
+ /// If there is no sub-crate, the project name is returned.
pub fn crate_name(&self, module_name: Option) -> String {
match module_name {
None => self.project_crate_name(),
@@ -99,7 +105,8 @@ impl Project {
}
/// Searches for main Projects' Cargo.toml.
- pub fn find_cargo_toml(path: PathBuf) -> Option {
+ /// Ensures that the project is an Odra project.
+ pub fn find_odra_cargo_toml(path: PathBuf) -> Option {
match Self::find_file_upwards("Odra.toml", path) {
None => None,
Some(odra_toml_path) => {
@@ -136,7 +143,7 @@ impl Project {
.collect()
}
- fn find_odra_toml(path: PathBuf) -> Option {
+ pub fn find_odra_toml(path: PathBuf) -> Option {
Self::find_file_upwards("Odra.toml", path)
}
@@ -169,7 +176,20 @@ impl Project {
}
pub fn project_odra_location(&self) -> OdraLocation {
- let cargo_toml = load_cargo_toml(&self.cargo_toml_location);
+ OdraLocation::from_project(load_cargo_toml(&self.cargo_toml_location))
+ }
+}
+
+#[derive(Debug, Clone)]
+pub enum OdraLocation {
+ Local(PathBuf),
+ /// git repo, branch
+ Remote(String, Option),
+ CratesIO(String),
+}
+
+impl OdraLocation {
+ pub fn from_project(cargo_toml: Manifest) -> OdraLocation {
let dependencies = match cargo_toml.workspace {
None => cargo_toml.dependencies,
Some(workspace) => workspace.dependencies,
@@ -212,14 +232,29 @@ impl Project {
}
}
}
-}
-#[derive(Debug, Clone)]
-pub enum OdraLocation {
- Local(PathBuf),
- /// git repo, branch
- Remote(String, Option),
- CratesIO(String),
+ pub fn from_source(source: Option) -> OdraLocation {
+ let source = if let Some(source) = source {
+ source
+ } else {
+ odra_latest_version()
+ };
+
+ // location on disk
+ let local = PathBuf::from(&source);
+ if local.exists() {
+ OdraLocation::Local(local)
+ } else {
+ // version
+ let version_regex = regex::Regex::new(r"^\d+\.\d+\.\d+$").unwrap();
+ if version_regex.is_match(&source) {
+ OdraLocation::CratesIO(source)
+ } else {
+ // branch
+ OdraLocation::Remote(ODRA_TEMPLATE_GH_REPO.to_string(), Some(source))
+ }
+ }
+ }
}
#[derive(Debug, Clone)]
diff --git a/src/template.rs b/src/template.rs
index ed2fffe..0a2dfd0 100644
--- a/src/template.rs
+++ b/src/template.rs
@@ -1,12 +1,30 @@
-use ureq::get;
+use serde_derive::{Deserialize, Serialize};
+use ureq::{get, serde_json};
use crate::{
command::read_file_content,
- consts::{MODULE_REGISTER, MODULE_TEMPLATE},
+ consts::{MODULE_REGISTER, MODULE_TEMPLATE, TEMPLATES_JSON_PATH},
errors::Error,
project::OdraLocation,
};
+/// Template type.
+#[derive(Serialize, Deserialize, PartialEq, Debug)]
+pub enum TemplateType {
+ Contract,
+ Project,
+ Internal,
+}
+
+/// Struct representing Template.
+#[derive(Serialize, Deserialize, Debug)]
+pub struct Template {
+ pub name: String,
+ pub description: String,
+ pub path: String,
+ pub template_type: TemplateType,
+}
+
/// This module contains templates for generating new contracts.
pub struct TemplateGenerator {
raw_repository_path: String,
@@ -21,52 +39,95 @@ impl TemplateGenerator {
}
}
- fn template_path(&self, template_name: &str, branch: String) -> String {
- format!(
- "{}/{}/templates/{}.rs.template",
- self.raw_repository_path, branch, template_name
- )
+ fn template_path(&self, template_path: &str, branch: String) -> String {
+ format!("{}/{}/{}", self.raw_repository_path, branch, template_path)
+ }
+
+ /// Fetches templates.json
+ pub fn fetch_templates(&self) -> Vec {
+ match self.odra_location.clone() {
+ OdraLocation::Local(path) => {
+ let path = path.join(TEMPLATES_JSON_PATH);
+ let path_string = path.to_str().unwrap().to_string();
+ serde_json::from_str(&read_file_content(path).unwrap_or_else(|_| {
+ Error::FailedToFetchTemplatesFile(path_string.clone()).print_and_die()
+ }))
+ .unwrap_or_else(|_| Error::FailedToParseTemplatesFile(path_string).print_and_die())
+ }
+ OdraLocation::Remote(_, branch) => {
+ let branch = branch.unwrap_or_else(|| "releases/latest".to_string());
+ let template_path = self.template_path(TEMPLATES_JSON_PATH, branch);
+ let templates_json = Self::download_template(&template_path);
+ serde_json::from_str(&templates_json).unwrap_or_else(|_| {
+ Error::FailedToParseTemplatesFile(template_path).print_and_die()
+ })
+ }
+ OdraLocation::CratesIO(version) => {
+ let branch = format!("release/{}", version);
+ let template_path = self.template_path(TEMPLATES_JSON_PATH, branch);
+ let templates_json = Self::download_template(&template_path);
+ serde_json::from_str(&templates_json).unwrap_or_else(|_| {
+ Error::FailedToParseTemplatesFile(template_path).print_and_die()
+ })
+ }
+ }
+ }
+
+ pub fn find_template(&self, template_name: &str) -> Template {
+ self.fetch_templates()
+ .into_iter()
+ .find(|template| template.name == template_name)
+ .unwrap_or_else(|| Error::TemplateNotFound(template_name.to_owned()).print_and_die())
}
- fn fetch_template(&self, template_name: &str) -> Result {
+ pub fn fetch_template(&self, template_name: &str) -> String {
+ let template = self.find_template(template_name);
+
+ if template.template_type == TemplateType::Project {
+ Error::IncorrectTemplateType.print_and_die()
+ }
+
match self.odra_location.clone() {
OdraLocation::Local(path) => {
- let path = path
- .join("templates")
- .join(template_name)
- .with_extension("rs.template");
- read_file_content(path)
- .map_err(|_| Error::FailedToFetchTemplate(template_name.to_owned()))
+ let path = path.join(template.path);
+ read_file_content(path).unwrap_or_else(|_| {
+ Error::FailedToFetchTemplate(template_name.to_owned()).print_and_die()
+ })
}
OdraLocation::Remote(_, branch) => {
let branch = branch.unwrap_or_else(|| "releases/latest".to_string());
- let template_path = self.template_path(template_name, branch);
- get(&template_path)
- .call()
- .map_err(|_| Error::FailedToFetchTemplate(template_path.clone()))
- .and_then(|res| {
- res.into_string()
- .map_err(|_| Error::FailedToParseTemplate(template_path.clone()))
- })
+ let template_path = self.template_path(&template.path, branch);
+ Self::download_template(&template_path)
}
OdraLocation::CratesIO(version) => {
let branch = format!("release/{}", version);
- let template_path = self.template_path(template_name, branch);
- get(&template_path)
- .call()
- .map_err(|_| Error::FailedToFetchTemplate(template_path.clone()))
- .and_then(|res| {
- res.into_string()
- .map_err(|_| Error::FailedToParseTemplate(template_path.clone()))
- })
+ let template_path = self.template_path(&template.path, branch);
+ Self::download_template(&template_path)
}
}
}
+ fn download_template(template_path: &String) -> String {
+ get(&template_path.clone())
+ .call()
+ .unwrap_or_else(|_| {
+ Error::FailedToFetchTemplate(template_path.to_string()).print_and_die()
+ })
+ .into_string()
+ .unwrap_or_else(|_| {
+ Error::FailedToParseTemplate(template_path.to_string()).print_and_die()
+ })
+ }
+
/// Returns content of the new module file.
- pub fn module_template(&self, module_name: &str) -> Result {
+ pub fn module_template(
+ &self,
+ module_name: &str,
+ template_name: Option,
+ ) -> Result {
+ let template_name = template_name.unwrap_or_else(|| MODULE_TEMPLATE.to_string());
Ok(self
- .fetch_template(MODULE_TEMPLATE)?
+ .fetch_template(&template_name)
.replace("#module_name", module_name))
}
@@ -77,7 +138,7 @@ impl TemplateGenerator {
module_name: &str,
) -> Result {
Ok(self
- .fetch_template(MODULE_REGISTER)?
+ .fetch_template(MODULE_REGISTER)
.replace("#contract_name", contract_name)
.replace("#module_name", module_name))
}
diff --git a/src/actions/utils.rs b/src/utils.rs
similarity index 75%
rename from src/actions/utils.rs
rename to src/utils.rs
index 00fcabf..879d671 100644
--- a/src/actions/utils.rs
+++ b/src/utils.rs
@@ -1,4 +1,13 @@
-use crate::{command, errors::Error, odra_toml::Contract, paths::to_camel_case, project::Project};
+use ureq::serde_json;
+
+use crate::{
+ command,
+ consts::ODRA_GITHUB_API_DATA,
+ errors::Error,
+ odra_toml::Contract,
+ paths::to_camel_case,
+ project::Project,
+};
/// Check if wasm32-unknown-unknown target is installed.
pub fn check_target_requirements() {
@@ -59,3 +68,16 @@ fn parse_contracts_names(names_string: String) -> Result, &'static s
}),
}
}
+
+pub fn odra_latest_version() -> String {
+ let response: serde_json::Value = ureq::get(ODRA_GITHUB_API_DATA)
+ .call()
+ .unwrap_or_else(|_| {
+ Error::FailedToFetchTemplate(ODRA_GITHUB_API_DATA.to_string()).print_and_die()
+ })
+ .into_json()
+ .unwrap_or_else(|_| {
+ Error::FailedToParseTemplate(ODRA_GITHUB_API_DATA.to_string()).print_and_die()
+ });
+ response["tag_name"].as_str().unwrap().to_string()
+}