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