From d96603c7b1ddc5c8b03a13ffa9e6a4879c6e37fb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1s=20Senovilla=20Polo?= Date: Mon, 30 Sep 2024 20:19:46 +0200 Subject: [PATCH 01/46] Add pop-add feature with config-type and runtime-pallet options; Update pop new pallet to include the created pallet in runtime if needed; rust_writer module added to allow these features --- Cargo.lock | 116 ++++---- Cargo.toml | 4 + crates/pop-cli/Cargo.toml | 1 + .../pop-cli/src/commands/add/config_type.rs | 203 +++++++++++++ .../src/commands/add/config_type/tests.rs | 89 ++++++ crates/pop-cli/src/commands/add/mod.rs | 25 ++ .../src/commands/add/runtime_pallet.rs | 98 +++++++ .../add/runtime_pallet/common_pallets.rs | 72 +++++ .../src/commands/add/runtime_pallet/tests.rs | 1 + crates/pop-cli/src/commands/mod.rs | 8 + crates/pop-cli/src/commands/new/pallet.rs | 69 ++++- crates/pop-common/Cargo.toml | 4 + crates/pop-common/src/errors.rs | 6 + crates/pop-common/src/helpers.rs | 11 + crates/pop-common/src/lib.rs | 7 +- crates/pop-common/src/manifest.rs | 152 +++++++++- crates/pop-common/src/manifest/types.rs | 10 + crates/pop-common/src/rust_writer.rs | 202 +++++++++++++ crates/pop-common/src/rust_writer/expand.rs | 269 ++++++++++++++++++ crates/pop-common/src/rust_writer/helpers.rs | 75 +++++ crates/pop-common/src/rust_writer/parse.rs | 66 +++++ crates/pop-common/src/rust_writer/types.rs | 24 ++ crates/pop-parachains/Cargo.toml | 1 + .../src/new_pallet/new_pallet_options.rs | 11 + .../pallet/advanced_mode/src/lib.rs.templ | 2 +- 25 files changed, 1459 insertions(+), 67 deletions(-) create mode 100644 crates/pop-cli/src/commands/add/config_type.rs create mode 100644 crates/pop-cli/src/commands/add/config_type/tests.rs create mode 100644 crates/pop-cli/src/commands/add/mod.rs create mode 100644 crates/pop-cli/src/commands/add/runtime_pallet.rs create mode 100644 crates/pop-cli/src/commands/add/runtime_pallet/common_pallets.rs create mode 100644 crates/pop-cli/src/commands/add/runtime_pallet/tests.rs create mode 100644 crates/pop-common/src/manifest/types.rs create mode 100644 crates/pop-common/src/rust_writer.rs create mode 100644 crates/pop-common/src/rust_writer/expand.rs create mode 100644 crates/pop-common/src/rust_writer/helpers.rs create mode 100644 crates/pop-common/src/rust_writer/parse.rs create mode 100644 crates/pop-common/src/rust_writer/types.rs diff --git a/Cargo.lock b/Cargo.lock index 5943f5564..3b10984ca 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -355,7 +355,7 @@ dependencies = [ "proc-macro2", "quote", "serde", - "syn 2.0.74", + "syn 2.0.77", ] [[package]] @@ -533,7 +533,7 @@ checksum = "16e62a023e7c117e27523144c5d2459f4397fcc3cab0085af8e2224f643a0193" dependencies = [ "proc-macro2", "quote", - "syn 2.0.74", + "syn 2.0.77", ] [[package]] @@ -550,7 +550,7 @@ checksum = "6e0c28dcc82d7c8ead5cb13beb15405b57b8546e93215673ff8ca0349a028107" dependencies = [ "proc-macro2", "quote", - "syn 2.0.74", + "syn 2.0.77", ] [[package]] @@ -848,7 +848,7 @@ dependencies = [ "proc-macro-crate 3.1.0", "proc-macro2", "quote", - "syn 2.0.74", + "syn 2.0.77", "syn_derive", ] @@ -1075,7 +1075,7 @@ dependencies = [ "heck 0.5.0", "proc-macro2", "quote", - "syn 2.0.74", + "syn 2.0.77", ] [[package]] @@ -1505,7 +1505,7 @@ checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.74", + "syn 2.0.77", ] [[package]] @@ -1532,7 +1532,7 @@ dependencies = [ "proc-macro2", "quote", "scratch", - "syn 2.0.74", + "syn 2.0.77", ] [[package]] @@ -1549,7 +1549,7 @@ checksum = "35de3b547387863c8f82013c4f79f1c2162edee956383e4089e1d04c18c4f16c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.74", + "syn 2.0.77", ] [[package]] @@ -1597,7 +1597,7 @@ dependencies = [ "proc-macro2", "quote", "strsim 0.11.1", - "syn 2.0.74", + "syn 2.0.77", ] [[package]] @@ -1619,7 +1619,7 @@ checksum = "d336a2a514f6ccccaa3e09b02d41d35330c07ddf03a62165fcec10bb561c7806" dependencies = [ "darling_core 0.20.10", "quote", - "syn 2.0.74", + "syn 2.0.77", ] [[package]] @@ -1687,7 +1687,7 @@ checksum = "d65d7ce8132b7c0e54497a4d9a55a1c2a0912a0d786cf894472ba818fba45762" dependencies = [ "proc-macro2", "quote", - "syn 2.0.74", + "syn 2.0.77", ] [[package]] @@ -1698,7 +1698,7 @@ checksum = "62d671cc41a825ebabc75757b62d3d168c577f9149b2d49ece1dad1f72119d25" dependencies = [ "proc-macro2", "quote", - "syn 2.0.74", + "syn 2.0.77", ] [[package]] @@ -1709,7 +1709,7 @@ checksum = "67e77553c4162a157adbf834ebae5b415acbecbeafc7a74b0e886657506a7611" dependencies = [ "proc-macro2", "quote", - "syn 2.0.74", + "syn 2.0.77", ] [[package]] @@ -1722,7 +1722,7 @@ dependencies = [ "proc-macro2", "quote", "rustc_version", - "syn 2.0.74", + "syn 2.0.77", ] [[package]] @@ -1793,7 +1793,7 @@ checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.74", + "syn 2.0.77", ] [[package]] @@ -1823,7 +1823,7 @@ dependencies = [ "proc-macro2", "quote", "regex", - "syn 2.0.74", + "syn 2.0.77", "termcolor", "toml 0.8.19", "walkdir", @@ -2078,7 +2078,7 @@ dependencies = [ "prettyplease", "proc-macro2", "quote", - "syn 2.0.74", + "syn 2.0.77", ] [[package]] @@ -2310,7 +2310,7 @@ checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" dependencies = [ "proc-macro2", "quote", - "syn 2.0.74", + "syn 2.0.77", ] [[package]] @@ -3804,7 +3804,7 @@ checksum = "cb26336e6dc7cc76e7927d2c9e7e3bb376d7af65a6f56a0b16c47d18a9b1abc5" dependencies = [ "proc-macro2", "quote", - "syn 2.0.74", + "syn 2.0.77", ] [[package]] @@ -4242,7 +4242,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.74", + "syn 2.0.77", ] [[package]] @@ -4407,6 +4407,12 @@ version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" +[[package]] +name = "pathdiff" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8835116a5c179084a830efb3adc117ab007512b535bc1a21c991d3b32a6b44dd" + [[package]] name = "pbkdf2" version = "0.12.2" @@ -4464,7 +4470,7 @@ dependencies = [ "pest_meta", "proc-macro2", "quote", - "syn 2.0.74", + "syn 2.0.77", ] [[package]] @@ -4495,7 +4501,7 @@ checksum = "2f38a4412a78282e09a2cf38d195ea5420d15ba0602cb375210efbc877243965" dependencies = [ "proc-macro2", "quote", - "syn 2.0.74", + "syn 2.0.77", ] [[package]] @@ -4562,7 +4568,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6380dbe1fb03ecc74ad55d841cfc75480222d153ba69ddcb00977866cbdabdb8" dependencies = [ "polkavm-derive-impl 0.5.0", - "syn 2.0.74", + "syn 2.0.77", ] [[package]] @@ -4592,7 +4598,7 @@ dependencies = [ "polkavm-common 0.5.0", "proc-macro2", "quote", - "syn 2.0.74", + "syn 2.0.77", ] [[package]] @@ -4604,7 +4610,7 @@ dependencies = [ "polkavm-common 0.8.0", "proc-macro2", "quote", - "syn 2.0.74", + "syn 2.0.77", ] [[package]] @@ -4616,7 +4622,7 @@ dependencies = [ "polkavm-common 0.9.0", "proc-macro2", "quote", - "syn 2.0.74", + "syn 2.0.77", ] [[package]] @@ -4626,7 +4632,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "15e85319a0d5129dc9f021c62607e0804f5fb777a05cdda44d750ac0732def66" dependencies = [ "polkavm-derive-impl 0.8.0", - "syn 2.0.74", + "syn 2.0.77", ] [[package]] @@ -4636,7 +4642,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8ba81f7b5faac81e528eb6158a6f3c9e0bb1008e0ffa19653bc8dea925ecb429" dependencies = [ "polkavm-derive-impl 0.9.0", - "syn 2.0.74", + "syn 2.0.77", ] [[package]] @@ -4690,6 +4696,7 @@ dependencies = [ "sp-weights", "strum 0.26.3", "strum_macros 0.26.4", + "syn 2.0.77", "tempfile", "tokio", "url", @@ -4706,12 +4713,16 @@ dependencies = [ "git2", "git2_credentials", "mockito", + "pathdiff", + "prettyplease", + "proc-macro2", "regex", "reqwest 0.12.5", "serde", "serde_json", "strum 0.26.3", "strum_macros 0.26.4", + "syn 2.0.77", "tar", "tempfile", "thiserror", @@ -4767,6 +4778,7 @@ dependencies = [ "strum 0.26.3", "strum_macros 0.26.4", "symlink", + "syn 2.0.77", "tar", "tempfile", "thiserror", @@ -4848,12 +4860,12 @@ dependencies = [ [[package]] name = "prettyplease" -version = "0.2.20" +version = "0.2.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f12335488a2f3b0a83b14edad48dca9879ce89b2edd10e80237e4e852dd645e" +checksum = "479cf940fbbb3426c32c5d5176f62ad57549a0bb84773423ba8be9d089f5faba" dependencies = [ "proc-macro2", - "syn 2.0.74", + "syn 2.0.77", ] [[package]] @@ -5063,7 +5075,7 @@ checksum = "bcc303e793d3734489387d205e9b186fac9c6cfacedd98cbb2e8a5943595f3e6" dependencies = [ "proc-macro2", "quote", - "syn 2.0.74", + "syn 2.0.77", ] [[package]] @@ -5690,7 +5702,7 @@ dependencies = [ "proc-macro2", "quote", "scale-info", - "syn 2.0.74", + "syn 2.0.77", "thiserror", ] @@ -5745,7 +5757,7 @@ dependencies = [ "proc-macro2", "quote", "serde_derive_internals", - "syn 2.0.74", + "syn 2.0.77", ] [[package]] @@ -5918,7 +5930,7 @@ checksum = "24008e81ff7613ed8e5ba0cfaf24e2c2f1e5b8a0495711e44fcd4882fca62bcf" dependencies = [ "proc-macro2", "quote", - "syn 2.0.74", + "syn 2.0.77", ] [[package]] @@ -5929,7 +5941,7 @@ checksum = "18d26a20a969b9e3fdf2fc2d9f21eda6c40e2de84c9408bb5d3b05d499aae711" dependencies = [ "proc-macro2", "quote", - "syn 2.0.74", + "syn 2.0.77", ] [[package]] @@ -5953,7 +5965,7 @@ checksum = "6c64451ba24fc7a6a2d60fc75dd9c83c90903b19028d4eff35e88fc1e86564e9" dependencies = [ "proc-macro2", "quote", - "syn 2.0.74", + "syn 2.0.77", ] [[package]] @@ -6437,7 +6449,7 @@ checksum = "48d09fa0a5f7299fb81ee25ae3853d26200f7a348148aed6de76be905c007dbe" dependencies = [ "proc-macro2", "quote", - "syn 2.0.74", + "syn 2.0.77", ] [[package]] @@ -6558,7 +6570,7 @@ dependencies = [ "proc-macro-crate 3.1.0", "proc-macro2", "quote", - "syn 2.0.74", + "syn 2.0.77", ] [[package]] @@ -6764,7 +6776,7 @@ dependencies = [ "proc-macro2", "quote", "rustversion", - "syn 2.0.74", + "syn 2.0.77", ] [[package]] @@ -6838,7 +6850,7 @@ dependencies = [ "scale-info", "scale-typegen", "subxt-metadata", - "syn 2.0.74", + "syn 2.0.77", "thiserror", "tokio", ] @@ -6901,7 +6913,7 @@ dependencies = [ "quote", "scale-typegen", "subxt-codegen", - "syn 2.0.74", + "syn 2.0.77", ] [[package]] @@ -6958,9 +6970,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.74" +version = "2.0.77" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fceb41e3d546d0bd83421d3409b1460cc7444cd389341a4c880fe7a042cb3d7" +checksum = "9f35bcdf61fd8e7be6caf75f429fdca8beb3ed76584befb503b1569faee373ed" dependencies = [ "proc-macro2", "quote", @@ -6976,7 +6988,7 @@ dependencies = [ "proc-macro-error", "proc-macro2", "quote", - "syn 2.0.74", + "syn 2.0.77", ] [[package]] @@ -7101,7 +7113,7 @@ checksum = "a4558b58466b9ad7ca0f102865eccc95938dca1a74a856f2b57b6629050da261" dependencies = [ "proc-macro2", "quote", - "syn 2.0.74", + "syn 2.0.77", ] [[package]] @@ -7196,7 +7208,7 @@ checksum = "693d596312e88961bc67d7f1f97af8a70227d9f90c31bba5806eec004978d752" dependencies = [ "proc-macro2", "quote", - "syn 2.0.74", + "syn 2.0.77", ] [[package]] @@ -7432,7 +7444,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.74", + "syn 2.0.77", ] [[package]] @@ -7794,7 +7806,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.74", + "syn 2.0.77", "wasm-bindgen-shared", ] @@ -7828,7 +7840,7 @@ checksum = "afc340c74d9005395cf9dd098506f7f44e38f2b4a21c6aaacf9a105ea5e1e836" dependencies = [ "proc-macro2", "quote", - "syn 2.0.74", + "syn 2.0.77", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -8475,7 +8487,7 @@ checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.74", + "syn 2.0.77", ] [[package]] @@ -8495,7 +8507,7 @@ checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" dependencies = [ "proc-macro2", "quote", - "syn 2.0.74", + "syn 2.0.77", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index 8ca9fa23f..280104b1f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -30,11 +30,15 @@ git2 = { version = "0.18", features = ["vendored-openssl"] } glob = "0.3.1" log = "0.4.20" mockito = "1.4.0" +pathdiff = "0.2.1" predicates = "3.1.0" +prettyplease = "0.2.22" +proc-macro2 = "1.0.86" tar = "0.4.40" tempfile = "3.10" thiserror = "1.0.58" tokio-test = "0.4.4" +syn = { version = "2.0.77", features = ["full", "extra-traits"]} # networking reqwest = { version = "0.12", features = ["json"] } diff --git a/crates/pop-cli/Cargo.toml b/crates/pop-cli/Cargo.toml index 4a6a63df2..8fdc98372 100644 --- a/crates/pop-cli/Cargo.toml +++ b/crates/pop-cli/Cargo.toml @@ -19,6 +19,7 @@ env_logger.workspace = true os_info.workspace = true reqwest.workspace = true serde_json.workspace = true +syn.workspace = true tempfile.workspace = true tokio.workspace = true url.workspace = true diff --git a/crates/pop-cli/src/commands/add/config_type.rs b/crates/pop-cli/src/commands/add/config_type.rs new file mode 100644 index 000000000..5c55a7f50 --- /dev/null +++ b/crates/pop-cli/src/commands/add/config_type.rs @@ -0,0 +1,203 @@ +// SPDX-License-Identifier: GPL-3.0 + +use crate::cli::{traits::Cli as _, Cli}; +use clap::{error::ErrorKind, Args, Command}; +use cliclack; +use pop_common::{ + find_workspace_toml, format_dir, + rust_writer::{self, types::*}, +}; +use std::{fs, path::PathBuf}; + +#[cfg(test)] +mod tests; + +#[derive(Args, Debug, Clone)] +pub struct AddConfigTypeCommand { + #[arg(short, long, required = true, help = "Specify the path to the pallet crate.")] + pub(crate) path: PathBuf, + #[arg(short, long, required = true, help = "The name of the config type.")] + pub(crate) name: String, + #[arg(short, long, num_args(1..), required = true, help="Add trait bounds to your new config type.")] + pub(crate) bounds: Vec, + #[command(flatten)] + pub(crate) default_config: DefaultConfigTypeOptions, + #[arg( + long, + help = "Define a default value for your new config type to use in the default config." + )] + pub(crate) default_value: Option, + #[arg(long, help = "Define a value for your new config type to use in your runtime.")] + pub(crate) runtime_value: Option, + #[arg( + long, + help = "If your pallet is included in a runtime, Pop-Cli will look for the impl block for your pallet's Config trait inside configs/mod.rs or lib.rs in the runtime crate by default in order to add the new type to the runtime. If your impl block is in another path, use this option to specify it." + )] + pub(crate) runtime_impl_path: Option, +} + +#[derive(Args, Debug, Clone)] +#[group(required = false, multiple = false)] +pub struct DefaultConfigTypeOptions { + #[arg( + long, + help = "Ensures the trait item will not be used as a default with the #[derive_impl(..)] attribute macro." + )] + pub(crate) no_default: bool, + #[arg( + long, + help = "Ensures that the trait DefaultConfig will not have any bounds for this trait item." + )] + pub(crate) no_default_bounds: bool, +} + +fn validate_config_options(command: &AddConfigTypeCommand, lib_content: &str) { + let mut cmd = Command::new(""); + + if command.runtime_impl_path.is_some() && command.runtime_value.is_none() { + cmd.error( + ErrorKind::ArgumentConflict, + "The use of --runtime-impl-path is forbidden if --runtime-value isn't used.", + ) + .exit() + } + + match command.default_config { + DefaultConfigTypeOptions { no_default: true, .. } if !lib_content.contains("pub mod config_preludes") => cmd.error( + ErrorKind::InvalidSubcommand, + "Cannot specify --no-default if the affected pallet doesn't implement a default config. Pop-Cli follows the convention and looks for a module called 'config_preludes' (defined either inside the pallet's lib file or its own file 'config_preludes.rs'), if your pallet uses a default config under another name, be sure to rename it as 'config_preludes' if you want to use this feature of Pop-Cli." + ).exit(), + DefaultConfigTypeOptions { no_default: true, .. } if command.default_value.is_some() => cmd + .error( + ErrorKind::ArgumentConflict, + "Cannot specify a default value for a no-default config type.", + ) + .exit(), + DefaultConfigTypeOptions { no_default: true, .. } if command.runtime_value.is_none() => cmd + .error( + ErrorKind::ArgumentConflict, + "Types without a default value need a runtime value.", + ) + .exit(), + DefaultConfigTypeOptions { no_default_bounds: true, .. } if !lib_content.contains("pub mod config_preludes") => cmd.error( + ErrorKind::InvalidSubcommand, + "Cannot specify --no-default-bounds if the affected pallet doesn't implement a default config. Pop-Cli follows the convention and looks for a module called 'config_preludes' (defined either inside the pallet's lib file or its own file 'config_preludes.rs'), if your pallet uses a default config under another name, be sure to rename it as 'config_preludes' if you want to use this feature of Pop-Cli." + ).exit(), + DefaultConfigTypeOptions { no_default_bounds: true, .. } + if command.default_value.is_none() && command.runtime_value.is_none() => + cmd.error( + ErrorKind::ArgumentConflict, + "The type needs at least a default value or a runtime value.", + ) + .exit(), + DefaultConfigTypeOptions { no_default: false, no_default_bounds: false } if command.default_value.is_some() && !lib_content.contains("pub mod config_preludes") => cmd.error( + ErrorKind::InvalidSubcommand, + "Cannot specify a --default-value if the affected pallet doesn't implement a default config. Pop-Cli follows the convention and looks for a module called 'config_preludes' (defined either inside the pallet's lib file or its own file 'config_preludes.rs'), if your pallet uses a default config under another name, be sure to rename it as 'config_preludes' if you want to use this feature of Pop-Cli." + ).exit(), + DefaultConfigTypeOptions { no_default: false, no_default_bounds: false } + if command.default_value.is_none() && command.runtime_value.is_none() => + cmd.error( + ErrorKind::ArgumentConflict, + "The type needs at least a default value or a runtime value.", + ) + .exit(), + _ => (), + } +} + +impl AddConfigTypeCommand { + pub(crate) async fn execute(self) -> anyhow::Result<()> { + Cli.intro("Add a new type to your pallet")?; + let mut cmd = Command::new(""); + let src = &self.path.join("src"); + // Check that the path correspond to a pallet using that the file lib.rs always contains the + // line #[pallet::pallet]. + let lib_path = src.join("lib.rs"); + if !lib_path.is_file() { + cmd.error( + ErrorKind::InvalidValue, + "Make sure that the used path correspond to a pallet crate.", + ) + .exit(); + } + let lib_content = fs::read_to_string(&lib_path)?; + if !lib_content.contains("#[pallet::pallet]") { + cmd.error( + ErrorKind::InvalidValue, + "Make sure that the used path correspond to a pallet crate.", + ) + .exit(); + } + + // Check that the command is correct + validate_config_options(&self, &lib_content); + + let spinner = cliclack::spinner(); + spinner.start("Updating pallet's config trait..."); + + // Update the config trait in lib.rs + rust_writer::update_config_trait( + &lib_path, + &self.name, + self.bounds.iter().map(|bound| bound.as_str()).collect(), + match &self.default_config { + DefaultConfigTypeOptions { no_default: true, .. } => DefaultConfigType::NoDefault, + DefaultConfigTypeOptions { no_default_bounds: true, .. } => + DefaultConfigType::NoDefaultBounds, + _ => DefaultConfigType::Default, + }, + )?; + + match &self.default_config { + // No_default only adds the runtime value to runtimes + DefaultConfigTypeOptions { no_default: true, .. } => { + spinner.set_message("Adding your type to pallet's related runtimes..."); + // Add the new type to the mock runtime + rust_writer::add_type_to_runtimes( + &self.path, + &self.name, + self.runtime_value.as_ref().expect("validate options stops the execution from clap if runtime_value is none in this scenario; qed;"), + self.runtime_impl_path.as_deref() + )?; + }, + // Otherwise, the type is added at least to one: the runtimes or the default + // config + _ => { + if let Some(runtime_value) = &self.runtime_value { + spinner.set_message("Adding your type to pallet's related runtimes..."); + // Add the new type to the mock runtime + rust_writer::add_type_to_runtimes( + &self.path, + &self.name, + runtime_value, + self.runtime_impl_path.as_deref(), + )?; + } + if let Some(default_value) = &self.default_value { + spinner.set_message( + "Adding your type's default value to the pallet's config preludes...", + ); + // If config_preludes is defined in its own file, we pass it to + // 'add_type_to_config_preludes", otherwise we pass lib.rs + let config_preludes_path = src.join("config_preludes.rs"); + let file_path = if config_preludes_path.is_file() { + &config_preludes_path + } else { + &lib_path + }; + + rust_writer::add_type_to_config_preludes(file_path, &self.name, default_value)?; + } + }, + }; + + if let Some(mut workspace_toml) = find_workspace_toml(&self.path) { + workspace_toml.pop(); + format_dir(&workspace_toml)?; + } else { + format_dir(&self.path)?; + } + spinner.stop("Your type is ready to be used in your pallet 🚀"); + Ok(()) + } +} diff --git a/crates/pop-cli/src/commands/add/config_type/tests.rs b/crates/pop-cli/src/commands/add/config_type/tests.rs new file mode 100644 index 000000000..086522b81 --- /dev/null +++ b/crates/pop-cli/src/commands/add/config_type/tests.rs @@ -0,0 +1,89 @@ +// SPDX-License-Identifier: GPL-3.0 + +use assert_cmd::Command; +use predicates::prelude::*; + +struct TestBuilder { + cmd: Command, +} + +impl TestBuilder { + fn cmd_add_pallet_config_type() -> Self { + let mut cmd = Command::cargo_bin("pop").unwrap(); + cmd.arg("add") + .arg("pallet") + .arg("path/to/pallet") + .arg("config") + .arg("MyType") + .arg("--bounds") + .arg("MyBound"); + Self { cmd } + } + + fn cmd_success(&mut self) { + self.cmd.assert().success(); + } + + fn cmd_fails_with_message(&mut self, message: &str) { + self.cmd.assert().failure().stderr(predicate::str::contains(message)); + } +} + +#[test] +fn config_options_no_default_custom_validation_works() { + // --no-default + --default-value isn't a valid combination + let mut builder = TestBuilder::cmd_add_pallet_config_type(); + builder.cmd.arg("--no-default").arg("--default-value").arg("u32"); + + builder.cmd_fails_with_message("Cannot specify a default value for a no-default config type."); + + // --no-default without --runtime-value isn't a valid combination + builder = TestBuilder::cmd_add_pallet_config_type(); + builder.cmd.arg("--no-default"); + builder.cmd_fails_with_message("Types without a default value need a runtime value."); + + // --no-default + --runtime-value OK + builder.cmd.arg("--runtime-value").arg("u32"); + builder.cmd_success(); +} + +#[test] +fn config_options_no_default_bounds_validation_works() { + // --no-default-bounds fails without runtime value and default value + let mut builder = TestBuilder::cmd_add_pallet_config_type(); + builder.cmd.arg("--no-default-bounds"); + builder.cmd_fails_with_message("The type needs at least a default value or a runtime value."); + + // --no-default-bounds + --runtime-value works + builder.cmd.arg("--runtime-value").arg("u32"); + builder.cmd_success(); + + // --no-default-bounds + --default-value works + builder = TestBuilder::cmd_add_pallet_config_type(); + builder.cmd.arg("--no-default-bounds").arg("--default-value").arg("u32"); + builder.cmd_success(); + + // --no-default-bounds + --default-value + --runtime-value works + builder.cmd.arg("--runtime-value").arg("u32"); + builder.cmd_success(); +} + +#[test] +fn config_options_default_not_specified_validation_works() { + // default not specified fails without runtime value and default value + let mut builder = TestBuilder::cmd_add_pallet_config_type(); + builder.cmd_fails_with_message("The type needs at least a default value or a runtime value."); + + // default not specified + --runtime-value works + builder.cmd.arg("--runtime-value").arg("u32"); + builder.cmd_success(); + + // default not specified + --default-value works + builder = TestBuilder::cmd_add_pallet_config_type(); + builder.cmd.arg("--default-value").arg("u32"); + builder.cmd_success(); + + // default not specified + --default-value + --runtime-value works + builder.cmd.arg("--runtime-value").arg("u32"); + builder.cmd_success(); +} diff --git a/crates/pop-cli/src/commands/add/mod.rs b/crates/pop-cli/src/commands/add/mod.rs new file mode 100644 index 000000000..e12e4917e --- /dev/null +++ b/crates/pop-cli/src/commands/add/mod.rs @@ -0,0 +1,25 @@ +// SPDX-License-Identifier: GPL-3.0 + +use clap::{Args, Subcommand}; + +pub mod config_type; +pub mod runtime_pallet; + +/// Arguments for adding a new feature to existing code +#[derive(Args)] +#[command(args_conflicts_with_subcommands = true)] +pub struct AddArgs { + #[command(subcommand)] + pub command: Command, +} + +#[derive(Subcommand)] +pub enum Command { + /// Add a new config type to an existing pallet + #[cfg(feature = "parachain")] + #[clap(alias = "C")] + ConfigType(config_type::AddConfigTypeCommand), + /// Add a new pallet to an existing runtime + #[clap(alias = "P")] + RuntimePallet(runtime_pallet::AddRuntimePalletCommand), +} diff --git a/crates/pop-cli/src/commands/add/runtime_pallet.rs b/crates/pop-cli/src/commands/add/runtime_pallet.rs new file mode 100644 index 000000000..5761ed110 --- /dev/null +++ b/crates/pop-cli/src/commands/add/runtime_pallet.rs @@ -0,0 +1,98 @@ +// SPDX-License-Identifier: GPL-3.0 + +use crate::{ + cli::{traits::Cli as _, Cli}, + multiselect_pick, +}; +use clap::{error::ErrorKind, Args, Command}; +use cliclack::multiselect; +use pop_common::{ + find_pallet_runtime_impl_path, find_workspace_toml, format_dir, + manifest::types::CrateDependencie, rust_writer, +}; +use std::path::PathBuf; +use strum::{EnumMessage, IntoEnumIterator}; + +mod common_pallets; + +#[cfg(test)] +mod tests; + +#[derive(Args, Debug, Clone)] +pub struct AddRuntimePalletCommand { + #[arg(short, long, required = true, help = "Specify the path to the runtime crate.")] + pub(crate) path: PathBuf, + #[arg(long, value_enum, num_args(1..), required = false, help = "The pallets you want to include to your runtime.")] + pub(crate) pallets: Vec, + #[arg( + long, + help = "Pop-Cli will place the impl blocks for your pallets' Config traits inside configs/mod.rs or lib.rs in the runtime crate by default. If you want to place them in another path, use this option to specify it." + )] + pub(crate) runtime_impl_path: Option, +} + +impl AddRuntimePalletCommand { + pub(crate) async fn execute(self) -> anyhow::Result<()> { + Cli.intro("Add a new pallet to your runtime")?; + let mut cmd = Command::new(""); + let src = &self.path.join("src"); + let lib_path = src.join("lib.rs"); + if !lib_path.is_file() { + cmd.error( + ErrorKind::InvalidValue, + "Make sure that the used path correspond to a runtime crate.", + ) + .exit(); + } + + let runtime_impl_path = + match self.runtime_impl_path.or_else(|| find_pallet_runtime_impl_path(&lib_path)) { + Some(runtime_impl_path) => runtime_impl_path, + None => cmd + .error( + ErrorKind::InvalidValue, + "Make sure that the used path correspond to a runtime crate.", + ) + .exit(), + }; + + let spinner = cliclack::spinner(); + spinner.start("Updating runtime..."); + + let pallets = if self.pallets.is_empty() { + multiselect_pick!( + common_pallets::CommonPallets, + "Select the pallets you want to include in your runtime" + ) + } else { + self.pallets + }; + + for pallet in pallets { + // Add the pallet to the crate and to the runtime module + rust_writer::add_pallet_to_runtime_module( + &pallet.get_crate_name(), + &lib_path, + CrateDependencie::External { version: pallet.get_version() }, + )?; + // Add the pallet impl block + rust_writer::add_pallet_impl_block_to_runtime( + &pallet.get_crate_name(), + &runtime_impl_path, + pallet.get_parameter_types(), + pallet.get_config_types(), + pallet.get_config_values(), + pallet.get_default_config(), + )?; + } + + if let Some(mut workspace_toml) = find_workspace_toml(&self.path) { + workspace_toml.pop(); + format_dir(&workspace_toml)?; + } else { + format_dir(&self.path)?; + } + spinner.stop("Your runtime has been updated and it's ready to use 🚀"); + Ok(()) + } +} diff --git a/crates/pop-cli/src/commands/add/runtime_pallet/common_pallets.rs b/crates/pop-cli/src/commands/add/runtime_pallet/common_pallets.rs new file mode 100644 index 000000000..1bfd62658 --- /dev/null +++ b/crates/pop-cli/src/commands/add/runtime_pallet/common_pallets.rs @@ -0,0 +1,72 @@ +// SPDX-License-Identifier: GPL-3.0 +use clap::ValueEnum; +use pop_common::rust_writer::types::ParameterTypes; +use strum_macros::{EnumIter, EnumMessage}; +use syn::{parse_quote, Type}; + +#[derive(Debug, Copy, Clone, PartialEq, EnumIter, EnumMessage, ValueEnum)] +pub enum CommonPallets { + /// Add pallet-balances to your runtime. + #[strum(message = "Balances", detailed_message = "Add pallet-balances to your runtime.")] + Balances, + /// Add pallet-contracts to your runtime. + #[strum(message = "Contracts", detailed_message = "Add pallet-contracts to your runtime.")] + Contracts, +} + +impl CommonPallets { + pub fn get_crate_name(&self) -> String { + match self { + CommonPallets::Balances => "pallet-balances".to_string(), + CommonPallets::Contracts => "pallet-contracts".to_string(), + } + } + + pub fn get_version(&self) -> String { + match self { + CommonPallets::Balances => "39.0.0".to_string(), + CommonPallets::Contracts => "27.0.0".to_string(), + } + } + + pub fn get_parameter_types(&self) -> Vec { + match self { + CommonPallets::Balances => Vec::new(), + CommonPallets::Contracts => vec![ParameterTypes { + ident: "Schedule".to_string(), + type_: parse_quote! {pallet_contracts::Schedule}, + value: parse_quote! {Default::default()}, + }], + } + } + + pub fn get_config_types(&self) -> Vec { + match self { + CommonPallets::Balances => vec!["AccountStore".to_string()], + CommonPallets::Contracts => + vec!["Currency".to_string(), "Schedule".to_string(), "CallStack".to_string()], + } + } + + pub fn get_config_values(&self) -> Vec { + match self { + CommonPallets::Balances => { + vec![parse_quote! {System}] + }, + CommonPallets::Contracts => { + vec![ + parse_quote! {Balances}, + parse_quote! {[pallet_contracts::Frame; 5]}, + parse_quote! {Schedule}, + ] + }, + } + } + + pub fn get_default_config(&self) -> bool { + match self { + CommonPallets::Balances => true, + CommonPallets::Contracts => true, + } + } +} diff --git a/crates/pop-cli/src/commands/add/runtime_pallet/tests.rs b/crates/pop-cli/src/commands/add/runtime_pallet/tests.rs new file mode 100644 index 000000000..ea448e289 --- /dev/null +++ b/crates/pop-cli/src/commands/add/runtime_pallet/tests.rs @@ -0,0 +1 @@ +// SPDX-License-Identifier: GPL-3.0 diff --git a/crates/pop-cli/src/commands/mod.rs b/crates/pop-cli/src/commands/mod.rs index 34c2f10b3..0f8ab1a5f 100644 --- a/crates/pop-cli/src/commands/mod.rs +++ b/crates/pop-cli/src/commands/mod.rs @@ -5,6 +5,7 @@ use clap::Subcommand; use pop_common::templates::Template; use serde_json::{json, Value}; +pub(crate) mod add; pub(crate) mod build; pub(crate) mod call; pub(crate) mod clean; @@ -41,6 +42,9 @@ pub(crate) enum Command { /// Remove generated/cached artifacts. #[clap(alias = "C")] Clean(clean::CleanArgs), + /// Add a feature to existing Rust code + #[clap(alias = "a")] + Add(add::AddArgs), } /// Help message for the build command. @@ -122,6 +126,10 @@ impl Command { .map(|_| Value::Null) }, }, + Self::Add(args) => match args.command { + add::Command::ConfigType(cmd) => cmd.execute().await.map(|_| json!("default")), + add::Command::RuntimePallet(cmd) => cmd.execute().await.map(|_| json!("default")), + }, } } } diff --git a/crates/pop-cli/src/commands/new/pallet.rs b/crates/pop-cli/src/commands/new/pallet.rs index ba47d49a4..2f0e0d57e 100644 --- a/crates/pop-cli/src/commands/new/pallet.rs +++ b/crates/pop-cli/src/commands/new/pallet.rs @@ -7,13 +7,18 @@ use crate::{ use clap::{Args, Subcommand}; use cliclack::{confirm, input, multiselect, outro, outro_cancel}; -use pop_common::{add_crate_to_workspace, find_workspace_toml, prefix_with_current_dir_if_needed}; +use pop_common::{ + add_crate_to_workspace, find_crate_name, find_pallet_runtime_impl_path, + find_pallet_runtime_lib_path, find_workspace_toml, format_dir, + manifest::types::CrateDependencie, prefix_with_current_dir_if_needed, rust_writer, +}; use pop_parachains::{ create_pallet_template, TemplatePalletConfig, TemplatePalletConfigCommonTypes, TemplatePalletOptions, TemplatePalletStorageTypes, }; -use std::{fs, path::PathBuf, process::Command}; +use std::{fs, path::PathBuf}; use strum::{EnumMessage, IntoEnumIterator}; +use syn::Type; fn after_help_simple() -> &'static str { r#"Examples: @@ -47,6 +52,11 @@ pub struct NewPalletCommand { pub(crate) authors: Option, #[arg(short, long, help = "Pallet description", default_value = "Frame Pallet")] pub(crate) description: Option, + #[arg( + long, + help = "If your pallet is created in a workspace containing a runtime, Pop-Cli will try to add the impl block for your pallet's Config trait inside configs/mod.rs or lib.rs in the runtime crate by default. If you need to use another path, use this option to specify it." + )] + pub(crate) runtime_impl_path: Option, #[command(subcommand)] pub(crate) mode: Option, } @@ -176,25 +186,62 @@ impl NewPalletCommand { pallet_in_workspace: workspace_toml.is_some(), pallet_advanced_mode: self.mode.is_some(), pallet_default_config, - pallet_common_types, + pallet_common_types: pallet_common_types.clone(), pallet_storage, pallet_genesis, pallet_custom_origin, }, )?; + let pallet_name = find_crate_name(&pallet_path.join("Cargo.toml"))?; + + spinner.set_message("Adding the pallet to your runtime if needed..."); + // Check if the pallet has to be included in a runtime and include it if so + if let (Some(runtime_lib_path), Some(runtime_impl_path)) = ( + find_pallet_runtime_lib_path(&pallet_path), + self.runtime_impl_path.or_else(|| find_pallet_runtime_impl_path(&pallet_path)), + ) { + // If the pallet has been created inside a workspace containing a runtime, add the + // pallet to that runtime. + + rust_writer::add_pallet_to_runtime_module( + &pallet_name, + &runtime_lib_path, + CrateDependencie::Local { local_crate_path: pallet_path.to_path_buf() }, + )?; + // Add pallet's impl block + let (types, values) = if pallet_default_config { + (Vec::new(), Vec::new()) + } else { + let types: Vec = pallet_common_types + .clone() + .iter() + .map(|type_| type_.get_message().unwrap_or_default().to_string()) + .collect(); + let values: Vec = + pallet_common_types.iter().map(|type_| type_.common_value()).collect(); + (types, values) + }; + rust_writer::add_pallet_impl_block_to_runtime( + &pallet_name, + &runtime_impl_path, + Vec::new(), + types, + values, + pallet_default_config, + )?; + } // If the pallet has been created inside a workspace, add it to that workspace - if let Some(workspace_toml) = workspace_toml { + if let Some(mut workspace_toml) = workspace_toml { add_crate_to_workspace(&workspace_toml, &pallet_path)?; + // Format the whole workspace + workspace_toml.pop(); + format_dir(&workspace_toml)?; + } else { + // Format the pallet dir + format_dir(&pallet_path)?; } - // Format the dir. If this fails we do nothing, it's not a major failure - Command::new("cargo") - .arg("fmt") - .arg("--all") - .current_dir(&pallet_path) - .output()?; - spinner.stop("Generation complete"); outro(format!( "cd into \"{}\" and enjoy hacking! 🚀", diff --git a/crates/pop-common/Cargo.toml b/crates/pop-common/Cargo.toml index 8a3afe616..073cc1727 100644 --- a/crates/pop-common/Cargo.toml +++ b/crates/pop-common/Cargo.toml @@ -14,6 +14,9 @@ duct.workspace = true flate2.workspace = true git2.workspace = true git2_credentials.workspace = true +pathdiff.workspace = true +proc-macro2.workspace = true +prettyplease.workspace = true regex.workspace = true reqwest.workspace = true serde_json.workspace = true @@ -25,6 +28,7 @@ thiserror.workspace = true tokio.workspace = true toml_edit.workspace = true url.workspace = true +syn.workspace = true [dev-dependencies] mockito.workspace = true diff --git a/crates/pop-common/src/errors.rs b/crates/pop-common/src/errors.rs index 02fb0c9b1..117c780eb 100644 --- a/crates/pop-common/src/errors.rs +++ b/crates/pop-common/src/errors.rs @@ -21,10 +21,16 @@ pub enum Error { ParseError(#[from] url::ParseError), #[error("SourceError error: {0}")] SourceError(#[from] sourcing::Error), + #[error("Syn parse error: {0}. To preserve your not-docs comments and blank lines, Pop-CLi temporarily transform them to comments followed by a marker type associated to that doc. This error is likely originated cause one of your files has a not-doc comment/blank line in a place where that marker type cannot be placed. Example:\nmatch option{{\n\t//This is the painful comment\n\tSome(some)=>(),\n\tNone=>()\n}}")] + SynError(#[from] syn::Error), #[error("TemplateError error: {0}")] TemplateError(#[from] templates::Error), + #[error("TomlError: {0}")] + TomlError(#[from] toml_edit::TomlError), #[error("Unsupported command: {0}")] UnsupportedCommand(String), #[error("Unsupported platform: {arch} {os}")] UnsupportedPlatform { arch: &'static str, os: &'static str }, + #[error("Unable to write to the introduced path. {0}")] + WriteError(String), } diff --git a/crates/pop-common/src/helpers.rs b/crates/pop-common/src/helpers.rs index a63ed854e..a525776aa 100644 --- a/crates/pop-common/src/helpers.rs +++ b/crates/pop-common/src/helpers.rs @@ -6,6 +6,7 @@ use std::{ fs, io::{Read, Write}, path::{Component, Path, PathBuf}, + process::{Command, Output}, }; /// Replaces occurrences of specified strings in a file with new values. @@ -55,6 +56,16 @@ pub fn prefix_with_current_dir_if_needed(path: PathBuf) -> PathBuf { path } +pub fn format_dir(path: &Path) -> Result { + Command::new("cargo") + .arg("+nightly") + .arg("fmt") + .arg("--all") + .current_dir(path) + .output() + .or(Command::new("cargo").arg("fmt").arg("--all").current_dir(path).output()) +} + #[cfg(test)] mod tests { use super::*; diff --git a/crates/pop-common/src/lib.rs b/crates/pop-common/src/lib.rs index 7206bc7ee..bdb24ffdb 100644 --- a/crates/pop-common/src/lib.rs +++ b/crates/pop-common/src/lib.rs @@ -3,14 +3,17 @@ pub mod errors; pub mod git; pub mod helpers; pub mod manifest; +pub mod rust_writer; pub mod sourcing; pub mod templates; pub use build::Profile; pub use errors::Error; pub use git::{Git, GitHub, Release}; -pub use helpers::{get_project_name_from_path, prefix_with_current_dir_if_needed, replace_in_file}; -pub use manifest::{add_crate_to_workspace, find_workspace_toml}; +pub use helpers::{ + format_dir, get_project_name_from_path, prefix_with_current_dir_if_needed, replace_in_file, +}; +pub use manifest::*; pub use templates::extractor::extract_template_files; static APP_USER_AGENT: &str = concat!(env!("CARGO_PKG_NAME"), "/", env!("CARGO_PKG_VERSION")); diff --git a/crates/pop-common/src/manifest.rs b/crates/pop-common/src/manifest.rs index ff84c1be8..fa2cb395c 100644 --- a/crates/pop-common/src/manifest.rs +++ b/crates/pop-common/src/manifest.rs @@ -1,13 +1,15 @@ // SPDX-License-Identifier: GPL-3.0 +pub mod types; use crate::Error; use anyhow; pub use cargo_toml::{Dependency, Manifest}; +use pathdiff::diff_paths; use std::{ fs::{read_to_string, write}, path::{Path, PathBuf}, }; -use toml_edit::{value, Array, DocumentMut, Item, Value}; +use toml_edit::{value, Array, DocumentMut, InlineTable, Item, Table, Value}; /// Parses the contents of a `Cargo.toml` manifest. /// @@ -56,6 +58,18 @@ pub fn find_workspace_toml(target_dir: &Path) -> Option { None } +pub fn find_crate_manifest(target_dir: &Path) -> Option { + let mut dir = target_dir; + while let Some(parent) = dir.parent() { + let cargo_toml = parent.join("Cargo.toml"); + if cargo_toml.exists() { + return Some(cargo_toml); + } + dir = parent; + } + None +} + /// This function is used to add a crate to a workspace. /// # Arguments /// * `workspace_toml` - The path to the workspace `Cargo.toml` @@ -97,6 +111,142 @@ pub fn add_crate_to_workspace(workspace_toml: &Path, crate_path: &Path) -> anyho Ok(()) } +pub fn add_crate_to_dependencies( + manifest_path: &Path, + crate_name: &str, + dependencie_format: types::CrateDependencie, +) -> Result<(), Error> { + fn do_add_crate_to_dependencies( + manifest_path: &Path, + dependencies: &mut Table, + crate_name: &str, + dependencie_format: types::CrateDependencie, + ) -> Result<(), Error> { + match dependencie_format { + types::CrateDependencie::Workspace => { + let mut crate_declaration = Table::new(); + crate_declaration.set_dotted(true); + crate_declaration.insert("workspace", value(true)); + dependencies.insert(crate_name, Item::Table(crate_declaration)); + }, + types::CrateDependencie::External { version } => { + let mut crate_declaration = InlineTable::new(); + crate_declaration.insert( + "version", + value(version) + .as_value() + .expect("version is String, so value(version) is Value::String; qed;") + .clone(), + ); + crate_declaration.insert( + "default-features", + value(false) + .as_value() + .expect("false is bool so value(false) is Value::Boolean; qed;") + .clone(), + ); + dependencies.insert(crate_name, value(crate_declaration)); + }, + types::CrateDependencie::Local { local_crate_path } => { + let mut crate_declaration = InlineTable::new(); + let relative_path = if let Some(path) = diff_paths( + &local_crate_path, + manifest_path.parent().expect("A file's always contained in a directory;qed;"), + ) + .and_then(|path| path.to_str().map(|path| path.to_string())) + { + path + } else { + return Err(Error::Config("Calling add_crate_to_dependencies with a internal crate whose path isn't valid.".to_string())) + }; + + crate_declaration.insert( + "path", + value(&relative_path) + .as_value() + .expect("version is String, so value(version) is Value::String; qed;") + .clone(), + ); + crate_declaration.insert( + "default-features", + value(false) + .as_value() + .expect("false is bool so value(false) is Value::Boolean; qed;") + .clone(), + ); + dependencies.insert(crate_name, value(crate_declaration)); + }, + } + Ok(()) + } + let content = read_to_string(manifest_path)?; + let mut doc = content.parse::()?; + if let Some(Item::Table(dependencies)) = doc.get_mut("dependencies") { + do_add_crate_to_dependencies(manifest_path, dependencies, crate_name, dependencie_format)?; + } else { + let mut dependencies = Table::new(); + do_add_crate_to_dependencies( + manifest_path, + &mut dependencies, + crate_name, + dependencie_format, + )?; + doc.insert("dependencies", Item::Table(dependencies)); + } + + write(manifest_path, doc.to_string())?; + Ok(()) +} + +pub fn find_crate_name(manifest_path: &Path) -> Result { + Ok(Manifest::from_path(manifest_path)? + .package + .ok_or(cargo_toml::Error::Other("Package not found in Cargo.toml")) + .map(|package| package.name)?) +} + +pub fn find_pallet_runtime_lib_path(pallet_path: &Path) -> Option { + if let Some(mut workspace_toml) = find_workspace_toml(pallet_path) { + match Manifest::from_path(&workspace_toml) + .ok() + .map(|manifest| manifest.workspace.map(|workspace| workspace.members)) + { + Some(Some(members)) if members.contains(&"runtime".to_string()) => { + workspace_toml.pop(); + Some(workspace_toml.join("runtime").join("src").join("lib.rs")) + }, + _ => None, + } + } else { + None + } +} + +pub fn find_pallet_runtime_impl_path(path: &Path) -> Option { + if let Some(mut workspace_toml) = find_workspace_toml(path) { + match Manifest::from_path(&workspace_toml) + .ok() + .map(|manifest| manifest.workspace.map(|workspace| workspace.members)) + { + Some(Some(members)) if members.contains(&"runtime".to_string()) => { + // Support for both cases: impl inside runtime lib.rs or defined inside + // configs/mod.rs + workspace_toml.pop(); + let runtime_src_path = workspace_toml.join("runtime").join("src"); + let config_mod_path = runtime_src_path.join("configs").join("mod.rs"); + if config_mod_path.is_file() { + Some(config_mod_path) + } else { + Some(runtime_src_path.join("lib.rs")) + } + }, + _ => None, + } + } else { + None + } +} + #[cfg(test)] mod tests { use super::*; diff --git a/crates/pop-common/src/manifest/types.rs b/crates/pop-common/src/manifest/types.rs new file mode 100644 index 000000000..ce714ab26 --- /dev/null +++ b/crates/pop-common/src/manifest/types.rs @@ -0,0 +1,10 @@ +// SPDX-License-Identifier: GPL-3.0 + +use std::path::PathBuf; + +#[derive(Debug, Clone, PartialEq)] +pub enum CrateDependencie { + External { version: String }, + Local { local_crate_path: PathBuf }, + Workspace, +} diff --git a/crates/pop-common/src/rust_writer.rs b/crates/pop-common/src/rust_writer.rs new file mode 100644 index 000000000..929eb9b5c --- /dev/null +++ b/crates/pop-common/src/rust_writer.rs @@ -0,0 +1,202 @@ +// SPDX-License-Identifier: GPL-3.0 + +use crate::{ + manifest::{ + add_crate_to_dependencies, find_crate_manifest, find_crate_name, + find_pallet_runtime_impl_path, types::CrateDependencie, + }, + Error, +}; +use prettyplease::unparse; +use std::{fs, path::Path}; +use syn::Type; + +mod expand; +mod helpers; +mod parse; +pub mod types; + +pub fn update_config_trait( + file_path: &Path, + type_name: &str, + trait_bounds: Vec<&str>, + default_config: types::DefaultConfigType, +) -> Result<(), Error> { + let mut ast = helpers::preserve_and_parse(fs::read_to_string(file_path)?)?; + + // Expand the config trait + expand::expand_pallet_config_trait(&mut ast, default_config, type_name, trait_bounds); + let generated_code = helpers::resolve_preserved(unparse(&ast)); + + fs::write(file_path, &generated_code).map_err(|_| { + Error::WriteError(format!("Path :{}", file_path.to_str().unwrap_or("Invalid UTF-8 path"))) + })?; + + Ok(()) +} + +pub fn add_type_to_runtimes( + pallet_path: &Path, + type_name: &str, + runtime_value: &str, + runtime_impl_path: Option<&Path>, +) -> Result<(), Error> { + fn do_add_type_to_runtime( + file_content: &str, + file_path: &Path, + pallet_manifest_path: &Path, + type_name: &str, + runtime_value: &str, + ) -> Result<(), Error> { + let mut ast = helpers::preserve_and_parse(file_content.to_string())?; + + let pallet_name = find_crate_name(pallet_manifest_path)?.replace("-", "_"); + + expand::expand_runtime_add_type_to_impl_block( + &mut ast, + type_name, + runtime_value, + &pallet_name, + ); + + let generated_code = helpers::resolve_preserved(unparse(&ast)); + + fs::write(file_path, generated_code).map_err(|_| { + Error::WriteError(format!( + "Path :{}", + file_path.to_str().unwrap_or("Invalid UTF-8 path") + )) + })?; + + Ok(()) + } + + let src = pallet_path.join("src"); + let pallet_manifest_path = pallet_path.join("Cargo.toml"); + // All pallets should have a mock runtime, so we add the type to it. + let mock_path = src.join("mock.rs"); + let mock_content = fs::read_to_string(&mock_path)?; + do_add_type_to_runtime( + &mock_content, + &mock_path, + &pallet_manifest_path, + type_name, + runtime_value, + )?; + + // If the pallet is contained inside a runtime add the type to that runtime as well + if let Some(runtime_impl_path) = runtime_impl_path + .map(|inner| inner.to_path_buf()) + .or_else(|| find_pallet_runtime_impl_path(pallet_path)) + { + let runtime_impl_content = fs::read_to_string(&runtime_impl_path)?; + do_add_type_to_runtime( + &runtime_impl_content, + &runtime_impl_path, + &pallet_manifest_path, + type_name, + runtime_value, + )?; + } + Ok(()) +} + +pub fn add_type_to_config_preludes( + file_path: &Path, + type_name: &str, + default_value: &str, +) -> Result<(), Error> { + let mut ast = helpers::preserve_and_parse(fs::read_to_string(file_path)?)?; + + // Expand the config_preludes + expand::expand_pallet_config_preludes(&mut ast, type_name, default_value); + + let generated_code = helpers::resolve_preserved(unparse(&ast)); + + fs::write(file_path, generated_code).map_err(|_| { + Error::WriteError(format!("Path :{}", file_path.to_str().unwrap_or("Invalid UTF-8 path"))) + })?; + + Ok(()) +} + +pub fn add_pallet_to_runtime_module( + pallet_name: &str, + runtime_lib_path: &Path, + pallet_dependencie_type: CrateDependencie, +) -> Result<(), Error> { + // Find the pallet name and the pallet item to be added to the runtime. If the pallet_name is + // behind the form pallet-some-thing, pallet_item becomes Something. + let pallet_item = helpers::capitalize_str( + &pallet_name + .split("pallet-") + .last() + .ok_or(Error::Config( + "Pallet crates are supposed to be called pallet-something.".to_string(), + ))? + .replace("-", ""), + ); + + let mut ast = helpers::preserve_and_parse(fs::read_to_string(runtime_lib_path)?)?; + + // Parse the runtime to find which of the runtime macros is being used and the highest + // pallet index used (if needed). + let (highest_index, used_macro) = + parse::find_highest_pallet_index_and_runtime_macro_version(&ast); + // Expand the ast with the new pallet. pallet-some-thing becomes pallet_some_thing in the code + expand::expand_runtime_add_pallet( + &mut ast, + highest_index, + used_macro, + &pallet_name.replace("-", "_"), + &pallet_item, + ); + + let generated_code = helpers::resolve_preserved(unparse(&ast)); + + fs::write(runtime_lib_path, generated_code).map_err(|_| { + Error::WriteError(format!( + "Path :{}", + runtime_lib_path.to_str().unwrap_or("Invalid UTF-8 path") + )) + })?; + + // Update the crate's manifest to add the pallet crate + let runtime_manifest = find_crate_manifest(runtime_lib_path) + .expect("Runtime is a crate, so it contains a manifest; qed;"); + + add_crate_to_dependencies(&runtime_manifest, pallet_name, pallet_dependencie_type)?; + + Ok(()) +} + +pub fn add_pallet_impl_block_to_runtime( + pallet_name: &str, + runtime_impl_path: &Path, + parameter_types: Vec, + types: Vec, + values: Vec, + default_config: bool, +) -> Result<(), Error> { + let mut ast = helpers::preserve_and_parse(fs::read_to_string(runtime_impl_path)?)?; + + // Expand the runtime to add the impl_block + expand::expand_runtime_add_impl_block( + &mut ast, + &pallet_name.replace("-", "_"), + parameter_types, + types, + values, + default_config, + ); + + let generated_code = helpers::resolve_preserved(unparse(&ast)); + + fs::write(runtime_impl_path, generated_code).map_err(|_| { + Error::WriteError(format!( + "Path :{}", + runtime_impl_path.to_str().unwrap_or("Invalid UTF-8 path") + )) + })?; + Ok(()) +} diff --git a/crates/pop-common/src/rust_writer/expand.rs b/crates/pop-common/src/rust_writer/expand.rs new file mode 100644 index 000000000..23a4e45ab --- /dev/null +++ b/crates/pop-common/src/rust_writer/expand.rs @@ -0,0 +1,269 @@ +// SPDX-License-Identifier: GPL-3.0 + +use crate::rust_writer::{helpers::capitalize_str, types::*}; +use proc_macro2::{Group, Literal, Span, TokenStream, TokenTree}; +use syn::{ + parse_quote, Expr, File, Ident, ImplItem, Item, ItemImpl, ItemMacro, ItemMod, ItemTrait, Macro, + Meta, MetaList, TraitItem, Type, +}; + +pub(crate) fn expand_pallet_config_trait( + ast: &mut File, + default_config: DefaultConfigType, + type_name: &str, + trait_bounds: Vec<&str>, +) { + let type_name = Ident::new(&capitalize_str(type_name), Span::call_site()); + let trait_bounds = trait_bounds + .iter() + .map(|bound| Ident::new(&capitalize_str(bound), Span::call_site())) + .collect::>(); + for item in &mut ast.items { + match item { + Item::Mod(ItemMod { ident, content, .. }) + if *ident == "pallet" && content.is_some() => + { + let (_, items) = + content.as_mut().expect("content is always Some thanks to the match guard"); + for item in items { + match item { + Item::Trait(ItemTrait { ident, items, .. }) if *ident == "Config" => { + items.push(match default_config { + DefaultConfigType::Default => TraitItem::Type(parse_quote! { + ///EMPTY_LINE + type #type_name: #(#trait_bounds +)*; + }), + DefaultConfigType::NoDefault => TraitItem::Type(parse_quote! { + ///EMPTY_LINE + #[pallet::no_default] + type #type_name: #(#trait_bounds +)*; + }), + DefaultConfigType::NoDefaultBounds => { + TraitItem::Type(parse_quote! { + ///EMPTY_LINE + #[pallet::no_default_bounds] + type #type_name: #(#trait_bounds +)*; + }) + }, + }); + }, + _ => continue, + } + } + }, + _ => continue, + } + } +} + +pub(crate) fn expand_pallet_config_preludes(ast: &mut File, type_name: &str, default_value: &str) { + let type_name = Ident::new(&capitalize_str(type_name), Span::call_site()); + let default_value: Type = parse_quote! {#default_value}; + + for item in &mut ast.items { + match item { + // In case file_path points to lib.rs, config_preludes is contained inside pallet mod in + // lib.rs so we have to look for that module and the impl blocks for structs defined + // inside it, equivalently impl blocks using the register_default_impl macro + Item::Mod(ItemMod { ident, content, .. }) + if *ident == "pallet" && content.is_some() => + { + let (_, items) = + content.as_mut().expect("content is always Some thanks to the match guard"); + for item in items { + match item { + Item::Mod(ItemMod { ident, content, .. }) + if *ident == "config_preludes" && content.is_some() => + { + let (_, items) = content + .as_mut() + .expect("content is always Some thanks to the match guard"); + for item in items { + match item { + Item::Impl(ItemImpl { attrs, items, .. }) + if attrs.iter().any(|attribute| { + if let Meta::List(MetaList { + path: syn::Path { segments, .. }, + .. + }) = &attribute.meta + { + segments.iter().any(|segment| { + segment.ident == "register_default_impl" + }) + } else { + false + } + }) => + items.push(ImplItem::Type(parse_quote! { + type #type_name = #default_value; + })), + _ => continue, + } + } + }, + _ => continue, + } + } + }, + // In case file_path points to config_preludes.rs, we have to look for the impl blocks + // for structs defined inside the file. + Item::Impl(ItemImpl { attrs, items, .. }) + if attrs.iter().any(|attribute| { + if let Meta::List(MetaList { path: syn::Path { segments, .. }, .. }) = + &attribute.meta + { + segments.iter().any(|segment| segment.ident == "register_default_impl") + } else { + false + } + }) => + items.push(ImplItem::Type(parse_quote! { + type #type_name = #default_value; + })), + _ => continue, + } + } +} + +pub(crate) fn expand_runtime_add_pallet( + ast: &mut File, + highest_index: u8, + used_macro: RuntimeUsedMacro, + pallet_name: &str, + pallet_item: &str, +) { + let pallet_item = Ident::new(pallet_item, Span::call_site()); + let pallet_name = Ident::new(pallet_name, Span::call_site()); + + match used_macro { + RuntimeUsedMacro::Runtime => { + // Convert the highest_index in Ident + let highest_index = Literal::u8_unsuffixed(highest_index.saturating_add(1)); + for item in &mut ast.items { + match item { + Item::Mod(ItemMod { ident, content, .. }) + if *ident == "runtime" && content.is_some() => + { + let (_, items) = content + .as_mut() + .expect("content is always Some thanks to the match guard"); + items.push(Item::Type(parse_quote! { + #[runtime::pallet_index(#highest_index)] + pub type #pallet_item = #pallet_name; + })); + }, + _ => continue, + } + } + }, + RuntimeUsedMacro::ConstructRuntime => { + for item in &mut ast.items { + match item { + Item::Macro(ItemMacro { + mac: Macro { path: syn::Path { segments, .. }, tokens, .. }, + .. + }) if segments.iter().any(|segment| segment.ident == "construct_runtime") => { + // construct_runtime! contains the definition of either a struct or an + // enum whose variants/items are the pallets, so basically the pallets + // are containedd inside a TokenTree::Group and we can suppose that + // there's nothing else inside construct_runtime, so it's enough with + // finding a group. + let mut token_tree: Vec = tokens.clone().into_iter().collect(); + for token in token_tree.iter_mut() { + if let TokenTree::Group(group) = token { + let mut stream = group.stream(); + stream.extend::(parse_quote! { + #pallet_item: #pallet_name, + }); + let new_group = Group::new(group.delimiter(), stream); + *token = TokenTree::Group(new_group); + } + } + *tokens = TokenStream::from_iter(token_tree); + }, + _ => continue, + } + } + }, + RuntimeUsedMacro::NotFound => (), + } +} + +pub(crate) fn expand_runtime_add_impl_block( + ast: &mut File, + pallet_name: &str, + parameter_types: Vec, + types: Vec, + values: Vec, + default_config: bool, +) { + let pallet_name = Ident::new(pallet_name, Span::call_site()); + let types: Vec = types + .iter() + .map(|type_| Ident::new(&capitalize_str(type_), Span::call_site())) + .collect(); + let parameter_idents: Vec = parameter_types + .iter() + .map(|item| Ident::new(&item.ident, Span::call_site())) + .collect(); + let parameter_types_types: Vec<&Type> = + parameter_types.iter().map(|item| &item.type_).collect(); + let parameter_values: Vec<&Expr> = parameter_types.iter().map(|item| &item.value).collect(); + let items = &mut ast.items; + + // It's enough checking that parameter_idents isn't empty, by construction all the 3 Vec have + // the same lenght + if !parameter_idents.is_empty() { + items.push(Item::Macro(parse_quote! { + ///EMPTY_LINE + parameter_types!{ + #( + pub #parameter_idents: #parameter_types_types = #parameter_values; + )* + } + })); + } + if default_config { + items.push(Item::Impl(parse_quote! { + ///EMPTY_LINE + #[derive_impl(#pallet_name::config_preludes::TestDefaultConfig)] + impl #pallet_name::Config for Runtime{ + #( + type #types = #values; + )* + } + })); + } else { + items.push(Item::Impl(parse_quote! { + ///EMPTY_LINE + impl #pallet_name::Config for Runtime{ + #( + type #types = #values; + )* + } + })); + } +} + +pub(crate) fn expand_runtime_add_type_to_impl_block( + ast: &mut File, + type_name: &str, + runtime_value: &str, + pallet_name: &str, +) { + let type_name = Ident::new(&capitalize_str(type_name), Span::call_site()); + let runtime_value = Ident::new(&capitalize_str(runtime_value), Span::call_site()); + for item in &mut ast.items { + match item { + Item::Impl(ItemImpl { + trait_: Some((_, syn::Path { segments, .. }, _)), + items, + .. + }) if segments.iter().any(|segment| segment.ident == pallet_name) => + items.push(ImplItem::Type(parse_quote! { + type #type_name = #runtime_value; + })), + _ => continue, + } + } +} diff --git a/crates/pop-common/src/rust_writer/helpers.rs b/crates/pop-common/src/rust_writer/helpers.rs new file mode 100644 index 000000000..7dfd13830 --- /dev/null +++ b/crates/pop-common/src/rust_writer/helpers.rs @@ -0,0 +1,75 @@ +use crate::Error; +use regex::{Captures, Regex}; +use syn::{parse_file, File}; + +pub(crate) fn preserve_and_parse(code: String) -> Result { + let mut preserved_code = String::new(); + code.lines().for_each(|line| { + let trimmed_line = line.trim_start(); + if trimmed_line.starts_with("//") && + !trimmed_line.starts_with("///") && + !trimmed_line.starts_with("//!") + { + // Use trimmed_line to avoid tabs before TEMP_DOC + preserved_code + .push_str(&format!("///TEMP_DOC{}\ntype temp_marker = ();\n", trimmed_line)); + } else if trimmed_line.starts_with("#![") { + // Global attributes may be hard to parse with syn, so we comment them to solve + // potential issues related to them. + preserved_code + .push_str(&format!("///TEMP_DOC{}\ntype temp_marker = ();\n", trimmed_line)); + } else if trimmed_line.is_empty() { + preserved_code.push_str("///EMPTY_LINE\ntype temp_marker = ();\n"); + } else { + preserved_code.push_str(&format!("{}\n", line)); + } + }); + + Ok(parse_file(&preserved_code)?) +} + +pub(crate) fn resolve_preserved(code: String) -> String { + let mut output = String::new(); + // Inside declarative macros invocations, everything is a token so the comments became #[doc]. + // ///EMPTY_LINE comments became #[doc = "EMPTY_LINE"] which are 4 tokens in the AST. When the + // AST is converted to a String, new line characters can appear in the middle of any of those + // tokens, so to properly convert them in a new line we can use regex. + let mut re = + Regex::new(r#"#\s*\[\s*doc\s*=\s*"EMPTY_LINE"\s*\]"#).expect("The regex is valid; qed;"); + let code = re.replace_all(&code, "\n").to_string(); + // Same happens with 'type temp_marker = ();'. This lines also delete them from everywhere, not + // just inside declarative macros + re = Regex::new(r"type\s+temp_marker\s*=\s*\(\);\s*").expect("The regex is valid; qed;"); + let code = re.replace_all(&code, "\n").to_string(); + // Same happens with #[doc= "TEMP_DOC whatever"] but we also need to keep track of "whatever". + // As the #[doc] attribute may be present anywhere, be sure to keep spaces before and after the + // comment to don't leave commented some lines of code. + re = Regex::new(r#"#\s*\[\s*doc\s*=\s*"TEMP_DOC(.*?)"\s*\]"#).expect("The regex is valid;qed;"); + let code = re.replace_all(&code, |caps: &Captures| format!("\n{}\n", &caps[1])).to_string(); + + // Resolve the comments outside declarative macros. + code.lines().for_each(|line| { + let trimmed_line = line.trim_start(); + + match trimmed_line { + comment if trimmed_line.strip_prefix("///TEMP_DOC").is_some() => + output.push_str(comment + .strip_prefix("///TEMP_DOC") + .expect("The match guard guarantees this is always some; qed;") + ), + _ if trimmed_line.strip_prefix("///EMPTY_LINE").is_some() => output.push('\n'), + _ => output.push_str(&format!("{}\n", line)), + } + }); + output +} + +pub(crate) fn capitalize_str(input: &str) -> String { + if input.is_empty() { + return String::new(); + } + + let first_char = input.chars().next().expect("The introduced str isn't empty").to_uppercase(); + let rest = &input[1..]; + format!("{}{}", first_char, rest) +} diff --git a/crates/pop-common/src/rust_writer/parse.rs b/crates/pop-common/src/rust_writer/parse.rs new file mode 100644 index 000000000..1af4b5b01 --- /dev/null +++ b/crates/pop-common/src/rust_writer/parse.rs @@ -0,0 +1,66 @@ +// SPDX-License-Identifier: GPL-3.0 + +use crate::rust_writer::types::RuntimeUsedMacro; +use std::cmp; +use syn::{File, Item, ItemMacro, ItemMod, ItemType, Macro, Meta, MetaList}; + +/// Find the highest implemented pallet index in the outer enum if using the macro +/// #[runtime]. We suppose it's a u8, it's not likely that a runtime implements more than 256 +/// pallets. Also determine if the runtime uses either #[runtime] or construct_runtime!, in +/// the latter we don't find the highest_index as specifying indexes isn't mandatory and +/// construct runtime will infer the pallet index. +pub(crate) fn find_highest_pallet_index_and_runtime_macro_version( + ast: &File, +) -> (u8, RuntimeUsedMacro) { + let mut highest_index = 0u8; + let mut used_macro = RuntimeUsedMacro::NotFound; + for item in &ast.items { + match item { + // If runtime is using the new macro #[runtime], the pallets are listed inside a + // module called runtime as types annotated with #[runtime::pallet_index(n)] where n + // is the pallet index. + Item::Mod(ItemMod { ident, content, .. }) + if *ident == "runtime" && content.is_some() => + { + used_macro = RuntimeUsedMacro::Runtime; + let (_, items) = + content.as_ref().expect("content is always Some thanks to the match guard"); + for item in items { + if let Item::Type(ItemType { attrs, .. }) = item { + if let Some(pallet_index_attribute) = attrs.iter().find(|attribute| { + if let Meta::List(MetaList { + path: syn::Path { segments, .. }, .. + }) = &attribute.meta + { + segments.iter().any(|segment| segment.ident == "pallet_index") + } else { + false + } + }) { + // As the attribute at this point is for sure + // #[runtime::pallet_index(n)], so meta is a MetaList where tokens + // is a TokenStream of exactly one element: the literal n. + let mut pallet_index = 0u8; + if let Meta::List(MetaList { tokens, .. }) = + &pallet_index_attribute.meta + { + pallet_index = tokens.clone().into_iter().next().expect("This iterator has one element due to the attribute shape; qed;").to_string().parse::().expect("The macro #[runtime::pallet_index(n)] is only valid if n is a valid number, so we can parse it to u8; qed;"); + } + // Despite the pallets will likely be ordered by call_index in the + // runtime, that's not always true, so we keep the highest index in + // order to give the added pallet the next index + highest_index = cmp::max(highest_index, pallet_index); + } + } + } + }, + // If runtime is using the construct_runtime! macro, keep track of it + Item::Macro(ItemMacro { + mac: Macro { path: syn::Path { segments, .. }, .. }, .. + }) if segments.iter().any(|segment| segment.ident == "construct_runtime") => + used_macro = RuntimeUsedMacro::ConstructRuntime, + _ => continue, + } + } + (highest_index, used_macro) +} diff --git a/crates/pop-common/src/rust_writer/types.rs b/crates/pop-common/src/rust_writer/types.rs new file mode 100644 index 000000000..9f41f0907 --- /dev/null +++ b/crates/pop-common/src/rust_writer/types.rs @@ -0,0 +1,24 @@ +// SPDX-License-Identifier: GPL-3.0 + +use syn::{Expr, Type}; + +#[derive(Debug, Clone, PartialEq)] +pub enum DefaultConfigType { + Default, + NoDefault, + NoDefaultBounds, +} + +#[derive(Debug, Clone, PartialEq)] +pub enum RuntimeUsedMacro { + Runtime, + ConstructRuntime, + NotFound, +} + +#[derive(Debug, Clone, PartialEq)] +pub struct ParameterTypes { + pub ident: String, + pub type_: Type, + pub value: Expr, +} diff --git a/crates/pop-parachains/Cargo.toml b/crates/pop-parachains/Cargo.toml index 1ac8166b0..76c42495c 100644 --- a/crates/pop-parachains/Cargo.toml +++ b/crates/pop-parachains/Cargo.toml @@ -17,6 +17,7 @@ glob.workspace = true serde_json.workspace = true strum.workspace = true strum_macros.workspace = true +syn.workspace = true tar.workspace = true tempfile.workspace = true thiserror.workspace = true diff --git a/crates/pop-parachains/src/new_pallet/new_pallet_options.rs b/crates/pop-parachains/src/new_pallet/new_pallet_options.rs index d0109a3d6..547e15f15 100644 --- a/crates/pop-parachains/src/new_pallet/new_pallet_options.rs +++ b/crates/pop-parachains/src/new_pallet/new_pallet_options.rs @@ -1,5 +1,6 @@ use clap::ValueEnum; use strum_macros::{EnumIter, EnumMessage}; +use syn::{parse_quote, Type}; /// This enum is used to register from the CLI which types that are kind of usual in config traits /// are included in the pallet @@ -27,6 +28,16 @@ pub enum TemplatePalletConfigCommonTypes { Currency, } +impl TemplatePalletConfigCommonTypes { + pub fn common_value(&self) -> Type { + match self { + TemplatePalletConfigCommonTypes::RuntimeEvent => parse_quote! {RuntimeEvent}, + TemplatePalletConfigCommonTypes::RuntimeOrigin => parse_quote! {RuntimeOrigin}, + TemplatePalletConfigCommonTypes::Currency => parse_quote! {Balances}, + } + } +} + /// This enum is used to determine which storage shape has a storage item in the pallet #[derive(Debug, Copy, Clone, PartialEq, EnumIter, EnumMessage, ValueEnum)] pub enum TemplatePalletStorageTypes { diff --git a/crates/pop-parachains/templates/pallet/advanced_mode/src/lib.rs.templ b/crates/pop-parachains/templates/pallet/advanced_mode/src/lib.rs.templ index e64b37dee..af51f966b 100644 --- a/crates/pop-parachains/templates/pallet/advanced_mode/src/lib.rs.templ +++ b/crates/pop-parachains/templates/pallet/advanced_mode/src/lib.rs.templ @@ -18,7 +18,7 @@ use frame::traits::{fungible, VariantCount}; pub mod config_preludes; {{- endif }} -use pallet::*; +pub use pallet::*; // A module where the main logic of the pallet is stored mod pallet_logic; From 3ee92dd1fd58358c473d83e72fa66a114315b5b8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1s=20Senovilla=20Polo?= Date: Mon, 30 Sep 2024 20:46:14 +0200 Subject: [PATCH 02/46] Small bug with config_preludes expansion --- crates/pop-common/src/rust_writer/expand.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/crates/pop-common/src/rust_writer/expand.rs b/crates/pop-common/src/rust_writer/expand.rs index 23a4e45ab..1542e4d09 100644 --- a/crates/pop-common/src/rust_writer/expand.rs +++ b/crates/pop-common/src/rust_writer/expand.rs @@ -58,7 +58,7 @@ pub(crate) fn expand_pallet_config_trait( pub(crate) fn expand_pallet_config_preludes(ast: &mut File, type_name: &str, default_value: &str) { let type_name = Ident::new(&capitalize_str(type_name), Span::call_site()); - let default_value: Type = parse_quote! {#default_value}; + let default_value = Ident::new(default_value, Span::call_site()); for item in &mut ast.items { match item { @@ -204,7 +204,7 @@ pub(crate) fn expand_runtime_add_impl_block( .collect(); let parameter_idents: Vec = parameter_types .iter() - .map(|item| Ident::new(&item.ident, Span::call_site())) + .map(|item| Ident::new(&capitalize_str(&item.ident), Span::call_site())) .collect(); let parameter_types_types: Vec<&Type> = parameter_types.iter().map(|item| &item.type_).collect(); @@ -252,7 +252,7 @@ pub(crate) fn expand_runtime_add_type_to_impl_block( pallet_name: &str, ) { let type_name = Ident::new(&capitalize_str(type_name), Span::call_site()); - let runtime_value = Ident::new(&capitalize_str(runtime_value), Span::call_site()); + let runtime_value = Ident::new(runtime_value, Span::call_site()); for item in &mut ast.items { match item { Item::Impl(ItemImpl { From 47d4a4186d5c3698f7416541d6524f9d241e3a73 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1s=20Senovilla=20Polo?= Date: Tue, 1 Oct 2024 21:41:14 +0200 Subject: [PATCH 03/46] Workaround to preseve non-used declarative macros if rust_writer is used --- crates/pop-common/src/errors.rs | 2 +- crates/pop-common/src/rust_writer.rs | 15 ++-- crates/pop-common/src/rust_writer/helpers.rs | 89 ++++++++++++++++++-- 3 files changed, 91 insertions(+), 15 deletions(-) diff --git a/crates/pop-common/src/errors.rs b/crates/pop-common/src/errors.rs index 117c780eb..70942a0b3 100644 --- a/crates/pop-common/src/errors.rs +++ b/crates/pop-common/src/errors.rs @@ -21,7 +21,7 @@ pub enum Error { ParseError(#[from] url::ParseError), #[error("SourceError error: {0}")] SourceError(#[from] sourcing::Error), - #[error("Syn parse error: {0}. To preserve your not-docs comments and blank lines, Pop-CLi temporarily transform them to comments followed by a marker type associated to that doc. This error is likely originated cause one of your files has a not-doc comment/blank line in a place where that marker type cannot be placed. Example:\nmatch option{{\n\t//This is the painful comment\n\tSome(some)=>(),\n\tNone=>()\n}}")] + #[error("Syn parse error: {0}. To preserve your not-docs comments, blank lines and declarative macro invocations, Pop-CLi temporarily transform them to comments followed by a marker type associated to that doc. This error is likely originated cause one of your files has such an element in a place where that marker type cannot be placed. Example: the type marker cannot be defined inside a match block\nmatch option{{\n\t//This is the painful comment\n\tSome(some)=>(),\n\tNone=>()\n}}")] SynError(#[from] syn::Error), #[error("TemplateError error: {0}")] TemplateError(#[from] templates::Error), diff --git a/crates/pop-common/src/rust_writer.rs b/crates/pop-common/src/rust_writer.rs index 929eb9b5c..2a816c69b 100644 --- a/crates/pop-common/src/rust_writer.rs +++ b/crates/pop-common/src/rust_writer.rs @@ -22,7 +22,7 @@ pub fn update_config_trait( trait_bounds: Vec<&str>, default_config: types::DefaultConfigType, ) -> Result<(), Error> { - let mut ast = helpers::preserve_and_parse(fs::read_to_string(file_path)?)?; + let mut ast = helpers::preserve_and_parse(fs::read_to_string(file_path)?, vec![])?; // Expand the config trait expand::expand_pallet_config_trait(&mut ast, default_config, type_name, trait_bounds); @@ -48,7 +48,7 @@ pub fn add_type_to_runtimes( type_name: &str, runtime_value: &str, ) -> Result<(), Error> { - let mut ast = helpers::preserve_and_parse(file_content.to_string())?; + let mut ast = helpers::preserve_and_parse(file_content.to_string(), vec![])?; let pallet_name = find_crate_name(pallet_manifest_path)?.replace("-", "_"); @@ -106,7 +106,7 @@ pub fn add_type_to_config_preludes( type_name: &str, default_value: &str, ) -> Result<(), Error> { - let mut ast = helpers::preserve_and_parse(fs::read_to_string(file_path)?)?; + let mut ast = helpers::preserve_and_parse(fs::read_to_string(file_path)?, vec![])?; // Expand the config_preludes expand::expand_pallet_config_preludes(&mut ast, type_name, default_value); @@ -137,7 +137,12 @@ pub fn add_pallet_to_runtime_module( .replace("-", ""), ); - let mut ast = helpers::preserve_and_parse(fs::read_to_string(runtime_lib_path)?)?; + // As the runtime may be constructed with construc_runtime!, we have to avoid preserving that + // macro with comments + let mut ast = helpers::preserve_and_parse( + fs::read_to_string(runtime_lib_path)?, + vec!["construct_runtime"], + )?; // Parse the runtime to find which of the runtime macros is being used and the highest // pallet index used (if needed). @@ -178,7 +183,7 @@ pub fn add_pallet_impl_block_to_runtime( values: Vec, default_config: bool, ) -> Result<(), Error> { - let mut ast = helpers::preserve_and_parse(fs::read_to_string(runtime_impl_path)?)?; + let mut ast = helpers::preserve_and_parse(fs::read_to_string(runtime_impl_path)?, vec![])?; // Expand the runtime to add the impl_block expand::expand_runtime_add_impl_block( diff --git a/crates/pop-common/src/rust_writer/helpers.rs b/crates/pop-common/src/rust_writer/helpers.rs index 7dfd13830..2583747b1 100644 --- a/crates/pop-common/src/rust_writer/helpers.rs +++ b/crates/pop-common/src/rust_writer/helpers.rs @@ -2,15 +2,20 @@ use crate::Error; use regex::{Captures, Regex}; use syn::{parse_file, File}; -pub(crate) fn preserve_and_parse(code: String) -> Result { +pub(crate) fn preserve_and_parse(code: String, exempt_macros: Vec<&str>) -> Result { + // First of all, preserve declarative macros except those that are exempted. As declarative + // macros invocations AST are basically a TokenStream, they don't keep format when unparsed and + // rustfmt doesn't work well at all inside all macro invocations, so it's better to keep them + // commented unless we explicitly need to modify them + let code = preserve_macro_invocations(code, exempt_macros); let mut preserved_code = String::new(); + // Preserve the rest of the code code.lines().for_each(|line| { let trimmed_line = line.trim_start(); if trimmed_line.starts_with("//") && !trimmed_line.starts_with("///") && !trimmed_line.starts_with("//!") { - // Use trimmed_line to avoid tabs before TEMP_DOC preserved_code .push_str(&format!("///TEMP_DOC{}\ntype temp_marker = ();\n", trimmed_line)); } else if trimmed_line.starts_with("#![") { @@ -21,16 +26,16 @@ pub(crate) fn preserve_and_parse(code: String) -> Result { } else if trimmed_line.is_empty() { preserved_code.push_str("///EMPTY_LINE\ntype temp_marker = ();\n"); } else { - preserved_code.push_str(&format!("{}\n", line)); + preserved_code.push_str(&format!("{}\n", trimmed_line)); } }); - Ok(parse_file(&preserved_code)?) } pub(crate) fn resolve_preserved(code: String) -> String { let mut output = String::new(); - // Inside declarative macros invocations, everything is a token so the comments became #[doc]. + // Inside non-preserved declarative macros invocations, everything is a token so the doc + // comments became #[doc] in order to preserve them (tokens doesn't accept doc comments). // ///EMPTY_LINE comments became #[doc = "EMPTY_LINE"] which are 4 tokens in the AST. When the // AST is converted to a String, new line characters can appear in the middle of any of those // tokens, so to properly convert them in a new line we can use regex. @@ -52,11 +57,19 @@ pub(crate) fn resolve_preserved(code: String) -> String { let trimmed_line = line.trim_start(); match trimmed_line { - comment if trimmed_line.strip_prefix("///TEMP_DOC").is_some() => - output.push_str(comment + comment if trimmed_line.strip_prefix("///TEMP_DOC").is_some() => output.push_str( + comment .strip_prefix("///TEMP_DOC") - .expect("The match guard guarantees this is always some; qed;") - ), + .expect("The match guard guarantees this is always some; qed;"), + ), + comment if trimmed_line.strip_prefix("///TEMP_MACRO").is_some() => output.push_str( + &format!( + "{}\n", + comment + .strip_prefix("///TEMP_MACRO") + .expect("The match guard guarantees this is always some; qed;"), + ) + ), _ if trimmed_line.strip_prefix("///EMPTY_LINE").is_some() => output.push('\n'), _ => output.push_str(&format!("{}\n", line)), } @@ -73,3 +86,61 @@ pub(crate) fn capitalize_str(input: &str) -> String { let rest = &input[1..]; format!("{}{}", first_char, rest) } + +fn preserve_macro_invocations(code: String, exempt_macros: Vec<&str>) -> String { + let re = + Regex::new(r"(?P[a-zA-Z_]+)!\s*[\{\(\[]").expect("The regex is valid; qed;"); + let mut result = String::new(); + + let mut macro_block = String::new(); + + let mut delimiter_counts = vec![ + ('{', 0), + ('}', 0), + ('(', 0), + (')', 0), + ('[', 0), + (']', 0), + ]; + + for line in code.lines() { + match re.find(line) { + Some(found) + if exempt_macros.contains( + &&re.captures(found.as_str()).expect( + "As found has been found with the regex, it captures the macro_name; qed;", + )["macro_name"], + ) => + result.push_str(&format!("{}\n", line)), + Some(_) => { + macro_block.push_str(&format!("{}\n", line)); + for (char, count) in delimiter_counts.iter_mut() { + if line.contains(*char) { + *count += line.matches(*char).count(); + } + } + }, + None if macro_block.is_empty() => result.push_str(&format!("{}\n", line)), + _ => { + macro_block.push_str(&format!("{}\n", line)); + for (char, count) in delimiter_counts.iter_mut() { + if line.contains(*char) { + *count += line.matches(*char).count(); + } + } + }, + } + if delimiter_counts[0].1 == delimiter_counts[1].1 && + delimiter_counts[2].1 == delimiter_counts[3].1 && + delimiter_counts[4].1 == delimiter_counts[5].1 && + !macro_block.is_empty() + { + macro_block.lines().for_each(|line| { + result.push_str(&format!("///TEMP_MACRO{}\n", line)); + }); + result.push_str("type temp_marker = ();\n"); + macro_block = String::new(); + } + }; + result +} From caad226d2faf461581a306c0481d04b269a59e04 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1s=20Senovilla=20Polo?= Date: Sat, 5 Oct 2024 12:22:40 +0200 Subject: [PATCH 04/46] Refactor: pop add runtime-pallet => pop add pallet + it detects if it's been run in a runtime workspace --- crates/pop-cli/src/commands/add/mod.rs | 4 +- .../src/commands/add/runtime_pallet.rs | 98 ------------------- .../add/runtime_pallet/common_pallets.rs | 72 -------------- .../src/commands/add/runtime_pallet/tests.rs | 1 - crates/pop-cli/src/commands/mod.rs | 2 +- 5 files changed, 3 insertions(+), 174 deletions(-) delete mode 100644 crates/pop-cli/src/commands/add/runtime_pallet.rs delete mode 100644 crates/pop-cli/src/commands/add/runtime_pallet/common_pallets.rs delete mode 100644 crates/pop-cli/src/commands/add/runtime_pallet/tests.rs diff --git a/crates/pop-cli/src/commands/add/mod.rs b/crates/pop-cli/src/commands/add/mod.rs index e12e4917e..849026ec0 100644 --- a/crates/pop-cli/src/commands/add/mod.rs +++ b/crates/pop-cli/src/commands/add/mod.rs @@ -3,7 +3,7 @@ use clap::{Args, Subcommand}; pub mod config_type; -pub mod runtime_pallet; +pub mod pallet; /// Arguments for adding a new feature to existing code #[derive(Args)] @@ -21,5 +21,5 @@ pub enum Command { ConfigType(config_type::AddConfigTypeCommand), /// Add a new pallet to an existing runtime #[clap(alias = "P")] - RuntimePallet(runtime_pallet::AddRuntimePalletCommand), + Pallet(pallet::AddPalletCommand), } diff --git a/crates/pop-cli/src/commands/add/runtime_pallet.rs b/crates/pop-cli/src/commands/add/runtime_pallet.rs deleted file mode 100644 index 5761ed110..000000000 --- a/crates/pop-cli/src/commands/add/runtime_pallet.rs +++ /dev/null @@ -1,98 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0 - -use crate::{ - cli::{traits::Cli as _, Cli}, - multiselect_pick, -}; -use clap::{error::ErrorKind, Args, Command}; -use cliclack::multiselect; -use pop_common::{ - find_pallet_runtime_impl_path, find_workspace_toml, format_dir, - manifest::types::CrateDependencie, rust_writer, -}; -use std::path::PathBuf; -use strum::{EnumMessage, IntoEnumIterator}; - -mod common_pallets; - -#[cfg(test)] -mod tests; - -#[derive(Args, Debug, Clone)] -pub struct AddRuntimePalletCommand { - #[arg(short, long, required = true, help = "Specify the path to the runtime crate.")] - pub(crate) path: PathBuf, - #[arg(long, value_enum, num_args(1..), required = false, help = "The pallets you want to include to your runtime.")] - pub(crate) pallets: Vec, - #[arg( - long, - help = "Pop-Cli will place the impl blocks for your pallets' Config traits inside configs/mod.rs or lib.rs in the runtime crate by default. If you want to place them in another path, use this option to specify it." - )] - pub(crate) runtime_impl_path: Option, -} - -impl AddRuntimePalletCommand { - pub(crate) async fn execute(self) -> anyhow::Result<()> { - Cli.intro("Add a new pallet to your runtime")?; - let mut cmd = Command::new(""); - let src = &self.path.join("src"); - let lib_path = src.join("lib.rs"); - if !lib_path.is_file() { - cmd.error( - ErrorKind::InvalidValue, - "Make sure that the used path correspond to a runtime crate.", - ) - .exit(); - } - - let runtime_impl_path = - match self.runtime_impl_path.or_else(|| find_pallet_runtime_impl_path(&lib_path)) { - Some(runtime_impl_path) => runtime_impl_path, - None => cmd - .error( - ErrorKind::InvalidValue, - "Make sure that the used path correspond to a runtime crate.", - ) - .exit(), - }; - - let spinner = cliclack::spinner(); - spinner.start("Updating runtime..."); - - let pallets = if self.pallets.is_empty() { - multiselect_pick!( - common_pallets::CommonPallets, - "Select the pallets you want to include in your runtime" - ) - } else { - self.pallets - }; - - for pallet in pallets { - // Add the pallet to the crate and to the runtime module - rust_writer::add_pallet_to_runtime_module( - &pallet.get_crate_name(), - &lib_path, - CrateDependencie::External { version: pallet.get_version() }, - )?; - // Add the pallet impl block - rust_writer::add_pallet_impl_block_to_runtime( - &pallet.get_crate_name(), - &runtime_impl_path, - pallet.get_parameter_types(), - pallet.get_config_types(), - pallet.get_config_values(), - pallet.get_default_config(), - )?; - } - - if let Some(mut workspace_toml) = find_workspace_toml(&self.path) { - workspace_toml.pop(); - format_dir(&workspace_toml)?; - } else { - format_dir(&self.path)?; - } - spinner.stop("Your runtime has been updated and it's ready to use 🚀"); - Ok(()) - } -} diff --git a/crates/pop-cli/src/commands/add/runtime_pallet/common_pallets.rs b/crates/pop-cli/src/commands/add/runtime_pallet/common_pallets.rs deleted file mode 100644 index 1bfd62658..000000000 --- a/crates/pop-cli/src/commands/add/runtime_pallet/common_pallets.rs +++ /dev/null @@ -1,72 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0 -use clap::ValueEnum; -use pop_common::rust_writer::types::ParameterTypes; -use strum_macros::{EnumIter, EnumMessage}; -use syn::{parse_quote, Type}; - -#[derive(Debug, Copy, Clone, PartialEq, EnumIter, EnumMessage, ValueEnum)] -pub enum CommonPallets { - /// Add pallet-balances to your runtime. - #[strum(message = "Balances", detailed_message = "Add pallet-balances to your runtime.")] - Balances, - /// Add pallet-contracts to your runtime. - #[strum(message = "Contracts", detailed_message = "Add pallet-contracts to your runtime.")] - Contracts, -} - -impl CommonPallets { - pub fn get_crate_name(&self) -> String { - match self { - CommonPallets::Balances => "pallet-balances".to_string(), - CommonPallets::Contracts => "pallet-contracts".to_string(), - } - } - - pub fn get_version(&self) -> String { - match self { - CommonPallets::Balances => "39.0.0".to_string(), - CommonPallets::Contracts => "27.0.0".to_string(), - } - } - - pub fn get_parameter_types(&self) -> Vec { - match self { - CommonPallets::Balances => Vec::new(), - CommonPallets::Contracts => vec![ParameterTypes { - ident: "Schedule".to_string(), - type_: parse_quote! {pallet_contracts::Schedule}, - value: parse_quote! {Default::default()}, - }], - } - } - - pub fn get_config_types(&self) -> Vec { - match self { - CommonPallets::Balances => vec!["AccountStore".to_string()], - CommonPallets::Contracts => - vec!["Currency".to_string(), "Schedule".to_string(), "CallStack".to_string()], - } - } - - pub fn get_config_values(&self) -> Vec { - match self { - CommonPallets::Balances => { - vec![parse_quote! {System}] - }, - CommonPallets::Contracts => { - vec![ - parse_quote! {Balances}, - parse_quote! {[pallet_contracts::Frame; 5]}, - parse_quote! {Schedule}, - ] - }, - } - } - - pub fn get_default_config(&self) -> bool { - match self { - CommonPallets::Balances => true, - CommonPallets::Contracts => true, - } - } -} diff --git a/crates/pop-cli/src/commands/add/runtime_pallet/tests.rs b/crates/pop-cli/src/commands/add/runtime_pallet/tests.rs deleted file mode 100644 index ea448e289..000000000 --- a/crates/pop-cli/src/commands/add/runtime_pallet/tests.rs +++ /dev/null @@ -1 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0 diff --git a/crates/pop-cli/src/commands/mod.rs b/crates/pop-cli/src/commands/mod.rs index 0f8ab1a5f..5a8c821b3 100644 --- a/crates/pop-cli/src/commands/mod.rs +++ b/crates/pop-cli/src/commands/mod.rs @@ -128,7 +128,7 @@ impl Command { }, Self::Add(args) => match args.command { add::Command::ConfigType(cmd) => cmd.execute().await.map(|_| json!("default")), - add::Command::RuntimePallet(cmd) => cmd.execute().await.map(|_| json!("default")), + add::Command::Pallet(cmd) => cmd.execute().await.map(|_| json!("default")), }, } } From 2168974ad68ce8c18736a79310d7fcd753658ab1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1s=20Senovilla=20Polo?= Date: Sat, 5 Oct 2024 12:23:41 +0200 Subject: [PATCH 05/46] Refactor: pop add runtime-pallet => pop add pallet + it detects if it's been run in a runtime workspace --- crates/pop-cli/src/commands/add/pallet.rs | 109 ++++++++++++++++++ .../src/commands/add/pallet/common_pallets.rs | 72 ++++++++++++ .../pop-cli/src/commands/add/pallet/tests.rs | 1 + 3 files changed, 182 insertions(+) create mode 100644 crates/pop-cli/src/commands/add/pallet.rs create mode 100644 crates/pop-cli/src/commands/add/pallet/common_pallets.rs create mode 100644 crates/pop-cli/src/commands/add/pallet/tests.rs diff --git a/crates/pop-cli/src/commands/add/pallet.rs b/crates/pop-cli/src/commands/add/pallet.rs new file mode 100644 index 000000000..4b3af681b --- /dev/null +++ b/crates/pop-cli/src/commands/add/pallet.rs @@ -0,0 +1,109 @@ +// SPDX-License-Identifier: GPL-3.0 + +use crate::{ + cli::{traits::Cli as _, Cli}, + multiselect_pick, +}; +use clap::{error::ErrorKind, Args, Command}; +use cliclack::multiselect; +use pop_common::{ + find_pallet_runtime_impl_path, find_workspace_toml, format_dir, + manifest::types::CrateDependencie, rust_writer, +}; +use std::{path::PathBuf, env::current_dir}; +use strum::{EnumMessage, IntoEnumIterator}; + +mod common_pallets; + +#[cfg(test)] +mod tests; + +#[derive(Args, Debug, Clone)] +pub struct AddPalletCommand { + #[arg(short = 'r', long, help = "Specify the path to the runtime crate.")] + pub(crate) path: Option, + #[arg(short, long, value_enum, num_args(1..), required = false, help = "The pallets you want to include to your runtime.")] + pub(crate) pallets: Vec, + #[arg( + long, + help = "Pop-Cli will place the impl blocks for your pallets' Config traits inside configs/mod.rs or lib.rs in the runtime crate by default. If you want to place them in another path, use this option to specify it." + )] + pub(crate) runtime_impl_path: Option, +} + +impl AddPalletCommand { + pub(crate) async fn execute(self) -> anyhow::Result<()> { + Cli.intro("Add a new pallet to your runtime")?; + let path = if let Some(path) = &self.path{ + path + } else { + let working_dir = current_dir().expect("Cannot modify your working directory"); + // Give the chance to use the command either from a workspace containing a runtime or from a runtime crate if path not specified + if working_dir.join("runtime").exists(){ + &working_dir.join("runtime") + } else { + &working_dir.clone() + } + }; + let mut cmd = Command::new(""); + let src = path.join("src"); + let lib_path = src.join("lib.rs"); + if !lib_path.is_file() { + cmd.error( + ErrorKind::InvalidValue, + "Make sure that the used path correspond to a runtime crate.", + ) + .exit(); + } + + let runtime_impl_path = + match self.runtime_impl_path.or_else(|| find_pallet_runtime_impl_path(&lib_path)) { + Some(runtime_impl_path) => runtime_impl_path, + None => cmd + .error( + ErrorKind::InvalidValue, + "Make sure that the used path correspond to a runtime crate.", + ) + .exit(), + }; + + let spinner = cliclack::spinner(); + spinner.start("Updating runtime..."); + + let pallets = if self.pallets.is_empty() { + multiselect_pick!( + common_pallets::CommonPallets, + "Select the pallets you want to include in your runtime" + ) + } else { + self.pallets + }; + + for pallet in pallets { + // Add the pallet to the crate and to the runtime module + rust_writer::add_pallet_to_runtime_module( + &pallet.get_crate_name(), + &lib_path, + CrateDependencie::External { version: pallet.get_version() }, + )?; + // Add the pallet impl block + rust_writer::add_pallet_impl_block_to_runtime( + &pallet.get_crate_name(), + &runtime_impl_path, + pallet.get_parameter_types(), + pallet.get_config_types(), + pallet.get_config_values(), + pallet.get_default_config(), + )?; + } + + if let Some(mut workspace_toml) = find_workspace_toml(path) { + workspace_toml.pop(); + format_dir(&workspace_toml)?; + } else { + format_dir(path)?; + } + spinner.stop("Your runtime has been updated and it's ready to use 🚀"); + Ok(()) + } +} diff --git a/crates/pop-cli/src/commands/add/pallet/common_pallets.rs b/crates/pop-cli/src/commands/add/pallet/common_pallets.rs new file mode 100644 index 000000000..1bfd62658 --- /dev/null +++ b/crates/pop-cli/src/commands/add/pallet/common_pallets.rs @@ -0,0 +1,72 @@ +// SPDX-License-Identifier: GPL-3.0 +use clap::ValueEnum; +use pop_common::rust_writer::types::ParameterTypes; +use strum_macros::{EnumIter, EnumMessage}; +use syn::{parse_quote, Type}; + +#[derive(Debug, Copy, Clone, PartialEq, EnumIter, EnumMessage, ValueEnum)] +pub enum CommonPallets { + /// Add pallet-balances to your runtime. + #[strum(message = "Balances", detailed_message = "Add pallet-balances to your runtime.")] + Balances, + /// Add pallet-contracts to your runtime. + #[strum(message = "Contracts", detailed_message = "Add pallet-contracts to your runtime.")] + Contracts, +} + +impl CommonPallets { + pub fn get_crate_name(&self) -> String { + match self { + CommonPallets::Balances => "pallet-balances".to_string(), + CommonPallets::Contracts => "pallet-contracts".to_string(), + } + } + + pub fn get_version(&self) -> String { + match self { + CommonPallets::Balances => "39.0.0".to_string(), + CommonPallets::Contracts => "27.0.0".to_string(), + } + } + + pub fn get_parameter_types(&self) -> Vec { + match self { + CommonPallets::Balances => Vec::new(), + CommonPallets::Contracts => vec![ParameterTypes { + ident: "Schedule".to_string(), + type_: parse_quote! {pallet_contracts::Schedule}, + value: parse_quote! {Default::default()}, + }], + } + } + + pub fn get_config_types(&self) -> Vec { + match self { + CommonPallets::Balances => vec!["AccountStore".to_string()], + CommonPallets::Contracts => + vec!["Currency".to_string(), "Schedule".to_string(), "CallStack".to_string()], + } + } + + pub fn get_config_values(&self) -> Vec { + match self { + CommonPallets::Balances => { + vec![parse_quote! {System}] + }, + CommonPallets::Contracts => { + vec![ + parse_quote! {Balances}, + parse_quote! {[pallet_contracts::Frame; 5]}, + parse_quote! {Schedule}, + ] + }, + } + } + + pub fn get_default_config(&self) -> bool { + match self { + CommonPallets::Balances => true, + CommonPallets::Contracts => true, + } + } +} diff --git a/crates/pop-cli/src/commands/add/pallet/tests.rs b/crates/pop-cli/src/commands/add/pallet/tests.rs new file mode 100644 index 000000000..ea448e289 --- /dev/null +++ b/crates/pop-cli/src/commands/add/pallet/tests.rs @@ -0,0 +1 @@ +// SPDX-License-Identifier: GPL-3.0 From 764b9ab537eb6e2a4fb03ba104b0109156e57efe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1s=20Senovilla=20Polo?= Date: Sat, 5 Oct 2024 12:33:12 +0200 Subject: [PATCH 06/46] Remake error message if pop add pallet path not valid --- crates/pop-cli/src/commands/add/pallet.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/pop-cli/src/commands/add/pallet.rs b/crates/pop-cli/src/commands/add/pallet.rs index 4b3af681b..e87f69aca 100644 --- a/crates/pop-cli/src/commands/add/pallet.rs +++ b/crates/pop-cli/src/commands/add/pallet.rs @@ -51,7 +51,7 @@ impl AddPalletCommand { if !lib_path.is_file() { cmd.error( ErrorKind::InvalidValue, - "Make sure that the used path correspond to a runtime crate.", + "Make sure to run this command either in a workspace containing a runtime crate/a runtime crate or to specify the path to the runtime crate using -r.", ) .exit(); } From 9b78cb47287ee408f819eab67a7dae7fc0faf045 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1s=20Senovilla=20Polo?= Date: Sat, 5 Oct 2024 12:36:34 +0200 Subject: [PATCH 07/46] pop add pallet path argument becomes runtime_path --- crates/pop-cli/src/commands/add/pallet.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/crates/pop-cli/src/commands/add/pallet.rs b/crates/pop-cli/src/commands/add/pallet.rs index e87f69aca..f69e72a65 100644 --- a/crates/pop-cli/src/commands/add/pallet.rs +++ b/crates/pop-cli/src/commands/add/pallet.rs @@ -20,8 +20,8 @@ mod tests; #[derive(Args, Debug, Clone)] pub struct AddPalletCommand { - #[arg(short = 'r', long, help = "Specify the path to the runtime crate.")] - pub(crate) path: Option, + #[arg(short, long, help = "Specify the path to the runtime crate.")] + pub(crate) runtime_path: Option, #[arg(short, long, value_enum, num_args(1..), required = false, help = "The pallets you want to include to your runtime.")] pub(crate) pallets: Vec, #[arg( @@ -34,7 +34,7 @@ pub struct AddPalletCommand { impl AddPalletCommand { pub(crate) async fn execute(self) -> anyhow::Result<()> { Cli.intro("Add a new pallet to your runtime")?; - let path = if let Some(path) = &self.path{ + let path = if let Some(path) = &self.runtime_path{ path } else { let working_dir = current_dir().expect("Cannot modify your working directory"); From 37e9fe1926f8a44f1fcb3cb04b4d29a3600bebf2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1s=20Senovilla=20Polo?= Date: Sat, 5 Oct 2024 17:37:14 +0200 Subject: [PATCH 08/46] Rust writer functions refactor to make them more correct --- Cargo.lock | 1 + crates/pop-cli/Cargo.toml | 1 + .../pop-cli/src/commands/add/config_type.rs | 24 +++--- crates/pop-cli/src/commands/add/pallet.rs | 25 ++++--- .../src/commands/add/pallet/common_pallets.rs | 14 ++-- crates/pop-cli/src/commands/new/pallet.rs | 10 ++- crates/pop-common/src/helpers.rs | 10 +++ crates/pop-common/src/lib.rs | 3 +- crates/pop-common/src/rust_writer.rs | 74 +++++++++++-------- crates/pop-common/src/rust_writer/expand.rs | 50 +++---------- crates/pop-common/src/rust_writer/helpers.rs | 42 +++-------- 11 files changed, 125 insertions(+), 129 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 3b10984ca..7c48055ac 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4690,6 +4690,7 @@ dependencies = [ "pop-parachains", "pop-telemetry", "predicates", + "proc-macro2", "reqwest 0.12.5", "serde_json", "sp-core", diff --git a/crates/pop-cli/Cargo.toml b/crates/pop-cli/Cargo.toml index 8fdc98372..eeca27938 100644 --- a/crates/pop-cli/Cargo.toml +++ b/crates/pop-cli/Cargo.toml @@ -17,6 +17,7 @@ anyhow.workspace = true duct.workspace = true env_logger.workspace = true os_info.workspace = true +proc-macro2.workspace = true reqwest.workspace = true serde_json.workspace = true syn.workspace = true diff --git a/crates/pop-cli/src/commands/add/config_type.rs b/crates/pop-cli/src/commands/add/config_type.rs index 5c55a7f50..2e12daa6f 100644 --- a/crates/pop-cli/src/commands/add/config_type.rs +++ b/crates/pop-cli/src/commands/add/config_type.rs @@ -4,10 +4,12 @@ use crate::cli::{traits::Cli as _, Cli}; use clap::{error::ErrorKind, Args, Command}; use cliclack; use pop_common::{ - find_workspace_toml, format_dir, + capitalize_str, find_workspace_toml, format_dir, rust_writer::{self, types::*}, }; +use proc_macro2::Span; use std::{fs, path::PathBuf}; +use syn::{parse_str, Ident, Type}; #[cfg(test)] mod tests; @@ -134,12 +136,12 @@ impl AddConfigTypeCommand { let spinner = cliclack::spinner(); spinner.start("Updating pallet's config trait..."); - + let type_name_ident = Ident::new(&capitalize_str(&self.name), Span::call_site()); // Update the config trait in lib.rs rust_writer::update_config_trait( &lib_path, - &self.name, - self.bounds.iter().map(|bound| bound.as_str()).collect(), + type_name_ident.clone(), + self.bounds.iter().map(|bound| Ident::new(&bound, Span::call_site())).collect(), match &self.default_config { DefaultConfigTypeOptions { no_default: true, .. } => DefaultConfigType::NoDefault, DefaultConfigTypeOptions { no_default_bounds: true, .. } => @@ -155,8 +157,8 @@ impl AddConfigTypeCommand { // Add the new type to the mock runtime rust_writer::add_type_to_runtimes( &self.path, - &self.name, - self.runtime_value.as_ref().expect("validate options stops the execution from clap if runtime_value is none in this scenario; qed;"), + type_name_ident.clone(), + parse_str::(&self.runtime_value.expect("validate options stops the execution from clap if runtime_value is none in this scenario; qed;"))?, self.runtime_impl_path.as_deref() )?; }, @@ -168,8 +170,8 @@ impl AddConfigTypeCommand { // Add the new type to the mock runtime rust_writer::add_type_to_runtimes( &self.path, - &self.name, - runtime_value, + type_name_ident.clone(), + parse_str::(&runtime_value)?, self.runtime_impl_path.as_deref(), )?; } @@ -186,7 +188,11 @@ impl AddConfigTypeCommand { &lib_path }; - rust_writer::add_type_to_config_preludes(file_path, &self.name, default_value)?; + rust_writer::add_type_to_config_preludes( + file_path, + type_name_ident, + parse_str::(&default_value)?, + )?; } }, }; diff --git a/crates/pop-cli/src/commands/add/pallet.rs b/crates/pop-cli/src/commands/add/pallet.rs index f69e72a65..1fd3333a1 100644 --- a/crates/pop-cli/src/commands/add/pallet.rs +++ b/crates/pop-cli/src/commands/add/pallet.rs @@ -10,7 +10,7 @@ use pop_common::{ find_pallet_runtime_impl_path, find_workspace_toml, format_dir, manifest::types::CrateDependencie, rust_writer, }; -use std::{path::PathBuf, env::current_dir}; +use std::{env::current_dir, path::PathBuf}; use strum::{EnumMessage, IntoEnumIterator}; mod common_pallets; @@ -34,17 +34,18 @@ pub struct AddPalletCommand { impl AddPalletCommand { pub(crate) async fn execute(self) -> anyhow::Result<()> { Cli.intro("Add a new pallet to your runtime")?; - let path = if let Some(path) = &self.runtime_path{ - path - } else { - let working_dir = current_dir().expect("Cannot modify your working directory"); - // Give the chance to use the command either from a workspace containing a runtime or from a runtime crate if path not specified - if working_dir.join("runtime").exists(){ - &working_dir.join("runtime") - } else { - &working_dir.clone() - } - }; + let path = if let Some(path) = &self.runtime_path { + path + } else { + let working_dir = current_dir().expect("Cannot modify your working directory"); + // Give the chance to use the command either from a workspace containing a runtime or + // from a runtime crate if path not specified + if working_dir.join("runtime").exists() { + &working_dir.join("runtime") + } else { + &working_dir.clone() + } + }; let mut cmd = Command::new(""); let src = path.join("src"); let lib_path = src.join("lib.rs"); diff --git a/crates/pop-cli/src/commands/add/pallet/common_pallets.rs b/crates/pop-cli/src/commands/add/pallet/common_pallets.rs index 1bfd62658..9c19c5429 100644 --- a/crates/pop-cli/src/commands/add/pallet/common_pallets.rs +++ b/crates/pop-cli/src/commands/add/pallet/common_pallets.rs @@ -1,8 +1,9 @@ // SPDX-License-Identifier: GPL-3.0 use clap::ValueEnum; use pop_common::rust_writer::types::ParameterTypes; +use proc_macro2::Span; use strum_macros::{EnumIter, EnumMessage}; -use syn::{parse_quote, Type}; +use syn::{parse_quote, Ident, Type}; #[derive(Debug, Copy, Clone, PartialEq, EnumIter, EnumMessage, ValueEnum)] pub enum CommonPallets { @@ -40,11 +41,14 @@ impl CommonPallets { } } - pub fn get_config_types(&self) -> Vec { + pub fn get_config_types(&self) -> Vec { match self { - CommonPallets::Balances => vec!["AccountStore".to_string()], - CommonPallets::Contracts => - vec!["Currency".to_string(), "Schedule".to_string(), "CallStack".to_string()], + CommonPallets::Balances => vec![Ident::new("AccountStore", Span::call_site())], + CommonPallets::Contracts => vec![ + Ident::new("Currency", Span::call_site()), + Ident::new("Schedule", Span::call_site()), + Ident::new("CallStack", Span::call_site()), + ], } } diff --git a/crates/pop-cli/src/commands/new/pallet.rs b/crates/pop-cli/src/commands/new/pallet.rs index 2f0e0d57e..164838030 100644 --- a/crates/pop-cli/src/commands/new/pallet.rs +++ b/crates/pop-cli/src/commands/new/pallet.rs @@ -16,9 +16,10 @@ use pop_parachains::{ create_pallet_template, TemplatePalletConfig, TemplatePalletConfigCommonTypes, TemplatePalletOptions, TemplatePalletStorageTypes, }; +use proc_macro2::Span; use std::{fs, path::PathBuf}; use strum::{EnumMessage, IntoEnumIterator}; -use syn::Type; +use syn::{Ident, Type}; fn after_help_simple() -> &'static str { r#"Examples: @@ -212,15 +213,18 @@ impl NewPalletCommand { let (types, values) = if pallet_default_config { (Vec::new(), Vec::new()) } else { - let types: Vec = pallet_common_types + let types: Vec = pallet_common_types .clone() .iter() - .map(|type_| type_.get_message().unwrap_or_default().to_string()) + .map(|type_| { + Ident::new(type_.get_message().unwrap_or_default(), Span::call_site()) + }) .collect(); let values: Vec = pallet_common_types.iter().map(|type_| type_.common_value()).collect(); (types, values) }; + rust_writer::add_pallet_impl_block_to_runtime( &pallet_name, &runtime_impl_path, diff --git a/crates/pop-common/src/helpers.rs b/crates/pop-common/src/helpers.rs index a525776aa..528d4b652 100644 --- a/crates/pop-common/src/helpers.rs +++ b/crates/pop-common/src/helpers.rs @@ -66,6 +66,16 @@ pub fn format_dir(path: &Path) -> Result { .or(Command::new("cargo").arg("fmt").arg("--all").current_dir(path).output()) } +pub fn capitalize_str(input: &str) -> String { + if input.is_empty() { + return String::new(); + } + + let first_char = input.chars().next().expect("The introduced str isn't empty").to_uppercase(); + let rest = &input[1..]; + format!("{}{}", first_char, rest) +} + #[cfg(test)] mod tests { use super::*; diff --git a/crates/pop-common/src/lib.rs b/crates/pop-common/src/lib.rs index bdb24ffdb..a49aa4710 100644 --- a/crates/pop-common/src/lib.rs +++ b/crates/pop-common/src/lib.rs @@ -11,7 +11,8 @@ pub use build::Profile; pub use errors::Error; pub use git::{Git, GitHub, Release}; pub use helpers::{ - format_dir, get_project_name_from_path, prefix_with_current_dir_if_needed, replace_in_file, + capitalize_str, format_dir, get_project_name_from_path, prefix_with_current_dir_if_needed, + replace_in_file, }; pub use manifest::*; pub use templates::extractor::extract_template_files; diff --git a/crates/pop-common/src/rust_writer.rs b/crates/pop-common/src/rust_writer.rs index 2a816c69b..6d4dc23e1 100644 --- a/crates/pop-common/src/rust_writer.rs +++ b/crates/pop-common/src/rust_writer.rs @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-3.0 use crate::{ + capitalize_str, manifest::{ add_crate_to_dependencies, find_crate_manifest, find_crate_name, find_pallet_runtime_impl_path, types::CrateDependencie, @@ -8,8 +9,9 @@ use crate::{ Error, }; use prettyplease::unparse; +use proc_macro2::Span; use std::{fs, path::Path}; -use syn::Type; +use syn::{parse_str, Ident, Type}; mod expand; mod helpers; @@ -18,8 +20,8 @@ pub mod types; pub fn update_config_trait( file_path: &Path, - type_name: &str, - trait_bounds: Vec<&str>, + type_name: Ident, + trait_bounds: Vec, default_config: types::DefaultConfigType, ) -> Result<(), Error> { let mut ast = helpers::preserve_and_parse(fs::read_to_string(file_path)?, vec![])?; @@ -37,16 +39,16 @@ pub fn update_config_trait( pub fn add_type_to_runtimes( pallet_path: &Path, - type_name: &str, - runtime_value: &str, + type_name: Ident, + runtime_value: Type, runtime_impl_path: Option<&Path>, ) -> Result<(), Error> { fn do_add_type_to_runtime( file_content: &str, file_path: &Path, pallet_manifest_path: &Path, - type_name: &str, - runtime_value: &str, + type_name: Ident, + runtime_value: Type, ) -> Result<(), Error> { let mut ast = helpers::preserve_and_parse(file_content.to_string(), vec![])?; @@ -80,8 +82,8 @@ pub fn add_type_to_runtimes( &mock_content, &mock_path, &pallet_manifest_path, - type_name, - runtime_value, + type_name.clone(), + runtime_value.clone(), )?; // If the pallet is contained inside a runtime add the type to that runtime as well @@ -103,8 +105,8 @@ pub fn add_type_to_runtimes( pub fn add_type_to_config_preludes( file_path: &Path, - type_name: &str, - default_value: &str, + type_name: Ident, + default_value: Type, ) -> Result<(), Error> { let mut ast = helpers::preserve_and_parse(fs::read_to_string(file_path)?, vec![])?; @@ -125,18 +127,6 @@ pub fn add_pallet_to_runtime_module( runtime_lib_path: &Path, pallet_dependencie_type: CrateDependencie, ) -> Result<(), Error> { - // Find the pallet name and the pallet item to be added to the runtime. If the pallet_name is - // behind the form pallet-some-thing, pallet_item becomes Something. - let pallet_item = helpers::capitalize_str( - &pallet_name - .split("pallet-") - .last() - .ok_or(Error::Config( - "Pallet crates are supposed to be called pallet-something.".to_string(), - ))? - .replace("-", ""), - ); - // As the runtime may be constructed with construc_runtime!, we have to avoid preserving that // macro with comments let mut ast = helpers::preserve_and_parse( @@ -148,13 +138,30 @@ pub fn add_pallet_to_runtime_module( // pallet index used (if needed). let (highest_index, used_macro) = parse::find_highest_pallet_index_and_runtime_macro_version(&ast); + + // Find the pallet name and the pallet item to be added to the runtime. If the pallet_name is + // behind the form pallet-some-thing, pallet_item becomes Something. + let pallet_item = Ident::new( + &capitalize_str( + &pallet_name + .split("pallet-") + .last() + .ok_or(Error::Config( + "Pallet crates are supposed to be called pallet-something.".to_string(), + ))? + .replace("-", ""), + ), + Span::call_site(), + ); + let pallet_name_type = parse_str::(&pallet_name.replace("-", "_"))?; + // Expand the ast with the new pallet. pallet-some-thing becomes pallet_some_thing in the code expand::expand_runtime_add_pallet( &mut ast, highest_index, used_macro, - &pallet_name.replace("-", "_"), - &pallet_item, + pallet_name_type, + pallet_item, ); let generated_code = helpers::resolve_preserved(unparse(&ast)); @@ -179,21 +186,28 @@ pub fn add_pallet_impl_block_to_runtime( pallet_name: &str, runtime_impl_path: &Path, parameter_types: Vec, - types: Vec, + types: Vec, values: Vec, default_config: bool, ) -> Result<(), Error> { let mut ast = helpers::preserve_and_parse(fs::read_to_string(runtime_impl_path)?, vec![])?; - + let pallet_name_ident = Ident::new(&pallet_name.replace("-", "_"), Span::call_site()); // Expand the runtime to add the impl_block expand::expand_runtime_add_impl_block( &mut ast, - &pallet_name.replace("-", "_"), + pallet_name_ident, parameter_types, - types, - values, default_config, ); + // Expand the block to add the types + types.into_iter().zip(values.into_iter()).for_each(|(type_, value)| { + expand::expand_runtime_add_type_to_impl_block( + &mut ast, + type_, + value, + &pallet_name.replace("-", "_"), + ) + }); let generated_code = helpers::resolve_preserved(unparse(&ast)); diff --git a/crates/pop-common/src/rust_writer/expand.rs b/crates/pop-common/src/rust_writer/expand.rs index 1542e4d09..a9ee74d84 100644 --- a/crates/pop-common/src/rust_writer/expand.rs +++ b/crates/pop-common/src/rust_writer/expand.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-3.0 -use crate::rust_writer::{helpers::capitalize_str, types::*}; +use crate::{capitalize_str, rust_writer::types::*}; use proc_macro2::{Group, Literal, Span, TokenStream, TokenTree}; use syn::{ parse_quote, Expr, File, Ident, ImplItem, Item, ItemImpl, ItemMacro, ItemMod, ItemTrait, Macro, @@ -10,14 +10,9 @@ use syn::{ pub(crate) fn expand_pallet_config_trait( ast: &mut File, default_config: DefaultConfigType, - type_name: &str, - trait_bounds: Vec<&str>, + type_name: Ident, + trait_bounds: Vec, ) { - let type_name = Ident::new(&capitalize_str(type_name), Span::call_site()); - let trait_bounds = trait_bounds - .iter() - .map(|bound| Ident::new(&capitalize_str(bound), Span::call_site())) - .collect::>(); for item in &mut ast.items { match item { Item::Mod(ItemMod { ident, content, .. }) @@ -56,10 +51,7 @@ pub(crate) fn expand_pallet_config_trait( } } -pub(crate) fn expand_pallet_config_preludes(ast: &mut File, type_name: &str, default_value: &str) { - let type_name = Ident::new(&capitalize_str(type_name), Span::call_site()); - let default_value = Ident::new(default_value, Span::call_site()); - +pub(crate) fn expand_pallet_config_preludes(ast: &mut File, type_name: Ident, default_value: Type) { for item in &mut ast.items { match item { // In case file_path points to lib.rs, config_preludes is contained inside pallet mod in @@ -129,12 +121,9 @@ pub(crate) fn expand_runtime_add_pallet( ast: &mut File, highest_index: u8, used_macro: RuntimeUsedMacro, - pallet_name: &str, - pallet_item: &str, + pallet_name: Type, + pallet_item: Ident, ) { - let pallet_item = Ident::new(pallet_item, Span::call_site()); - let pallet_name = Ident::new(pallet_name, Span::call_site()); - match used_macro { RuntimeUsedMacro::Runtime => { // Convert the highest_index in Ident @@ -191,17 +180,10 @@ pub(crate) fn expand_runtime_add_pallet( pub(crate) fn expand_runtime_add_impl_block( ast: &mut File, - pallet_name: &str, + pallet_name: Ident, parameter_types: Vec, - types: Vec, - values: Vec, default_config: bool, ) { - let pallet_name = Ident::new(pallet_name, Span::call_site()); - let types: Vec = types - .iter() - .map(|type_| Ident::new(&capitalize_str(type_), Span::call_site())) - .collect(); let parameter_idents: Vec = parameter_types .iter() .map(|item| Ident::new(&capitalize_str(&item.ident), Span::call_site())) @@ -227,32 +209,22 @@ pub(crate) fn expand_runtime_add_impl_block( items.push(Item::Impl(parse_quote! { ///EMPTY_LINE #[derive_impl(#pallet_name::config_preludes::TestDefaultConfig)] - impl #pallet_name::Config for Runtime{ - #( - type #types = #values; - )* - } + impl #pallet_name::Config for Runtime{} })); } else { items.push(Item::Impl(parse_quote! { ///EMPTY_LINE - impl #pallet_name::Config for Runtime{ - #( - type #types = #values; - )* - } + impl #pallet_name::Config for Runtime{} })); } } pub(crate) fn expand_runtime_add_type_to_impl_block( ast: &mut File, - type_name: &str, - runtime_value: &str, + type_name: Ident, + runtime_value: Type, pallet_name: &str, ) { - let type_name = Ident::new(&capitalize_str(type_name), Span::call_site()); - let runtime_value = Ident::new(runtime_value, Span::call_site()); for item in &mut ast.items { match item { Item::Impl(ItemImpl { diff --git a/crates/pop-common/src/rust_writer/helpers.rs b/crates/pop-common/src/rust_writer/helpers.rs index 2583747b1..d1f98675e 100644 --- a/crates/pop-common/src/rust_writer/helpers.rs +++ b/crates/pop-common/src/rust_writer/helpers.rs @@ -58,18 +58,17 @@ pub(crate) fn resolve_preserved(code: String) -> String { match trimmed_line { comment if trimmed_line.strip_prefix("///TEMP_DOC").is_some() => output.push_str( - comment - .strip_prefix("///TEMP_DOC") - .expect("The match guard guarantees this is always some; qed;"), - ), - comment if trimmed_line.strip_prefix("///TEMP_MACRO").is_some() => output.push_str( - &format!( - "{}\n", - comment - .strip_prefix("///TEMP_MACRO") - .expect("The match guard guarantees this is always some; qed;"), - ) + comment + .strip_prefix("///TEMP_DOC") + .expect("The match guard guarantees this is always some; qed;"), ), + comment if trimmed_line.strip_prefix("///TEMP_MACRO").is_some() => + output.push_str(&format!( + "{}\n", + comment + .strip_prefix("///TEMP_MACRO") + .expect("The match guard guarantees this is always some; qed;"), + )), _ if trimmed_line.strip_prefix("///EMPTY_LINE").is_some() => output.push('\n'), _ => output.push_str(&format!("{}\n", line)), } @@ -77,16 +76,6 @@ pub(crate) fn resolve_preserved(code: String) -> String { output } -pub(crate) fn capitalize_str(input: &str) -> String { - if input.is_empty() { - return String::new(); - } - - let first_char = input.chars().next().expect("The introduced str isn't empty").to_uppercase(); - let rest = &input[1..]; - format!("{}{}", first_char, rest) -} - fn preserve_macro_invocations(code: String, exempt_macros: Vec<&str>) -> String { let re = Regex::new(r"(?P[a-zA-Z_]+)!\s*[\{\(\[]").expect("The regex is valid; qed;"); @@ -94,14 +83,7 @@ fn preserve_macro_invocations(code: String, exempt_macros: Vec<&str>) -> String let mut macro_block = String::new(); - let mut delimiter_counts = vec![ - ('{', 0), - ('}', 0), - ('(', 0), - (')', 0), - ('[', 0), - (']', 0), - ]; + let mut delimiter_counts = vec![('{', 0), ('}', 0), ('(', 0), (')', 0), ('[', 0), (']', 0)]; for line in code.lines() { match re.find(line) { @@ -141,6 +123,6 @@ fn preserve_macro_invocations(code: String, exempt_macros: Vec<&str>) -> String result.push_str("type temp_marker = ();\n"); macro_block = String::new(); } - }; + } result } From 4f07e102a66f9e18f0768ee74688e3a680ef9c26 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1s=20Senovilla=20Polo?= Date: Sun, 6 Oct 2024 19:29:20 +0200 Subject: [PATCH 09/46] Redo pop add config-type --- .../pop-cli/src/commands/add/config_type.rs | 239 +++++++----------- .../commands/add/config_type/common_types.rs | 135 ++++++++++ crates/pop-cli/src/commands/add/pallet.rs | 16 +- crates/pop-common/src/rust_writer.rs | 55 +++- crates/pop-common/src/rust_writer/expand.rs | 51 +++- crates/pop-common/src/rust_writer/parse.rs | 33 ++- crates/pop-common/src/rust_writer/types.rs | 6 +- 7 files changed, 351 insertions(+), 184 deletions(-) create mode 100644 crates/pop-cli/src/commands/add/config_type/common_types.rs diff --git a/crates/pop-cli/src/commands/add/config_type.rs b/crates/pop-cli/src/commands/add/config_type.rs index 2e12daa6f..d340f7453 100644 --- a/crates/pop-cli/src/commands/add/config_type.rs +++ b/crates/pop-cli/src/commands/add/config_type.rs @@ -1,36 +1,27 @@ // SPDX-License-Identifier: GPL-3.0 -use crate::cli::{traits::Cli as _, Cli}; +mod common_types; +#[cfg(test)] +mod tests; + +use crate::{cli::{traits::Cli as _, Cli}, multiselect_pick}; use clap::{error::ErrorKind, Args, Command}; -use cliclack; +use cliclack::multiselect; use pop_common::{ capitalize_str, find_workspace_toml, format_dir, - rust_writer::{self, types::*}, + rust_writer::{self, types::*}, prefix_with_current_dir_if_needed }; use proc_macro2::Span; use std::{fs, path::PathBuf}; -use syn::{parse_str, Ident, Type}; - -#[cfg(test)] -mod tests; +use syn::{parse_quote, Ident}; +use strum::{EnumMessage, IntoEnumIterator}; #[derive(Args, Debug, Clone)] pub struct AddConfigTypeCommand { #[arg(short, long, required = true, help = "Specify the path to the pallet crate.")] - pub(crate) path: PathBuf, - #[arg(short, long, required = true, help = "The name of the config type.")] - pub(crate) name: String, - #[arg(short, long, num_args(1..), required = true, help="Add trait bounds to your new config type.")] - pub(crate) bounds: Vec, - #[command(flatten)] - pub(crate) default_config: DefaultConfigTypeOptions, - #[arg( - long, - help = "Define a default value for your new config type to use in the default config." - )] - pub(crate) default_value: Option, - #[arg(long, help = "Define a value for your new config type to use in your runtime.")] - pub(crate) runtime_value: Option, + pub(crate) pallet_path: PathBuf, + #[arg(short, long, value_enum, num_args(1..), required = false, help = "The types you want to include in your pallet.")] + pub(crate) types: Vec, #[arg( long, help = "If your pallet is included in a runtime, Pop-Cli will look for the impl block for your pallet's Config trait inside configs/mod.rs or lib.rs in the runtime crate by default in order to add the new type to the runtime. If your impl block is in another path, use this option to specify it." @@ -38,80 +29,13 @@ pub struct AddConfigTypeCommand { pub(crate) runtime_impl_path: Option, } -#[derive(Args, Debug, Clone)] -#[group(required = false, multiple = false)] -pub struct DefaultConfigTypeOptions { - #[arg( - long, - help = "Ensures the trait item will not be used as a default with the #[derive_impl(..)] attribute macro." - )] - pub(crate) no_default: bool, - #[arg( - long, - help = "Ensures that the trait DefaultConfig will not have any bounds for this trait item." - )] - pub(crate) no_default_bounds: bool, -} - -fn validate_config_options(command: &AddConfigTypeCommand, lib_content: &str) { - let mut cmd = Command::new(""); - - if command.runtime_impl_path.is_some() && command.runtime_value.is_none() { - cmd.error( - ErrorKind::ArgumentConflict, - "The use of --runtime-impl-path is forbidden if --runtime-value isn't used.", - ) - .exit() - } - - match command.default_config { - DefaultConfigTypeOptions { no_default: true, .. } if !lib_content.contains("pub mod config_preludes") => cmd.error( - ErrorKind::InvalidSubcommand, - "Cannot specify --no-default if the affected pallet doesn't implement a default config. Pop-Cli follows the convention and looks for a module called 'config_preludes' (defined either inside the pallet's lib file or its own file 'config_preludes.rs'), if your pallet uses a default config under another name, be sure to rename it as 'config_preludes' if you want to use this feature of Pop-Cli." - ).exit(), - DefaultConfigTypeOptions { no_default: true, .. } if command.default_value.is_some() => cmd - .error( - ErrorKind::ArgumentConflict, - "Cannot specify a default value for a no-default config type.", - ) - .exit(), - DefaultConfigTypeOptions { no_default: true, .. } if command.runtime_value.is_none() => cmd - .error( - ErrorKind::ArgumentConflict, - "Types without a default value need a runtime value.", - ) - .exit(), - DefaultConfigTypeOptions { no_default_bounds: true, .. } if !lib_content.contains("pub mod config_preludes") => cmd.error( - ErrorKind::InvalidSubcommand, - "Cannot specify --no-default-bounds if the affected pallet doesn't implement a default config. Pop-Cli follows the convention and looks for a module called 'config_preludes' (defined either inside the pallet's lib file or its own file 'config_preludes.rs'), if your pallet uses a default config under another name, be sure to rename it as 'config_preludes' if you want to use this feature of Pop-Cli." - ).exit(), - DefaultConfigTypeOptions { no_default_bounds: true, .. } - if command.default_value.is_none() && command.runtime_value.is_none() => - cmd.error( - ErrorKind::ArgumentConflict, - "The type needs at least a default value or a runtime value.", - ) - .exit(), - DefaultConfigTypeOptions { no_default: false, no_default_bounds: false } if command.default_value.is_some() && !lib_content.contains("pub mod config_preludes") => cmd.error( - ErrorKind::InvalidSubcommand, - "Cannot specify a --default-value if the affected pallet doesn't implement a default config. Pop-Cli follows the convention and looks for a module called 'config_preludes' (defined either inside the pallet's lib file or its own file 'config_preludes.rs'), if your pallet uses a default config under another name, be sure to rename it as 'config_preludes' if you want to use this feature of Pop-Cli." - ).exit(), - DefaultConfigTypeOptions { no_default: false, no_default_bounds: false } - if command.default_value.is_none() && command.runtime_value.is_none() => - cmd.error( - ErrorKind::ArgumentConflict, - "The type needs at least a default value or a runtime value.", - ) - .exit(), - _ => (), - } -} impl AddConfigTypeCommand { pub(crate) async fn execute(self) -> anyhow::Result<()> { Cli.intro("Add a new type to your pallet")?; let mut cmd = Command::new(""); - let src = &self.path.join("src"); + let pallet_path = prefix_with_current_dir_if_needed(self.pallet_path); + let src = pallet_path.join("src"); // Check that the path correspond to a pallet using that the file lib.rs always contains the // line #[pallet::pallet]. let lib_path = src.join("lib.rs"); @@ -131,79 +55,88 @@ impl AddConfigTypeCommand { .exit(); } - // Check that the command is correct - validate_config_options(&self, &lib_content); + let mut types = if self.types.is_empty() { + multiselect_pick!( + common_types::CommonTypes, + "Select the types you want to include in your pallet" + ) + } else { + self.types + }; + + types = common_types::complete_dependencies(types); + + let using_default_config = lib_content.contains("pub mod config_preludes"); let spinner = cliclack::spinner(); spinner.start("Updating pallet's config trait..."); - let type_name_ident = Ident::new(&capitalize_str(&self.name), Span::call_site()); - // Update the config trait in lib.rs - rust_writer::update_config_trait( - &lib_path, - type_name_ident.clone(), - self.bounds.iter().map(|bound| Ident::new(&bound, Span::call_site())).collect(), - match &self.default_config { - DefaultConfigTypeOptions { no_default: true, .. } => DefaultConfigType::NoDefault, - DefaultConfigTypeOptions { no_default_bounds: true, .. } => - DefaultConfigType::NoDefaultBounds, - _ => DefaultConfigType::Default, - }, - )?; - match &self.default_config { - // No_default only adds the runtime value to runtimes - DefaultConfigTypeOptions { no_default: true, .. } => { - spinner.set_message("Adding your type to pallet's related runtimes..."); - // Add the new type to the mock runtime - rust_writer::add_type_to_runtimes( - &self.path, - type_name_ident.clone(), - parse_str::(&self.runtime_value.expect("validate options stops the execution from clap if runtime_value is none in this scenario; qed;"))?, - self.runtime_impl_path.as_deref() - )?; - }, - // Otherwise, the type is added at least to one: the runtimes or the default - // config - _ => { - if let Some(runtime_value) = &self.runtime_value { - spinner.set_message("Adding your type to pallet's related runtimes..."); - // Add the new type to the mock runtime - rust_writer::add_type_to_runtimes( - &self.path, - type_name_ident.clone(), - parse_str::(&runtime_value)?, - self.runtime_impl_path.as_deref(), - )?; - } - if let Some(default_value) = &self.default_value { - spinner.set_message( - "Adding your type's default value to the pallet's config preludes...", - ); - // If config_preludes is defined in its own file, we pass it to - // 'add_type_to_config_preludes", otherwise we pass lib.rs - let config_preludes_path = src.join("config_preludes.rs"); - let file_path = if config_preludes_path.is_file() { - &config_preludes_path - } else { - &lib_path - }; + for type_ in types{ + rust_writer::add_use_statements( + &lib_path, + type_.get_needed_use_statements() + )?; - rust_writer::add_type_to_config_preludes( - file_path, - type_name_ident, - parse_str::(&default_value)?, - )?; - } - }, - }; + rust_writer::add_composite_enums( + &lib_path, + type_.get_needed_composite_enums() + )?; + + let type_name_ident = Ident::new(&capitalize_str(type_.get_message().unwrap_or_default()), Span::call_site()); + let default_config = if using_default_config{ + type_.get_default_config() + } else { + // Here the inner element's irrelevant, so we place a simple type definition + DefaultConfigType::Default{type_default_impl: parse_quote!{type A = ();}} + }; + // Update the config trait in lib.rs + rust_writer::update_config_trait( + &lib_path, + type_name_ident.clone(), + type_.get_common_trait_bounds(), + &default_config + )?; - if let Some(mut workspace_toml) = find_workspace_toml(&self.path) { + match default_config { + // Need to update default config + DefaultConfigType::Default{ type_default_impl } | DefaultConfigType::NoDefaultBounds{type_default_impl} if using_default_config => { + spinner.set_message( + "Adding your type's default value to the pallet's config preludes...", + ); + // If config_preludes is defined in its own file, we pass it to + // 'add_type_to_config_preludes", otherwise we pass lib.rs + let config_preludes_path = src.join("config_preludes.rs"); + let file_path = if config_preludes_path.is_file() { + &config_preludes_path + } else { + &lib_path + }; + + rust_writer::add_type_to_config_preludes( + file_path, + type_default_impl + )?; + }, + // Need to update runtimes + _ => { + spinner.set_message("Adding your type to pallet's related runtimes..."); + rust_writer::add_type_to_runtimes( + &pallet_path, + type_name_ident, + type_.get_common_runtime_value(), + self.runtime_impl_path.as_deref() + )?; + } + } + } + + if let Some(mut workspace_toml) = find_workspace_toml(&pallet_path) { workspace_toml.pop(); format_dir(&workspace_toml)?; } else { - format_dir(&self.path)?; + format_dir(&pallet_path)?; } spinner.stop("Your type is ready to be used in your pallet 🚀"); Ok(()) } -} +} \ No newline at end of file diff --git a/crates/pop-cli/src/commands/add/config_type/common_types.rs b/crates/pop-cli/src/commands/add/config_type/common_types.rs new file mode 100644 index 000000000..ff837ad3a --- /dev/null +++ b/crates/pop-cli/src/commands/add/config_type/common_types.rs @@ -0,0 +1,135 @@ +// SPDX-License-Identifier: GPL-3.0 +use clap::ValueEnum; +use strum_macros::{EnumIter, EnumMessage}; +use syn::{parse_quote, Type, TraitBound, ImplItem, ItemUse, ItemEnum}; +use pop_common::rust_writer::types::DefaultConfigType; + +/// This enum is used to register from the CLI which types that are kind of usual in config traits +/// are included in the pallet +#[derive(Debug, Copy, Clone, PartialEq, EnumIter, EnumMessage, ValueEnum)] +pub enum CommonTypes { + /// This type will enable your pallet to emit events. + #[strum( + message = "RuntimeEvent", + detailed_message = "This type will enable your pallet to emit events." + )] + RuntimeEvent, + /// This type will be helpful if your pallet needs to deal with the outer RuntimeOrigin enum, + /// or if your pallet needs to use custom origins. + #[strum( + message = "RuntimeOrigin", + detailed_message = "This type will be helpful if your pallet needs to deal with the outer RuntimeOrigin enum, or if your pallet needs to use custom origins." + )] + RuntimeOrigin, + /// This type will be helpful if your pallet needs to hold funds. + #[strum( + message = "RuntimeHoldReason", + detailed_message = "This type will be helpful if your pallet needs to hold funds." + )] + RuntimeHoldReason, + /// This type will be helpful if your pallet needs to freeze funds. + #[strum( + message = "RuntimeFreezeReason", + detailed_message = "This type will be helpful if your pallet needs to freeze funds." + )] + RuntimeFreezeReason, + /// This type will allow your pallet to manage fungible assets. If you add this type to your pallet, RuntimeHoldReason and RuntimeFreezeReason will be added as well + #[strum( + message = "Fungibles", + detailed_message = "This type will allow your pallet to manage fungible assets. If you add this type to your pallet, RuntimeHoldReason and RuntimeFreezeReason will be added as well" + )] + Fungibles, +} + +impl CommonTypes { + pub fn get_common_trait_bounds(&self) -> Vec{ + match self{ + CommonTypes::RuntimeEvent => vec![parse_quote!{From>}, parse_quote!{IsType<::RuntimeEvent>}], + CommonTypes::RuntimeOrigin => vec![parse_quote!{From>}], + CommonTypes::RuntimeHoldReason => vec![parse_quote!{From}], + CommonTypes::RuntimeFreezeReason => vec![parse_quote!{VariantCount}], + CommonTypes::Fungibles => vec![ + parse_quote! {fungible::Inspect}, + parse_quote!{fungible::Mutate}, + parse_quote!{fungible::hold::Inspect}, + parse_quote!{fungible::hold::Mutate}, + parse_quote!{fungible::freeze::Inspect}, + parse_quote!{fungible::freeze::Mutate} + ] + } + } + + pub fn get_common_runtime_value(&self) -> Type { + match self { + CommonTypes::RuntimeEvent => parse_quote! {RuntimeEvent}, + CommonTypes::RuntimeOrigin => parse_quote! {RuntimeOrigin}, + CommonTypes::RuntimeHoldReason => parse_quote! {RuntimeHoldReason}, + CommonTypes::RuntimeFreezeReason => parse_quote! {RuntimeFreezeReason}, + CommonTypes::Fungibles => parse_quote! {Balances}, + } + } + + + pub fn get_default_config(&self) -> DefaultConfigType{ + match self{ + CommonTypes::RuntimeEvent => DefaultConfigType::NoDefaultBounds{type_default_impl: ImplItem::Type(parse_quote!{ + #[inject_runtime_type] + type RuntimeEvent = (); + })}, + CommonTypes::RuntimeOrigin => DefaultConfigType::NoDefaultBounds{type_default_impl: ImplItem::Type(parse_quote!{ + #[inject_runtime_type] + type RuntimeOrigin = (); + })}, + CommonTypes::RuntimeHoldReason => DefaultConfigType::NoDefaultBounds{type_default_impl: ImplItem::Type(parse_quote!{ + #[inject_runtime_type] + type RuntimeHoldReason = (); + })}, + CommonTypes::RuntimeFreezeReason => DefaultConfigType::NoDefaultBounds{type_default_impl: ImplItem::Type(parse_quote!{ + #[inject_runtime_type] + type RuntimeFreezeReason = (); + })}, + CommonTypes::Fungibles => DefaultConfigType::NoDefault, + } + } + + pub fn get_needed_use_statements(&self) -> Vec{ + match self{ + CommonTypes::RuntimeEvent => Vec::new(), + CommonTypes::RuntimeOrigin => Vec::new(), + CommonTypes::RuntimeHoldReason => Vec::new(), + CommonTypes::RuntimeFreezeReason => vec![parse_quote!{use frame::traits::VariantCount;}], + CommonTypes::Fungibles => vec![parse_quote!{use frame::traits::fungible;}], + } + } + + pub fn get_needed_composite_enums(&self) -> Vec{ + match self{ + CommonTypes::RuntimeEvent => Vec::new(), + CommonTypes::RuntimeOrigin => Vec::new(), + CommonTypes::RuntimeHoldReason => vec![parse_quote!{ + /// A reason for the pallet placing a hold on funds. + #[pallet::composite_enum] + pub enum HoldReason { + /// Some hold reason + #[codec(index = 0)] + SomeHoldReason, + } + }], + CommonTypes::RuntimeFreezeReason => Vec::new(), + CommonTypes::Fungibles => Vec::new() + } + } +} + +pub fn complete_dependencies(mut types: Vec) -> Vec{ + if types.contains(&CommonTypes::Fungibles){ + if !types.contains(&CommonTypes::RuntimeHoldReason){ + types.push(CommonTypes::RuntimeHoldReason); + } + + if !types.contains(&CommonTypes::RuntimeFreezeReason){ + types.push(CommonTypes::RuntimeFreezeReason); + } + } + types +} \ No newline at end of file diff --git a/crates/pop-cli/src/commands/add/pallet.rs b/crates/pop-cli/src/commands/add/pallet.rs index 1fd3333a1..fb934d36b 100644 --- a/crates/pop-cli/src/commands/add/pallet.rs +++ b/crates/pop-cli/src/commands/add/pallet.rs @@ -8,7 +8,7 @@ use clap::{error::ErrorKind, Args, Command}; use cliclack::multiselect; use pop_common::{ find_pallet_runtime_impl_path, find_workspace_toml, format_dir, - manifest::types::CrateDependencie, rust_writer, + manifest::types::CrateDependencie, rust_writer,prefix_with_current_dir_if_needed }; use std::{env::current_dir, path::PathBuf}; use strum::{EnumMessage, IntoEnumIterator}; @@ -34,20 +34,20 @@ pub struct AddPalletCommand { impl AddPalletCommand { pub(crate) async fn execute(self) -> anyhow::Result<()> { Cli.intro("Add a new pallet to your runtime")?; - let path = if let Some(path) = &self.runtime_path { - path + let runtime_path = if let Some(path) = &self.runtime_path { + prefix_with_current_dir_if_needed(path.to_path_buf()) } else { let working_dir = current_dir().expect("Cannot modify your working directory"); // Give the chance to use the command either from a workspace containing a runtime or // from a runtime crate if path not specified if working_dir.join("runtime").exists() { - &working_dir.join("runtime") + prefix_with_current_dir_if_needed(working_dir.join("runtime")) } else { - &working_dir.clone() + prefix_with_current_dir_if_needed(working_dir) } }; let mut cmd = Command::new(""); - let src = path.join("src"); + let src = runtime_path.join("src"); let lib_path = src.join("lib.rs"); if !lib_path.is_file() { cmd.error( @@ -98,11 +98,11 @@ impl AddPalletCommand { )?; } - if let Some(mut workspace_toml) = find_workspace_toml(path) { + if let Some(mut workspace_toml) = find_workspace_toml(&runtime_path) { workspace_toml.pop(); format_dir(&workspace_toml)?; } else { - format_dir(path)?; + format_dir(&runtime_path)?; } spinner.stop("Your runtime has been updated and it's ready to use 🚀"); Ok(()) diff --git a/crates/pop-common/src/rust_writer.rs b/crates/pop-common/src/rust_writer.rs index 6d4dc23e1..8e887872b 100644 --- a/crates/pop-common/src/rust_writer.rs +++ b/crates/pop-common/src/rust_writer.rs @@ -11,7 +11,7 @@ use crate::{ use prettyplease::unparse; use proc_macro2::Span; use std::{fs, path::Path}; -use syn::{parse_str, Ident, Type}; +use syn::{parse_str, Ident, Type, TraitBound, ImplItem, ItemUse, ItemEnum}; mod expand; mod helpers; @@ -21,11 +21,11 @@ pub mod types; pub fn update_config_trait( file_path: &Path, type_name: Ident, - trait_bounds: Vec, - default_config: types::DefaultConfigType, + trait_bounds: Vec, + default_config: &types::DefaultConfigType, ) -> Result<(), Error> { let mut ast = helpers::preserve_and_parse(fs::read_to_string(file_path)?, vec![])?; - + // Expand the config trait expand::expand_pallet_config_trait(&mut ast, default_config, type_name, trait_bounds); let generated_code = helpers::resolve_preserved(unparse(&ast)); @@ -105,13 +105,12 @@ pub fn add_type_to_runtimes( pub fn add_type_to_config_preludes( file_path: &Path, - type_name: Ident, - default_value: Type, + type_default_impl: ImplItem, ) -> Result<(), Error> { let mut ast = helpers::preserve_and_parse(fs::read_to_string(file_path)?, vec![])?; // Expand the config_preludes - expand::expand_pallet_config_preludes(&mut ast, type_name, default_value); + expand::expand_pallet_config_preludes(&mut ast, type_default_impl); let generated_code = helpers::resolve_preserved(unparse(&ast)); @@ -219,3 +218,45 @@ pub fn add_pallet_impl_block_to_runtime( })?; Ok(()) } + +pub fn add_use_statements( + file_path: &Path, + use_statements: Vec +) -> Result<(), Error>{ + let mut ast = helpers::preserve_and_parse(fs::read_to_string(file_path)?, vec![])?; + + use_statements.into_iter().for_each(|use_statement|{ + if !parse::find_use_statement(&ast, &use_statement){ + expand::expand_add_use_statement(&mut ast, use_statement) + } + }); + + let generated_code = helpers::resolve_preserved(unparse(&ast)); + + fs::write(file_path, &generated_code).map_err(|_| { + Error::WriteError(format!("Path :{}", file_path.to_str().unwrap_or("Invalid UTF-8 path"))) + })?; + + Ok(()) +} + +pub fn add_composite_enums( + file_path: &Path, + composite_enums: Vec +) -> Result<(), Error>{ + let mut ast = helpers::preserve_and_parse(fs::read_to_string(file_path)?, vec![])?; + + composite_enums.into_iter().for_each(|composite_enum|{ + if !parse::find_composite_enum(&ast, &composite_enum){ + expand::expand_add_composite_enum(&mut ast, composite_enum); + } + }); + + let generated_code = helpers::resolve_preserved(unparse(&ast)); + + fs::write(file_path, &generated_code).map_err(|_| { + Error::WriteError(format!("Path :{}", file_path.to_str().unwrap_or("Invalid UTF-8 path"))) + })?; + + Ok(()) +} diff --git a/crates/pop-common/src/rust_writer/expand.rs b/crates/pop-common/src/rust_writer/expand.rs index a9ee74d84..f47cd06d6 100644 --- a/crates/pop-common/src/rust_writer/expand.rs +++ b/crates/pop-common/src/rust_writer/expand.rs @@ -4,14 +4,14 @@ use crate::{capitalize_str, rust_writer::types::*}; use proc_macro2::{Group, Literal, Span, TokenStream, TokenTree}; use syn::{ parse_quote, Expr, File, Ident, ImplItem, Item, ItemImpl, ItemMacro, ItemMod, ItemTrait, Macro, - Meta, MetaList, TraitItem, Type, + Meta, MetaList, TraitItem, Type, TraitBound, ItemUse, ItemEnum, ItemStruct }; pub(crate) fn expand_pallet_config_trait( ast: &mut File, - default_config: DefaultConfigType, + default_config: &DefaultConfigType, type_name: Ident, - trait_bounds: Vec, + trait_bounds: Vec, ) { for item in &mut ast.items { match item { @@ -24,7 +24,7 @@ pub(crate) fn expand_pallet_config_trait( match item { Item::Trait(ItemTrait { ident, items, .. }) if *ident == "Config" => { items.push(match default_config { - DefaultConfigType::Default => TraitItem::Type(parse_quote! { + DefaultConfigType::Default{..} => TraitItem::Type(parse_quote! { ///EMPTY_LINE type #type_name: #(#trait_bounds +)*; }), @@ -33,7 +33,7 @@ pub(crate) fn expand_pallet_config_trait( #[pallet::no_default] type #type_name: #(#trait_bounds +)*; }), - DefaultConfigType::NoDefaultBounds => { + DefaultConfigType::NoDefaultBounds{..} => { TraitItem::Type(parse_quote! { ///EMPTY_LINE #[pallet::no_default_bounds] @@ -51,7 +51,7 @@ pub(crate) fn expand_pallet_config_trait( } } -pub(crate) fn expand_pallet_config_preludes(ast: &mut File, type_name: Ident, default_value: Type) { +pub(crate) fn expand_pallet_config_preludes(ast: &mut File, type_default_impl: ImplItem) { for item in &mut ast.items { match item { // In case file_path points to lib.rs, config_preludes is contained inside pallet mod in @@ -86,9 +86,7 @@ pub(crate) fn expand_pallet_config_preludes(ast: &mut File, type_name: Ident, de false } }) => - items.push(ImplItem::Type(parse_quote! { - type #type_name = #default_value; - })), + items.push(type_default_impl.clone()), _ => continue, } } @@ -109,9 +107,7 @@ pub(crate) fn expand_pallet_config_preludes(ast: &mut File, type_name: Ident, de false } }) => - items.push(ImplItem::Type(parse_quote! { - type #type_name = #default_value; - })), + items.push(type_default_impl.clone()), _ => continue, } } @@ -239,3 +235,34 @@ pub(crate) fn expand_runtime_add_type_to_impl_block( } } } + +pub(crate) fn expand_add_use_statement(ast: &mut File, use_statement: ItemUse){ + let items = &mut ast.items; + // Find the first use statement + let position = items.iter().position(|item| matches!(item, Item::Use(_))) + .unwrap_or(0); + // Insert the use statement where needed + items.insert(position, Item::Use(use_statement)); +} + +pub(crate) fn expand_add_composite_enum(ast: &mut File, composite_enum: ItemEnum){ + for item in &mut ast.items{ + match item{ + Item::Mod(ItemMod { ident, content, .. }) + if *ident == "pallet" && content.is_some() => + { + let (_, items) = + content.as_mut().expect("content is always Some thanks to the match guard"); + // Find the Pallet struct position + let position = items.iter().position(|item| match item{ + Item::Struct(ItemStruct{ident, ..}) if *ident=="Pallet" => true, + _ => false + }) + .unwrap_or(0); + // Insert the composite_enum just before the Pallet struct + items.insert(position.saturating_sub(1), Item::Enum(composite_enum.clone())); + }, + _ => continue + } + } +} diff --git a/crates/pop-common/src/rust_writer/parse.rs b/crates/pop-common/src/rust_writer/parse.rs index 1af4b5b01..e9ceb4408 100644 --- a/crates/pop-common/src/rust_writer/parse.rs +++ b/crates/pop-common/src/rust_writer/parse.rs @@ -2,7 +2,7 @@ use crate::rust_writer::types::RuntimeUsedMacro; use std::cmp; -use syn::{File, Item, ItemMacro, ItemMod, ItemType, Macro, Meta, MetaList}; +use syn::{File, Item, ItemMacro, ItemMod, ItemType, Macro, Meta, MetaList, ItemUse, ItemEnum}; /// Find the highest implemented pallet index in the outer enum if using the macro /// #[runtime]. We suppose it's a u8, it's not likely that a runtime implements more than 256 @@ -64,3 +64,34 @@ pub(crate) fn find_highest_pallet_index_and_runtime_macro_version( } (highest_index, used_macro) } + +pub(crate) fn find_use_statement(ast: &File, use_statement: &ItemUse) -> bool{ + for item in &ast.items{ + match item{ + Item::Use(item_use) if item_use == use_statement => return true, + _ => continue + } + } + false +} + +pub(crate) fn find_composite_enum(ast: &File, composite_enum: &ItemEnum) -> bool{ + for item in &ast.items{ + match item{ + Item::Mod(ItemMod { ident, content, .. }) + if *ident == "pallet" && content.is_some() => + { + let (_, items) = + content.as_ref().expect("content is always Some thanks to the match guard"); + for item in items { + match item{ + Item::Enum(ItemEnum{ident,..}) if *ident == composite_enum.ident => return true, + _ => continue + } + } + }, + _ => continue + } + } + false +} diff --git a/crates/pop-common/src/rust_writer/types.rs b/crates/pop-common/src/rust_writer/types.rs index 9f41f0907..34e5c9d72 100644 --- a/crates/pop-common/src/rust_writer/types.rs +++ b/crates/pop-common/src/rust_writer/types.rs @@ -1,12 +1,12 @@ // SPDX-License-Identifier: GPL-3.0 -use syn::{Expr, Type}; +use syn::{Expr, Type, ImplItem}; #[derive(Debug, Clone, PartialEq)] pub enum DefaultConfigType { - Default, + Default{type_default_impl: ImplItem}, NoDefault, - NoDefaultBounds, + NoDefaultBounds{type_default_impl: ImplItem}, } #[derive(Debug, Clone, PartialEq)] From 521639acfe24a05a4adf7024759a26f412f14a26 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1s=20Senovilla=20Polo?= Date: Sun, 6 Oct 2024 19:32:06 +0200 Subject: [PATCH 10/46] Fmt + clippy --- .../pop-cli/src/commands/add/config_type.rs | 129 +++++++------- .../commands/add/config_type/common_types.rs | 164 ++++++++++-------- crates/pop-cli/src/commands/add/pallet.rs | 2 +- crates/pop-common/src/rust_writer.rs | 48 +++-- crates/pop-common/src/rust_writer/expand.rs | 59 +++---- crates/pop-common/src/rust_writer/helpers.rs | 2 +- crates/pop-common/src/rust_writer/parse.rs | 45 ++--- crates/pop-common/src/rust_writer/types.rs | 6 +- 8 files changed, 231 insertions(+), 224 deletions(-) diff --git a/crates/pop-cli/src/commands/add/config_type.rs b/crates/pop-cli/src/commands/add/config_type.rs index d340f7453..41551713f 100644 --- a/crates/pop-cli/src/commands/add/config_type.rs +++ b/crates/pop-cli/src/commands/add/config_type.rs @@ -4,17 +4,20 @@ mod common_types; #[cfg(test)] mod tests; -use crate::{cli::{traits::Cli as _, Cli}, multiselect_pick}; +use crate::{ + cli::{traits::Cli as _, Cli}, + multiselect_pick, +}; use clap::{error::ErrorKind, Args, Command}; use cliclack::multiselect; use pop_common::{ - capitalize_str, find_workspace_toml, format_dir, - rust_writer::{self, types::*}, prefix_with_current_dir_if_needed + capitalize_str, find_workspace_toml, format_dir, prefix_with_current_dir_if_needed, + rust_writer::{self, types::*}, }; use proc_macro2::Span; use std::{fs, path::PathBuf}; -use syn::{parse_quote, Ident}; use strum::{EnumMessage, IntoEnumIterator}; +use syn::{parse_quote, Ident}; #[derive(Args, Debug, Clone)] pub struct AddConfigTypeCommand { @@ -29,12 +32,11 @@ pub struct AddConfigTypeCommand { pub(crate) runtime_impl_path: Option, } - impl AddConfigTypeCommand { pub(crate) async fn execute(self) -> anyhow::Result<()> { Cli.intro("Add a new type to your pallet")?; let mut cmd = Command::new(""); - let pallet_path = prefix_with_current_dir_if_needed(self.pallet_path); + let pallet_path = prefix_with_current_dir_if_needed(self.pallet_path); let src = pallet_path.join("src"); // Check that the path correspond to a pallet using that the file lib.rs always contains the // line #[pallet::pallet]. @@ -55,7 +57,7 @@ impl AddConfigTypeCommand { .exit(); } - let mut types = if self.types.is_empty() { + let mut types = if self.types.is_empty() { multiselect_pick!( common_types::CommonTypes, "Select the types you want to include in your pallet" @@ -64,71 +66,68 @@ impl AddConfigTypeCommand { self.types }; - types = common_types::complete_dependencies(types); + types = common_types::complete_dependencies(types); - let using_default_config = lib_content.contains("pub mod config_preludes"); + let using_default_config = lib_content.contains("pub mod config_preludes"); let spinner = cliclack::spinner(); spinner.start("Updating pallet's config trait..."); - for type_ in types{ - rust_writer::add_use_statements( - &lib_path, - type_.get_needed_use_statements() - )?; + for type_ in types { + rust_writer::add_use_statements(&lib_path, type_.get_needed_use_statements())?; - rust_writer::add_composite_enums( - &lib_path, - type_.get_needed_composite_enums() - )?; + rust_writer::add_composite_enums(&lib_path, type_.get_needed_composite_enums())?; - let type_name_ident = Ident::new(&capitalize_str(type_.get_message().unwrap_or_default()), Span::call_site()); - let default_config = if using_default_config{ - type_.get_default_config() - } else { - // Here the inner element's irrelevant, so we place a simple type definition - DefaultConfigType::Default{type_default_impl: parse_quote!{type A = ();}} - }; - // Update the config trait in lib.rs - rust_writer::update_config_trait( - &lib_path, - type_name_ident.clone(), - type_.get_common_trait_bounds(), - &default_config - )?; + let type_name_ident = Ident::new( + &capitalize_str(type_.get_message().unwrap_or_default()), + Span::call_site(), + ); + let default_config = if using_default_config { + type_.get_default_config() + } else { + // Here the inner element's irrelevant, so we place a simple type definition + DefaultConfigType::Default { type_default_impl: parse_quote! {type A = ();} } + }; + // Update the config trait in lib.rs + rust_writer::update_config_trait( + &lib_path, + type_name_ident.clone(), + type_.get_common_trait_bounds(), + &default_config, + )?; - match default_config { - // Need to update default config - DefaultConfigType::Default{ type_default_impl } | DefaultConfigType::NoDefaultBounds{type_default_impl} if using_default_config => { - spinner.set_message( - "Adding your type's default value to the pallet's config preludes...", - ); - // If config_preludes is defined in its own file, we pass it to - // 'add_type_to_config_preludes", otherwise we pass lib.rs - let config_preludes_path = src.join("config_preludes.rs"); - let file_path = if config_preludes_path.is_file() { - &config_preludes_path - } else { - &lib_path - }; - - rust_writer::add_type_to_config_preludes( - file_path, - type_default_impl - )?; - }, - // Need to update runtimes - _ => { - spinner.set_message("Adding your type to pallet's related runtimes..."); - rust_writer::add_type_to_runtimes( - &pallet_path, - type_name_ident, - type_.get_common_runtime_value(), - self.runtime_impl_path.as_deref() - )?; - } - } - } + match default_config { + // Need to update default config + DefaultConfigType::Default { type_default_impl } | + DefaultConfigType::NoDefaultBounds { type_default_impl } + if using_default_config => + { + spinner.set_message( + "Adding your type's default value to the pallet's config preludes...", + ); + // If config_preludes is defined in its own file, we pass it to + // 'add_type_to_config_preludes", otherwise we pass lib.rs + let config_preludes_path = src.join("config_preludes.rs"); + let file_path = if config_preludes_path.is_file() { + &config_preludes_path + } else { + &lib_path + }; + + rust_writer::add_type_to_config_preludes(file_path, type_default_impl)?; + }, + // Need to update runtimes + _ => { + spinner.set_message("Adding your type to pallet's related runtimes..."); + rust_writer::add_type_to_runtimes( + &pallet_path, + type_name_ident, + type_.get_common_runtime_value(), + self.runtime_impl_path.as_deref(), + )?; + }, + } + } if let Some(mut workspace_toml) = find_workspace_toml(&pallet_path) { workspace_toml.pop(); @@ -139,4 +138,4 @@ impl AddConfigTypeCommand { spinner.stop("Your type is ready to be used in your pallet 🚀"); Ok(()) } -} \ No newline at end of file +} diff --git a/crates/pop-cli/src/commands/add/config_type/common_types.rs b/crates/pop-cli/src/commands/add/config_type/common_types.rs index ff837ad3a..3863a138a 100644 --- a/crates/pop-cli/src/commands/add/config_type/common_types.rs +++ b/crates/pop-cli/src/commands/add/config_type/common_types.rs @@ -1,8 +1,8 @@ // SPDX-License-Identifier: GPL-3.0 use clap::ValueEnum; -use strum_macros::{EnumIter, EnumMessage}; -use syn::{parse_quote, Type, TraitBound, ImplItem, ItemUse, ItemEnum}; use pop_common::rust_writer::types::DefaultConfigType; +use strum_macros::{EnumIter, EnumMessage}; +use syn::{parse_quote, ImplItem, ItemEnum, ItemUse, TraitBound, Type}; /// This enum is used to register from the CLI which types that are kind of usual in config traits /// are included in the pallet @@ -21,19 +21,20 @@ pub enum CommonTypes { detailed_message = "This type will be helpful if your pallet needs to deal with the outer RuntimeOrigin enum, or if your pallet needs to use custom origins." )] RuntimeOrigin, - /// This type will be helpful if your pallet needs to hold funds. + /// This type will be helpful if your pallet needs to hold funds. #[strum( message = "RuntimeHoldReason", detailed_message = "This type will be helpful if your pallet needs to hold funds." )] RuntimeHoldReason, - /// This type will be helpful if your pallet needs to freeze funds. + /// This type will be helpful if your pallet needs to freeze funds. #[strum( message = "RuntimeFreezeReason", detailed_message = "This type will be helpful if your pallet needs to freeze funds." )] RuntimeFreezeReason, - /// This type will allow your pallet to manage fungible assets. If you add this type to your pallet, RuntimeHoldReason and RuntimeFreezeReason will be added as well + /// This type will allow your pallet to manage fungible assets. If you add this type to your + /// pallet, RuntimeHoldReason and RuntimeFreezeReason will be added as well #[strum( message = "Fungibles", detailed_message = "This type will allow your pallet to manage fungible assets. If you add this type to your pallet, RuntimeHoldReason and RuntimeFreezeReason will be added as well" @@ -42,22 +43,25 @@ pub enum CommonTypes { } impl CommonTypes { - pub fn get_common_trait_bounds(&self) -> Vec{ - match self{ - CommonTypes::RuntimeEvent => vec![parse_quote!{From>}, parse_quote!{IsType<::RuntimeEvent>}], - CommonTypes::RuntimeOrigin => vec![parse_quote!{From>}], - CommonTypes::RuntimeHoldReason => vec![parse_quote!{From}], - CommonTypes::RuntimeFreezeReason => vec![parse_quote!{VariantCount}], + pub fn get_common_trait_bounds(&self) -> Vec { + match self { + CommonTypes::RuntimeEvent => vec![ + parse_quote! {From>}, + parse_quote! {IsType<::RuntimeEvent>}, + ], + CommonTypes::RuntimeOrigin => vec![parse_quote! {From>}], + CommonTypes::RuntimeHoldReason => vec![parse_quote! {From}], + CommonTypes::RuntimeFreezeReason => vec![parse_quote! {VariantCount}], CommonTypes::Fungibles => vec![ - parse_quote! {fungible::Inspect}, - parse_quote!{fungible::Mutate}, - parse_quote!{fungible::hold::Inspect}, - parse_quote!{fungible::hold::Mutate}, - parse_quote!{fungible::freeze::Inspect}, - parse_quote!{fungible::freeze::Mutate} - ] - } - } + parse_quote! {fungible::Inspect}, + parse_quote! {fungible::Mutate}, + parse_quote! {fungible::hold::Inspect}, + parse_quote! {fungible::hold::Mutate}, + parse_quote! {fungible::freeze::Inspect}, + parse_quote! {fungible::freeze::Mutate}, + ], + } + } pub fn get_common_runtime_value(&self) -> Type { match self { @@ -69,67 +73,75 @@ impl CommonTypes { } } + pub fn get_default_config(&self) -> DefaultConfigType { + match self { + CommonTypes::RuntimeEvent => DefaultConfigType::NoDefaultBounds { + type_default_impl: ImplItem::Type(parse_quote! { + #[inject_runtime_type] + type RuntimeEvent = (); + }), + }, + CommonTypes::RuntimeOrigin => DefaultConfigType::NoDefaultBounds { + type_default_impl: ImplItem::Type(parse_quote! { + #[inject_runtime_type] + type RuntimeOrigin = (); + }), + }, + CommonTypes::RuntimeHoldReason => DefaultConfigType::NoDefaultBounds { + type_default_impl: ImplItem::Type(parse_quote! { + #[inject_runtime_type] + type RuntimeHoldReason = (); + }), + }, + CommonTypes::RuntimeFreezeReason => DefaultConfigType::NoDefaultBounds { + type_default_impl: ImplItem::Type(parse_quote! { + #[inject_runtime_type] + type RuntimeFreezeReason = (); + }), + }, + CommonTypes::Fungibles => DefaultConfigType::NoDefault, + } + } - pub fn get_default_config(&self) -> DefaultConfigType{ - match self{ - CommonTypes::RuntimeEvent => DefaultConfigType::NoDefaultBounds{type_default_impl: ImplItem::Type(parse_quote!{ - #[inject_runtime_type] - type RuntimeEvent = (); - })}, - CommonTypes::RuntimeOrigin => DefaultConfigType::NoDefaultBounds{type_default_impl: ImplItem::Type(parse_quote!{ - #[inject_runtime_type] - type RuntimeOrigin = (); - })}, - CommonTypes::RuntimeHoldReason => DefaultConfigType::NoDefaultBounds{type_default_impl: ImplItem::Type(parse_quote!{ - #[inject_runtime_type] - type RuntimeHoldReason = (); - })}, - CommonTypes::RuntimeFreezeReason => DefaultConfigType::NoDefaultBounds{type_default_impl: ImplItem::Type(parse_quote!{ - #[inject_runtime_type] - type RuntimeFreezeReason = (); - })}, - CommonTypes::Fungibles => DefaultConfigType::NoDefault, - } - } - - pub fn get_needed_use_statements(&self) -> Vec{ - match self{ - CommonTypes::RuntimeEvent => Vec::new(), + pub fn get_needed_use_statements(&self) -> Vec { + match self { + CommonTypes::RuntimeEvent => Vec::new(), CommonTypes::RuntimeOrigin => Vec::new(), CommonTypes::RuntimeHoldReason => Vec::new(), - CommonTypes::RuntimeFreezeReason => vec![parse_quote!{use frame::traits::VariantCount;}], - CommonTypes::Fungibles => vec![parse_quote!{use frame::traits::fungible;}], - } - } + CommonTypes::RuntimeFreezeReason => + vec![parse_quote! {use frame::traits::VariantCount;}], + CommonTypes::Fungibles => vec![parse_quote! {use frame::traits::fungible;}], + } + } - pub fn get_needed_composite_enums(&self) -> Vec{ - match self{ - CommonTypes::RuntimeEvent => Vec::new(), + pub fn get_needed_composite_enums(&self) -> Vec { + match self { + CommonTypes::RuntimeEvent => Vec::new(), CommonTypes::RuntimeOrigin => Vec::new(), - CommonTypes::RuntimeHoldReason => vec![parse_quote!{ - /// A reason for the pallet placing a hold on funds. - #[pallet::composite_enum] - pub enum HoldReason { - /// Some hold reason - #[codec(index = 0)] - SomeHoldReason, - } - }], - CommonTypes::RuntimeFreezeReason => Vec::new(), - CommonTypes::Fungibles => Vec::new() - } - } + CommonTypes::RuntimeHoldReason => vec![parse_quote! { + /// A reason for the pallet placing a hold on funds. + #[pallet::composite_enum] + pub enum HoldReason { + /// Some hold reason + #[codec(index = 0)] + SomeHoldReason, + } + }], + CommonTypes::RuntimeFreezeReason => Vec::new(), + CommonTypes::Fungibles => Vec::new(), + } + } } -pub fn complete_dependencies(mut types: Vec) -> Vec{ - if types.contains(&CommonTypes::Fungibles){ - if !types.contains(&CommonTypes::RuntimeHoldReason){ - types.push(CommonTypes::RuntimeHoldReason); - } +pub fn complete_dependencies(mut types: Vec) -> Vec { + if types.contains(&CommonTypes::Fungibles) { + if !types.contains(&CommonTypes::RuntimeHoldReason) { + types.push(CommonTypes::RuntimeHoldReason); + } - if !types.contains(&CommonTypes::RuntimeFreezeReason){ - types.push(CommonTypes::RuntimeFreezeReason); - } - } - types -} \ No newline at end of file + if !types.contains(&CommonTypes::RuntimeFreezeReason) { + types.push(CommonTypes::RuntimeFreezeReason); + } + } + types +} diff --git a/crates/pop-cli/src/commands/add/pallet.rs b/crates/pop-cli/src/commands/add/pallet.rs index fb934d36b..81c534e4c 100644 --- a/crates/pop-cli/src/commands/add/pallet.rs +++ b/crates/pop-cli/src/commands/add/pallet.rs @@ -8,7 +8,7 @@ use clap::{error::ErrorKind, Args, Command}; use cliclack::multiselect; use pop_common::{ find_pallet_runtime_impl_path, find_workspace_toml, format_dir, - manifest::types::CrateDependencie, rust_writer,prefix_with_current_dir_if_needed + manifest::types::CrateDependencie, prefix_with_current_dir_if_needed, rust_writer, }; use std::{env::current_dir, path::PathBuf}; use strum::{EnumMessage, IntoEnumIterator}; diff --git a/crates/pop-common/src/rust_writer.rs b/crates/pop-common/src/rust_writer.rs index 8e887872b..e9c48721c 100644 --- a/crates/pop-common/src/rust_writer.rs +++ b/crates/pop-common/src/rust_writer.rs @@ -11,7 +11,7 @@ use crate::{ use prettyplease::unparse; use proc_macro2::Span; use std::{fs, path::Path}; -use syn::{parse_str, Ident, Type, TraitBound, ImplItem, ItemUse, ItemEnum}; +use syn::{parse_str, Ident, ImplItem, ItemEnum, ItemUse, TraitBound, Type}; mod expand; mod helpers; @@ -25,7 +25,7 @@ pub fn update_config_trait( default_config: &types::DefaultConfigType, ) -> Result<(), Error> { let mut ast = helpers::preserve_and_parse(fs::read_to_string(file_path)?, vec![])?; - + // Expand the config trait expand::expand_pallet_config_trait(&mut ast, default_config, type_name, trait_bounds); let generated_code = helpers::resolve_preserved(unparse(&ast)); @@ -199,7 +199,7 @@ pub fn add_pallet_impl_block_to_runtime( default_config, ); // Expand the block to add the types - types.into_iter().zip(values.into_iter()).for_each(|(type_, value)| { + types.into_iter().zip(values).for_each(|(type_, value)| { expand::expand_runtime_add_type_to_impl_block( &mut ast, type_, @@ -219,44 +219,38 @@ pub fn add_pallet_impl_block_to_runtime( Ok(()) } -pub fn add_use_statements( - file_path: &Path, - use_statements: Vec -) -> Result<(), Error>{ - let mut ast = helpers::preserve_and_parse(fs::read_to_string(file_path)?, vec![])?; +pub fn add_use_statements(file_path: &Path, use_statements: Vec) -> Result<(), Error> { + let mut ast = helpers::preserve_and_parse(fs::read_to_string(file_path)?, vec![])?; - use_statements.into_iter().for_each(|use_statement|{ - if !parse::find_use_statement(&ast, &use_statement){ - expand::expand_add_use_statement(&mut ast, use_statement) - } - }); + use_statements.into_iter().for_each(|use_statement| { + if !parse::find_use_statement(&ast, &use_statement) { + expand::expand_add_use_statement(&mut ast, use_statement) + } + }); - let generated_code = helpers::resolve_preserved(unparse(&ast)); + let generated_code = helpers::resolve_preserved(unparse(&ast)); fs::write(file_path, &generated_code).map_err(|_| { Error::WriteError(format!("Path :{}", file_path.to_str().unwrap_or("Invalid UTF-8 path"))) })?; - Ok(()) + Ok(()) } -pub fn add_composite_enums( - file_path: &Path, - composite_enums: Vec -) -> Result<(), Error>{ - let mut ast = helpers::preserve_and_parse(fs::read_to_string(file_path)?, vec![])?; +pub fn add_composite_enums(file_path: &Path, composite_enums: Vec) -> Result<(), Error> { + let mut ast = helpers::preserve_and_parse(fs::read_to_string(file_path)?, vec![])?; - composite_enums.into_iter().for_each(|composite_enum|{ - if !parse::find_composite_enum(&ast, &composite_enum){ - expand::expand_add_composite_enum(&mut ast, composite_enum); - } - }); + composite_enums.into_iter().for_each(|composite_enum| { + if !parse::find_composite_enum(&ast, &composite_enum) { + expand::expand_add_composite_enum(&mut ast, composite_enum); + } + }); - let generated_code = helpers::resolve_preserved(unparse(&ast)); + let generated_code = helpers::resolve_preserved(unparse(&ast)); fs::write(file_path, &generated_code).map_err(|_| { Error::WriteError(format!("Path :{}", file_path.to_str().unwrap_or("Invalid UTF-8 path"))) })?; - Ok(()) + Ok(()) } diff --git a/crates/pop-common/src/rust_writer/expand.rs b/crates/pop-common/src/rust_writer/expand.rs index f47cd06d6..ec03ded5a 100644 --- a/crates/pop-common/src/rust_writer/expand.rs +++ b/crates/pop-common/src/rust_writer/expand.rs @@ -3,8 +3,8 @@ use crate::{capitalize_str, rust_writer::types::*}; use proc_macro2::{Group, Literal, Span, TokenStream, TokenTree}; use syn::{ - parse_quote, Expr, File, Ident, ImplItem, Item, ItemImpl, ItemMacro, ItemMod, ItemTrait, Macro, - Meta, MetaList, TraitItem, Type, TraitBound, ItemUse, ItemEnum, ItemStruct + parse_quote, Expr, File, Ident, ImplItem, Item, ItemEnum, ItemImpl, ItemMacro, ItemMod, + ItemStruct, ItemTrait, ItemUse, Macro, Meta, MetaList, TraitBound, TraitItem, Type, }; pub(crate) fn expand_pallet_config_trait( @@ -24,16 +24,17 @@ pub(crate) fn expand_pallet_config_trait( match item { Item::Trait(ItemTrait { ident, items, .. }) if *ident == "Config" => { items.push(match default_config { - DefaultConfigType::Default{..} => TraitItem::Type(parse_quote! { - ///EMPTY_LINE - type #type_name: #(#trait_bounds +)*; - }), + DefaultConfigType::Default { .. } => + TraitItem::Type(parse_quote! { + ///EMPTY_LINE + type #type_name: #(#trait_bounds +)*; + }), DefaultConfigType::NoDefault => TraitItem::Type(parse_quote! { ///EMPTY_LINE #[pallet::no_default] type #type_name: #(#trait_bounds +)*; }), - DefaultConfigType::NoDefaultBounds{..} => { + DefaultConfigType::NoDefaultBounds { .. } => { TraitItem::Type(parse_quote! { ///EMPTY_LINE #[pallet::no_default_bounds] @@ -236,33 +237,33 @@ pub(crate) fn expand_runtime_add_type_to_impl_block( } } -pub(crate) fn expand_add_use_statement(ast: &mut File, use_statement: ItemUse){ - let items = &mut ast.items; - // Find the first use statement - let position = items.iter().position(|item| matches!(item, Item::Use(_))) - .unwrap_or(0); - // Insert the use statement where needed - items.insert(position, Item::Use(use_statement)); +pub(crate) fn expand_add_use_statement(ast: &mut File, use_statement: ItemUse) { + let items = &mut ast.items; + // Find the first use statement + let position = items.iter().position(|item| matches!(item, Item::Use(_))).unwrap_or(0); + // Insert the use statement where needed + items.insert(position, Item::Use(use_statement)); } -pub(crate) fn expand_add_composite_enum(ast: &mut File, composite_enum: ItemEnum){ - for item in &mut ast.items{ - match item{ +pub(crate) fn expand_add_composite_enum(ast: &mut File, composite_enum: ItemEnum) { + for item in &mut ast.items { + match item { Item::Mod(ItemMod { ident, content, .. }) if *ident == "pallet" && content.is_some() => { let (_, items) = content.as_mut().expect("content is always Some thanks to the match guard"); - // Find the Pallet struct position - let position = items.iter().position(|item| match item{ - Item::Struct(ItemStruct{ident, ..}) if *ident=="Pallet" => true, - _ => false - }) - .unwrap_or(0); - // Insert the composite_enum just before the Pallet struct - items.insert(position.saturating_sub(1), Item::Enum(composite_enum.clone())); - }, - _ => continue - } - } + // Find the Pallet struct position + let position = items + .iter() + .position( + |item| matches!(item, Item::Struct(ItemStruct { ident, .. }) if *ident == "Pallet"), + ) + .unwrap_or(0); + // Insert the composite_enum just before the Pallet struct + items.insert(position.saturating_sub(1), Item::Enum(composite_enum.clone())); + }, + _ => continue, + } + } } diff --git a/crates/pop-common/src/rust_writer/helpers.rs b/crates/pop-common/src/rust_writer/helpers.rs index d1f98675e..ca3c8ce16 100644 --- a/crates/pop-common/src/rust_writer/helpers.rs +++ b/crates/pop-common/src/rust_writer/helpers.rs @@ -83,7 +83,7 @@ fn preserve_macro_invocations(code: String, exempt_macros: Vec<&str>) -> String let mut macro_block = String::new(); - let mut delimiter_counts = vec![('{', 0), ('}', 0), ('(', 0), (')', 0), ('[', 0), (']', 0)]; + let mut delimiter_counts = [('{', 0), ('}', 0), ('(', 0), (')', 0), ('[', 0), (']', 0)]; for line in code.lines() { match re.find(line) { diff --git a/crates/pop-common/src/rust_writer/parse.rs b/crates/pop-common/src/rust_writer/parse.rs index e9ceb4408..7021c509c 100644 --- a/crates/pop-common/src/rust_writer/parse.rs +++ b/crates/pop-common/src/rust_writer/parse.rs @@ -2,7 +2,7 @@ use crate::rust_writer::types::RuntimeUsedMacro; use std::cmp; -use syn::{File, Item, ItemMacro, ItemMod, ItemType, Macro, Meta, MetaList, ItemUse, ItemEnum}; +use syn::{File, Item, ItemEnum, ItemMacro, ItemMod, ItemType, ItemUse, Macro, Meta, MetaList}; /// Find the highest implemented pallet index in the outer enum if using the macro /// #[runtime]. We suppose it's a u8, it's not likely that a runtime implements more than 256 @@ -65,33 +65,34 @@ pub(crate) fn find_highest_pallet_index_and_runtime_macro_version( (highest_index, used_macro) } -pub(crate) fn find_use_statement(ast: &File, use_statement: &ItemUse) -> bool{ - for item in &ast.items{ - match item{ - Item::Use(item_use) if item_use == use_statement => return true, - _ => continue - } - } - false +pub(crate) fn find_use_statement(ast: &File, use_statement: &ItemUse) -> bool { + for item in &ast.items { + match item { + Item::Use(item_use) if item_use == use_statement => return true, + _ => continue, + } + } + false } -pub(crate) fn find_composite_enum(ast: &File, composite_enum: &ItemEnum) -> bool{ - for item in &ast.items{ - match item{ +pub(crate) fn find_composite_enum(ast: &File, composite_enum: &ItemEnum) -> bool { + for item in &ast.items { + match item { Item::Mod(ItemMod { ident, content, .. }) if *ident == "pallet" && content.is_some() => { let (_, items) = content.as_ref().expect("content is always Some thanks to the match guard"); for item in items { - match item{ - Item::Enum(ItemEnum{ident,..}) if *ident == composite_enum.ident => return true, - _ => continue - } - } - }, - _ => continue - } - } - false + match item { + Item::Enum(ItemEnum { ident, .. }) if *ident == composite_enum.ident => + return true, + _ => continue, + } + } + }, + _ => continue, + } + } + false } diff --git a/crates/pop-common/src/rust_writer/types.rs b/crates/pop-common/src/rust_writer/types.rs index 34e5c9d72..af0d52d47 100644 --- a/crates/pop-common/src/rust_writer/types.rs +++ b/crates/pop-common/src/rust_writer/types.rs @@ -1,12 +1,12 @@ // SPDX-License-Identifier: GPL-3.0 -use syn::{Expr, Type, ImplItem}; +use syn::{Expr, ImplItem, Type}; #[derive(Debug, Clone, PartialEq)] pub enum DefaultConfigType { - Default{type_default_impl: ImplItem}, + Default { type_default_impl: ImplItem }, NoDefault, - NoDefaultBounds{type_default_impl: ImplItem}, + NoDefaultBounds { type_default_impl: ImplItem }, } #[derive(Debug, Clone, PartialEq)] From d0e502799f4462188305a5a6d74199d0fb0b5e6e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1s=20Senovilla=20Polo?= Date: Sat, 9 Nov 2024 12:21:29 +0100 Subject: [PATCH 11/46] Add first expand tests --- .../pop-cli/src/commands/add/config_type.rs | 2 - .../src/commands/add/config_type/tests.rs | 89 ------ crates/pop-cli/src/commands/add/pallet.rs | 3 - .../pop-cli/src/commands/add/pallet/tests.rs | 1 - crates/pop-cli/src/common/helpers.rs | 2 +- crates/pop-common/src/rust_writer/expand.rs | 7 +- .../src/rust_writer/expand/tests.rs | 289 ++++++++++++++++++ .../rust_writer/test_files/basic_pallet.rs | 30 ++ .../basic_pallet_with_config_preludes.rs | 85 ++++++ .../test_files/outer_config_preludes.rs | 55 ++++ 10 files changed, 465 insertions(+), 98 deletions(-) delete mode 100644 crates/pop-cli/src/commands/add/config_type/tests.rs delete mode 100644 crates/pop-cli/src/commands/add/pallet/tests.rs create mode 100644 crates/pop-common/src/rust_writer/expand/tests.rs create mode 100644 crates/pop-common/src/rust_writer/test_files/basic_pallet.rs create mode 100644 crates/pop-common/src/rust_writer/test_files/basic_pallet_with_config_preludes.rs create mode 100644 crates/pop-common/src/rust_writer/test_files/outer_config_preludes.rs diff --git a/crates/pop-cli/src/commands/add/config_type.rs b/crates/pop-cli/src/commands/add/config_type.rs index 41551713f..182b8876b 100644 --- a/crates/pop-cli/src/commands/add/config_type.rs +++ b/crates/pop-cli/src/commands/add/config_type.rs @@ -1,8 +1,6 @@ // SPDX-License-Identifier: GPL-3.0 mod common_types; -#[cfg(test)] -mod tests; use crate::{ cli::{traits::Cli as _, Cli}, diff --git a/crates/pop-cli/src/commands/add/config_type/tests.rs b/crates/pop-cli/src/commands/add/config_type/tests.rs deleted file mode 100644 index 086522b81..000000000 --- a/crates/pop-cli/src/commands/add/config_type/tests.rs +++ /dev/null @@ -1,89 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0 - -use assert_cmd::Command; -use predicates::prelude::*; - -struct TestBuilder { - cmd: Command, -} - -impl TestBuilder { - fn cmd_add_pallet_config_type() -> Self { - let mut cmd = Command::cargo_bin("pop").unwrap(); - cmd.arg("add") - .arg("pallet") - .arg("path/to/pallet") - .arg("config") - .arg("MyType") - .arg("--bounds") - .arg("MyBound"); - Self { cmd } - } - - fn cmd_success(&mut self) { - self.cmd.assert().success(); - } - - fn cmd_fails_with_message(&mut self, message: &str) { - self.cmd.assert().failure().stderr(predicate::str::contains(message)); - } -} - -#[test] -fn config_options_no_default_custom_validation_works() { - // --no-default + --default-value isn't a valid combination - let mut builder = TestBuilder::cmd_add_pallet_config_type(); - builder.cmd.arg("--no-default").arg("--default-value").arg("u32"); - - builder.cmd_fails_with_message("Cannot specify a default value for a no-default config type."); - - // --no-default without --runtime-value isn't a valid combination - builder = TestBuilder::cmd_add_pallet_config_type(); - builder.cmd.arg("--no-default"); - builder.cmd_fails_with_message("Types without a default value need a runtime value."); - - // --no-default + --runtime-value OK - builder.cmd.arg("--runtime-value").arg("u32"); - builder.cmd_success(); -} - -#[test] -fn config_options_no_default_bounds_validation_works() { - // --no-default-bounds fails without runtime value and default value - let mut builder = TestBuilder::cmd_add_pallet_config_type(); - builder.cmd.arg("--no-default-bounds"); - builder.cmd_fails_with_message("The type needs at least a default value or a runtime value."); - - // --no-default-bounds + --runtime-value works - builder.cmd.arg("--runtime-value").arg("u32"); - builder.cmd_success(); - - // --no-default-bounds + --default-value works - builder = TestBuilder::cmd_add_pallet_config_type(); - builder.cmd.arg("--no-default-bounds").arg("--default-value").arg("u32"); - builder.cmd_success(); - - // --no-default-bounds + --default-value + --runtime-value works - builder.cmd.arg("--runtime-value").arg("u32"); - builder.cmd_success(); -} - -#[test] -fn config_options_default_not_specified_validation_works() { - // default not specified fails without runtime value and default value - let mut builder = TestBuilder::cmd_add_pallet_config_type(); - builder.cmd_fails_with_message("The type needs at least a default value or a runtime value."); - - // default not specified + --runtime-value works - builder.cmd.arg("--runtime-value").arg("u32"); - builder.cmd_success(); - - // default not specified + --default-value works - builder = TestBuilder::cmd_add_pallet_config_type(); - builder.cmd.arg("--default-value").arg("u32"); - builder.cmd_success(); - - // default not specified + --default-value + --runtime-value works - builder.cmd.arg("--runtime-value").arg("u32"); - builder.cmd_success(); -} diff --git a/crates/pop-cli/src/commands/add/pallet.rs b/crates/pop-cli/src/commands/add/pallet.rs index 81c534e4c..7e80a27c7 100644 --- a/crates/pop-cli/src/commands/add/pallet.rs +++ b/crates/pop-cli/src/commands/add/pallet.rs @@ -15,9 +15,6 @@ use strum::{EnumMessage, IntoEnumIterator}; mod common_pallets; -#[cfg(test)] -mod tests; - #[derive(Args, Debug, Clone)] pub struct AddPalletCommand { #[arg(short, long, help = "Specify the path to the runtime crate.")] diff --git a/crates/pop-cli/src/commands/add/pallet/tests.rs b/crates/pop-cli/src/commands/add/pallet/tests.rs deleted file mode 100644 index ea448e289..000000000 --- a/crates/pop-cli/src/commands/add/pallet/tests.rs +++ /dev/null @@ -1 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0 diff --git a/crates/pop-cli/src/common/helpers.rs b/crates/pop-cli/src/common/helpers.rs index 87e9f1c27..03ca57fa5 100644 --- a/crates/pop-cli/src/common/helpers.rs +++ b/crates/pop-cli/src/common/helpers.rs @@ -61,7 +61,7 @@ #[macro_export] macro_rules! multiselect_pick { ($enum: ty, $prompt_message: expr $(, $excluded_variants: expr)?) => {{ - // Ensure the enum is 1-byte long. This is needed cause fieldless enums with > 256 elements + // Ensure the enum is 1-byte long. This is needed cause fieldless enums with > 256 elements // will lead to unexpected behavior as the conversion to u8 for them isn't detected as wrong // at compile time. Enums containing variants with fields will be catched at compile time. // Weird but possible. diff --git a/crates/pop-common/src/rust_writer/expand.rs b/crates/pop-common/src/rust_writer/expand.rs index ec03ded5a..ff9bda81f 100644 --- a/crates/pop-common/src/rust_writer/expand.rs +++ b/crates/pop-common/src/rust_writer/expand.rs @@ -1,5 +1,8 @@ // SPDX-License-Identifier: GPL-3.0 +#[cfg(test)] +mod tests; + use crate::{capitalize_str, rust_writer::types::*}; use proc_macro2::{Group, Literal, Span, TokenStream, TokenTree}; use syn::{ @@ -55,7 +58,7 @@ pub(crate) fn expand_pallet_config_trait( pub(crate) fn expand_pallet_config_preludes(ast: &mut File, type_default_impl: ImplItem) { for item in &mut ast.items { match item { - // In case file_path points to lib.rs, config_preludes is contained inside pallet mod in + // In case ast points to lib.rs, config_preludes is contained inside pallet mod in // lib.rs so we have to look for that module and the impl blocks for structs defined // inside it, equivalently impl blocks using the register_default_impl macro Item::Mod(ItemMod { ident, content, .. }) @@ -96,7 +99,7 @@ pub(crate) fn expand_pallet_config_preludes(ast: &mut File, type_default_impl: I } } }, - // In case file_path points to config_preludes.rs, we have to look for the impl blocks + // In case ast points to config_preludes.rs, we have to look for the impl blocks // for structs defined inside the file. Item::Impl(ItemImpl { attrs, items, .. }) if attrs.iter().any(|attribute| { diff --git a/crates/pop-common/src/rust_writer/expand/tests.rs b/crates/pop-common/src/rust_writer/expand/tests.rs new file mode 100644 index 000000000..08a359eaa --- /dev/null +++ b/crates/pop-common/src/rust_writer/expand/tests.rs @@ -0,0 +1,289 @@ +// SPDX-License-Identifier: GPL-3.0 + +use super::*; +use crate::rust_writer::helpers; +use std::{fs, path::PathBuf}; + +struct TestBuilder { + test_files: PathBuf, + ast: File, +} + +impl Default for TestBuilder { + fn default() -> Self { + Self { + test_files: PathBuf::from(env!("CARGO_MANIFEST_DIR")) + .join("src") + .join("rust_writer") + .join("test_files"), + ast: parse_quote! {}, + } + } +} + +impl TestBuilder { + fn add_basic_pallet_ast(&mut self) { + self.ast = helpers::preserve_and_parse( + fs::read_to_string(self.test_files.join("basic_pallet.rs")) + .expect("Error reading pallet file in add_basic_pallet_ast"), + vec![], + ) + .expect("Error parsing pallet file in add_basic_pallet_ast"); + } + + fn add_basic_pallet_with_config_preludes_ast(&mut self) { + self.ast = helpers::preserve_and_parse( + fs::read_to_string(self.test_files.join("basic_pallet_with_config_preludes.rs")) + .expect("Error reading pallet file in add_basic_pallet_with_config_preludes_ast"), + vec![], + ) + .expect("Error parsing pallet file in add_basic_pallet_with_config_preludes_ast"); + } + + fn add_outer_config_preludes_ast(&mut self) { + self.ast = helpers::preserve_and_parse( + fs::read_to_string(self.test_files.join("outer_config_preludes.rs")) + .expect("Error reading pallet file in add_outer_config_preludes_ast"), + vec![], + ) + .expect("Error parsing pallet file in add_outer_config_preludes_ast"); + } + + fn assert_in_config_items(&self, contains: bool, checked_item: TraitItem) { + let mut assert_happened = false; + for item in &self.ast.items { + match item { + Item::Mod(ItemMod { ident, content, .. }) + if *ident == "pallet" && content.is_some() => + { + let (_, items) = + content.as_ref().expect("content is always Some thanks to the match guard"); + for item in items { + match item { + Item::Trait(ItemTrait { ident, items, .. }) if *ident == "Config" => { + if contains { + assert!(items.contains(&checked_item)); + } else { + assert!(!items.contains(&checked_item)); + } + assert_happened = true; + }, + _ => continue, + } + } + }, + _ => continue, + } + } + assert!(assert_happened); + } + + fn assert_type_added_to_config_preludes(&self, contains: bool, type_: ImplItem) { + let mut assert_happened = false; + for item in &self.ast.items { + match item { + // In case ast using inner config_preludes + Item::Mod(ItemMod { ident, content, .. }) + if *ident == "pallet" && content.is_some() => + { + let (_, items) = + content.as_ref().expect("content is always Some thanks to the match guard"); + for item in items { + match item { + Item::Mod(ItemMod { ident, content, .. }) + if *ident == "config_preludes" && content.is_some() => + { + let (_, items) = content + .as_ref() + .expect("content is always Some thanks to the match guard"); + for item in items { + match item { + Item::Impl(ItemImpl { attrs, items, .. }) + if attrs.iter().any(|attribute| { + if let Meta::List(MetaList { + path: syn::Path { segments, .. }, + .. + }) = &attribute.meta + { + segments.iter().any(|segment| { + segment.ident == "register_default_impl" + }) + } else { + false + } + }) => + { + if contains { + assert!(items.contains(&type_)); + } else { + assert!(!items.contains(&type_)); + } + assert_happened = true; + }, + _ => continue, + } + } + }, + _ => continue, + } + } + }, + // In case ast using an outer config preludes + Item::Impl(ItemImpl { attrs, items, .. }) + if attrs.iter().any(|attribute| { + if let Meta::List(MetaList { path: syn::Path { segments, .. }, .. }) = + &attribute.meta + { + segments.iter().any(|segment| segment.ident == "register_default_impl") + } else { + false + } + }) => + { + if contains { + assert!(items.contains(&type_)); + } else { + assert!(!items.contains(&type_)); + } + assert_happened = true; + }, + _ => continue, + } + } + assert!(assert_happened); + } +} + +#[test] +fn expand_pallet_config_trait_works_well_test() { + let mut test_builder = TestBuilder::default(); + //This test modifies the config trait of the pallet, so the ast contained in the builder is + //the basic pallet's ast. + test_builder.add_basic_pallet_ast(); + + //A helper type to pass to expand_pallet_config_trait. + let mut default_config_type = + DefaultConfigType::Default { type_default_impl: parse_quote! {type whatever = ();} }; + + //Check that the config trait doesn't include ```MyDefaultType```. + test_builder.assert_in_config_items( + false, + TraitItem::Type(parse_quote! { + ///EMPTY_LINE + type MyDefaultType: Bound1 + From +; + }), + ); + + //Expand the pallet config trait with our type. + expand_pallet_config_trait( + &mut test_builder.ast, + &default_config_type, + Ident::new("MyDefaultType", Span::call_site()), + vec![parse_quote! {Bound1}, parse_quote! {From}], + ); + + //Now ```MyDefaultType``` is part of the ast. + test_builder.assert_in_config_items( + true, + TraitItem::Type(parse_quote! { + ///EMPTY_LINE + type MyDefaultType: Bound1 + From +; + }), + ); + + test_builder.assert_in_config_items( + false, + TraitItem::Type(parse_quote! { + ///EMPTY_LINE + #[pallet::no_default] + type MyNoDefaultType: Bound1 + From +; + }), + ); + + default_config_type = DefaultConfigType::NoDefault; + expand_pallet_config_trait( + &mut test_builder.ast, + &default_config_type, + Ident::new("MyNoDefaultType", Span::call_site()), + vec![parse_quote! {Bound1}, parse_quote! {From}], + ); + + test_builder.assert_in_config_items( + true, + TraitItem::Type(parse_quote! { + ///EMPTY_LINE + #[pallet::no_default] + type MyNoDefaultType: Bound1 + From +; + }), + ); + + test_builder.assert_in_config_items( + false, + TraitItem::Type(parse_quote! { + ///EMPTY_LINE + #[pallet::no_default_bounds] + type MyNoDefaultBoundsType: Bound1 + From +; + }), + ); + + default_config_type = DefaultConfigType::NoDefaultBounds { + type_default_impl: parse_quote! {type whatever = ();}, + }; + expand_pallet_config_trait( + &mut test_builder.ast, + &default_config_type, + Ident::new("MyNoDefaultBoundsType", Span::call_site()), + vec![parse_quote! {Bound1}, parse_quote! {From}], + ); + + test_builder.assert_in_config_items( + true, + TraitItem::Type(parse_quote! { + ///EMPTY_LINE + #[pallet::no_default_bounds] + type MyNoDefaultBoundsType: Bound1 + From +; + }), + ); +} + +#[test] +fn expand_pallet_config_preludes_inner_module_works_well_test() { + let mut test_builder = TestBuilder::default(); + //This test uses a pallet lib containing config_preludes. + test_builder.add_basic_pallet_with_config_preludes_ast(); + + // Type to add + let my_type = ImplItem::Type(parse_quote! { + type MyType = (); + }); + + //Check that the config type's not included. + test_builder.assert_type_added_to_config_preludes(false, my_type.clone()); + + //Expand the pallet's config_preludes. + expand_pallet_config_preludes(&mut test_builder.ast, my_type.clone()); + + //Check that the config type's included. + test_builder.assert_type_added_to_config_preludes(true, my_type.clone()); +} + +#[test] +fn expand_pallet_config_preludes_outer_file_works_well_test() { + let mut test_builder = TestBuilder::default(); + //This test uses a pallet lib containing config_preludes. + test_builder.add_outer_config_preludes_ast(); + + // Type to add + let my_type = ImplItem::Type(parse_quote! { + type MyType = (); + }); + + //Check that the config type's not included. + test_builder.assert_type_added_to_config_preludes(false, my_type.clone()); + + //Expand the pallet's config_preludes. + expand_pallet_config_preludes(&mut test_builder.ast, my_type.clone()); + + //Check that the config type's included. + test_builder.assert_type_added_to_config_preludes(true, my_type.clone()); +} diff --git a/crates/pop-common/src/rust_writer/test_files/basic_pallet.rs b/crates/pop-common/src/rust_writer/test_files/basic_pallet.rs new file mode 100644 index 000000000..f8f698df0 --- /dev/null +++ b/crates/pop-common/src/rust_writer/test_files/basic_pallet.rs @@ -0,0 +1,30 @@ +// SPDX-License-Identifier: GPL-3.0 + +#![cfg_attr(not(feature = "std"), no_std)] + +use frame::prelude::*; + +pub use pallet::*; + +#[cfg(test)] +mod mock; + +#[cfg(test)] +mod tests; + +#[cfg(feature = "runtime-benchmarks")] +mod benchmarking; + +#[frame::pallet] +pub mod pallet { + use super::*; + + #[pallet::pallet] + pub struct Pallet(_); + + #[pallet::config(with_default)] + pub trait Config: frame_system::Config {} + + #[pallet::call] + impl Pallet {} +} diff --git a/crates/pop-common/src/rust_writer/test_files/basic_pallet_with_config_preludes.rs b/crates/pop-common/src/rust_writer/test_files/basic_pallet_with_config_preludes.rs new file mode 100644 index 000000000..d78a169bf --- /dev/null +++ b/crates/pop-common/src/rust_writer/test_files/basic_pallet_with_config_preludes.rs @@ -0,0 +1,85 @@ +// SPDX-License-Identifier: GPL-3.0 + +#![cfg_attr(not(feature = "std"), no_std)] + +use frame::prelude::*; + +pub use pallet::*; + +#[cfg(test)] +mod mock; + +#[cfg(test)] +mod tests; + +#[cfg(feature = "runtime-benchmarks")] +mod benchmarking; + +#[frame::pallet] +pub mod pallet { + use super::*; + + pub mod config_preludes{ + use super::*; + use frame::runtime::prelude::derive_impl; + /// Provides a viable default config that can be used with + /// [`derive_impl`] to derive a testing pallet config + /// based on this one. + pub struct TestDefaultConfig; + + #[derive_impl(frame_system::config_preludes::TestDefaultConfig, no_aggregated_types)] + impl frame::deps::frame_system::DefaultConfig for TestDefaultConfig {} + + #[register_default_impl(TestDefaultConfig)] + impl DefaultConfig for TestDefaultConfig { + } + + /// Default configurations of this pallet in a solochain environment. + pub struct SolochainDefaultConfig; + + #[derive_impl( + frame_system::config_preludes::SolochainDefaultConfig, + no_aggregated_types + )] + impl frame::deps::frame_system::DefaultConfig for SolochainDefaultConfig {} + + #[register_default_impl(SolochainDefaultConfig)] + impl DefaultConfig for SolochainDefaultConfig { + } + + /// Default configurations of this pallet in a solochain environment. + pub struct RelayChainDefaultConfig; + + #[derive_impl( + frame_system::config_preludes::RelayChainDefaultConfig, + no_aggregated_types + )] + impl frame::deps::frame_system::DefaultConfig for RelayChainDefaultConfig {} + + #[register_default_impl(RelayChainDefaultConfig)] + impl DefaultConfig for RelayChainDefaultConfig { + } + + /// Default configurations of this pallet in a solochain environment. + pub struct ParaChainDefaultConfig; + + #[derive_impl( + frame_system::config_preludes::ParaChainDefaultConfig, + no_aggregated_types + )] + impl frame::deps::frame_system::DefaultConfig for ParaChainDefaultConfig {} + + #[register_default_impl(ParaChainDefaultConfig)] + impl DefaultConfig for ParaChainDefaultConfig { + } + } + + #[pallet::pallet] + pub struct Pallet(_); + + #[pallet::config(with_default)] + pub trait Config: frame_system::Config {} + + #[pallet::call] + impl Pallet {} +} diff --git a/crates/pop-common/src/rust_writer/test_files/outer_config_preludes.rs b/crates/pop-common/src/rust_writer/test_files/outer_config_preludes.rs new file mode 100644 index 000000000..d4285ecbb --- /dev/null +++ b/crates/pop-common/src/rust_writer/test_files/outer_config_preludes.rs @@ -0,0 +1,55 @@ +// SPDX-License-Identifier: GPL-3.0 + +use super::*; +use frame::runtime::prelude::derive_impl; + +/// Provides a viable default config that can be used with +/// [`derive_impl`] to derive a testing pallet config +/// based on this one. +pub struct TestDefaultConfig; + +#[derive_impl(frame_system::config_preludes::TestDefaultConfig, no_aggregated_types)] +impl frame::deps::frame_system::DefaultConfig for TestDefaultConfig {} + +#[register_default_impl(TestDefaultConfig)] +impl DefaultConfig for TestDefaultConfig { +} + +/// Default configurations of this pallet in a solochain environment. +pub struct SolochainDefaultConfig; + +#[derive_impl( + frame_system::config_preludes::SolochainDefaultConfig, + no_aggregated_types +)] +impl frame::deps::frame_system::DefaultConfig for SolochainDefaultConfig {} + +#[register_default_impl(SolochainDefaultConfig)] +impl DefaultConfig for SolochainDefaultConfig { +} + +/// Default configurations of this pallet in a solochain environment. +pub struct RelayChainDefaultConfig; + +#[derive_impl( + frame_system::config_preludes::RelayChainDefaultConfig, + no_aggregated_types +)] +impl frame::deps::frame_system::DefaultConfig for RelayChainDefaultConfig {} + +#[register_default_impl(RelayChainDefaultConfig)] +impl DefaultConfig for RelayChainDefaultConfig { +} + +/// Default configurations of this pallet in a solochain environment. +pub struct ParaChainDefaultConfig; + +#[derive_impl( + frame_system::config_preludes::ParaChainDefaultConfig, + no_aggregated_types +)] +impl frame::deps::frame_system::DefaultConfig for ParaChainDefaultConfig {} + +#[register_default_impl(ParaChainDefaultConfig)] +impl DefaultConfig for ParaChainDefaultConfig { +} From 65beb6e5dfd32d0026048113fcdcfaea80fb058e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1s=20Senovilla=20Polo?= Date: Sat, 9 Nov 2024 12:33:32 +0100 Subject: [PATCH 12/46] Add a new type of error to describe something; cannot write runtime if not found --- crates/pop-common/src/errors.rs | 2 ++ crates/pop-common/src/rust_writer.rs | 6 ++++++ 2 files changed, 8 insertions(+) diff --git a/crates/pop-common/src/errors.rs b/crates/pop-common/src/errors.rs index 70942a0b3..78d0238d7 100644 --- a/crates/pop-common/src/errors.rs +++ b/crates/pop-common/src/errors.rs @@ -9,6 +9,8 @@ pub enum Error { AnyhowError(#[from] anyhow::Error), #[error("Configuration error: {0}")] Config(String), + #[error("{0}")] + Descriptive(String), #[error("a git error occurred: {0}")] Git(String), #[error("IO error: {0}")] diff --git a/crates/pop-common/src/rust_writer.rs b/crates/pop-common/src/rust_writer.rs index e9c48721c..3bfbd6532 100644 --- a/crates/pop-common/src/rust_writer.rs +++ b/crates/pop-common/src/rust_writer.rs @@ -138,6 +138,12 @@ pub fn add_pallet_to_runtime_module( let (highest_index, used_macro) = parse::find_highest_pallet_index_and_runtime_macro_version(&ast); + if let types::RuntimeUsedMacro::NotFound = used_macro { + return Err(Error::Descriptive( + format! {"Unable to find a runtime declaration in {:?}", runtime_lib_path}, + )); + } + // Find the pallet name and the pallet item to be added to the runtime. If the pallet_name is // behind the form pallet-some-thing, pallet_item becomes Something. let pallet_item = Ident::new( From 93b5ddc5fec1883d9fecf9c6b6fc3d3625908b32 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1s=20Senovilla=20Polo?= Date: Sat, 9 Nov 2024 12:51:30 +0100 Subject: [PATCH 13/46] Test files for expanding runtime macros --- .../runtime_using_construct_runtime_macro.rs | 258 ++++++++++++++++ .../test_files/runtime_using_runtime_macro.rs | 281 ++++++++++++++++++ 2 files changed, 539 insertions(+) create mode 100644 crates/pop-common/src/rust_writer/test_files/runtime_using_construct_runtime_macro.rs create mode 100644 crates/pop-common/src/rust_writer/test_files/runtime_using_runtime_macro.rs diff --git a/crates/pop-common/src/rust_writer/test_files/runtime_using_construct_runtime_macro.rs b/crates/pop-common/src/rust_writer/test_files/runtime_using_construct_runtime_macro.rs new file mode 100644 index 000000000..136f534e5 --- /dev/null +++ b/crates/pop-common/src/rust_writer/test_files/runtime_using_construct_runtime_macro.rs @@ -0,0 +1,258 @@ +// SPDX-License-Identifier: GPL-3.0 + +#![cfg_attr(not(feature = "std"), no_std)] +// `construct_runtime!` does a lot of recursion and requires us to increase the limit to 256. +#![recursion_limit = "256"] + +// Make the WASM binary available. +#[cfg(feature = "std")] +include!(concat!(env!("OUT_DIR"), "/wasm_binary.rs")); + +pub mod apis; +#[cfg(feature = "runtime-benchmarks")] +mod benchmarks; +mod configs; +mod weights; + +use smallvec::smallvec; +use sp_runtime::{ + create_runtime_str, generic, impl_opaque_keys, + traits::{BlakeTwo256, IdentifyAccount, Verify}, + MultiSignature, +}; + +use sp_std::prelude::*; +#[cfg(feature = "std")] +use sp_version::NativeVersion; +use sp_version::RuntimeVersion; + +use frame_support::{construct_runtime, weights::{ + constants::WEIGHT_REF_TIME_PER_SECOND, Weight, WeightToFeeCoefficient, WeightToFeeCoefficients, + WeightToFeePolynomial, +}}; +pub use sp_consensus_aura::sr25519::AuthorityId as AuraId; +pub use sp_runtime::{MultiAddress, Perbill, Permill}; + +#[cfg(any(feature = "std", test))] +pub use sp_runtime::BuildStorage; + +use weights::ExtrinsicBaseWeight; + +/// Alias to 512-bit hash when used in the context of a transaction signature on the chain. +pub type Signature = MultiSignature; + +/// Some way of identifying an account on the chain. We intentionally make it equivalent +/// to the public key of our transaction signing scheme. +pub type AccountId = <::Signer as IdentifyAccount>::AccountId; + +/// Balance of an account. +pub type Balance = u128; + +/// Index of a transaction in the chain. +pub type Nonce = u32; + +/// A hash of some data used by the chain. +pub type Hash = sp_core::H256; + +/// An index to a block. +pub type BlockNumber = u32; + +/// The address format for describing accounts. +pub type Address = MultiAddress; + +/// Block header type as expected by this runtime. +pub type Header = generic::Header; + +/// Block type as expected by this runtime. +pub type Block = generic::Block; + +/// A Block signed with a Justification +pub type SignedBlock = generic::SignedBlock; + +/// BlockId type as expected by this runtime. +pub type BlockId = generic::BlockId; + +/// The SignedExtension to the basic transaction logic. +#[docify::export(template_signed_extra)] +pub type SignedExtra = ( + frame_system::CheckNonZeroSender, + frame_system::CheckSpecVersion, + frame_system::CheckTxVersion, + frame_system::CheckGenesis, + frame_system::CheckEra, + frame_system::CheckNonce, + frame_system::CheckWeight, + pallet_transaction_payment::ChargeTransactionPayment, + cumulus_primitives_storage_weight_reclaim::StorageWeightReclaim, + frame_metadata_hash_extension::CheckMetadataHash, +); + +/// Unchecked extrinsic type as expected by this runtime. +pub type UncheckedExtrinsic = + generic::UncheckedExtrinsic; + +/// Migrations to apply on runtime upgrade. +pub type Migrations = pallet_xcm::migration::MigrateToLatestXcmVersion; + +/// Executive: handles dispatch to the various modules. +pub type Executive = frame_executive::Executive< + Runtime, + Block, + frame_system::ChainContext, + Runtime, + AllPalletsWithSystem, + Migrations, +>; + +/// Handles converting a weight scalar to a fee value, based on the scale and granularity of the +/// node's balance type. +/// +/// This should typically create a mapping between the following ranges: +/// - `[0, MAXIMUM_BLOCK_WEIGHT]` +/// - `[Balance::min, Balance::max]` +/// +/// Yet, it can be used for any other sort of change to weight-fee. Some examples being: +/// - Setting it to `0` will essentially disable the weight fee. +/// - Setting it to `1` will cause the literal `#[weight = x]` values to be charged. +pub struct WeightToFee; +impl WeightToFeePolynomial for WeightToFee { + type Balance = Balance; + fn polynomial() -> WeightToFeeCoefficients { + // in Rococo, extrinsic base weight (smallest non-zero weight) is mapped to 1 MILLIUNIT: + // in our template, we map to 1/10 of that, or 1/10 MILLIUNIT + let p = MILLIUNIT / 10; + let q = 100 * Balance::from(ExtrinsicBaseWeight::get().ref_time()); + smallvec![WeightToFeeCoefficient { + degree: 1, + negative: false, + coeff_frac: Perbill::from_rational(p % q, q), + coeff_integer: p / q, + }] + } +} + +/// Opaque types. These are used by the CLI to instantiate machinery that don't need to know +/// the specifics of the runtime. They can then be made to be agnostic over specific formats +/// of data like extrinsics, allowing for them to continue syncing the network through upgrades +/// to even the core data structures. +pub mod opaque { + use super::*; + use sp_runtime::{ + generic, + traits::{BlakeTwo256, Hash as HashT}, + }; + + pub use sp_runtime::OpaqueExtrinsic as UncheckedExtrinsic; + /// Opaque block header type. + pub type Header = generic::Header; + /// Opaque block type. + pub type Block = generic::Block; + /// Opaque block identifier type. + pub type BlockId = generic::BlockId; + /// Opaque block hash type. + pub type Hash = ::Output; +} + +impl_opaque_keys! { + pub struct SessionKeys { + pub aura: Aura, + } +} + +const spec_name: RuntimeString = create_runtime_str!("parachain-template-runtime"); + +const impl_name: RuntimeString = create_runtime_str!("parachain-template-runtime"); + +#[sp_version::runtime_version] +pub const VERSION: RuntimeVersion = RuntimeVersion { + spec_name, + impl_name, + authoring_version: 1, + spec_version: 1, + impl_version: 0, + apis: apis::RUNTIME_API_VERSIONS, + transaction_version: 1, + state_version: 1, +}; + +/// This determines the average expected block time that we are targeting. +/// Blocks will be produced at a minimum duration defined by `SLOT_DURATION`. +/// `SLOT_DURATION` is picked up by `pallet_timestamp` which is in turn picked +/// up by `pallet_aura` to implement `fn slot_duration()`. +/// +/// Change this to adjust the block time. +pub const MILLISECS_PER_BLOCK: u64 = 6000; + +// NOTE: Currently it is not possible to change the slot duration after the chain has started. +// Attempting to do so will brick block production. +pub const SLOT_DURATION: u64 = MILLISECS_PER_BLOCK; + +// Time is measured by number of blocks. +pub const MINUTES: BlockNumber = 60_000 / (MILLISECS_PER_BLOCK as BlockNumber); +pub const HOURS: BlockNumber = MINUTES * 60; +pub const DAYS: BlockNumber = HOURS * 24; + +// Unit = the base number of indivisible units for balances +pub const UNIT: Balance = 1_000_000_000_000; +pub const CENTIUNIT: Balance = 10_000_000_000; +pub const MILLIUNIT: Balance = 1_000_000_000; +pub const MICROUNIT: Balance = 1_000_000; + +/// The existential deposit. Set to 1/10 of the Connected Relay Chain. +pub const EXISTENTIAL_DEPOSIT: Balance = MILLIUNIT; + +/// We assume that ~5% of the block weight is consumed by `on_initialize` handlers. This is +/// used to limit the maximal weight of a single extrinsic. +const AVERAGE_ON_INITIALIZE_RATIO: Perbill = Perbill::from_percent(5); + +/// We allow `Normal` extrinsics to fill up the block up to 75%, the rest can be used by +/// `Operational` extrinsics. +const NORMAL_DISPATCH_RATIO: Perbill = Perbill::from_percent(75); + +/// We allow for 2 seconds of compute with a 6-second average block. +const MAXIMUM_BLOCK_WEIGHT: Weight = Weight::from_parts( + WEIGHT_REF_TIME_PER_SECOND.saturating_mul(2), + cumulus_primitives_core::relay_chain::MAX_POV_SIZE as u64, +); + +/// Maximum number of blocks simultaneously accepted by the Runtime, not yet included +/// into the relay chain. +const UNINCLUDED_SEGMENT_CAPACITY: u32 = 3; +/// How many parachain blocks are processed by the relay chain per parent. Limits the +/// number of blocks authored per slot. +const BLOCK_PROCESSING_VELOCITY: u32 = 1; +/// Relay chain slot duration, in milliseconds. +const RELAY_CHAIN_SLOT_DURATION_MILLIS: u32 = 6000; + +/// Aura consensus hook +type ConsensusHook = cumulus_pallet_aura_ext::FixedVelocityConsensusHook< + Runtime, + RELAY_CHAIN_SLOT_DURATION_MILLIS, + BLOCK_PROCESSING_VELOCITY, + UNINCLUDED_SEGMENT_CAPACITY, +>; + +/// The version information used to identify this runtime when compiled natively. +#[cfg(feature = "std")] +pub fn native_version() -> NativeVersion { + NativeVersion { + runtime_version: VERSION, + can_author_with: Default::default(), + } +} + +construct_runtime! { + pub enum Runtime{ + System:frame_system, + ParachainSystem: cumulus_pallet_parachain_system, + Timestamp: pallet_timestamp, + ParachainInfo:parachain_info, + Balances: pallet_balances, + TransactionPayment: pallet_transaction_payment + } +} + +cumulus_pallet_parachain_system::register_validate_block! { + Runtime = Runtime, + BlockExecutor = cumulus_pallet_aura_ext::BlockExecutor::, +} diff --git a/crates/pop-common/src/rust_writer/test_files/runtime_using_runtime_macro.rs b/crates/pop-common/src/rust_writer/test_files/runtime_using_runtime_macro.rs new file mode 100644 index 000000000..6374e6727 --- /dev/null +++ b/crates/pop-common/src/rust_writer/test_files/runtime_using_runtime_macro.rs @@ -0,0 +1,281 @@ +// SPDX-License-Identifier: GPL-3.0 + +#![cfg_attr(not(feature = "std"), no_std)] +// `construct_runtime!` does a lot of recursion and requires us to increase the limit to 256. +#![recursion_limit = "256"] + +// Make the WASM binary available. +#[cfg(feature = "std")] +include!(concat!(env!("OUT_DIR"), "/wasm_binary.rs")); + +pub mod apis; +#[cfg(feature = "runtime-benchmarks")] +mod benchmarks; +mod configs; +mod weights; + +use smallvec::smallvec; +use sp_runtime::{ + create_runtime_str, generic, impl_opaque_keys, + traits::{BlakeTwo256, IdentifyAccount, Verify}, + MultiSignature, +}; + +use sp_std::prelude::*; +#[cfg(feature = "std")] +use sp_version::NativeVersion; +use sp_version::RuntimeVersion; + +use frame_support::weights::{ + constants::WEIGHT_REF_TIME_PER_SECOND, Weight, WeightToFeeCoefficient, WeightToFeeCoefficients, + WeightToFeePolynomial, +}; +pub use sp_consensus_aura::sr25519::AuthorityId as AuraId; +pub use sp_runtime::{MultiAddress, Perbill, Permill}; + +#[cfg(any(feature = "std", test))] +pub use sp_runtime::BuildStorage; + +use weights::ExtrinsicBaseWeight; + +/// Alias to 512-bit hash when used in the context of a transaction signature on the chain. +pub type Signature = MultiSignature; + +/// Some way of identifying an account on the chain. We intentionally make it equivalent +/// to the public key of our transaction signing scheme. +pub type AccountId = <::Signer as IdentifyAccount>::AccountId; + +/// Balance of an account. +pub type Balance = u128; + +/// Index of a transaction in the chain. +pub type Nonce = u32; + +/// A hash of some data used by the chain. +pub type Hash = sp_core::H256; + +/// An index to a block. +pub type BlockNumber = u32; + +/// The address format for describing accounts. +pub type Address = MultiAddress; + +/// Block header type as expected by this runtime. +pub type Header = generic::Header; + +/// Block type as expected by this runtime. +pub type Block = generic::Block; + +/// A Block signed with a Justification +pub type SignedBlock = generic::SignedBlock; + +/// BlockId type as expected by this runtime. +pub type BlockId = generic::BlockId; + +/// The SignedExtension to the basic transaction logic. +#[docify::export(template_signed_extra)] +pub type SignedExtra = ( + frame_system::CheckNonZeroSender, + frame_system::CheckSpecVersion, + frame_system::CheckTxVersion, + frame_system::CheckGenesis, + frame_system::CheckEra, + frame_system::CheckNonce, + frame_system::CheckWeight, + pallet_transaction_payment::ChargeTransactionPayment, + cumulus_primitives_storage_weight_reclaim::StorageWeightReclaim, + frame_metadata_hash_extension::CheckMetadataHash, +); + +/// Unchecked extrinsic type as expected by this runtime. +pub type UncheckedExtrinsic = + generic::UncheckedExtrinsic; + +/// Migrations to apply on runtime upgrade. +pub type Migrations = pallet_xcm::migration::MigrateToLatestXcmVersion; + +/// Executive: handles dispatch to the various modules. +pub type Executive = frame_executive::Executive< + Runtime, + Block, + frame_system::ChainContext, + Runtime, + AllPalletsWithSystem, + Migrations, +>; + +/// Handles converting a weight scalar to a fee value, based on the scale and granularity of the +/// node's balance type. +/// +/// This should typically create a mapping between the following ranges: +/// - `[0, MAXIMUM_BLOCK_WEIGHT]` +/// - `[Balance::min, Balance::max]` +/// +/// Yet, it can be used for any other sort of change to weight-fee. Some examples being: +/// - Setting it to `0` will essentially disable the weight fee. +/// - Setting it to `1` will cause the literal `#[weight = x]` values to be charged. +pub struct WeightToFee; +impl WeightToFeePolynomial for WeightToFee { + type Balance = Balance; + fn polynomial() -> WeightToFeeCoefficients { + // in Rococo, extrinsic base weight (smallest non-zero weight) is mapped to 1 MILLIUNIT: + // in our template, we map to 1/10 of that, or 1/10 MILLIUNIT + let p = MILLIUNIT / 10; + let q = 100 * Balance::from(ExtrinsicBaseWeight::get().ref_time()); + smallvec![WeightToFeeCoefficient { + degree: 1, + negative: false, + coeff_frac: Perbill::from_rational(p % q, q), + coeff_integer: p / q, + }] + } +} + +/// Opaque types. These are used by the CLI to instantiate machinery that don't need to know +/// the specifics of the runtime. They can then be made to be agnostic over specific formats +/// of data like extrinsics, allowing for them to continue syncing the network through upgrades +/// to even the core data structures. +pub mod opaque { + use super::*; + use sp_runtime::{ + generic, + traits::{BlakeTwo256, Hash as HashT}, + }; + + pub use sp_runtime::OpaqueExtrinsic as UncheckedExtrinsic; + /// Opaque block header type. + pub type Header = generic::Header; + /// Opaque block type. + pub type Block = generic::Block; + /// Opaque block identifier type. + pub type BlockId = generic::BlockId; + /// Opaque block hash type. + pub type Hash = ::Output; +} + +impl_opaque_keys! { + pub struct SessionKeys { + pub aura: Aura, + } +} + +const spec_name: RuntimeString = create_runtime_str!("parachain-template-runtime"); + +const impl_name: RuntimeString = create_runtime_str!("parachain-template-runtime"); + +#[sp_version::runtime_version] +pub const VERSION: RuntimeVersion = RuntimeVersion { + spec_name, + impl_name, + authoring_version: 1, + spec_version: 1, + impl_version: 0, + apis: apis::RUNTIME_API_VERSIONS, + transaction_version: 1, + state_version: 1, +}; + +/// This determines the average expected block time that we are targeting. +/// Blocks will be produced at a minimum duration defined by `SLOT_DURATION`. +/// `SLOT_DURATION` is picked up by `pallet_timestamp` which is in turn picked +/// up by `pallet_aura` to implement `fn slot_duration()`. +/// +/// Change this to adjust the block time. +pub const MILLISECS_PER_BLOCK: u64 = 6000; + +// NOTE: Currently it is not possible to change the slot duration after the chain has started. +// Attempting to do so will brick block production. +pub const SLOT_DURATION: u64 = MILLISECS_PER_BLOCK; + +// Time is measured by number of blocks. +pub const MINUTES: BlockNumber = 60_000 / (MILLISECS_PER_BLOCK as BlockNumber); +pub const HOURS: BlockNumber = MINUTES * 60; +pub const DAYS: BlockNumber = HOURS * 24; + +// Unit = the base number of indivisible units for balances +pub const UNIT: Balance = 1_000_000_000_000; +pub const CENTIUNIT: Balance = 10_000_000_000; +pub const MILLIUNIT: Balance = 1_000_000_000; +pub const MICROUNIT: Balance = 1_000_000; + +/// The existential deposit. Set to 1/10 of the Connected Relay Chain. +pub const EXISTENTIAL_DEPOSIT: Balance = MILLIUNIT; + +/// We assume that ~5% of the block weight is consumed by `on_initialize` handlers. This is +/// used to limit the maximal weight of a single extrinsic. +const AVERAGE_ON_INITIALIZE_RATIO: Perbill = Perbill::from_percent(5); + +/// We allow `Normal` extrinsics to fill up the block up to 75%, the rest can be used by +/// `Operational` extrinsics. +const NORMAL_DISPATCH_RATIO: Perbill = Perbill::from_percent(75); + +/// We allow for 2 seconds of compute with a 6-second average block. +const MAXIMUM_BLOCK_WEIGHT: Weight = Weight::from_parts( + WEIGHT_REF_TIME_PER_SECOND.saturating_mul(2), + cumulus_primitives_core::relay_chain::MAX_POV_SIZE as u64, +); + +/// Maximum number of blocks simultaneously accepted by the Runtime, not yet included +/// into the relay chain. +const UNINCLUDED_SEGMENT_CAPACITY: u32 = 3; +/// How many parachain blocks are processed by the relay chain per parent. Limits the +/// number of blocks authored per slot. +const BLOCK_PROCESSING_VELOCITY: u32 = 1; +/// Relay chain slot duration, in milliseconds. +const RELAY_CHAIN_SLOT_DURATION_MILLIS: u32 = 6000; + +/// Aura consensus hook +type ConsensusHook = cumulus_pallet_aura_ext::FixedVelocityConsensusHook< + Runtime, + RELAY_CHAIN_SLOT_DURATION_MILLIS, + BLOCK_PROCESSING_VELOCITY, + UNINCLUDED_SEGMENT_CAPACITY, +>; + +/// The version information used to identify this runtime when compiled natively. +#[cfg(feature = "std")] +pub fn native_version() -> NativeVersion { + NativeVersion { + runtime_version: VERSION, + can_author_with: Default::default(), + } +} + +#[frame_support::runtime] +mod runtime { + // Create the runtime by composing the FRAME pallets that were previously configured. + #[runtime::runtime] + #[runtime::derive( + RuntimeCall, + RuntimeEvent, + RuntimeError, + RuntimeOrigin, + RuntimeFreezeReason, + RuntimeHoldReason, + RuntimeSlashReason, + RuntimeLockId, + RuntimeTask + )] + pub struct Runtime; + + // System support stuff. + #[runtime::pallet_index(0)] + pub type System = frame_system::Pallet; + #[runtime::pallet_index(1)] + pub type ParachainSystem = cumulus_pallet_parachain_system::Pallet; + #[runtime::pallet_index(2)] + pub type Timestamp = pallet_timestamp::Pallet; + #[runtime::pallet_index(3)] + pub type ParachainInfo = parachain_info::Pallet; + + // Monetary stuff. + #[runtime::pallet_index(10)] + pub type Balances = pallet_balances::Pallet; + #[runtime::pallet_index(11)] + pub type TransactionPayment = pallet_transaction_payment::Pallet; +} + +cumulus_pallet_parachain_system::register_validate_block! { + Runtime = Runtime, + BlockExecutor = cumulus_pallet_aura_ext::BlockExecutor::, +} From f8c98d55b8fe4d5b64fcaf30d9a2d544d9120b22 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1s=20Senovilla=20Polo?= Date: Sat, 9 Nov 2024 13:47:41 +0100 Subject: [PATCH 14/46] Macro to reduce add_ast functions in pop_common::rust_writer::expand::tests --- .../src/rust_writer/expand/tests.rs | 59 +++++++++---------- 1 file changed, 27 insertions(+), 32 deletions(-) diff --git a/crates/pop-common/src/rust_writer/expand/tests.rs b/crates/pop-common/src/rust_writer/expand/tests.rs index 08a359eaa..93ccbda51 100644 --- a/crates/pop-common/src/rust_writer/expand/tests.rs +++ b/crates/pop-common/src/rust_writer/expand/tests.rs @@ -21,35 +21,30 @@ impl Default for TestBuilder { } } -impl TestBuilder { - fn add_basic_pallet_ast(&mut self) { - self.ast = helpers::preserve_and_parse( - fs::read_to_string(self.test_files.join("basic_pallet.rs")) - .expect("Error reading pallet file in add_basic_pallet_ast"), - vec![], - ) - .expect("Error parsing pallet file in add_basic_pallet_ast"); - } - - fn add_basic_pallet_with_config_preludes_ast(&mut self) { - self.ast = helpers::preserve_and_parse( - fs::read_to_string(self.test_files.join("basic_pallet_with_config_preludes.rs")) - .expect("Error reading pallet file in add_basic_pallet_with_config_preludes_ast"), - vec![], - ) - .expect("Error parsing pallet file in add_basic_pallet_with_config_preludes_ast"); - } +macro_rules! add_ast_to_builder{ + ($([$name: ident, $file: literal $(, $macro_excluded: literal)?]),*) => { + $( + fn $name(&mut self){ + self.ast = helpers::preserve_and_parse( + fs::read_to_string(self.test_files.join($file)) + .expect(concat!{"Error reading file in ", stringify!($name)}), + vec![$($macro_excluded)?]) + .expect(concat!{"Error parsing file in ", stringify!($name)}); + } + )* + }; +} - fn add_outer_config_preludes_ast(&mut self) { - self.ast = helpers::preserve_and_parse( - fs::read_to_string(self.test_files.join("outer_config_preludes.rs")) - .expect("Error reading pallet file in add_outer_config_preludes_ast"), - vec![], - ) - .expect("Error parsing pallet file in add_outer_config_preludes_ast"); +impl TestBuilder { + add_ast_to_builder! { + [add_basic_pallet_ast, "basic_pallet.rs"], + [add_basic_pallet_with_config_preludes_ast, "basic_pallet_with_config_preludes.rs"], + [add_outer_config_preludes_ast, "outer_config_preludes.rs"], + [add_runtime_using_runtime_macro_ast, "runtime_using_runtime_macro.rs"], + [add_runtime_using_construct_runtime_macro_ast, "runtime_using_construct_runtime_macro.rs", "construct_runtime"] } - fn assert_in_config_items(&self, contains: bool, checked_item: TraitItem) { + fn assert_item_in_config_trait(&self, contains: bool, checked_item: TraitItem) { let mut assert_happened = false; for item in &self.ast.items { match item { @@ -166,7 +161,7 @@ fn expand_pallet_config_trait_works_well_test() { DefaultConfigType::Default { type_default_impl: parse_quote! {type whatever = ();} }; //Check that the config trait doesn't include ```MyDefaultType```. - test_builder.assert_in_config_items( + test_builder.assert_item_in_config_trait( false, TraitItem::Type(parse_quote! { ///EMPTY_LINE @@ -183,7 +178,7 @@ fn expand_pallet_config_trait_works_well_test() { ); //Now ```MyDefaultType``` is part of the ast. - test_builder.assert_in_config_items( + test_builder.assert_item_in_config_trait( true, TraitItem::Type(parse_quote! { ///EMPTY_LINE @@ -191,7 +186,7 @@ fn expand_pallet_config_trait_works_well_test() { }), ); - test_builder.assert_in_config_items( + test_builder.assert_item_in_config_trait( false, TraitItem::Type(parse_quote! { ///EMPTY_LINE @@ -208,7 +203,7 @@ fn expand_pallet_config_trait_works_well_test() { vec![parse_quote! {Bound1}, parse_quote! {From}], ); - test_builder.assert_in_config_items( + test_builder.assert_item_in_config_trait( true, TraitItem::Type(parse_quote! { ///EMPTY_LINE @@ -217,7 +212,7 @@ fn expand_pallet_config_trait_works_well_test() { }), ); - test_builder.assert_in_config_items( + test_builder.assert_item_in_config_trait( false, TraitItem::Type(parse_quote! { ///EMPTY_LINE @@ -236,7 +231,7 @@ fn expand_pallet_config_trait_works_well_test() { vec![parse_quote! {Bound1}, parse_quote! {From}], ); - test_builder.assert_in_config_items( + test_builder.assert_item_in_config_trait( true, TraitItem::Type(parse_quote! { ///EMPTY_LINE From 83b48a19e72914496205db3f347070b8063e3cf1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1s=20Senovilla=20Polo?= Date: Sat, 9 Nov 2024 17:35:33 +0100 Subject: [PATCH 15/46] Add tests expand runtime add pallet --- crates/pop-common/src/rust_writer/expand.rs | 2 +- .../src/rust_writer/expand/tests.rs | 166 ++++++++++++++++-- .../runtime_using_construct_runtime_macro.rs | 2 +- 3 files changed, 153 insertions(+), 17 deletions(-) diff --git a/crates/pop-common/src/rust_writer/expand.rs b/crates/pop-common/src/rust_writer/expand.rs index ff9bda81f..7600433bd 100644 --- a/crates/pop-common/src/rust_writer/expand.rs +++ b/crates/pop-common/src/rust_writer/expand.rs @@ -174,7 +174,7 @@ pub(crate) fn expand_runtime_add_pallet( } } }, - RuntimeUsedMacro::NotFound => (), + _ => (), } } diff --git a/crates/pop-common/src/rust_writer/expand/tests.rs b/crates/pop-common/src/rust_writer/expand/tests.rs index 93ccbda51..4729ede2e 100644 --- a/crates/pop-common/src/rust_writer/expand/tests.rs +++ b/crates/pop-common/src/rust_writer/expand/tests.rs @@ -3,6 +3,7 @@ use super::*; use crate::rust_writer::helpers; use std::{fs, path::PathBuf}; +use syn::parse_str; struct TestBuilder { test_files: PathBuf, @@ -56,11 +57,7 @@ impl TestBuilder { for item in items { match item { Item::Trait(ItemTrait { ident, items, .. }) if *ident == "Config" => { - if contains { - assert!(items.contains(&checked_item)); - } else { - assert!(!items.contains(&checked_item)); - } + assert_eq!(items.contains(&checked_item), contains); assert_happened = true; }, _ => continue, @@ -108,11 +105,7 @@ impl TestBuilder { } }) => { - if contains { - assert!(items.contains(&type_)); - } else { - assert!(!items.contains(&type_)); - } + assert_eq!(items.contains(&type_), contains); assert_happened = true; }, _ => continue, @@ -135,11 +128,7 @@ impl TestBuilder { } }) => { - if contains { - assert!(items.contains(&type_)); - } else { - assert!(!items.contains(&type_)); - } + assert_eq!(items.contains(&type_), contains); assert_happened = true; }, _ => continue, @@ -147,6 +136,74 @@ impl TestBuilder { } assert!(assert_happened); } + + fn assert_pallet_in_runtime( + &self, + contains: bool, + expected_index: Literal, + used_macro: RuntimeUsedMacro, + pallet_name: Type, + pallet_item: Ident, + ) { + let mut assert_happened = false; + match used_macro { + RuntimeUsedMacro::Runtime => + for item in &self.ast.items { + match item { + Item::Mod(ItemMod { ident, content, .. }) + if *ident == "runtime" && content.is_some() => + { + let (_, items) = content + .as_ref() + .expect("content is always Some thanks to the match guard"); + + assert_eq!( + items.contains(&Item::Type(parse_quote! { + #[runtime::pallet_index(#expected_index)] + pub type #pallet_item = #pallet_name; + })), + contains + ); + assert_happened = true; + }, + _ => continue, + } + }, + RuntimeUsedMacro::ConstructRuntime => + for item in &self.ast.items { + match item { + Item::Macro(ItemMacro { + mac: Macro { path: syn::Path { segments, .. }, tokens, .. }, + .. + }) if segments + .iter() + .any(|segment| segment.ident == "construct_runtime") => + { + let mut token_tree: Vec = + tokens.clone().into_iter().collect(); + for token in token_tree.iter_mut() { + if let TokenTree::Group(group) = token { + let new_pallet_token_stream: TokenStream = parse_quote! { + #pallet_item:#pallet_name, + }; + assert_eq!( + group + .stream() + .to_string() + .contains(&new_pallet_token_stream.to_string()), + contains + ); + assert_happened = true; + } + } + }, + _ => continue, + } + }, + _ => (), + } + assert!(assert_happened); + } } #[test] @@ -282,3 +339,82 @@ fn expand_pallet_config_preludes_outer_file_works_well_test() { //Check that the config type's included. test_builder.assert_type_added_to_config_preludes(true, my_type.clone()); } + +#[test] +fn add_pallet_to_runtime_using_runtime_macro_works_well_test() { + let mut test_builder = TestBuilder::default(); + test_builder.add_runtime_using_runtime_macro_ast(); + + // Arbitrary highest index to pass to expand_runtime_add_pallet + let highest_index = 11u8; + // Expected index as syn::literal + let expected_index = Literal::u8_unsuffixed(highest_index.saturating_add(1)); + + let pallet_item = Ident::new("Test", Span::call_site()); + let pallet_name: Type = parse_str("pallet_test").expect( + "Error parsing pallet_test in add_pallet_to_runtime_using_runtime_macro_works_well_test", + ); + + test_builder.assert_pallet_in_runtime( + false, + expected_index.clone(), + RuntimeUsedMacro::Runtime, + pallet_name.clone(), + pallet_item.clone(), + ); + + expand_runtime_add_pallet( + &mut test_builder.ast, + highest_index, + RuntimeUsedMacro::Runtime, + pallet_name.clone(), + pallet_item.clone(), + ); + + test_builder.assert_pallet_in_runtime( + true, + expected_index, + RuntimeUsedMacro::Runtime, + pallet_name, + pallet_item, + ); +} + +#[test] +fn add_pallet_to_runtime_using_construct_runtime_macro_works_well_test() { + let mut test_builder = TestBuilder::default(); + test_builder.add_runtime_using_construct_runtime_macro_ast(); + + // Expected index as syn::literal, needed for assert_pallet_in_runtime but not relevant in this + // case + let expected_index = Literal::u8_unsuffixed(0u8); + + let pallet_item = Ident::new("Test", Span::call_site()); + let pallet_name: Type = parse_str("pallet_test").expect( + "Error parsing pallet_test in add_pallet_to_runtime_using_runtime_macro_works_well_test", + ); + + test_builder.assert_pallet_in_runtime( + false, + expected_index.clone(), + RuntimeUsedMacro::ConstructRuntime, + pallet_name.clone(), + pallet_item.clone(), + ); + + expand_runtime_add_pallet( + &mut test_builder.ast, + 0u8, + RuntimeUsedMacro::ConstructRuntime, + pallet_name.clone(), + pallet_item.clone(), + ); + + test_builder.assert_pallet_in_runtime( + true, + expected_index, + RuntimeUsedMacro::ConstructRuntime, + pallet_name, + pallet_item, + ); +} diff --git a/crates/pop-common/src/rust_writer/test_files/runtime_using_construct_runtime_macro.rs b/crates/pop-common/src/rust_writer/test_files/runtime_using_construct_runtime_macro.rs index 136f534e5..faaea67d6 100644 --- a/crates/pop-common/src/rust_writer/test_files/runtime_using_construct_runtime_macro.rs +++ b/crates/pop-common/src/rust_writer/test_files/runtime_using_construct_runtime_macro.rs @@ -248,7 +248,7 @@ construct_runtime! { Timestamp: pallet_timestamp, ParachainInfo:parachain_info, Balances: pallet_balances, - TransactionPayment: pallet_transaction_payment + TransactionPayment: pallet_transaction_payment, } } From dc16a9beabee2f29a969c0107cd02ceba1512d87 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1s=20Senovilla=20Polo?= Date: Wed, 13 Nov 2024 18:55:42 +0100 Subject: [PATCH 16/46] Changing ParameterTypes struct so it uses Ident instead of String --- crates/pop-cli/src/commands/add/pallet/common_pallets.rs | 2 +- crates/pop-common/src/rust_writer/expand.rs | 4 ++-- crates/pop-common/src/rust_writer/types.rs | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/crates/pop-cli/src/commands/add/pallet/common_pallets.rs b/crates/pop-cli/src/commands/add/pallet/common_pallets.rs index 9c19c5429..4d3e54b68 100644 --- a/crates/pop-cli/src/commands/add/pallet/common_pallets.rs +++ b/crates/pop-cli/src/commands/add/pallet/common_pallets.rs @@ -34,7 +34,7 @@ impl CommonPallets { match self { CommonPallets::Balances => Vec::new(), CommonPallets::Contracts => vec![ParameterTypes { - ident: "Schedule".to_string(), + ident: Ident::new("Schedule", Span::call_site()), type_: parse_quote! {pallet_contracts::Schedule}, value: parse_quote! {Default::default()}, }], diff --git a/crates/pop-common/src/rust_writer/expand.rs b/crates/pop-common/src/rust_writer/expand.rs index 7600433bd..5f7e1cfc9 100644 --- a/crates/pop-common/src/rust_writer/expand.rs +++ b/crates/pop-common/src/rust_writer/expand.rs @@ -184,9 +184,9 @@ pub(crate) fn expand_runtime_add_impl_block( parameter_types: Vec, default_config: bool, ) { - let parameter_idents: Vec = parameter_types + let parameter_idents: Vec<&Ident> = parameter_types .iter() - .map(|item| Ident::new(&capitalize_str(&item.ident), Span::call_site())) + .map(|item| &item.ident) .collect(); let parameter_types_types: Vec<&Type> = parameter_types.iter().map(|item| &item.type_).collect(); diff --git a/crates/pop-common/src/rust_writer/types.rs b/crates/pop-common/src/rust_writer/types.rs index af0d52d47..40e67d75a 100644 --- a/crates/pop-common/src/rust_writer/types.rs +++ b/crates/pop-common/src/rust_writer/types.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-3.0 -use syn::{Expr, ImplItem, Type}; +use syn::{Expr, ImplItem, Type, Ident}; #[derive(Debug, Clone, PartialEq)] pub enum DefaultConfigType { @@ -18,7 +18,7 @@ pub enum RuntimeUsedMacro { #[derive(Debug, Clone, PartialEq)] pub struct ParameterTypes { - pub ident: String, + pub ident: Ident, pub type_: Type, pub value: Expr, } From 98eb50242cadd19a9e6fae5fc1a4e8be42ff20b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1s=20Senovilla=20Polo?= Date: Wed, 13 Nov 2024 19:31:39 +0100 Subject: [PATCH 17/46] Adding test for expand_runtime_add_impl_block --- crates/pop-common/src/rust_writer/expand.rs | 20 ++- .../src/rust_writer/expand/tests.rs | 137 +++++++++++++++++- crates/pop-common/src/rust_writer/types.rs | 2 +- 3 files changed, 145 insertions(+), 14 deletions(-) diff --git a/crates/pop-common/src/rust_writer/expand.rs b/crates/pop-common/src/rust_writer/expand.rs index 5f7e1cfc9..b005c4495 100644 --- a/crates/pop-common/src/rust_writer/expand.rs +++ b/crates/pop-common/src/rust_writer/expand.rs @@ -3,7 +3,7 @@ #[cfg(test)] mod tests; -use crate::{capitalize_str, rust_writer::types::*}; +use crate::rust_writer::types::*; use proc_macro2::{Group, Literal, Span, TokenStream, TokenTree}; use syn::{ parse_quote, Expr, File, Ident, ImplItem, Item, ItemEnum, ItemImpl, ItemMacro, ItemMod, @@ -184,18 +184,15 @@ pub(crate) fn expand_runtime_add_impl_block( parameter_types: Vec, default_config: bool, ) { - let parameter_idents: Vec<&Ident> = parameter_types - .iter() - .map(|item| &item.ident) - .collect(); - let parameter_types_types: Vec<&Type> = - parameter_types.iter().map(|item| &item.type_).collect(); - let parameter_values: Vec<&Expr> = parameter_types.iter().map(|item| &item.value).collect(); let items = &mut ast.items; - // It's enough checking that parameter_idents isn't empty, by construction all the 3 Vec have - // the same lenght - if !parameter_idents.is_empty() { + if !parameter_types.is_empty() { + let parameter_idents: Vec<&Ident> = + parameter_types.iter().map(|item| &item.ident).collect(); + let parameter_types_types: Vec<&Type> = + parameter_types.iter().map(|item| &item.type_).collect(); + let parameter_values: Vec<&Expr> = parameter_types.iter().map(|item| &item.value).collect(); + items.push(Item::Macro(parse_quote! { ///EMPTY_LINE parameter_types!{ @@ -205,6 +202,7 @@ pub(crate) fn expand_runtime_add_impl_block( } })); } + if default_config { items.push(Item::Impl(parse_quote! { ///EMPTY_LINE diff --git a/crates/pop-common/src/rust_writer/expand/tests.rs b/crates/pop-common/src/rust_writer/expand/tests.rs index 4729ede2e..8ebd8b74a 100644 --- a/crates/pop-common/src/rust_writer/expand/tests.rs +++ b/crates/pop-common/src/rust_writer/expand/tests.rs @@ -204,6 +204,54 @@ impl TestBuilder { } assert!(assert_happened); } + + fn assert_impl_block_contained( + &self, + contains: bool, + pallet_name: Ident, + parameter_types: Vec, + using_default_config: bool, + ) { + if !parameter_types.is_empty() { + let parameter_idents: Vec<&Ident> = + parameter_types.iter().map(|item| &item.ident).collect(); + let parameter_types_types: Vec<&Type> = + parameter_types.iter().map(|item| &item.type_).collect(); + let parameter_values: Vec<&Expr> = + parameter_types.iter().map(|item| &item.value).collect(); + + assert_eq!( + self.ast.items.contains(&Item::Macro(parse_quote! { + ///EMPTY_LINE + parameter_types!{ + #( + pub #parameter_idents: #parameter_types_types = #parameter_values; + )* + } + })), + contains + ); + } + + if using_default_config { + assert_eq!( + self.ast.items.contains(&Item::Impl(parse_quote! { + ///EMPTY_LINE + #[derive_impl(#pallet_name::config_preludes::TestDefaultConfig)] + impl #pallet_name::Config for Runtime{} + })), + contains + ); + } else { + assert_eq!( + self.ast.items.contains(&Item::Impl(parse_quote! { + ///EMPTY_LINE + impl #pallet_name::Config for Runtime{} + })), + contains + ); + } + } } #[test] @@ -341,7 +389,7 @@ fn expand_pallet_config_preludes_outer_file_works_well_test() { } #[test] -fn add_pallet_to_runtime_using_runtime_macro_works_well_test() { +fn expand_runtime_add_pallet_using_runtime_macro_works_well_test() { let mut test_builder = TestBuilder::default(); test_builder.add_runtime_using_runtime_macro_ast(); @@ -381,7 +429,7 @@ fn add_pallet_to_runtime_using_runtime_macro_works_well_test() { } #[test] -fn add_pallet_to_runtime_using_construct_runtime_macro_works_well_test() { +fn expand_runtime_add_pallet_using_construct_runtime_macro_works_well_test() { let mut test_builder = TestBuilder::default(); test_builder.add_runtime_using_construct_runtime_macro_ast(); @@ -418,3 +466,88 @@ fn add_pallet_to_runtime_using_construct_runtime_macro_works_well_test() { pallet_item, ); } + +#[test] +fn expand_runtime_add_impl_block_works_well_test() { + let mut test_builder = TestBuilder::default(); + test_builder.add_runtime_using_runtime_macro_ast(); + + let mut parameter_types = Vec::new(); + let pallet_name = Ident::new("Test", Span::call_site()); + + // Impl pallet without defautl config not added + test_builder.assert_impl_block_contained( + false, + pallet_name.clone(), + parameter_types.clone(), + false, + ); + expand_runtime_add_impl_block( + &mut test_builder.ast, + pallet_name.clone(), + parameter_types.clone(), + false, + ); + // Impl pallet without default config added. + test_builder.assert_impl_block_contained( + true, + pallet_name.clone(), + parameter_types.clone(), + false, + ); + + let pallet_name = Ident::new("Test2", Span::call_site()); + // Impl pallet with default config not added + test_builder.assert_impl_block_contained( + false, + pallet_name.clone(), + parameter_types.clone(), + true, + ); + expand_runtime_add_impl_block( + &mut test_builder.ast, + pallet_name.clone(), + parameter_types.clone(), + true, + ); + //Impl pallet with default config added + test_builder.assert_impl_block_contained( + true, + pallet_name.clone(), + parameter_types.clone(), + true, + ); + + let pallet_name = Ident::new("Test3", Span::call_site()); + parameter_types.push(ParameterTypes { + ident: Ident::new("MyType1", Span::call_site()), + type_: parse_quote! {Type}, + value: parse_quote! {Default::default()}, + }); + parameter_types.push(ParameterTypes { + ident: Ident::new("MyType2", Span::call_site()), + type_: parse_quote! {Type}, + value: parse_quote! {Default::default()}, + }); + + // Impl pallet block + parameter_types block not added + test_builder.assert_impl_block_contained( + false, + pallet_name.clone(), + parameter_types.clone(), + true, + ); + expand_runtime_add_impl_block( + &mut test_builder.ast, + pallet_name.clone(), + parameter_types.clone(), + true, + ); + //Impl pallet block + parameter_types block not added + test_builder.assert_impl_block_contained( + true, + pallet_name.clone(), + parameter_types.clone(), + true, + ); +} diff --git a/crates/pop-common/src/rust_writer/types.rs b/crates/pop-common/src/rust_writer/types.rs index 40e67d75a..d7f7473e9 100644 --- a/crates/pop-common/src/rust_writer/types.rs +++ b/crates/pop-common/src/rust_writer/types.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-3.0 -use syn::{Expr, ImplItem, Type, Ident}; +use syn::{Expr, Ident, ImplItem, Type}; #[derive(Debug, Clone, PartialEq)] pub enum DefaultConfigType { From 63894c8e457d82733fb5caf1c8d9cb02fb1f57ef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1s=20Senovilla=20Polo?= Date: Wed, 13 Nov 2024 19:48:14 +0100 Subject: [PATCH 18/46] Add test for expand_runtime_add_impl_block --- .../src/rust_writer/expand/tests.rs | 74 +++++++++++++++++++ 1 file changed, 74 insertions(+) diff --git a/crates/pop-common/src/rust_writer/expand/tests.rs b/crates/pop-common/src/rust_writer/expand/tests.rs index 8ebd8b74a..cf14f691b 100644 --- a/crates/pop-common/src/rust_writer/expand/tests.rs +++ b/crates/pop-common/src/rust_writer/expand/tests.rs @@ -252,6 +252,35 @@ impl TestBuilder { ); } } + + fn assert_type_in_impl_block( + &self, + contains: bool, + type_name: Ident, + runtime_value: Type, + pallet_name: &str, + ) { + let mut assert_happened = false; + for item in &self.ast.items { + match item { + Item::Impl(ItemImpl { + trait_: Some((_, syn::Path { segments, .. }, _)), + items, + .. + }) if segments.iter().any(|segment| segment.ident == pallet_name) => { + assert_eq!( + items.contains(&ImplItem::Type(parse_quote! { + type #type_name = #runtime_value; + })), + contains + ); + assert_happened = true; + }, + _ => continue, + } + } + assert!(assert_happened); + } } #[test] @@ -482,6 +511,7 @@ fn expand_runtime_add_impl_block_works_well_test() { parameter_types.clone(), false, ); + // Add them expand_runtime_add_impl_block( &mut test_builder.ast, pallet_name.clone(), @@ -504,6 +534,7 @@ fn expand_runtime_add_impl_block_works_well_test() { parameter_types.clone(), true, ); + // Add them expand_runtime_add_impl_block( &mut test_builder.ast, pallet_name.clone(), @@ -537,6 +568,7 @@ fn expand_runtime_add_impl_block_works_well_test() { parameter_types.clone(), true, ); + // Add them expand_runtime_add_impl_block( &mut test_builder.ast, pallet_name.clone(), @@ -551,3 +583,45 @@ fn expand_runtime_add_impl_block_works_well_test() { true, ); } + +#[test] +fn expand_runtime_add_type_to_impl_block_works_well_test() { + let mut test_builder = TestBuilder::default(); + test_builder.add_runtime_using_runtime_macro_ast(); + + let pallet_name = "Test"; + let type_name = Ident::new("MyType", Span::call_site()); + let runtime_value: Type = parse_quote! {Type}; + let parameter_types = Vec::new(); + + expand_runtime_add_impl_block( + &mut test_builder.ast, + Ident::new(pallet_name, Span::call_site()), + parameter_types, + false, + ); + + // The pallet impl block doesn't include the type + test_builder.assert_type_in_impl_block( + false, + type_name.clone(), + runtime_value.clone(), + pallet_name, + ); + + // Add it + expand_runtime_add_type_to_impl_block( + &mut test_builder.ast, + type_name.clone(), + runtime_value.clone(), + pallet_name, + ); + + // Now it's included in the ast + test_builder.assert_type_in_impl_block( + true, + type_name.clone(), + runtime_value.clone(), + pallet_name, + ); +} From 318c78bd4af1379088389f349564e0b0c2cb22a3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1s=20Senovilla=20Polo?= Date: Thu, 14 Nov 2024 19:01:03 +0100 Subject: [PATCH 19/46] Refactor: split expand_runtime_add_impl_block test in 3 different tests --- .../src/rust_writer/expand/tests.rs | 54 +++++++++++++------ 1 file changed, 38 insertions(+), 16 deletions(-) diff --git a/crates/pop-common/src/rust_writer/expand/tests.rs b/crates/pop-common/src/rust_writer/expand/tests.rs index cf14f691b..c724960b7 100644 --- a/crates/pop-common/src/rust_writer/expand/tests.rs +++ b/crates/pop-common/src/rust_writer/expand/tests.rs @@ -497,11 +497,11 @@ fn expand_runtime_add_pallet_using_construct_runtime_macro_works_well_test() { } #[test] -fn expand_runtime_add_impl_block_works_well_test() { +fn expand_runtime_add_impl_block_without_default_config_works_well_test() { let mut test_builder = TestBuilder::default(); test_builder.add_runtime_using_runtime_macro_ast(); - let mut parameter_types = Vec::new(); + let parameter_types = Vec::new(); let pallet_name = Ident::new("Test", Span::call_site()); // Impl pallet without defautl config not added @@ -511,13 +511,15 @@ fn expand_runtime_add_impl_block_works_well_test() { parameter_types.clone(), false, ); - // Add them + + // Add it expand_runtime_add_impl_block( &mut test_builder.ast, pallet_name.clone(), parameter_types.clone(), false, ); + // Impl pallet without default config added. test_builder.assert_impl_block_contained( true, @@ -525,8 +527,16 @@ fn expand_runtime_add_impl_block_works_well_test() { parameter_types.clone(), false, ); +} + +#[test] +fn expand_runtime_add_impl_block_with_default_config_works_well_test() { + let mut test_builder = TestBuilder::default(); + test_builder.add_runtime_using_runtime_macro_ast(); + + let pallet_name = Ident::new("Test", Span::call_site()); + let parameter_types = Vec::new(); - let pallet_name = Ident::new("Test2", Span::call_site()); // Impl pallet with default config not added test_builder.assert_impl_block_contained( false, @@ -534,13 +544,15 @@ fn expand_runtime_add_impl_block_works_well_test() { parameter_types.clone(), true, ); - // Add them + + // Add it expand_runtime_add_impl_block( &mut test_builder.ast, pallet_name.clone(), parameter_types.clone(), true, ); + //Impl pallet with default config added test_builder.assert_impl_block_contained( true, @@ -548,18 +560,26 @@ fn expand_runtime_add_impl_block_works_well_test() { parameter_types.clone(), true, ); +} - let pallet_name = Ident::new("Test3", Span::call_site()); - parameter_types.push(ParameterTypes { - ident: Ident::new("MyType1", Span::call_site()), - type_: parse_quote! {Type}, - value: parse_quote! {Default::default()}, - }); - parameter_types.push(ParameterTypes { - ident: Ident::new("MyType2", Span::call_site()), - type_: parse_quote! {Type}, - value: parse_quote! {Default::default()}, - }); +#[test] +fn expand_runtime_add_impl_block_using_parameter_types_works_well_test() { + let mut test_builder = TestBuilder::default(); + test_builder.add_runtime_using_runtime_macro_ast(); + + let pallet_name = Ident::new("Test", Span::call_site()); + let parameter_types = vec![ + ParameterTypes { + ident: Ident::new("MyType1", Span::call_site()), + type_: parse_quote! {Type}, + value: parse_quote! {Default::default()}, + }, + ParameterTypes { + ident: Ident::new("MyType2", Span::call_site()), + type_: parse_quote! {Type}, + value: parse_quote! {Default::default()}, + }, + ]; // Impl pallet block + parameter_types block not added test_builder.assert_impl_block_contained( @@ -568,6 +588,7 @@ fn expand_runtime_add_impl_block_works_well_test() { parameter_types.clone(), true, ); + // Add them expand_runtime_add_impl_block( &mut test_builder.ast, @@ -575,6 +596,7 @@ fn expand_runtime_add_impl_block_works_well_test() { parameter_types.clone(), true, ); + //Impl pallet block + parameter_types block not added test_builder.assert_impl_block_contained( true, From c7f44fcd8e63da78d5175ebeee023749368f9576 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1s=20Senovilla=20Polo?= Date: Sun, 17 Nov 2024 13:26:59 +0100 Subject: [PATCH 20/46] Add test expand add_use_statement --- .../src/rust_writer/expand/tests.rs | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/crates/pop-common/src/rust_writer/expand/tests.rs b/crates/pop-common/src/rust_writer/expand/tests.rs index c724960b7..75e03a02b 100644 --- a/crates/pop-common/src/rust_writer/expand/tests.rs +++ b/crates/pop-common/src/rust_writer/expand/tests.rs @@ -281,6 +281,10 @@ impl TestBuilder { } assert!(assert_happened); } + + fn assert_use_statement_included(&self, contains: bool, use_statement: ItemUse) { + assert_eq!(self.ast.items.contains(&Item::Use(use_statement)), contains); + } } #[test] @@ -647,3 +651,19 @@ fn expand_runtime_add_type_to_impl_block_works_well_test() { pallet_name, ); } + +#[test] +fn expand_add_use_statement_works_well_test() { + let mut test_builder = TestBuilder::default(); + test_builder.add_basic_pallet_ast(); + + let use_statement: ItemUse = parse_quote! { + use some_crate::some_module::some_function; + }; + + test_builder.assert_use_statement_included(false, use_statement.clone()); + + expand_add_use_statement(&mut test_builder.ast, use_statement.clone()); + + test_builder.assert_use_statement_included(true, use_statement); +} From ead6477c95756cf7d8749e619c38382f90e90bc6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1s=20Senovilla=20Polo?= Date: Sun, 17 Nov 2024 14:22:33 +0100 Subject: [PATCH 21/46] Finalizing expand tests --- crates/pop-common/src/rust_writer.rs | 2 +- crates/pop-common/src/rust_writer/expand.rs | 2 +- .../src/rust_writer/expand/tests.rs | 61 ++++++++++++++++++- 3 files changed, 62 insertions(+), 3 deletions(-) diff --git a/crates/pop-common/src/rust_writer.rs b/crates/pop-common/src/rust_writer.rs index 3bfbd6532..b79d7cba1 100644 --- a/crates/pop-common/src/rust_writer.rs +++ b/crates/pop-common/src/rust_writer.rs @@ -248,7 +248,7 @@ pub fn add_composite_enums(file_path: &Path, composite_enums: Vec) -> composite_enums.into_iter().for_each(|composite_enum| { if !parse::find_composite_enum(&ast, &composite_enum) { - expand::expand_add_composite_enum(&mut ast, composite_enum); + expand::expand_pallet_add_composite_enum(&mut ast, composite_enum); } }); diff --git a/crates/pop-common/src/rust_writer/expand.rs b/crates/pop-common/src/rust_writer/expand.rs index b005c4495..2407bf81c 100644 --- a/crates/pop-common/src/rust_writer/expand.rs +++ b/crates/pop-common/src/rust_writer/expand.rs @@ -246,7 +246,7 @@ pub(crate) fn expand_add_use_statement(ast: &mut File, use_statement: ItemUse) { items.insert(position, Item::Use(use_statement)); } -pub(crate) fn expand_add_composite_enum(ast: &mut File, composite_enum: ItemEnum) { +pub(crate) fn expand_pallet_add_composite_enum(ast: &mut File, composite_enum: ItemEnum) { for item in &mut ast.items { match item { Item::Mod(ItemMod { ident, content, .. }) diff --git a/crates/pop-common/src/rust_writer/expand/tests.rs b/crates/pop-common/src/rust_writer/expand/tests.rs index 75e03a02b..714892d99 100644 --- a/crates/pop-common/src/rust_writer/expand/tests.rs +++ b/crates/pop-common/src/rust_writer/expand/tests.rs @@ -283,7 +283,46 @@ impl TestBuilder { } fn assert_use_statement_included(&self, contains: bool, use_statement: ItemUse) { - assert_eq!(self.ast.items.contains(&Item::Use(use_statement)), contains); + // Find the first use statement + let position = + self.ast.items.iter().position(|item| matches!(item, Item::Use(_))).unwrap_or(0); + // The use statement has been added together with other use statements + if let Some(item) = self.ast.items.get(position) { + assert_eq!(item == &Item::Use(use_statement), contains); + } else { + assert!(false); + } + } + + fn assert_composite_enum_in_pallet(&self, contains: bool, composite_enum: ItemEnum) { + let mut assert_happened = false; + for item in &self.ast.items { + match item { + Item::Mod(ItemMod { ident, content, .. }) + if *ident == "pallet" && content.is_some() => + { + let (_, items) = + content.as_ref().expect("content is always Some thanks to the match guard"); + // Find the Pallet struct position + let position = items + .iter() + .position( + |item| matches!(item, Item::Struct(ItemStruct { ident, .. }) if *ident == "Pallet"), + ) + .unwrap_or(0); + // The composite enum has been added just before the Pallet struct (if prior + // insertion pallet is in position n, now it's in position n+1, as the item + // is included in position n-1, we have to check in n+1 - (n-1) = 2 + // positions before the actual position of pallet) + if let Some(item) = items.get(position.saturating_sub(2)) { + assert_eq!(item == &Item::Enum(composite_enum.clone()), contains); + assert_happened = true; + } + }, + _ => continue, + } + } + assert!(assert_happened); } } @@ -667,3 +706,23 @@ fn expand_add_use_statement_works_well_test() { test_builder.assert_use_statement_included(true, use_statement); } + +#[test] +fn expand_pallet_add_composite_enum_works_well_test() { + let mut test_builder = TestBuilder::default(); + test_builder.add_basic_pallet_ast(); + + let composite_enum: ItemEnum = parse_quote! { + #[pallet::composite_enum] + pub enum Enum { + #[codec(index = 0)] + SomeVariant, + #[codec(index=1)] + OtherVariant + } + }; + + test_builder.assert_composite_enum_in_pallet(false, composite_enum.clone()); + expand_pallet_add_composite_enum(&mut test_builder.ast, composite_enum.clone()); + test_builder.assert_composite_enum_in_pallet(true, composite_enum); +} From 62794a92ea7a9a94ec56db9f58b1ffab4b8386ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1s=20Senovilla=20Polo?= Date: Thu, 19 Dec 2024 19:15:32 +0100 Subject: [PATCH 22/46] Move test builder from expand test to rust writer tests --- crates/pop-common/src/rust_writer.rs | 2 + .../src/rust_writer/expand/tests.rs | 42 +---------------- .../pop-common/src/rust_writer/parse/tests.rs | 0 crates/pop-common/src/rust_writer/tests.rs | 3 ++ .../sample_files}/basic_pallet.rs | 0 .../basic_pallet_with_config_preludes.rs | 0 .../sample_files}/outer_config_preludes.rs | 0 .../runtime_using_construct_runtime_macro.rs | 0 .../runtime_using_runtime_macro.rs | 0 .../src/rust_writer/tests/test_builder.rs | 47 +++++++++++++++++++ 10 files changed, 53 insertions(+), 41 deletions(-) create mode 100644 crates/pop-common/src/rust_writer/parse/tests.rs create mode 100644 crates/pop-common/src/rust_writer/tests.rs rename crates/pop-common/src/rust_writer/{test_files => tests/sample_files}/basic_pallet.rs (100%) rename crates/pop-common/src/rust_writer/{test_files => tests/sample_files}/basic_pallet_with_config_preludes.rs (100%) rename crates/pop-common/src/rust_writer/{test_files => tests/sample_files}/outer_config_preludes.rs (100%) rename crates/pop-common/src/rust_writer/{test_files => tests/sample_files}/runtime_using_construct_runtime_macro.rs (100%) rename crates/pop-common/src/rust_writer/{test_files => tests/sample_files}/runtime_using_runtime_macro.rs (100%) create mode 100644 crates/pop-common/src/rust_writer/tests/test_builder.rs diff --git a/crates/pop-common/src/rust_writer.rs b/crates/pop-common/src/rust_writer.rs index b79d7cba1..1caae3fa1 100644 --- a/crates/pop-common/src/rust_writer.rs +++ b/crates/pop-common/src/rust_writer.rs @@ -17,6 +17,8 @@ mod expand; mod helpers; mod parse; pub mod types; +#[cfg(test)] +mod tests; pub fn update_config_trait( file_path: &Path, diff --git a/crates/pop-common/src/rust_writer/expand/tests.rs b/crates/pop-common/src/rust_writer/expand/tests.rs index 714892d99..514a5d61a 100644 --- a/crates/pop-common/src/rust_writer/expand/tests.rs +++ b/crates/pop-common/src/rust_writer/expand/tests.rs @@ -1,50 +1,10 @@ // SPDX-License-Identifier: GPL-3.0 use super::*; -use crate::rust_writer::helpers; -use std::{fs, path::PathBuf}; +use crate::rust_writer::tests::test_builder::TestBuilder; use syn::parse_str; -struct TestBuilder { - test_files: PathBuf, - ast: File, -} - -impl Default for TestBuilder { - fn default() -> Self { - Self { - test_files: PathBuf::from(env!("CARGO_MANIFEST_DIR")) - .join("src") - .join("rust_writer") - .join("test_files"), - ast: parse_quote! {}, - } - } -} - -macro_rules! add_ast_to_builder{ - ($([$name: ident, $file: literal $(, $macro_excluded: literal)?]),*) => { - $( - fn $name(&mut self){ - self.ast = helpers::preserve_and_parse( - fs::read_to_string(self.test_files.join($file)) - .expect(concat!{"Error reading file in ", stringify!($name)}), - vec![$($macro_excluded)?]) - .expect(concat!{"Error parsing file in ", stringify!($name)}); - } - )* - }; -} - impl TestBuilder { - add_ast_to_builder! { - [add_basic_pallet_ast, "basic_pallet.rs"], - [add_basic_pallet_with_config_preludes_ast, "basic_pallet_with_config_preludes.rs"], - [add_outer_config_preludes_ast, "outer_config_preludes.rs"], - [add_runtime_using_runtime_macro_ast, "runtime_using_runtime_macro.rs"], - [add_runtime_using_construct_runtime_macro_ast, "runtime_using_construct_runtime_macro.rs", "construct_runtime"] - } - fn assert_item_in_config_trait(&self, contains: bool, checked_item: TraitItem) { let mut assert_happened = false; for item in &self.ast.items { diff --git a/crates/pop-common/src/rust_writer/parse/tests.rs b/crates/pop-common/src/rust_writer/parse/tests.rs new file mode 100644 index 000000000..e69de29bb diff --git a/crates/pop-common/src/rust_writer/tests.rs b/crates/pop-common/src/rust_writer/tests.rs new file mode 100644 index 000000000..1b5261bb9 --- /dev/null +++ b/crates/pop-common/src/rust_writer/tests.rs @@ -0,0 +1,3 @@ +// SPDX-License-Identifier: GPL-3.0 + +pub(crate) mod test_builder; diff --git a/crates/pop-common/src/rust_writer/test_files/basic_pallet.rs b/crates/pop-common/src/rust_writer/tests/sample_files/basic_pallet.rs similarity index 100% rename from crates/pop-common/src/rust_writer/test_files/basic_pallet.rs rename to crates/pop-common/src/rust_writer/tests/sample_files/basic_pallet.rs diff --git a/crates/pop-common/src/rust_writer/test_files/basic_pallet_with_config_preludes.rs b/crates/pop-common/src/rust_writer/tests/sample_files/basic_pallet_with_config_preludes.rs similarity index 100% rename from crates/pop-common/src/rust_writer/test_files/basic_pallet_with_config_preludes.rs rename to crates/pop-common/src/rust_writer/tests/sample_files/basic_pallet_with_config_preludes.rs diff --git a/crates/pop-common/src/rust_writer/test_files/outer_config_preludes.rs b/crates/pop-common/src/rust_writer/tests/sample_files/outer_config_preludes.rs similarity index 100% rename from crates/pop-common/src/rust_writer/test_files/outer_config_preludes.rs rename to crates/pop-common/src/rust_writer/tests/sample_files/outer_config_preludes.rs diff --git a/crates/pop-common/src/rust_writer/test_files/runtime_using_construct_runtime_macro.rs b/crates/pop-common/src/rust_writer/tests/sample_files/runtime_using_construct_runtime_macro.rs similarity index 100% rename from crates/pop-common/src/rust_writer/test_files/runtime_using_construct_runtime_macro.rs rename to crates/pop-common/src/rust_writer/tests/sample_files/runtime_using_construct_runtime_macro.rs diff --git a/crates/pop-common/src/rust_writer/test_files/runtime_using_runtime_macro.rs b/crates/pop-common/src/rust_writer/tests/sample_files/runtime_using_runtime_macro.rs similarity index 100% rename from crates/pop-common/src/rust_writer/test_files/runtime_using_runtime_macro.rs rename to crates/pop-common/src/rust_writer/tests/sample_files/runtime_using_runtime_macro.rs diff --git a/crates/pop-common/src/rust_writer/tests/test_builder.rs b/crates/pop-common/src/rust_writer/tests/test_builder.rs new file mode 100644 index 000000000..ba939119d --- /dev/null +++ b/crates/pop-common/src/rust_writer/tests/test_builder.rs @@ -0,0 +1,47 @@ +// SPDX-License-Identifier: GPL-3.0 + +use crate::rust_writer::helpers; +use std::{fs, path::PathBuf}; +use syn::{File, parse_quote}; + +pub(crate) struct TestBuilder { + test_files: PathBuf, + pub(crate) ast: File, +} + +impl Default for TestBuilder { + fn default() -> Self { + Self { + test_files: PathBuf::from(env!("CARGO_MANIFEST_DIR")) + .join("src") + .join("rust_writer") + .join("tests") + .join("sample_files"), + ast: parse_quote! {}, + } + } +} + +macro_rules! add_ast_to_builder{ + ($([$name: ident, $file: literal $(, $macro_excluded: literal)?]),*) => { + $( + pub(crate) fn $name(&mut self){ + self.ast = helpers::preserve_and_parse( + fs::read_to_string(self.test_files.join($file)) + .expect(concat!{"Error reading file in ", stringify!($name)}), + vec![$($macro_excluded)?]) + .expect(concat!{"Error parsing file in ", stringify!($name)}); + } + )* + }; +} + +impl TestBuilder { + add_ast_to_builder! { + [add_basic_pallet_ast, "basic_pallet.rs"], + [add_basic_pallet_with_config_preludes_ast, "basic_pallet_with_config_preludes.rs"], + [add_outer_config_preludes_ast, "outer_config_preludes.rs"], + [add_runtime_using_runtime_macro_ast, "runtime_using_runtime_macro.rs"], + [add_runtime_using_construct_runtime_macro_ast, "runtime_using_construct_runtime_macro.rs", "construct_runtime"] + } +} From 4631badc54420e3304f6ac3fd3ffa5ee7f8ceaef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1s=20Senovilla=20Polo?= Date: Thu, 19 Dec 2024 20:42:24 +0100 Subject: [PATCH 23/46] Refactor rust_writer::parse + add several tests --- crates/pop-common/src/rust_writer.rs | 15 ++- crates/pop-common/src/rust_writer/expand.rs | 1 - .../src/rust_writer/expand/tests.rs | 1 - crates/pop-common/src/rust_writer/parse.rs | 79 ++++++++++------ .../pop-common/src/rust_writer/parse/tests.rs | 93 +++++++++++++++++++ .../src/rust_writer/tests/test_builder.rs | 4 +- crates/pop-common/src/rust_writer/types.rs | 1 - 7 files changed, 154 insertions(+), 40 deletions(-) diff --git a/crates/pop-common/src/rust_writer.rs b/crates/pop-common/src/rust_writer.rs index 1caae3fa1..aab61520b 100644 --- a/crates/pop-common/src/rust_writer.rs +++ b/crates/pop-common/src/rust_writer.rs @@ -16,9 +16,9 @@ use syn::{parse_str, Ident, ImplItem, ItemEnum, ItemUse, TraitBound, Type}; mod expand; mod helpers; mod parse; -pub mod types; #[cfg(test)] mod tests; +pub mod types; pub fn update_config_trait( file_path: &Path, @@ -136,14 +136,11 @@ pub fn add_pallet_to_runtime_module( )?; // Parse the runtime to find which of the runtime macros is being used and the highest - // pallet index used (if needed). - let (highest_index, used_macro) = - parse::find_highest_pallet_index_and_runtime_macro_version(&ast); - - if let types::RuntimeUsedMacro::NotFound = used_macro { - return Err(Error::Descriptive( - format! {"Unable to find a runtime declaration in {:?}", runtime_lib_path}, - )); + // pallet index used (if needed, otherwise 0). + let used_macro = parse::find_used_runtime_macro(&ast)?; + let mut highest_index = 0; + if let types::RuntimeUsedMacro::Runtime = used_macro { + highest_index = parse::find_highest_pallet_index(&ast)?; } // Find the pallet name and the pallet item to be added to the runtime. If the pallet_name is diff --git a/crates/pop-common/src/rust_writer/expand.rs b/crates/pop-common/src/rust_writer/expand.rs index 2407bf81c..dfc73a7b3 100644 --- a/crates/pop-common/src/rust_writer/expand.rs +++ b/crates/pop-common/src/rust_writer/expand.rs @@ -174,7 +174,6 @@ pub(crate) fn expand_runtime_add_pallet( } } }, - _ => (), } } diff --git a/crates/pop-common/src/rust_writer/expand/tests.rs b/crates/pop-common/src/rust_writer/expand/tests.rs index 514a5d61a..fcfe58f63 100644 --- a/crates/pop-common/src/rust_writer/expand/tests.rs +++ b/crates/pop-common/src/rust_writer/expand/tests.rs @@ -160,7 +160,6 @@ impl TestBuilder { _ => continue, } }, - _ => (), } assert!(assert_happened); } diff --git a/crates/pop-common/src/rust_writer/parse.rs b/crates/pop-common/src/rust_writer/parse.rs index 7021c509c..386fdfadf 100644 --- a/crates/pop-common/src/rust_writer/parse.rs +++ b/crates/pop-common/src/rust_writer/parse.rs @@ -1,36 +1,34 @@ // SPDX-License-Identifier: GPL-3.0 -use crate::rust_writer::types::RuntimeUsedMacro; +use crate::{rust_writer::types::RuntimeUsedMacro, Error}; use std::cmp; -use syn::{File, Item, ItemEnum, ItemMacro, ItemMod, ItemType, ItemUse, Macro, Meta, MetaList}; +use syn::{ + File, Item, ItemEnum, ItemMacro, ItemMod, ItemType, ItemUse, Macro, Meta, MetaList, Path, +}; + +#[cfg(test)] +mod tests; + +// Not more than 256 pallets are included in a runtime +type PalletIndex = u8; /// Find the highest implemented pallet index in the outer enum if using the macro -/// #[runtime]. We suppose it's a u8, it's not likely that a runtime implements more than 256 -/// pallets. Also determine if the runtime uses either #[runtime] or construct_runtime!, in -/// the latter we don't find the highest_index as specifying indexes isn't mandatory and -/// construct runtime will infer the pallet index. -pub(crate) fn find_highest_pallet_index_and_runtime_macro_version( - ast: &File, -) -> (u8, RuntimeUsedMacro) { - let mut highest_index = 0u8; - let mut used_macro = RuntimeUsedMacro::NotFound; +/// #[runtime]. +pub(crate) fn find_highest_pallet_index(ast: &File) -> Result { + let mut highest_index: PalletIndex = 0; + let mut found = false; for item in &ast.items { match item { - // If runtime is using the new macro #[runtime], the pallets are listed inside a - // module called runtime as types annotated with #[runtime::pallet_index(n)] where n - // is the pallet index. Item::Mod(ItemMod { ident, content, .. }) if *ident == "runtime" && content.is_some() => { - used_macro = RuntimeUsedMacro::Runtime; let (_, items) = content.as_ref().expect("content is always Some thanks to the match guard"); for item in items { if let Item::Type(ItemType { attrs, .. }) = item { if let Some(pallet_index_attribute) = attrs.iter().find(|attribute| { - if let Meta::List(MetaList { - path: syn::Path { segments, .. }, .. - }) = &attribute.meta + if let Meta::List(MetaList { path: Path { segments, .. }, .. }) = + &attribute.meta { segments.iter().any(|segment| segment.ident == "pallet_index") } else { @@ -44,25 +42,54 @@ pub(crate) fn find_highest_pallet_index_and_runtime_macro_version( if let Meta::List(MetaList { tokens, .. }) = &pallet_index_attribute.meta { - pallet_index = tokens.clone().into_iter().next().expect("This iterator has one element due to the attribute shape; qed;").to_string().parse::().expect("The macro #[runtime::pallet_index(n)] is only valid if n is a valid number, so we can parse it to u8; qed;"); + pallet_index = tokens.clone().into_iter().next().expect("This iterator has one element due to the attribute shape; qed;").to_string().parse::().expect("The macro #[runtime::pallet_index(n)] is only valid if n is a valid number, so we can parse it to PalletIndex; qed;"); } // Despite the pallets will likely be ordered by call_index in the - // runtime, that's not always true, so we keep the highest index in + // runtime, that's not necessarily true, so we keep the highest index in // order to give the added pallet the next index highest_index = cmp::max(highest_index, pallet_index); + found = true; } } } }, - // If runtime is using the construct_runtime! macro, keep track of it - Item::Macro(ItemMacro { - mac: Macro { path: syn::Path { segments, .. }, .. }, .. - }) if segments.iter().any(|segment| segment.ident == "construct_runtime") => - used_macro = RuntimeUsedMacro::ConstructRuntime, _ => continue, } } - (highest_index, used_macro) + + if !found { + return Err(Error::Descriptive( + format! {"Unable to find the highest pallet index in runtime file"}, + )) + } + Ok(highest_index) +} + +/// Determine whether a runtime's ast uses the construct_runtime! macro or the #[runtime] macro. +pub(crate) fn find_used_runtime_macro(ast: &File) -> Result { + for item in &ast.items { + match item { + Item::Mod(ItemMod { ident, attrs, .. }) + if *ident == "runtime" && + attrs.iter().any(|attribute| { + if let Meta::Path(Path { segments, .. }) = &attribute.meta { + segments.iter().any(|segment| segment.ident == "runtime") + } else { + false + } + }) => + { + return Ok(RuntimeUsedMacro::Runtime); + }, + Item::Macro(ItemMacro { mac: Macro { path: Path { segments, .. }, .. }, .. }) + if segments.iter().any(|segment| segment.ident == "construct_runtime") => + { + return Ok(RuntimeUsedMacro::ConstructRuntime); + }, + _ => (), + } + } + return Err(Error::Descriptive(format!("Unable to find a runtime declaration in runtime file"))); } pub(crate) fn find_use_statement(ast: &File, use_statement: &ItemUse) -> bool { diff --git a/crates/pop-common/src/rust_writer/parse/tests.rs b/crates/pop-common/src/rust_writer/parse/tests.rs index e69de29bb..f81223550 100644 --- a/crates/pop-common/src/rust_writer/parse/tests.rs +++ b/crates/pop-common/src/rust_writer/parse/tests.rs @@ -0,0 +1,93 @@ +// SPDX-License-Identifier: GPL-3.0 + +use super::*; +use crate::rust_writer::tests::test_builder::TestBuilder; +use syn::parse_quote; + +#[test] +fn find_highest_pallet_index_works_well() { + let mut test_builder = TestBuilder::default(); + + //find_highest_pallet_index should work with a runtime using the #[runtime] macro + test_builder.add_runtime_using_runtime_macro_ast(); + + let highest_index = find_highest_pallet_index(&test_builder.ast) + .expect("find_highest_pallet_index is supposed to be Ok"); + + // The highest index in the sample pallet is 11 + assert_eq!(highest_index, 11); +} + +#[test] +fn find_highest_pallet_index_fails_if_input_doesnt_use_runtime_macro() { + let mut test_builder = TestBuilder::default(); + + //Add a pallet file to the test_builder + test_builder.add_runtime_using_construct_runtime_macro_ast(); + + let failed_call = find_highest_pallet_index(&test_builder.ast); + + assert!(failed_call.is_err()); + if let Error::Descriptive(msg) = failed_call.unwrap_err() { + assert_eq!(msg, "Unable to find the highest pallet index in runtime file"); + } else { + panic!("find_highest_pallet_index should return only Error::Descriptive") + } +} + +#[test] +fn find_used_runtime_macro_with_construct_runtime_works_well() { + let mut test_builder = TestBuilder::default(); + + //Add the runtime with construct_runtime to the test_builder + test_builder.add_runtime_using_construct_runtime_macro_ast(); + + let used_macro = find_used_runtime_macro(&test_builder.ast) + .expect("find_used_runtime_macro is supposed to be Ok"); + + assert_eq!(used_macro, RuntimeUsedMacro::ConstructRuntime); +} + +#[test] +fn find_used_runtime_macro_with_runtime_macro_works_well() { + let mut test_builder = TestBuilder::default(); + + //Add the runtime with runtime to the test_builder + test_builder.add_runtime_using_runtime_macro_ast(); + + let used_macro = find_used_runtime_macro(&test_builder.ast) + .expect("find_used_runtime_macro is supposed to be Ok"); + + assert_eq!(used_macro, RuntimeUsedMacro::Runtime); +} + +#[test] +fn find_used_runtime_macro_fails_if_input_isnt_runtime_file() { + let mut test_builder = TestBuilder::default(); + + //Add a pallet file to the test_builder + test_builder.add_basic_pallet_ast(); + + let failed_call = find_used_runtime_macro(&test_builder.ast); + + assert!(failed_call.is_err()); + if let Error::Descriptive(msg) = failed_call.unwrap_err() { + assert_eq!(msg, "Unable to find a runtime declaration in runtime file"); + } else { + panic!("find_used_runtime_macro should return only Error::Descriptive") + } +} + +#[test] +fn find_use_statement_works_well() { + let mut test_builder = TestBuilder::default(); + + test_builder.add_basic_pallet_ast(); + + //Basic pallet has the use statement pub use pallet::*; + let valid_use_statement: ItemUse = parse_quote! {pub use pallet::*;}; + let invalid_use_statement: ItemUse = parse_quote! {use std::path::Path;}; + + assert!(find_use_statement(&test_builder.ast, &valid_use_statement)); + assert!(!find_use_statement(&test_builder.ast, &invalid_use_statement)); +} diff --git a/crates/pop-common/src/rust_writer/tests/test_builder.rs b/crates/pop-common/src/rust_writer/tests/test_builder.rs index ba939119d..cc256662e 100644 --- a/crates/pop-common/src/rust_writer/tests/test_builder.rs +++ b/crates/pop-common/src/rust_writer/tests/test_builder.rs @@ -2,7 +2,7 @@ use crate::rust_writer::helpers; use std::{fs, path::PathBuf}; -use syn::{File, parse_quote}; +use syn::{parse_quote, File}; pub(crate) struct TestBuilder { test_files: PathBuf, @@ -15,7 +15,7 @@ impl Default for TestBuilder { test_files: PathBuf::from(env!("CARGO_MANIFEST_DIR")) .join("src") .join("rust_writer") - .join("tests") + .join("tests") .join("sample_files"), ast: parse_quote! {}, } diff --git a/crates/pop-common/src/rust_writer/types.rs b/crates/pop-common/src/rust_writer/types.rs index d7f7473e9..2fb059d8f 100644 --- a/crates/pop-common/src/rust_writer/types.rs +++ b/crates/pop-common/src/rust_writer/types.rs @@ -13,7 +13,6 @@ pub enum DefaultConfigType { pub enum RuntimeUsedMacro { Runtime, ConstructRuntime, - NotFound, } #[derive(Debug, Clone, PartialEq)] From 343059f80148dae527f7fec69b02d88f1afedd5c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1s=20Senovilla=20Polo?= Date: Wed, 22 Jan 2025 18:45:33 +0100 Subject: [PATCH 24/46] correct find_composite_enum + finish rust_witer::parse tests --- crates/pop-common/src/rust_writer/parse.rs | 13 ++++++- .../pop-common/src/rust_writer/parse/tests.rs | 34 ++++++++++++++++++ .../tests/sample_files/basic_pallet.rs | 5 +++ .../basic_pallet_with_composite_enum.rs | 36 +++++++++++++++++++ .../src/rust_writer/tests/test_builder.rs | 1 + 5 files changed, 88 insertions(+), 1 deletion(-) create mode 100644 crates/pop-common/src/rust_writer/tests/sample_files/basic_pallet_with_composite_enum.rs diff --git a/crates/pop-common/src/rust_writer/parse.rs b/crates/pop-common/src/rust_writer/parse.rs index 386fdfadf..3e5bc73dc 100644 --- a/crates/pop-common/src/rust_writer/parse.rs +++ b/crates/pop-common/src/rust_writer/parse.rs @@ -112,7 +112,18 @@ pub(crate) fn find_composite_enum(ast: &File, composite_enum: &ItemEnum) -> bool content.as_ref().expect("content is always Some thanks to the match guard"); for item in items { match item { - Item::Enum(ItemEnum { ident, .. }) if *ident == composite_enum.ident => + Item::Enum(ItemEnum { ident, attrs, .. }) + if *ident == composite_enum.ident && + attrs.iter().any(|attribute| { + if let Meta::Path(Path { segments, .. }) = &attribute.meta { + // It's enough checking than composite_enum is in the path + segments + .iter() + .any(|segment| segment.ident == "composite_enum") + } else { + false + } + }) => return true, _ => continue, } diff --git a/crates/pop-common/src/rust_writer/parse/tests.rs b/crates/pop-common/src/rust_writer/parse/tests.rs index f81223550..b2f84fd3e 100644 --- a/crates/pop-common/src/rust_writer/parse/tests.rs +++ b/crates/pop-common/src/rust_writer/parse/tests.rs @@ -91,3 +91,37 @@ fn find_use_statement_works_well() { assert!(find_use_statement(&test_builder.ast, &valid_use_statement)); assert!(!find_use_statement(&test_builder.ast, &invalid_use_statement)); } + +#[test] +fn find_composite_enum_works_well() { + let mut test_builder = TestBuilder::default(); + + test_builder.add_basic_pallet_with_composite_enum_ast(); + + // This enum appears in the sample file basic_pallet_with_composite_enum + let composite_enum: ItemEnum = parse_quote! { + #[pallet::composite_enum] + pub enum SomeEnum { + #[codec(index = 0)] + Something, + } + }; + + // This enum doesn't appear in the sample file basic_pallet_with_composite_enum + let bad_composite_enum: ItemEnum = parse_quote! { + #[pallet::composite_enum] + pub enum OtherEnum{ + #[codec(index=0)] + Something, + } + }; + + assert!(find_composite_enum(&test_builder.ast, &composite_enum)); + assert!(!find_composite_enum(&test_builder.ast, &bad_composite_enum)); + + // basic pallet contains an enum called SomeEnum but it's not annotated as composite_enum + let mut test_builder = TestBuilder::default(); + + test_builder.add_basic_pallet_ast(); + assert!(!find_composite_enum(&test_builder.ast, &composite_enum)); +} diff --git a/crates/pop-common/src/rust_writer/tests/sample_files/basic_pallet.rs b/crates/pop-common/src/rust_writer/tests/sample_files/basic_pallet.rs index f8f698df0..89b01bbfe 100644 --- a/crates/pop-common/src/rust_writer/tests/sample_files/basic_pallet.rs +++ b/crates/pop-common/src/rust_writer/tests/sample_files/basic_pallet.rs @@ -19,6 +19,11 @@ mod benchmarking; pub mod pallet { use super::*; + pub enum SomeEnum { + #[codec(index = 0)] + Something, + } + #[pallet::pallet] pub struct Pallet(_); diff --git a/crates/pop-common/src/rust_writer/tests/sample_files/basic_pallet_with_composite_enum.rs b/crates/pop-common/src/rust_writer/tests/sample_files/basic_pallet_with_composite_enum.rs new file mode 100644 index 000000000..0e31e07d8 --- /dev/null +++ b/crates/pop-common/src/rust_writer/tests/sample_files/basic_pallet_with_composite_enum.rs @@ -0,0 +1,36 @@ +#![cfg_attr(not(feature = "std"), no_std)] + +use frame::prelude::*; + +use frame::traits::{fungible, VariantCount}; + +pub use pallet::*; + +#[cfg(test)] +mod mock; + +#[cfg(test)] +mod tests; + +#[cfg(feature = "runtime-benchmarks")] +mod benchmarking; + +#[frame::pallet] +pub mod pallet { + use super::*; + + #[pallet::composite_enum] + pub enum SomeEnum { + #[codec(index = 0)] + Something, + } + + #[pallet::pallet] + pub struct Pallet(_); + + #[pallet::config] + pub trait Config: frame_system::Config {} + + #[pallet::call] + impl Pallet {} +} diff --git a/crates/pop-common/src/rust_writer/tests/test_builder.rs b/crates/pop-common/src/rust_writer/tests/test_builder.rs index cc256662e..a50ad619d 100644 --- a/crates/pop-common/src/rust_writer/tests/test_builder.rs +++ b/crates/pop-common/src/rust_writer/tests/test_builder.rs @@ -40,6 +40,7 @@ impl TestBuilder { add_ast_to_builder! { [add_basic_pallet_ast, "basic_pallet.rs"], [add_basic_pallet_with_config_preludes_ast, "basic_pallet_with_config_preludes.rs"], + [add_basic_pallet_with_composite_enum_ast, "basic_pallet_with_composite_enum.rs"], [add_outer_config_preludes_ast, "outer_config_preludes.rs"], [add_runtime_using_runtime_macro_ast, "runtime_using_runtime_macro.rs"], [add_runtime_using_construct_runtime_macro_ast, "runtime_using_construct_runtime_macro.rs", "construct_runtime"] From 18e4fb008ed81090ac6943158957a86dfd01b42e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1s=20Senovilla=20Polo?= Date: Sun, 26 Jan 2025 18:58:36 +0100 Subject: [PATCH 25/46] New way of preserve code to improve performance and UX --- .../commands/add/config_type/common_types.rs | 1 + crates/pop-common/src/rust_writer.rs | 71 ++++++- crates/pop-common/src/rust_writer/expand.rs | 20 +- .../src/rust_writer/expand/tests.rs | 18 +- crates/pop-common/src/rust_writer/helpers.rs | 176 ++++++++---------- .../src/rust_writer/helpers/tests.rs | 3 + crates/pop-common/src/rust_writer/parse.rs | 9 +- crates/pop-common/src/rust_writer/types.rs | 56 +++++- 8 files changed, 222 insertions(+), 132 deletions(-) create mode 100644 crates/pop-common/src/rust_writer/helpers/tests.rs diff --git a/crates/pop-cli/src/commands/add/config_type/common_types.rs b/crates/pop-cli/src/commands/add/config_type/common_types.rs index 3863a138a..821006f38 100644 --- a/crates/pop-cli/src/commands/add/config_type/common_types.rs +++ b/crates/pop-cli/src/commands/add/config_type/common_types.rs @@ -119,6 +119,7 @@ impl CommonTypes { CommonTypes::RuntimeEvent => Vec::new(), CommonTypes::RuntimeOrigin => Vec::new(), CommonTypes::RuntimeHoldReason => vec![parse_quote! { + ///TEMP_DOC /// A reason for the pallet placing a hold on funds. #[pallet::composite_enum] pub enum HoldReason { diff --git a/crates/pop-common/src/rust_writer.rs b/crates/pop-common/src/rust_writer.rs index aab61520b..902200168 100644 --- a/crates/pop-common/src/rust_writer.rs +++ b/crates/pop-common/src/rust_writer.rs @@ -26,7 +26,10 @@ pub fn update_config_trait( trait_bounds: Vec, default_config: &types::DefaultConfigType, ) -> Result<(), Error> { - let mut ast = helpers::preserve_and_parse(fs::read_to_string(file_path)?, vec![])?; + let mut preserver = types::Preserver::new("pub mod pallet"); + preserver.add_inners(vec!["pub trait Config"]); + + let mut ast = helpers::preserve_and_parse(fs::read_to_string(file_path)?, vec![preserver])?; // Expand the config trait expand::expand_pallet_config_trait(&mut ast, default_config, type_name, trait_bounds); @@ -52,9 +55,10 @@ pub fn add_type_to_runtimes( type_name: Ident, runtime_value: Type, ) -> Result<(), Error> { - let mut ast = helpers::preserve_and_parse(file_content.to_string(), vec![])?; - let pallet_name = find_crate_name(pallet_manifest_path)?.replace("-", "_"); + let preserver = types::Preserver::new(&format!("impl {}::Config", pallet_name)); + + let mut ast = helpers::preserve_and_parse(file_content.to_string(), vec![preserver])?; expand::expand_runtime_add_type_to_impl_block( &mut ast, @@ -109,7 +113,51 @@ pub fn add_type_to_config_preludes( file_path: &Path, type_default_impl: ImplItem, ) -> Result<(), Error> { - let mut ast = helpers::preserve_and_parse(fs::read_to_string(file_path)?, vec![])?; + // Define preservers for the most common used struct names for default config. Both for + // independent module file and module contained inside pallet + let preserver_testchain_config = + types::Preserver::new("impl DefaultConfig for TestDefaultConfig"); + let mut preserver_testchain_config_inside_pallet_mod = types::Preserver::new("pub mod pallet"); + preserver_testchain_config_inside_pallet_mod + .add_inners(vec!["pub mod config_preludes", "impl DefaultConfig for TestDefaultConfig"]); + + let preserver_solochain_config = + types::Preserver::new("impl DefaultConfig for SolochainDefaultConfig"); + let mut preserver_solochain_config_inside_pallet_mod = types::Preserver::new("pub mod pallet"); + preserver_solochain_config_inside_pallet_mod.add_inners(vec![ + "pub mod config_preludes", + "impl DefaultConfig for SolochainDefaultConfig", + ]); + + let preserver_relaychain_config = + types::Preserver::new("impl DefaultConfig for RelayChainDefaultConfig"); + let mut preserver_relaychain_config_inside_pallet_mod = types::Preserver::new("pub mod pallet"); + preserver_relaychain_config_inside_pallet_mod.add_inners(vec![ + "pub mod config_preludes", + "impl DefaultConfig for RelayChainDefaultConfig", + ]); + + let preserver_parachain_config = + types::Preserver::new("impl DefaultConfig for ParaChainDefaultConfig"); + let mut preserver_parachain_config_inside_pallet_mod = types::Preserver::new("pub mod pallet"); + preserver_parachain_config_inside_pallet_mod.add_inners(vec![ + "pub mod config_preludes", + "impl DefaultConfig for ParaChainDefaultConfig", + ]); + + let mut ast = helpers::preserve_and_parse( + fs::read_to_string(file_path)?, + vec![ + preserver_testchain_config, + preserver_testchain_config_inside_pallet_mod, + preserver_solochain_config, + preserver_solochain_config_inside_pallet_mod, + preserver_relaychain_config, + preserver_relaychain_config_inside_pallet_mod, + preserver_parachain_config, + preserver_parachain_config_inside_pallet_mod, + ], + )?; // Expand the config_preludes expand::expand_pallet_config_preludes(&mut ast, type_default_impl); @@ -128,11 +176,11 @@ pub fn add_pallet_to_runtime_module( runtime_lib_path: &Path, pallet_dependencie_type: CrateDependencie, ) -> Result<(), Error> { - // As the runtime may be constructed with construc_runtime!, we have to avoid preserving that - // macro with comments + let preserver_construct_runtime = types::Preserver::new("construct_runtime!"); + let preserver_mod_runtime = types::Preserver::new("mod runtime"); let mut ast = helpers::preserve_and_parse( fs::read_to_string(runtime_lib_path)?, - vec!["construct_runtime"], + vec![preserver_construct_runtime, preserver_mod_runtime], )?; // Parse the runtime to find which of the runtime macros is being used and the highest @@ -194,6 +242,7 @@ pub fn add_pallet_impl_block_to_runtime( values: Vec, default_config: bool, ) -> Result<(), Error> { + // Nothing to preserve in this ast as this is a new impl block let mut ast = helpers::preserve_and_parse(fs::read_to_string(runtime_impl_path)?, vec![])?; let pallet_name_ident = Ident::new(&pallet_name.replace("-", "_"), Span::call_site()); // Expand the runtime to add the impl_block @@ -225,7 +274,9 @@ pub fn add_pallet_impl_block_to_runtime( } pub fn add_use_statements(file_path: &Path, use_statements: Vec) -> Result<(), Error> { - let mut ast = helpers::preserve_and_parse(fs::read_to_string(file_path)?, vec![])?; + // Preserve the first use statement to insert the new one where they're + let preserver = types::Preserver::new("use"); + let mut ast = helpers::preserve_and_parse(fs::read_to_string(file_path)?, vec![preserver])?; use_statements.into_iter().for_each(|use_statement| { if !parse::find_use_statement(&ast, &use_statement) { @@ -243,7 +294,9 @@ pub fn add_use_statements(file_path: &Path, use_statements: Vec) -> Res } pub fn add_composite_enums(file_path: &Path, composite_enums: Vec) -> Result<(), Error> { - let mut ast = helpers::preserve_and_parse(fs::read_to_string(file_path)?, vec![])?; + let mut preserver = types::Preserver::new("pub mod pallet"); + preserver.add_inners(vec!["pub struct Pallet"]); + let mut ast = helpers::preserve_and_parse(fs::read_to_string(file_path)?, vec![preserver])?; composite_enums.into_iter().for_each(|composite_enum| { if !parse::find_composite_enum(&ast, &composite_enum) { diff --git a/crates/pop-common/src/rust_writer/expand.rs b/crates/pop-common/src/rust_writer/expand.rs index dfc73a7b3..dfdb10fd8 100644 --- a/crates/pop-common/src/rust_writer/expand.rs +++ b/crates/pop-common/src/rust_writer/expand.rs @@ -4,7 +4,7 @@ mod tests; use crate::rust_writer::types::*; -use proc_macro2::{Group, Literal, Span, TokenStream, TokenTree}; +use proc_macro2::{Group, Literal, TokenStream, TokenTree}; use syn::{ parse_quote, Expr, File, Ident, ImplItem, Item, ItemEnum, ItemImpl, ItemMacro, ItemMod, ItemStruct, ItemTrait, ItemUse, Macro, Meta, MetaList, TraitBound, TraitItem, Type, @@ -29,17 +29,17 @@ pub(crate) fn expand_pallet_config_trait( items.push(match default_config { DefaultConfigType::Default { .. } => TraitItem::Type(parse_quote! { - ///EMPTY_LINE + ///TEMP_DOC type #type_name: #(#trait_bounds +)*; }), DefaultConfigType::NoDefault => TraitItem::Type(parse_quote! { - ///EMPTY_LINE + ///TEMP_DOC #[pallet::no_default] type #type_name: #(#trait_bounds +)*; }), DefaultConfigType::NoDefaultBounds { .. } => { TraitItem::Type(parse_quote! { - ///EMPTY_LINE + ///TEMP_DOC #[pallet::no_default_bounds] type #type_name: #(#trait_bounds +)*; }) @@ -193,7 +193,7 @@ pub(crate) fn expand_runtime_add_impl_block( let parameter_values: Vec<&Expr> = parameter_types.iter().map(|item| &item.value).collect(); items.push(Item::Macro(parse_quote! { - ///EMPTY_LINE + ///TEMP_DOC parameter_types!{ #( pub #parameter_idents: #parameter_types_types = #parameter_values; @@ -204,13 +204,13 @@ pub(crate) fn expand_runtime_add_impl_block( if default_config { items.push(Item::Impl(parse_quote! { - ///EMPTY_LINE + ///TEMP_DOC #[derive_impl(#pallet_name::config_preludes::TestDefaultConfig)] impl #pallet_name::Config for Runtime{} })); } else { items.push(Item::Impl(parse_quote! { - ///EMPTY_LINE + ///TEMP_DOC impl #pallet_name::Config for Runtime{} })); } @@ -242,7 +242,7 @@ pub(crate) fn expand_add_use_statement(ast: &mut File, use_statement: ItemUse) { // Find the first use statement let position = items.iter().position(|item| matches!(item, Item::Use(_))).unwrap_or(0); // Insert the use statement where needed - items.insert(position, Item::Use(use_statement)); + items.insert(position.saturating_add(1), Item::Use(use_statement)); } pub(crate) fn expand_pallet_add_composite_enum(ast: &mut File, composite_enum: ItemEnum) { @@ -260,8 +260,8 @@ pub(crate) fn expand_pallet_add_composite_enum(ast: &mut File, composite_enum: I |item| matches!(item, Item::Struct(ItemStruct { ident, .. }) if *ident == "Pallet"), ) .unwrap_or(0); - // Insert the composite_enum just before the Pallet struct - items.insert(position.saturating_sub(1), Item::Enum(composite_enum.clone())); + // Insert the composite_enum just after the Pallet struct + items.insert(position.saturating_add(1), Item::Enum(composite_enum.clone())); }, _ => continue, } diff --git a/crates/pop-common/src/rust_writer/expand/tests.rs b/crates/pop-common/src/rust_writer/expand/tests.rs index fcfe58f63..f42df57e9 100644 --- a/crates/pop-common/src/rust_writer/expand/tests.rs +++ b/crates/pop-common/src/rust_writer/expand/tests.rs @@ -181,7 +181,7 @@ impl TestBuilder { assert_eq!( self.ast.items.contains(&Item::Macro(parse_quote! { - ///EMPTY_LINE + ///TEMP_DOC parameter_types!{ #( pub #parameter_idents: #parameter_types_types = #parameter_values; @@ -195,7 +195,7 @@ impl TestBuilder { if using_default_config { assert_eq!( self.ast.items.contains(&Item::Impl(parse_quote! { - ///EMPTY_LINE + ///TEMP_DOC #[derive_impl(#pallet_name::config_preludes::TestDefaultConfig)] impl #pallet_name::Config for Runtime{} })), @@ -204,7 +204,7 @@ impl TestBuilder { } else { assert_eq!( self.ast.items.contains(&Item::Impl(parse_quote! { - ///EMPTY_LINE + ///TEMP_DOC impl #pallet_name::Config for Runtime{} })), contains @@ -300,7 +300,7 @@ fn expand_pallet_config_trait_works_well_test() { test_builder.assert_item_in_config_trait( false, TraitItem::Type(parse_quote! { - ///EMPTY_LINE + ///TEMP_DOC type MyDefaultType: Bound1 + From +; }), ); @@ -317,7 +317,7 @@ fn expand_pallet_config_trait_works_well_test() { test_builder.assert_item_in_config_trait( true, TraitItem::Type(parse_quote! { - ///EMPTY_LINE + ///TEMP_DOC type MyDefaultType: Bound1 + From +; }), ); @@ -325,7 +325,7 @@ fn expand_pallet_config_trait_works_well_test() { test_builder.assert_item_in_config_trait( false, TraitItem::Type(parse_quote! { - ///EMPTY_LINE + ///TEMP_DOC #[pallet::no_default] type MyNoDefaultType: Bound1 + From +; }), @@ -342,7 +342,7 @@ fn expand_pallet_config_trait_works_well_test() { test_builder.assert_item_in_config_trait( true, TraitItem::Type(parse_quote! { - ///EMPTY_LINE + ///TEMP_DOC #[pallet::no_default] type MyNoDefaultType: Bound1 + From +; }), @@ -351,7 +351,7 @@ fn expand_pallet_config_trait_works_well_test() { test_builder.assert_item_in_config_trait( false, TraitItem::Type(parse_quote! { - ///EMPTY_LINE + ///TEMP_DOC #[pallet::no_default_bounds] type MyNoDefaultBoundsType: Bound1 + From +; }), @@ -370,7 +370,7 @@ fn expand_pallet_config_trait_works_well_test() { test_builder.assert_item_in_config_trait( true, TraitItem::Type(parse_quote! { - ///EMPTY_LINE + ///TEMP_DOC #[pallet::no_default_bounds] type MyNoDefaultBoundsType: Bound1 + From +; }), diff --git a/crates/pop-common/src/rust_writer/helpers.rs b/crates/pop-common/src/rust_writer/helpers.rs index ca3c8ce16..3185472eb 100644 --- a/crates/pop-common/src/rust_writer/helpers.rs +++ b/crates/pop-common/src/rust_writer/helpers.rs @@ -1,128 +1,100 @@ -use crate::Error; +// SPDX-License-Identifier: GPL-3.0 + +use crate::{ + rust_writer::types::{DelimitersCount, Preserver}, + Error, +}; use regex::{Captures, Regex}; use syn::{parse_file, File}; -pub(crate) fn preserve_and_parse(code: String, exempt_macros: Vec<&str>) -> Result { - // First of all, preserve declarative macros except those that are exempted. As declarative - // macros invocations AST are basically a TokenStream, they don't keep format when unparsed and - // rustfmt doesn't work well at all inside all macro invocations, so it's better to keep them - // commented unless we explicitly need to modify them - let code = preserve_macro_invocations(code, exempt_macros); - let mut preserved_code = String::new(); - // Preserve the rest of the code - code.lines().for_each(|line| { - let trimmed_line = line.trim_start(); - if trimmed_line.starts_with("//") && - !trimmed_line.starts_with("///") && - !trimmed_line.starts_with("//!") - { - preserved_code - .push_str(&format!("///TEMP_DOC{}\ntype temp_marker = ();\n", trimmed_line)); - } else if trimmed_line.starts_with("#![") { - // Global attributes may be hard to parse with syn, so we comment them to solve - // potential issues related to them. - preserved_code - .push_str(&format!("///TEMP_DOC{}\ntype temp_marker = ();\n", trimmed_line)); - } else if trimmed_line.is_empty() { - preserved_code.push_str("///EMPTY_LINE\ntype temp_marker = ();\n"); - } else { - preserved_code.push_str(&format!("{}\n", trimmed_line)); - } - }); +#[cfg(test)] +mod tests; + +pub(crate) fn preserve_and_parse(code: String, preservers: Vec) -> Result { + let preserved_code = apply_preservers(code, preservers); Ok(parse_file(&preserved_code)?) } pub(crate) fn resolve_preserved(code: String) -> String { - let mut output = String::new(); // Inside non-preserved declarative macros invocations, everything is a token so the doc // comments became #[doc] in order to preserve them (tokens doesn't accept doc comments). - // ///EMPTY_LINE comments became #[doc = "EMPTY_LINE"] which are 4 tokens in the AST. When the + // ///TEMP_DOC comments became #[doc = "TEMP_DOC"] which are 4 tokens in the AST. When the // AST is converted to a String, new line characters can appear in the middle of any of those // tokens, so to properly convert them in a new line we can use regex. - let mut re = - Regex::new(r#"#\s*\[\s*doc\s*=\s*"EMPTY_LINE"\s*\]"#).expect("The regex is valid; qed;"); - let code = re.replace_all(&code, "\n").to_string(); - // Same happens with 'type temp_marker = ();'. This lines also delete them from everywhere, not - // just inside declarative macros - re = Regex::new(r"type\s+temp_marker\s*=\s*\(\);\s*").expect("The regex is valid; qed;"); - let code = re.replace_all(&code, "\n").to_string(); - // Same happens with #[doc= "TEMP_DOC whatever"] but we also need to keep track of "whatever". // As the #[doc] attribute may be present anywhere, be sure to keep spaces before and after the // comment to don't leave commented some lines of code. - re = Regex::new(r#"#\s*\[\s*doc\s*=\s*"TEMP_DOC(.*?)"\s*\]"#).expect("The regex is valid;qed;"); + let re = + Regex::new(r#"#\s*\[\s*doc\s*=\s*"TEMP_DOC(.*?)"\s*\]"#).expect("The regex is valid;qed;"); let code = re.replace_all(&code, |caps: &Captures| format!("\n{}\n", &caps[1])).to_string(); + // Delete all TEMP_DOCS and temp_marker present in the code and return the result. + code.replace("///TEMP_DOC", "").replace("type temp_marker = ();", "") +} - // Resolve the comments outside declarative macros. - code.lines().for_each(|line| { - let trimmed_line = line.trim_start(); +fn apply_preservers(code: String, mut preservers: Vec) -> String { + let mut delimiters_counts = DelimitersCount::new(); - match trimmed_line { - comment if trimmed_line.strip_prefix("///TEMP_DOC").is_some() => output.push_str( - comment - .strip_prefix("///TEMP_DOC") - .expect("The match guard guarantees this is always some; qed;"), - ), - comment if trimmed_line.strip_prefix("///TEMP_MACRO").is_some() => - output.push_str(&format!( - "{}\n", - comment - .strip_prefix("///TEMP_MACRO") - .expect("The match guard guarantees this is always some; qed;"), - )), - _ if trimmed_line.strip_prefix("///EMPTY_LINE").is_some() => output.push('\n'), - _ => output.push_str(&format!("{}\n", line)), - } - }); - output -} + let mut lines = code.lines(); -fn preserve_macro_invocations(code: String, exempt_macros: Vec<&str>) -> String { - let re = - Regex::new(r"(?P[a-zA-Z_]+)!\s*[\{\(\[]").expect("The regex is valid; qed;"); - let mut result = String::new(); + // Non-preserved lines are pushed to the Vec together with a new line character, so the bound + // #lines * 2 is an upper bound of the final capacity + let mut result: Vec = Vec::with_capacity(code.lines().count() * 2); + + while let Some(line) = lines.next() { + let trimmed_line = line.trim_start(); + if let Some(index) = preservers + .iter_mut() + .position(|preserver| trimmed_line.starts_with(preserver.lookup())) + { + delimiters_counts.count(line); + result.push(line.to_owned()); + result.push("\n".to_owned()); - let mut macro_block = String::new(); + let mut preserver = preservers.swap_remove(index); + let inner_preserver = preserver.take_inner(); - let mut delimiter_counts = [('{', 0), ('}', 0), ('(', 0), (')', 0), ('[', 0), (']', 0)]; + if let Some(inner_preserver_pointer) = inner_preserver { + let mut inner_code = String::new(); + while let Some(line) = lines.next() { + delimiters_counts.count(line); - for line in code.lines() { - match re.find(line) { - Some(found) - if exempt_macros.contains( - &&re.captures(found.as_str()).expect( - "As found has been found with the regex, it captures the macro_name; qed;", - )["macro_name"], - ) => - result.push_str(&format!("{}\n", line)), - Some(_) => { - macro_block.push_str(&format!("{}\n", line)); - for (char, count) in delimiter_counts.iter_mut() { - if line.contains(*char) { - *count += line.matches(*char).count(); + if delimiters_counts.is_complete() { + result.push(apply_preservers(inner_code, vec![*inner_preserver_pointer])); + result.push(line.to_owned()); + result.push("\n".to_owned()); + break; + } else { + inner_code.push_str(line); + inner_code.push_str("\n"); } } - }, - None if macro_block.is_empty() => result.push_str(&format!("{}\n", line)), - _ => { - macro_block.push_str(&format!("{}\n", line)); - for (char, count) in delimiter_counts.iter_mut() { - if line.contains(*char) { - *count += line.matches(*char).count(); - } + } + } else { + if delimiters_counts.is_complete() { + result.push(format!("///TEMP_DOC{}\n", line)); + } else { + if (trimmed_line.starts_with("//") && + !trimmed_line.starts_with("///") && + !trimmed_line.starts_with("//!")) || + trimmed_line.starts_with("#![") + { + // Preserve comments and global attributes. + // Global attributes may be hard to parse with syn, so we comment them to solve + // potential issues related to them. + result.push(format!("///TEMP_DOC{}\ntype temp_marker = ();", line)); + } else if line.is_empty() { + // Preserve empty lines inside a non-preserved block + result.push("///TEMP_DOC\ntype temp_marker = ();".to_owned()); + } else { + result.push(line.to_owned()); + result.push("\n".to_owned()); } - }, - } - if delimiter_counts[0].1 == delimiter_counts[1].1 && - delimiter_counts[2].1 == delimiter_counts[3].1 && - delimiter_counts[4].1 == delimiter_counts[5].1 && - !macro_block.is_empty() - { - macro_block.lines().for_each(|line| { - result.push_str(&format!("///TEMP_MACRO{}\n", line)); - }); - result.push_str("type temp_marker = ();\n"); - macro_block = String::new(); + + delimiters_counts.count(line); + } } } - result + + result.push("type temp_marker = ();".to_owned()); + + result.join("") } diff --git a/crates/pop-common/src/rust_writer/helpers/tests.rs b/crates/pop-common/src/rust_writer/helpers/tests.rs new file mode 100644 index 000000000..1e5d375f1 --- /dev/null +++ b/crates/pop-common/src/rust_writer/helpers/tests.rs @@ -0,0 +1,3 @@ +// SPDX-License-Identifier: GPL-3.0 + +use super::*; diff --git a/crates/pop-common/src/rust_writer/parse.rs b/crates/pop-common/src/rust_writer/parse.rs index 3e5bc73dc..c940a9ff8 100644 --- a/crates/pop-common/src/rust_writer/parse.rs +++ b/crates/pop-common/src/rust_writer/parse.rs @@ -42,7 +42,14 @@ pub(crate) fn find_highest_pallet_index(ast: &File) -> Result().expect("The macro #[runtime::pallet_index(n)] is only valid if n is a valid number, so we can parse it to PalletIndex; qed;"); + pallet_index = tokens + .clone() + .into_iter() + .next() + .expect("This iterator has one element due to the attribute shape; qed;") + .to_string() + .parse::() + .expect("The macro #[runtime::pallet_index(n)] is only valid if n is a valid number, so we can parse it to PalletIndex; qed;"); } // Despite the pallets will likely be ordered by call_index in the // runtime, that's not necessarily true, so we keep the highest index in diff --git a/crates/pop-common/src/rust_writer/types.rs b/crates/pop-common/src/rust_writer/types.rs index 2fb059d8f..122b9d23a 100644 --- a/crates/pop-common/src/rust_writer/types.rs +++ b/crates/pop-common/src/rust_writer/types.rs @@ -10,7 +10,7 @@ pub enum DefaultConfigType { } #[derive(Debug, Clone, PartialEq)] -pub enum RuntimeUsedMacro { +pub(crate) enum RuntimeUsedMacro { Runtime, ConstructRuntime, } @@ -21,3 +21,57 @@ pub struct ParameterTypes { pub type_: Type, pub value: Expr, } + +#[derive(Debug, Clone, PartialEq)] +pub(crate) struct Preserver { + lookup: String, + inner: Option>, +} + +impl Preserver { + pub(crate) fn new(lookup: &str) -> Self { + Self { lookup: lookup.to_owned(), inner: None } + } + + pub(crate) fn add_inners(&mut self, lookups: Vec<&str>) { + let mut current = self; + for lookup in lookups { + current.inner = Some(Box::new(Self::new(lookup))); + current = current.inner.as_mut().expect("Inner is Some due to the previous line; qed"); + } + } + + pub(crate) fn lookup(&self) -> &str { + &self.lookup + } + + pub(crate) fn take_inner(&mut self) -> Option> { + self.inner.take() + } +} + +#[derive(Debug, Clone, PartialEq)] +pub(crate) struct DelimitersCount { + counts: [u8; 6], +} + +impl DelimitersCount { + pub(crate) fn new() -> Self { + Self { counts: [0; 6] } + } + + pub(crate) fn is_complete(&self) -> bool { + self.counts[0] == self.counts[1] && // `{` and `}` + self.counts[2] == self.counts[3] && // `(` and `)` + self.counts[4] == self.counts[5] // `[` and `]` + } + + pub(crate) fn count(&mut self, line: &str) { + self.counts[0] += line.matches('{').count() as u8; + self.counts[1] += line.matches('}').count() as u8; + self.counts[2] += line.matches('(').count() as u8; + self.counts[3] += line.matches(')').count() as u8; + self.counts[4] += line.matches('[').count() as u8; + self.counts[5] += line.matches(']').count() as u8; + } +} From 4647bdd84b7897c051c689479cea8516f5806533 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1s=20Senovilla=20Polo?= Date: Sun, 26 Jan 2025 19:25:28 +0100 Subject: [PATCH 26/46] Fix preserver bug --- crates/pop-common/src/rust_writer/expand.rs | 6 +++--- crates/pop-common/src/rust_writer/helpers.rs | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/crates/pop-common/src/rust_writer/expand.rs b/crates/pop-common/src/rust_writer/expand.rs index dfdb10fd8..35978a594 100644 --- a/crates/pop-common/src/rust_writer/expand.rs +++ b/crates/pop-common/src/rust_writer/expand.rs @@ -33,9 +33,9 @@ pub(crate) fn expand_pallet_config_trait( type #type_name: #(#trait_bounds +)*; }), DefaultConfigType::NoDefault => TraitItem::Type(parse_quote! { - ///TEMP_DOC - #[pallet::no_default] - type #type_name: #(#trait_bounds +)*; + ///TEMP_DOC + #[pallet::no_default] + type #type_name: #(#trait_bounds +)*; }), DefaultConfigType::NoDefaultBounds { .. } => { TraitItem::Type(parse_quote! { diff --git a/crates/pop-common/src/rust_writer/helpers.rs b/crates/pop-common/src/rust_writer/helpers.rs index 3185472eb..4e13bc76f 100644 --- a/crates/pop-common/src/rust_writer/helpers.rs +++ b/crates/pop-common/src/rust_writer/helpers.rs @@ -81,7 +81,7 @@ fn apply_preservers(code: String, mut preservers: Vec) -> String { // Global attributes may be hard to parse with syn, so we comment them to solve // potential issues related to them. result.push(format!("///TEMP_DOC{}\ntype temp_marker = ();", line)); - } else if line.is_empty() { + } else if trimmed_line.is_empty() { // Preserve empty lines inside a non-preserved block result.push("///TEMP_DOC\ntype temp_marker = ();".to_owned()); } else { From 3b1c0036c8ee1c74407f286b1603926cd917e88a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1s=20Senovilla=20Polo?= Date: Tue, 28 Jan 2025 19:56:47 +0100 Subject: [PATCH 27/46] Improve commands to get a better UX --- crates/pop-cli/src/commands/add/mod.rs | 29 +++++++++++++------ .../{config_type.rs => pallet_config_type.rs} | 0 .../common_types.rs | 0 .../add/{pallet.rs => runtime_pallet.rs} | 0 .../common_pallets.rs | 0 crates/pop-cli/src/commands/mod.rs | 14 ++++++--- crates/pop-common/src/lib.rs | 12 ++++++-- crates/pop-common/src/manifest.rs | 2 +- 8 files changed, 40 insertions(+), 17 deletions(-) rename crates/pop-cli/src/commands/add/{config_type.rs => pallet_config_type.rs} (100%) rename crates/pop-cli/src/commands/add/{config_type => pallet_config_type}/common_types.rs (100%) rename crates/pop-cli/src/commands/add/{pallet.rs => runtime_pallet.rs} (100%) rename crates/pop-cli/src/commands/add/{pallet => runtime_pallet}/common_pallets.rs (100%) diff --git a/crates/pop-cli/src/commands/add/mod.rs b/crates/pop-cli/src/commands/add/mod.rs index 849026ec0..e2c4bbaf5 100644 --- a/crates/pop-cli/src/commands/add/mod.rs +++ b/crates/pop-cli/src/commands/add/mod.rs @@ -2,8 +2,8 @@ use clap::{Args, Subcommand}; -pub mod config_type; -pub mod pallet; +pub mod pallet_config_type; +pub mod runtime_pallet; /// Arguments for adding a new feature to existing code #[derive(Args)] @@ -14,12 +14,23 @@ pub struct AddArgs { } #[derive(Subcommand)] -pub enum Command { +pub enum Command{ + /// Expand your runtime using Pop-Cli +#[command(subcommand)] + Runtime(RuntimeCommand), + /// Expand a pallet using Pop-Cli + #[command(subcommand)] + Pallet(PalletCommand) +} + +#[derive(Subcommand)] +pub enum RuntimeCommand { + /// Add pallets to an existing runtime + Pallet(runtime_pallet::AddPalletCommand), +} + +#[derive(Subcommand)] +pub enum PalletCommand { /// Add a new config type to an existing pallet - #[cfg(feature = "parachain")] - #[clap(alias = "C")] - ConfigType(config_type::AddConfigTypeCommand), - /// Add a new pallet to an existing runtime - #[clap(alias = "P")] - Pallet(pallet::AddPalletCommand), + ConfigType(pallet_config_type::AddConfigTypeCommand), } diff --git a/crates/pop-cli/src/commands/add/config_type.rs b/crates/pop-cli/src/commands/add/pallet_config_type.rs similarity index 100% rename from crates/pop-cli/src/commands/add/config_type.rs rename to crates/pop-cli/src/commands/add/pallet_config_type.rs diff --git a/crates/pop-cli/src/commands/add/config_type/common_types.rs b/crates/pop-cli/src/commands/add/pallet_config_type/common_types.rs similarity index 100% rename from crates/pop-cli/src/commands/add/config_type/common_types.rs rename to crates/pop-cli/src/commands/add/pallet_config_type/common_types.rs diff --git a/crates/pop-cli/src/commands/add/pallet.rs b/crates/pop-cli/src/commands/add/runtime_pallet.rs similarity index 100% rename from crates/pop-cli/src/commands/add/pallet.rs rename to crates/pop-cli/src/commands/add/runtime_pallet.rs diff --git a/crates/pop-cli/src/commands/add/pallet/common_pallets.rs b/crates/pop-cli/src/commands/add/runtime_pallet/common_pallets.rs similarity index 100% rename from crates/pop-cli/src/commands/add/pallet/common_pallets.rs rename to crates/pop-cli/src/commands/add/runtime_pallet/common_pallets.rs diff --git a/crates/pop-cli/src/commands/mod.rs b/crates/pop-cli/src/commands/mod.rs index cbaaf683a..0fcf4fb85 100644 --- a/crates/pop-cli/src/commands/mod.rs +++ b/crates/pop-cli/src/commands/mod.rs @@ -42,8 +42,8 @@ pub(crate) enum Command { /// Remove generated/cached artifacts. #[clap(alias = "C")] Clean(clean::CleanArgs), - /// Add a feature to existing Rust code - #[clap(alias = "a")] + /// Add a new feature to your existing polkadot-sdk project + #[clap(name = "add-to", alias = "a")] Add(add::AddArgs), } @@ -126,8 +126,14 @@ impl Command { }, }, Self::Add(args) => match args.command { - add::Command::ConfigType(cmd) => cmd.execute().await.map(|_| json!("default")), - add::Command::Pallet(cmd) => cmd.execute().await.map(|_| json!("default")), + add::Command::Runtime(runtime_command) => match runtime_command { + add::RuntimeCommand::Pallet(cmd) => + cmd.execute().await.map(|_| json!("default")), + }, + add::Command::Pallet(pallet_command) => match pallet_command { + add::PalletCommand::ConfigType(cmd) => + cmd.execute().await.map(|_| json!("default")), + }, }, } } diff --git a/crates/pop-common/src/lib.rs b/crates/pop-common/src/lib.rs index d1b86bd76..7e2a62d1d 100644 --- a/crates/pop-common/src/lib.rs +++ b/crates/pop-common/src/lib.rs @@ -5,8 +5,14 @@ use std::net::TcpListener; pub use build::Profile; pub use errors::Error; pub use git::{Git, GitHub, Release}; -pub use helpers::{capitalize_str, get_project_name_from_path, prefix_with_current_dir_if_needed, replace_in_file, format_dir}; -pub use manifest::{add_crate_to_workspace, find_workspace_toml, find_pallet_runtime_impl_path, find_pallet_runtime_lib_path, find_crate_name}; +pub use helpers::{ + capitalize_str, format_dir, get_project_name_from_path, prefix_with_current_dir_if_needed, + replace_in_file, +}; +pub use manifest::{ + add_crate_to_workspace, find_crate_name, find_pallet_runtime_impl_path, + find_pallet_runtime_lib_path, find_workspace_toml, +}; pub use metadata::format_type; pub use signer::create_signer; pub use sourcing::set_executable_permission; @@ -19,10 +25,10 @@ pub mod errors; pub mod git; pub mod helpers; pub mod manifest; -pub mod rust_writer; /// Provides functionality for formatting and resolving metadata types. pub mod metadata; pub mod polkadot_sdk; +pub mod rust_writer; /// Provides functionality for creating a signer from a secret URI. pub mod signer; pub mod sourcing; diff --git a/crates/pop-common/src/manifest.rs b/crates/pop-common/src/manifest.rs index 656f7e6cd..c6597ed81 100644 --- a/crates/pop-common/src/manifest.rs +++ b/crates/pop-common/src/manifest.rs @@ -3,7 +3,7 @@ pub mod types; use crate::Error; use anyhow; -pub use cargo_toml::{Dependency, Manifest, LtoSetting, Profile, Profiles}; +pub use cargo_toml::{Dependency, LtoSetting, Manifest, Profile, Profiles}; use pathdiff::diff_paths; use std::{ fs::{read_to_string, write}, From 7bcbce7de5211ab69ac0deeb4267ac907f261245 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1s=20Senovilla=20Polo?= Date: Thu, 30 Jan 2025 19:49:02 +0100 Subject: [PATCH 28/46] rust writer helpers became rust writer preserver; solve a small bug with unpreserve function affecting declarative macros --- crates/pop-cli/src/commands/add/mod.rs | 14 ++++----- crates/pop-common/src/rust_writer.rs | 30 +++++++++---------- .../rust_writer/{helpers.rs => preserver.rs} | 8 +++-- .../{helpers => preserver}/tests.rs | 0 4 files changed, 28 insertions(+), 24 deletions(-) rename crates/pop-common/src/rust_writer/{helpers.rs => preserver.rs} (89%) rename crates/pop-common/src/rust_writer/{helpers => preserver}/tests.rs (100%) diff --git a/crates/pop-cli/src/commands/add/mod.rs b/crates/pop-cli/src/commands/add/mod.rs index e2c4bbaf5..adf15aa3b 100644 --- a/crates/pop-cli/src/commands/add/mod.rs +++ b/crates/pop-cli/src/commands/add/mod.rs @@ -14,13 +14,13 @@ pub struct AddArgs { } #[derive(Subcommand)] -pub enum Command{ - /// Expand your runtime using Pop-Cli -#[command(subcommand)] - Runtime(RuntimeCommand), - /// Expand a pallet using Pop-Cli - #[command(subcommand)] - Pallet(PalletCommand) +pub enum Command { + /// Expand your runtime using Pop-Cli + #[command(subcommand)] + Runtime(RuntimeCommand), + /// Expand a pallet using Pop-Cli + #[command(subcommand)] + Pallet(PalletCommand), } #[derive(Subcommand)] diff --git a/crates/pop-common/src/rust_writer.rs b/crates/pop-common/src/rust_writer.rs index 902200168..566d62aae 100644 --- a/crates/pop-common/src/rust_writer.rs +++ b/crates/pop-common/src/rust_writer.rs @@ -14,8 +14,8 @@ use std::{fs, path::Path}; use syn::{parse_str, Ident, ImplItem, ItemEnum, ItemUse, TraitBound, Type}; mod expand; -mod helpers; mod parse; +mod preserver; #[cfg(test)] mod tests; pub mod types; @@ -29,11 +29,11 @@ pub fn update_config_trait( let mut preserver = types::Preserver::new("pub mod pallet"); preserver.add_inners(vec!["pub trait Config"]); - let mut ast = helpers::preserve_and_parse(fs::read_to_string(file_path)?, vec![preserver])?; + let mut ast = preserver::preserve_and_parse(fs::read_to_string(file_path)?, vec![preserver])?; // Expand the config trait expand::expand_pallet_config_trait(&mut ast, default_config, type_name, trait_bounds); - let generated_code = helpers::resolve_preserved(unparse(&ast)); + let generated_code = preserver::resolve_preserved(unparse(&ast)); fs::write(file_path, &generated_code).map_err(|_| { Error::WriteError(format!("Path :{}", file_path.to_str().unwrap_or("Invalid UTF-8 path"))) @@ -58,7 +58,7 @@ pub fn add_type_to_runtimes( let pallet_name = find_crate_name(pallet_manifest_path)?.replace("-", "_"); let preserver = types::Preserver::new(&format!("impl {}::Config", pallet_name)); - let mut ast = helpers::preserve_and_parse(file_content.to_string(), vec![preserver])?; + let mut ast = preserver::preserve_and_parse(file_content.to_string(), vec![preserver])?; expand::expand_runtime_add_type_to_impl_block( &mut ast, @@ -67,7 +67,7 @@ pub fn add_type_to_runtimes( &pallet_name, ); - let generated_code = helpers::resolve_preserved(unparse(&ast)); + let generated_code = preserver::resolve_preserved(unparse(&ast)); fs::write(file_path, generated_code).map_err(|_| { Error::WriteError(format!( @@ -145,7 +145,7 @@ pub fn add_type_to_config_preludes( "impl DefaultConfig for ParaChainDefaultConfig", ]); - let mut ast = helpers::preserve_and_parse( + let mut ast = preserver::preserve_and_parse( fs::read_to_string(file_path)?, vec![ preserver_testchain_config, @@ -162,7 +162,7 @@ pub fn add_type_to_config_preludes( // Expand the config_preludes expand::expand_pallet_config_preludes(&mut ast, type_default_impl); - let generated_code = helpers::resolve_preserved(unparse(&ast)); + let generated_code = preserver::resolve_preserved(unparse(&ast)); fs::write(file_path, generated_code).map_err(|_| { Error::WriteError(format!("Path :{}", file_path.to_str().unwrap_or("Invalid UTF-8 path"))) @@ -178,7 +178,7 @@ pub fn add_pallet_to_runtime_module( ) -> Result<(), Error> { let preserver_construct_runtime = types::Preserver::new("construct_runtime!"); let preserver_mod_runtime = types::Preserver::new("mod runtime"); - let mut ast = helpers::preserve_and_parse( + let mut ast = preserver::preserve_and_parse( fs::read_to_string(runtime_lib_path)?, vec![preserver_construct_runtime, preserver_mod_runtime], )?; @@ -216,7 +216,7 @@ pub fn add_pallet_to_runtime_module( pallet_item, ); - let generated_code = helpers::resolve_preserved(unparse(&ast)); + let generated_code = preserver::resolve_preserved(unparse(&ast)); fs::write(runtime_lib_path, generated_code).map_err(|_| { Error::WriteError(format!( @@ -243,7 +243,7 @@ pub fn add_pallet_impl_block_to_runtime( default_config: bool, ) -> Result<(), Error> { // Nothing to preserve in this ast as this is a new impl block - let mut ast = helpers::preserve_and_parse(fs::read_to_string(runtime_impl_path)?, vec![])?; + let mut ast = preserver::preserve_and_parse(fs::read_to_string(runtime_impl_path)?, vec![])?; let pallet_name_ident = Ident::new(&pallet_name.replace("-", "_"), Span::call_site()); // Expand the runtime to add the impl_block expand::expand_runtime_add_impl_block( @@ -262,7 +262,7 @@ pub fn add_pallet_impl_block_to_runtime( ) }); - let generated_code = helpers::resolve_preserved(unparse(&ast)); + let generated_code = preserver::resolve_preserved(unparse(&ast)); fs::write(runtime_impl_path, generated_code).map_err(|_| { Error::WriteError(format!( @@ -276,7 +276,7 @@ pub fn add_pallet_impl_block_to_runtime( pub fn add_use_statements(file_path: &Path, use_statements: Vec) -> Result<(), Error> { // Preserve the first use statement to insert the new one where they're let preserver = types::Preserver::new("use"); - let mut ast = helpers::preserve_and_parse(fs::read_to_string(file_path)?, vec![preserver])?; + let mut ast = preserver::preserve_and_parse(fs::read_to_string(file_path)?, vec![preserver])?; use_statements.into_iter().for_each(|use_statement| { if !parse::find_use_statement(&ast, &use_statement) { @@ -284,7 +284,7 @@ pub fn add_use_statements(file_path: &Path, use_statements: Vec) -> Res } }); - let generated_code = helpers::resolve_preserved(unparse(&ast)); + let generated_code = preserver::resolve_preserved(unparse(&ast)); fs::write(file_path, &generated_code).map_err(|_| { Error::WriteError(format!("Path :{}", file_path.to_str().unwrap_or("Invalid UTF-8 path"))) @@ -296,7 +296,7 @@ pub fn add_use_statements(file_path: &Path, use_statements: Vec) -> Res pub fn add_composite_enums(file_path: &Path, composite_enums: Vec) -> Result<(), Error> { let mut preserver = types::Preserver::new("pub mod pallet"); preserver.add_inners(vec!["pub struct Pallet"]); - let mut ast = helpers::preserve_and_parse(fs::read_to_string(file_path)?, vec![preserver])?; + let mut ast = preserver::preserve_and_parse(fs::read_to_string(file_path)?, vec![preserver])?; composite_enums.into_iter().for_each(|composite_enum| { if !parse::find_composite_enum(&ast, &composite_enum) { @@ -304,7 +304,7 @@ pub fn add_composite_enums(file_path: &Path, composite_enums: Vec) -> } }); - let generated_code = helpers::resolve_preserved(unparse(&ast)); + let generated_code = preserver::resolve_preserved(unparse(&ast)); fs::write(file_path, &generated_code).map_err(|_| { Error::WriteError(format!("Path :{}", file_path.to_str().unwrap_or("Invalid UTF-8 path"))) diff --git a/crates/pop-common/src/rust_writer/helpers.rs b/crates/pop-common/src/rust_writer/preserver.rs similarity index 89% rename from crates/pop-common/src/rust_writer/helpers.rs rename to crates/pop-common/src/rust_writer/preserver.rs index 4e13bc76f..e3321e62c 100644 --- a/crates/pop-common/src/rust_writer/helpers.rs +++ b/crates/pop-common/src/rust_writer/preserver.rs @@ -26,8 +26,12 @@ pub(crate) fn resolve_preserved(code: String) -> String { let re = Regex::new(r#"#\s*\[\s*doc\s*=\s*"TEMP_DOC(.*?)"\s*\]"#).expect("The regex is valid;qed;"); let code = re.replace_all(&code, |caps: &Captures| format!("\n{}\n", &caps[1])).to_string(); - // Delete all TEMP_DOCS and temp_marker present in the code and return the result. - code.replace("///TEMP_DOC", "").replace("type temp_marker = ();", "") + // Same happens with 'type temp_marker = ();'. This lines also delete them from everywhere, not + // just inside declarative macros + let re = Regex::new(r"type\s+temp_marker\s*=\s*\(\);\s*").expect("The regex is valid; qed;"); + let code = re.replace_all(&code, "\n").to_string(); + // Delete all TEMP_DOCS present in the rest of the code and return the result. + code.replace("///TEMP_DOC", "") } fn apply_preservers(code: String, mut preservers: Vec) -> String { diff --git a/crates/pop-common/src/rust_writer/helpers/tests.rs b/crates/pop-common/src/rust_writer/preserver/tests.rs similarity index 100% rename from crates/pop-common/src/rust_writer/helpers/tests.rs rename to crates/pop-common/src/rust_writer/preserver/tests.rs From 740b35172abce8843167301d03de984a447791ce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1s=20Senovilla=20Polo?= Date: Fri, 31 Jan 2025 18:14:45 +0100 Subject: [PATCH 29/46] Improving error message --- crates/pop-common/src/errors.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/pop-common/src/errors.rs b/crates/pop-common/src/errors.rs index 384ffde72..dad42ec8b 100644 --- a/crates/pop-common/src/errors.rs +++ b/crates/pop-common/src/errors.rs @@ -31,7 +31,7 @@ pub enum Error { ParseSecretURI(String), #[error("SourceError error: {0}")] SourceError(#[from] sourcing::Error), - #[error("Syn parse error: {0}. To preserve your not-docs comments, blank lines and declarative macro invocations, Pop-CLi temporarily transform them to comments followed by a marker type associated to that doc. This error is likely originated cause one of your files has such an element in a place where that marker type cannot be placed. Example: the type marker cannot be defined inside a match block\nmatch option{{\n\t//This is the painful comment\n\tSome(some)=>(),\n\tNone=>()\n}}")] + #[error("Syn parse error: {0}. Pop CLI has to parse your code in order to expand it. To preserve its structure while parsing, some temporal type markers may be added in the target part of your code. If declaring a type in that part of the code is invalid Rust code, that may be the origin of this error. Please review the code you're modifying to solve this. Example: If you're modifying an Enum likee the following one, it'll fail as types cannot be defined inside enums\npub enum Enum{{\n\t//This is the painful comment\n\tA,\n\tB\n}}")] SynError(#[from] syn::Error), #[error("TemplateError error: {0}")] TemplateError(#[from] templates::Error), From 147e4f08b9d4f3baf86b348bdb352dd6c71b92ab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1s=20Senovilla=20Polo?= Date: Sat, 1 Feb 2025 20:50:34 +0100 Subject: [PATCH 30/46] Finishing pop add-to runtime pallet command; concurrent execution + dynamically computed pallet path --- .../src/commands/add/runtime_pallet.rs | 124 +++++++++++++----- .../add/runtime_pallet/common_pallets.rs | 13 +- crates/pop-cli/src/commands/new/pallet.rs | 19 ++- crates/pop-common/src/lib.rs | 4 +- crates/pop-common/src/manifest.rs | 61 +++++++-- crates/pop-common/src/rust_writer.rs | 36 +++-- crates/pop-common/src/rust_writer/expand.rs | 8 ++ .../src/rust_writer/expand/tests.rs | 38 +++++- .../src/rust_writer/tests/test_builder.rs | 17 ++- 9 files changed, 239 insertions(+), 81 deletions(-) diff --git a/crates/pop-cli/src/commands/add/runtime_pallet.rs b/crates/pop-cli/src/commands/add/runtime_pallet.rs index 7e80a27c7..5a88eddd7 100644 --- a/crates/pop-cli/src/commands/add/runtime_pallet.rs +++ b/crates/pop-cli/src/commands/add/runtime_pallet.rs @@ -7,34 +7,39 @@ use crate::{ use clap::{error::ErrorKind, Args, Command}; use cliclack::multiselect; use pop_common::{ - find_pallet_runtime_impl_path, find_workspace_toml, format_dir, - manifest::types::CrateDependencie, prefix_with_current_dir_if_needed, rust_writer, + find_workspace_toml, format_dir, get_pallet_impl_path, manifest, + prefix_with_current_dir_if_needed, rust_writer, }; -use std::{env::current_dir, path::PathBuf}; +use std::{env, path::PathBuf}; use strum::{EnumMessage, IntoEnumIterator}; mod common_pallets; #[derive(Args, Debug, Clone)] pub struct AddPalletCommand { - #[arg(short, long, help = "Specify the path to the runtime crate.")] - pub(crate) runtime_path: Option, #[arg(short, long, value_enum, num_args(1..), required = false, help = "The pallets you want to include to your runtime.")] pub(crate) pallets: Vec, + #[arg(short, long, help = "Specify the path to the runtime crate.")] + pub(crate) runtime_path: Option, #[arg( long, - help = "Pop-Cli will place the impl blocks for your pallets' Config traits inside configs/mod.rs or lib.rs in the runtime crate by default. If you want to place them in another path, use this option to specify it." + help = "Pop-Cli will place the impl blocks for your pallets' Config traits inside a dedicated file under configs directory. Use this argument to point to another path." )] - pub(crate) runtime_impl_path: Option, + pub(crate) pallet_impl_path: Option, } impl AddPalletCommand { pub(crate) async fn execute(self) -> anyhow::Result<()> { Cli.intro("Add a new pallet to your runtime")?; + let mut cmd = Command::new(""); + let runtime_path = if let Some(path) = &self.runtime_path { prefix_with_current_dir_if_needed(path.to_path_buf()) } else { - let working_dir = current_dir().expect("Cannot modify your working directory"); + let working_dir = match env::current_dir() { + Ok(working_dir) => working_dir, + _ => cmd.error(ErrorKind::Io, "Cannot modify the working crate").exit(), + }; // Give the chance to use the command either from a workspace containing a runtime or // from a runtime crate if path not specified if working_dir.join("runtime").exists() { @@ -43,7 +48,7 @@ impl AddPalletCommand { prefix_with_current_dir_if_needed(working_dir) } }; - let mut cmd = Command::new(""); + let src = runtime_path.join("src"); let lib_path = src.join("lib.rs"); if !lib_path.is_file() { @@ -54,17 +59,6 @@ impl AddPalletCommand { .exit(); } - let runtime_impl_path = - match self.runtime_impl_path.or_else(|| find_pallet_runtime_impl_path(&lib_path)) { - Some(runtime_impl_path) => runtime_impl_path, - None => cmd - .error( - ErrorKind::InvalidValue, - "Make sure that the used path correspond to a runtime crate.", - ) - .exit(), - }; - let spinner = cliclack::spinner(); spinner.start("Updating runtime..."); @@ -77,22 +71,81 @@ impl AddPalletCommand { self.pallets }; + let mut handles = Vec::new(); + // Mutex over the memory shared across threads + let mutex_cmd = std::sync::Arc::new(std::sync::Mutex::new(cmd)); + let mutex_pallet_impl_path = + std::sync::Arc::new(std::sync::Mutex::new(self.pallet_impl_path)); + let mutex_lib_path = std::sync::Arc::new(std::sync::Mutex::new(lib_path)); + let mutex_runtime_path = std::sync::Arc::new(std::sync::Mutex::new(runtime_path.clone())); + for pallet in pallets { - // Add the pallet to the crate and to the runtime module - rust_writer::add_pallet_to_runtime_module( - &pallet.get_crate_name(), - &lib_path, - CrateDependencie::External { version: pallet.get_version() }, - )?; - // Add the pallet impl block - rust_writer::add_pallet_impl_block_to_runtime( - &pallet.get_crate_name(), - &runtime_impl_path, - pallet.get_parameter_types(), - pallet.get_config_types(), - pallet.get_config_values(), - pallet.get_default_config(), - )?; + let mutex_cmd = std::sync::Arc::clone(&mutex_cmd); + let mutex_pallet_impl_path = std::sync::Arc::clone(&mutex_pallet_impl_path); + let mutex_lib_path = std::sync::Arc::clone(&mutex_lib_path); + let mutex_runtime_path = std::sync::Arc::clone(&mutex_runtime_path); + + handles.push(std::thread::spawn(move || -> Result<(), anyhow::Error> { + let mut cmd = mutex_cmd.lock().map_err(|e| anyhow::Error::msg(format!("{}", e)))?; + let pallet_impl_path = mutex_pallet_impl_path + .lock() + .map_err(|e| anyhow::Error::msg(format!("{}", e)))?; + let lib_path = + mutex_lib_path.lock().map_err(|e| anyhow::Error::msg(format!("{}", e)))?; + let runtime_path = + mutex_runtime_path.lock().map_err(|e| anyhow::Error::msg(format!("{}", e)))?; + + let mut pallet_computed_path: Option = None; + + let pallet_impl_path = match pallet_impl_path.as_ref().or_else(|| { + pallet_computed_path = get_pallet_impl_path( + &runtime_path, + &pallet + .get_crate_name() + .splitn(2, '-') + .nth(1) + .unwrap_or("pallet") + .to_string(), + ); + pallet_computed_path.as_ref() + }) { + Some(impl_path) => impl_path, + None => cmd + .error( + ErrorKind::InvalidValue, + "Make sure that the used path correspond to a runtime crate.", + ) + .exit(), + }; + + // Add the pallet to the crate and to the runtime module + rust_writer::add_pallet_to_runtime_module( + &pallet.get_crate_name(), + &lib_path, + manifest::types::CrateDependencie::External { version: pallet.get_version() }, + )?; + + // Add the pallet impl block and its related use statements + rust_writer::add_use_statements( + &pallet_impl_path, + pallet.get_impl_needed_use_statements(), + )?; + + rust_writer::add_pallet_impl_block_to_runtime( + &pallet.get_crate_name(), + &pallet_impl_path, + pallet.get_parameter_types(), + pallet.get_config_types(), + pallet.get_config_values(), + pallet.get_default_config(), + )?; + + Ok(()) + })); + } + + for handle in handles { + let _ = handle.join().expect("Unexpected error"); } if let Some(mut workspace_toml) = find_workspace_toml(&runtime_path) { @@ -101,6 +154,7 @@ impl AddPalletCommand { } else { format_dir(&runtime_path)?; } + spinner.stop("Your runtime has been updated and it's ready to use 🚀"); Ok(()) } diff --git a/crates/pop-cli/src/commands/add/runtime_pallet/common_pallets.rs b/crates/pop-cli/src/commands/add/runtime_pallet/common_pallets.rs index 4d3e54b68..b0d68c8bf 100644 --- a/crates/pop-cli/src/commands/add/runtime_pallet/common_pallets.rs +++ b/crates/pop-cli/src/commands/add/runtime_pallet/common_pallets.rs @@ -3,7 +3,7 @@ use clap::ValueEnum; use pop_common::rust_writer::types::ParameterTypes; use proc_macro2::Span; use strum_macros::{EnumIter, EnumMessage}; -use syn::{parse_quote, Ident, Type}; +use syn::{parse_quote, Ident, ItemUse, Type}; #[derive(Debug, Copy, Clone, PartialEq, EnumIter, EnumMessage, ValueEnum)] pub enum CommonPallets { @@ -41,6 +41,17 @@ impl CommonPallets { } } + pub fn get_impl_needed_use_statements(&self) -> Vec { + match self { + CommonPallets::Balances => vec![parse_quote!( + use crate::System; + )], + CommonPallets::Contracts => vec![parse_quote!( + use crate::Balances; + )], + } + } + pub fn get_config_types(&self) -> Vec { match self { CommonPallets::Balances => vec![Ident::new("AccountStore", Span::call_site())], diff --git a/crates/pop-cli/src/commands/new/pallet.rs b/crates/pop-cli/src/commands/new/pallet.rs index 164838030..aa4c9a35e 100644 --- a/crates/pop-cli/src/commands/new/pallet.rs +++ b/crates/pop-cli/src/commands/new/pallet.rs @@ -8,9 +8,9 @@ use crate::{ use clap::{Args, Subcommand}; use cliclack::{confirm, input, multiselect, outro, outro_cancel}; use pop_common::{ - add_crate_to_workspace, find_crate_name, find_pallet_runtime_impl_path, - find_pallet_runtime_lib_path, find_workspace_toml, format_dir, - manifest::types::CrateDependencie, prefix_with_current_dir_if_needed, rust_writer, + add_crate_to_workspace, find_crate_name, find_pallet_runtime_lib_path, find_workspace_toml, + format_dir, get_pallet_impl_path, manifest::types::CrateDependencie, + prefix_with_current_dir_if_needed, rust_writer, }; use pop_parachains::{ create_pallet_template, TemplatePalletConfig, TemplatePalletConfigCommonTypes, @@ -193,19 +193,24 @@ impl NewPalletCommand { pallet_custom_origin, }, )?; - let pallet_name = find_crate_name(&pallet_path.join("Cargo.toml"))?; + let pallet_crate_name = find_crate_name(&pallet_path.join("Cargo.toml"))?; spinner.set_message("Adding the pallet to your runtime if needed..."); // Check if the pallet has to be included in a runtime and include it if so if let (Some(runtime_lib_path), Some(runtime_impl_path)) = ( find_pallet_runtime_lib_path(&pallet_path), - self.runtime_impl_path.or_else(|| find_pallet_runtime_impl_path(&pallet_path)), + self.runtime_impl_path.or_else(|| { + get_pallet_impl_path( + &pallet_path, + &pallet_crate_name.splitn(2, '-').nth(1).unwrap_or("pallet").to_string(), + ) + }), ) { // If the pallet has been created inside a workspace containing a runtime, add the // pallet to that runtime. rust_writer::add_pallet_to_runtime_module( - &pallet_name, + &pallet_crate_name, &runtime_lib_path, CrateDependencie::Local { local_crate_path: pallet_path.to_path_buf() }, )?; @@ -226,7 +231,7 @@ impl NewPalletCommand { }; rust_writer::add_pallet_impl_block_to_runtime( - &pallet_name, + &pallet_crate_name, &runtime_impl_path, Vec::new(), types, diff --git a/crates/pop-common/src/lib.rs b/crates/pop-common/src/lib.rs index 7e2a62d1d..47ade7caf 100644 --- a/crates/pop-common/src/lib.rs +++ b/crates/pop-common/src/lib.rs @@ -10,8 +10,8 @@ pub use helpers::{ replace_in_file, }; pub use manifest::{ - add_crate_to_workspace, find_crate_name, find_pallet_runtime_impl_path, - find_pallet_runtime_lib_path, find_workspace_toml, + add_crate_to_workspace, find_crate_name, find_pallet_runtime_lib_path, find_workspace_toml, + get_pallet_impl_path, }; pub use metadata::format_type; pub use signer::create_signer; diff --git a/crates/pop-common/src/manifest.rs b/crates/pop-common/src/manifest.rs index c6597ed81..f9193782b 100644 --- a/crates/pop-common/src/manifest.rs +++ b/crates/pop-common/src/manifest.rs @@ -1,14 +1,16 @@ // SPDX-License-Identifier: GPL-3.0 pub mod types; -use crate::Error; +use crate::{rust_writer, Error}; use anyhow; pub use cargo_toml::{Dependency, LtoSetting, Manifest, Profile, Profiles}; use pathdiff::diff_paths; use std::{ fs::{read_to_string, write}, + io::Write, path::{Path, PathBuf}, }; +use syn::parse_quote; use toml_edit::{value, Array, DocumentMut, InlineTable, Item, Table, Value}; /// Parses the contents of a `Cargo.toml` manifest. @@ -223,22 +225,61 @@ pub fn find_pallet_runtime_lib_path(pallet_path: &Path) -> Option { } } -pub fn find_pallet_runtime_impl_path(path: &Path) -> Option { - if let Some(mut workspace_toml) = find_workspace_toml(path) { +pub fn get_pallet_impl_path(runtime_path: &Path, pallet_name: &str) -> Option { + if let Some(mut workspace_toml) = find_workspace_toml(runtime_path) { match Manifest::from_path(&workspace_toml) .ok() .map(|manifest| manifest.workspace.map(|workspace| workspace.members)) { Some(Some(members)) if members.contains(&"runtime".to_string()) => { - // Support for both cases: impl inside runtime lib.rs or defined inside - // configs/mod.rs + // Create the pallet config impl file workspace_toml.pop(); let runtime_src_path = workspace_toml.join("runtime").join("src"); - let config_mod_path = runtime_src_path.join("configs").join("mod.rs"); - if config_mod_path.is_file() { - Some(config_mod_path) - } else { - Some(runtime_src_path.join("lib.rs")) + let runtime_lib_path = runtime_src_path.join("lib.rs"); + let configs_rs_path = runtime_src_path.join("configs.rs"); + let configs_folder_path = runtime_src_path.join("configs"); + let configs_mod_path = configs_folder_path.join("mod.rs"); + let pallet_config_file = configs_folder_path.join(format!("{}.rs", pallet_name)); + match (configs_rs_path.exists(), configs_mod_path.exists()) { + // The runtime is using a configs module without the mod.rs sintax + (true, false) => { + let mut write_configs_rs = + std::fs::OpenOptions::new().append(true).open(configs_rs_path).ok()?; + writeln!(write_configs_rs, "{}", format!("mod {};", pallet_name)).ok()?; + std::fs::File::create(&pallet_config_file).ok()?; + Some(pallet_config_file) + }, + // The runtime is using a configs module with the mod.rs syntax + (false, true) => { + let mut write_configs_mod = + std::fs::OpenOptions::new().append(true).open(configs_mod_path).ok()?; + writeln!(write_configs_mod, "{}", format!("mod {};", pallet_name)).ok()?; + std::fs::File::create(&pallet_config_file).ok()?; + Some(pallet_config_file) + }, + // The runtime isn't using a configs module yet, we opt for the configs.rs + // convention + (false, false) => { + let mut write_configs_rs = std::fs::OpenOptions::new() + .create(true) + .write(true) + .open(configs_rs_path) + .ok()?; + writeln!(write_configs_rs, "{}", format!("mod {};", pallet_name)).ok()?; + std::fs::create_dir(configs_folder_path).ok()?; + std::fs::File::create(&pallet_config_file).ok()?; + rust_writer::add_mod_declarations( + &runtime_lib_path, + vec![parse_quote!( + pub mod configs; + )], + ) + .ok()?; + Some(pallet_config_file) + }, + // Both approaches at the sime time aren't supported by the compiler, so this is + // unreachable in a compiling project + (true, true) => unreachable!(), } }, _ => None, diff --git a/crates/pop-common/src/rust_writer.rs b/crates/pop-common/src/rust_writer.rs index 566d62aae..6109432b3 100644 --- a/crates/pop-common/src/rust_writer.rs +++ b/crates/pop-common/src/rust_writer.rs @@ -3,15 +3,14 @@ use crate::{ capitalize_str, manifest::{ - add_crate_to_dependencies, find_crate_manifest, find_crate_name, - find_pallet_runtime_impl_path, types::CrateDependencie, + add_crate_to_dependencies, find_crate_manifest, find_crate_name, types::CrateDependencie, }, Error, }; use prettyplease::unparse; use proc_macro2::Span; use std::{fs, path::Path}; -use syn::{parse_str, Ident, ImplItem, ItemEnum, ItemUse, TraitBound, Type}; +use syn::{parse_str, Ident, ImplItem, ItemEnum, ItemMod, ItemUse, TraitBound, Type}; mod expand; mod parse; @@ -93,10 +92,7 @@ pub fn add_type_to_runtimes( )?; // If the pallet is contained inside a runtime add the type to that runtime as well - if let Some(runtime_impl_path) = runtime_impl_path - .map(|inner| inner.to_path_buf()) - .or_else(|| find_pallet_runtime_impl_path(pallet_path)) - { + if let Some(runtime_impl_path) = runtime_impl_path.map(|inner| inner.to_path_buf()) { let runtime_impl_content = fs::read_to_string(&runtime_impl_path)?; do_add_type_to_runtime( &runtime_impl_content, @@ -236,14 +232,14 @@ pub fn add_pallet_to_runtime_module( pub fn add_pallet_impl_block_to_runtime( pallet_name: &str, - runtime_impl_path: &Path, + pallet_impl_path: &Path, parameter_types: Vec, types: Vec, values: Vec, default_config: bool, ) -> Result<(), Error> { // Nothing to preserve in this ast as this is a new impl block - let mut ast = preserver::preserve_and_parse(fs::read_to_string(runtime_impl_path)?, vec![])?; + let mut ast = preserver::preserve_and_parse(fs::read_to_string(pallet_impl_path)?, vec![])?; let pallet_name_ident = Ident::new(&pallet_name.replace("-", "_"), Span::call_site()); // Expand the runtime to add the impl_block expand::expand_runtime_add_impl_block( @@ -264,10 +260,10 @@ pub fn add_pallet_impl_block_to_runtime( let generated_code = preserver::resolve_preserved(unparse(&ast)); - fs::write(runtime_impl_path, generated_code).map_err(|_| { + fs::write(pallet_impl_path, generated_code).map_err(|_| { Error::WriteError(format!( "Path :{}", - runtime_impl_path.to_str().unwrap_or("Invalid UTF-8 path") + pallet_impl_path.to_str().unwrap_or("Invalid UTF-8 path") )) })?; Ok(()) @@ -293,6 +289,24 @@ pub fn add_use_statements(file_path: &Path, use_statements: Vec) -> Res Ok(()) } +pub fn add_mod_declarations(file_path: &Path, mod_declarations: Vec) -> Result<(), Error> { + // Preserve the first mod declaration to insert the new one where they're + let preserver = types::Preserver::new("mod"); + let mut ast = preserver::preserve_and_parse(fs::read_to_string(file_path)?, vec![preserver])?; + + mod_declarations + .into_iter() + .for_each(|mod_declaration| expand::expand_add_mod(&mut ast, mod_declaration)); + + let generated_code = preserver::resolve_preserved(unparse(&ast)); + + fs::write(file_path, &generated_code).map_err(|_| { + Error::WriteError(format!("Path :{}", file_path.to_str().unwrap_or("Invalid UTF-8 path"))) + })?; + + Ok(()) +} + pub fn add_composite_enums(file_path: &Path, composite_enums: Vec) -> Result<(), Error> { let mut preserver = types::Preserver::new("pub mod pallet"); preserver.add_inners(vec!["pub struct Pallet"]); diff --git a/crates/pop-common/src/rust_writer/expand.rs b/crates/pop-common/src/rust_writer/expand.rs index 35978a594..45ef7f054 100644 --- a/crates/pop-common/src/rust_writer/expand.rs +++ b/crates/pop-common/src/rust_writer/expand.rs @@ -245,6 +245,14 @@ pub(crate) fn expand_add_use_statement(ast: &mut File, use_statement: ItemUse) { items.insert(position.saturating_add(1), Item::Use(use_statement)); } +pub(crate) fn expand_add_mod(ast: &mut File, mod_: ItemMod) { + let items = &mut ast.items; + // Find the first mod + let position = items.iter().position(|item| matches!(item, Item::Mod(_))).unwrap_or(0); + // Insert the mod where needed + items.insert(position.saturating_add(1), Item::Mod(mod_)); +} + pub(crate) fn expand_pallet_add_composite_enum(ast: &mut File, composite_enum: ItemEnum) { for item in &mut ast.items { match item { diff --git a/crates/pop-common/src/rust_writer/expand/tests.rs b/crates/pop-common/src/rust_writer/expand/tests.rs index f42df57e9..97ee319b1 100644 --- a/crates/pop-common/src/rust_writer/expand/tests.rs +++ b/crates/pop-common/src/rust_writer/expand/tests.rs @@ -2,6 +2,7 @@ use super::*; use crate::rust_writer::tests::test_builder::TestBuilder; +use proc_macro2::Span; use syn::parse_str; impl TestBuilder { @@ -246,13 +247,25 @@ impl TestBuilder { let position = self.ast.items.iter().position(|item| matches!(item, Item::Use(_))).unwrap_or(0); // The use statement has been added together with other use statements - if let Some(item) = self.ast.items.get(position) { + if let Some(item) = self.ast.items.get(position.saturating_add(1)) { assert_eq!(item == &Item::Use(use_statement), contains); } else { assert!(false); } } + fn assert_mod_included(&self, contains: bool, mod_: ItemMod) { + // Find the first mod declaration + let position = + self.ast.items.iter().position(|item| matches!(item, Item::Mod(_))).unwrap_or(0); + // The mod has been added together with other mod declarations + if let Some(item) = self.ast.items.get(position.saturating_add(1)) { + assert_eq!(item == &Item::Mod(mod_), contains); + } else { + assert!(false); + } + } + fn assert_composite_enum_in_pallet(&self, contains: bool, composite_enum: ItemEnum) { let mut assert_happened = false; for item in &self.ast.items { @@ -269,11 +282,8 @@ impl TestBuilder { |item| matches!(item, Item::Struct(ItemStruct { ident, .. }) if *ident == "Pallet"), ) .unwrap_or(0); - // The composite enum has been added just before the Pallet struct (if prior - // insertion pallet is in position n, now it's in position n+1, as the item - // is included in position n-1, we have to check in n+1 - (n-1) = 2 - // positions before the actual position of pallet) - if let Some(item) = items.get(position.saturating_sub(2)) { + // The composite enum has been added just after the Pallet struct + if let Some(item) = items.get(position.saturating_add(1)) { assert_eq!(item == &Item::Enum(composite_enum.clone()), contains); assert_happened = true; } @@ -666,6 +676,22 @@ fn expand_add_use_statement_works_well_test() { test_builder.assert_use_statement_included(true, use_statement); } +#[test] +fn expand_add_mod_works_well_test() { + let mut test_builder = TestBuilder::default(); + test_builder.add_basic_pallet_ast(); + + let mod_: ItemMod = parse_quote! { + mod some_mod; + }; + + test_builder.assert_mod_included(false, mod_.clone()); + + expand_add_mod(&mut test_builder.ast, mod_.clone()); + + test_builder.assert_mod_included(true, mod_); +} + #[test] fn expand_pallet_add_composite_enum_works_well_test() { let mut test_builder = TestBuilder::default(); diff --git a/crates/pop-common/src/rust_writer/tests/test_builder.rs b/crates/pop-common/src/rust_writer/tests/test_builder.rs index a50ad619d..fb7576190 100644 --- a/crates/pop-common/src/rust_writer/tests/test_builder.rs +++ b/crates/pop-common/src/rust_writer/tests/test_builder.rs @@ -1,8 +1,7 @@ // SPDX-License-Identifier: GPL-3.0 -use crate::rust_writer::helpers; use std::{fs, path::PathBuf}; -use syn::{parse_quote, File}; +use syn::{parse_file, parse_quote, File}; pub(crate) struct TestBuilder { test_files: PathBuf, @@ -22,14 +21,14 @@ impl Default for TestBuilder { } } -macro_rules! add_ast_to_builder{ - ($([$name: ident, $file: literal $(, $macro_excluded: literal)?]),*) => { +macro_rules! add_ast_to_builder_no_preserve{ + ($([$name: ident, $file: literal]),*) => { $( pub(crate) fn $name(&mut self){ - self.ast = helpers::preserve_and_parse( - fs::read_to_string(self.test_files.join($file)) + self.ast = parse_file( + &fs::read_to_string(self.test_files.join($file)) .expect(concat!{"Error reading file in ", stringify!($name)}), - vec![$($macro_excluded)?]) + ) .expect(concat!{"Error parsing file in ", stringify!($name)}); } )* @@ -37,12 +36,12 @@ macro_rules! add_ast_to_builder{ } impl TestBuilder { - add_ast_to_builder! { + add_ast_to_builder_no_preserve! { [add_basic_pallet_ast, "basic_pallet.rs"], [add_basic_pallet_with_config_preludes_ast, "basic_pallet_with_config_preludes.rs"], [add_basic_pallet_with_composite_enum_ast, "basic_pallet_with_composite_enum.rs"], [add_outer_config_preludes_ast, "outer_config_preludes.rs"], [add_runtime_using_runtime_macro_ast, "runtime_using_runtime_macro.rs"], - [add_runtime_using_construct_runtime_macro_ast, "runtime_using_construct_runtime_macro.rs", "construct_runtime"] + [add_runtime_using_construct_runtime_macro_ast, "runtime_using_construct_runtime_macro.rs"] } } From 86c6c3f7c0b3b8c21513b16d5109704e0ab7e12d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1s=20Senovilla=20Polo?= Date: Sun, 2 Feb 2025 12:53:56 +0100 Subject: [PATCH 31/46] Small fixes --- .../src/commands/add/runtime_pallet.rs | 57 ++++---- crates/pop-cli/src/commands/new/pallet.rs | 28 ++-- crates/pop-common/src/manifest.rs | 122 +++++++++--------- 3 files changed, 100 insertions(+), 107 deletions(-) diff --git a/crates/pop-cli/src/commands/add/runtime_pallet.rs b/crates/pop-cli/src/commands/add/runtime_pallet.rs index 5a88eddd7..d929ef0bb 100644 --- a/crates/pop-cli/src/commands/add/runtime_pallet.rs +++ b/crates/pop-cli/src/commands/add/runtime_pallet.rs @@ -7,10 +7,13 @@ use crate::{ use clap::{error::ErrorKind, Args, Command}; use cliclack::multiselect; use pop_common::{ - find_workspace_toml, format_dir, get_pallet_impl_path, manifest, - prefix_with_current_dir_if_needed, rust_writer, + find_workspace_toml, format_dir, manifest, prefix_with_current_dir_if_needed, rust_writer, +}; +use std::{ + env, + path::PathBuf, + sync::{Arc, Mutex}, }; -use std::{env, path::PathBuf}; use strum::{EnumMessage, IntoEnumIterator}; mod common_pallets; @@ -49,9 +52,7 @@ impl AddPalletCommand { } }; - let src = runtime_path.join("src"); - let lib_path = src.join("lib.rs"); - if !lib_path.is_file() { + if !manifest::is_runtime_crate(&runtime_path) { cmd.error( ErrorKind::InvalidValue, "Make sure to run this command either in a workspace containing a runtime crate/a runtime crate or to specify the path to the runtime crate using -r.", @@ -73,32 +74,24 @@ impl AddPalletCommand { let mut handles = Vec::new(); // Mutex over the memory shared across threads - let mutex_cmd = std::sync::Arc::new(std::sync::Mutex::new(cmd)); - let mutex_pallet_impl_path = - std::sync::Arc::new(std::sync::Mutex::new(self.pallet_impl_path)); - let mutex_lib_path = std::sync::Arc::new(std::sync::Mutex::new(lib_path)); - let mutex_runtime_path = std::sync::Arc::new(std::sync::Mutex::new(runtime_path.clone())); + let mutex_pallet_impl_path = Arc::new(Mutex::new(self.pallet_impl_path)); + let mutex_runtime_path = Arc::new(Mutex::new(runtime_path.clone())); for pallet in pallets { - let mutex_cmd = std::sync::Arc::clone(&mutex_cmd); - let mutex_pallet_impl_path = std::sync::Arc::clone(&mutex_pallet_impl_path); - let mutex_lib_path = std::sync::Arc::clone(&mutex_lib_path); - let mutex_runtime_path = std::sync::Arc::clone(&mutex_runtime_path); - + let mutex_pallet_impl_path = Arc::clone(&mutex_pallet_impl_path); + let mutex_runtime_path = Arc::clone(&mutex_runtime_path); handles.push(std::thread::spawn(move || -> Result<(), anyhow::Error> { - let mut cmd = mutex_cmd.lock().map_err(|e| anyhow::Error::msg(format!("{}", e)))?; let pallet_impl_path = mutex_pallet_impl_path .lock() .map_err(|e| anyhow::Error::msg(format!("{}", e)))?; - let lib_path = - mutex_lib_path.lock().map_err(|e| anyhow::Error::msg(format!("{}", e)))?; let runtime_path = mutex_runtime_path.lock().map_err(|e| anyhow::Error::msg(format!("{}", e)))?; - let mut pallet_computed_path: Option = None; - - let pallet_impl_path = match pallet_impl_path.as_ref().or_else(|| { - pallet_computed_path = get_pallet_impl_path( + let runtime_lib_path = runtime_path.join("src").join("lib.rs"); + let pallet_impl_path = if pallet_impl_path.is_some() { + pallet_impl_path.clone().expect("The if statement ensures this is Some;qed;") + } else { + manifest::get_pallet_impl_path( &runtime_path, &pallet .get_crate_name() @@ -106,22 +99,13 @@ impl AddPalletCommand { .nth(1) .unwrap_or("pallet") .to_string(), - ); - pallet_computed_path.as_ref() - }) { - Some(impl_path) => impl_path, - None => cmd - .error( - ErrorKind::InvalidValue, - "Make sure that the used path correspond to a runtime crate.", - ) - .exit(), + )? }; // Add the pallet to the crate and to the runtime module rust_writer::add_pallet_to_runtime_module( &pallet.get_crate_name(), - &lib_path, + &runtime_lib_path, manifest::types::CrateDependencie::External { version: pallet.get_version() }, )?; @@ -145,7 +129,10 @@ impl AddPalletCommand { } for handle in handles { - let _ = handle.join().expect("Unexpected error"); + let result = handle.join().expect("Unexpected error"); + if result.is_err(){ + return result; + } } if let Some(mut workspace_toml) = find_workspace_toml(&runtime_path) { diff --git a/crates/pop-cli/src/commands/new/pallet.rs b/crates/pop-cli/src/commands/new/pallet.rs index aa4c9a35e..bf7e44aad 100644 --- a/crates/pop-cli/src/commands/new/pallet.rs +++ b/crates/pop-cli/src/commands/new/pallet.rs @@ -55,9 +55,9 @@ pub struct NewPalletCommand { pub(crate) description: Option, #[arg( long, - help = "If your pallet is created in a workspace containing a runtime, Pop-Cli will try to add the impl block for your pallet's Config trait inside configs/mod.rs or lib.rs in the runtime crate by default. If you need to use another path, use this option to specify it." + help = "If your pallet is created in a workspace containing a runtime, Pop-Cli will place the impl blocks for your pallets' Config traits inside a dedicated file under configs directory. Use this argument to point to another path." )] - pub(crate) runtime_impl_path: Option, + pub(crate) pallet_impl_path: Option, #[command(subcommand)] pub(crate) mode: Option, } @@ -195,25 +195,27 @@ impl NewPalletCommand { )?; let pallet_crate_name = find_crate_name(&pallet_path.join("Cargo.toml"))?; - spinner.set_message("Adding the pallet to your runtime if needed..."); // Check if the pallet has to be included in a runtime and include it if so - if let (Some(runtime_lib_path), Some(runtime_impl_path)) = ( - find_pallet_runtime_lib_path(&pallet_path), - self.runtime_impl_path.or_else(|| { - get_pallet_impl_path( - &pallet_path, - &pallet_crate_name.splitn(2, '-').nth(1).unwrap_or("pallet").to_string(), - ) - }), - ) { + if let Some(runtime_lib_path) = find_pallet_runtime_lib_path(&pallet_path) { // If the pallet has been created inside a workspace containing a runtime, add the // pallet to that runtime. + spinner.set_message("Adding the pallet to your runtime if needed..."); rust_writer::add_pallet_to_runtime_module( &pallet_crate_name, &runtime_lib_path, CrateDependencie::Local { local_crate_path: pallet_path.to_path_buf() }, )?; + + let pallet_impl_path = if let Some(impl_path) = self.pallet_impl_path { + impl_path.clone() + } else { + get_pallet_impl_path( + &pallet_path, + &pallet_crate_name.splitn(2, '-').nth(1).unwrap_or("pallet").to_string(), + )? + }; + // Add pallet's impl block let (types, values) = if pallet_default_config { (Vec::new(), Vec::new()) @@ -232,7 +234,7 @@ impl NewPalletCommand { rust_writer::add_pallet_impl_block_to_runtime( &pallet_crate_name, - &runtime_impl_path, + &pallet_impl_path, Vec::new(), types, values, diff --git a/crates/pop-common/src/manifest.rs b/crates/pop-common/src/manifest.rs index f9193782b..1bb8f4b8d 100644 --- a/crates/pop-common/src/manifest.rs +++ b/crates/pop-common/src/manifest.rs @@ -160,7 +160,7 @@ pub fn add_crate_to_dependencies( { path } else { - return Err(Error::Config("Calling add_crate_to_dependencies with a internal crate whose path isn't valid.".to_string())) + return Err(Error::Config("Calling add_crate_to_dependencies with a internal crate whose path isn't valid.".to_string())); }; crate_declaration.insert( @@ -208,79 +208,37 @@ pub fn find_crate_name(manifest_path: &Path) -> Result { .map(|package| package.name)?) } -pub fn find_pallet_runtime_lib_path(pallet_path: &Path) -> Option { - if let Some(mut workspace_toml) = find_workspace_toml(pallet_path) { +pub fn is_runtime_crate(path: &Path) -> bool { + // Ideally the runtime would be contained inside a workspace + if let Some(workspace_toml) = find_workspace_toml(path) { match Manifest::from_path(&workspace_toml) .ok() .map(|manifest| manifest.workspace.map(|workspace| workspace.members)) { - Some(Some(members)) if members.contains(&"runtime".to_string()) => { - workspace_toml.pop(); - Some(workspace_toml.join("runtime").join("src").join("lib.rs")) - }, - _ => None, + Some(Some(members)) + if members.contains(&"runtime".to_owned()) && + path.join("src").join("lib.rs").is_file() => + return true, + _ => (), } + } + // If not, at least it should be a lib crate + if path.join("src").join("lib.rs").is_file() { + true } else { - None + false } } -pub fn get_pallet_impl_path(runtime_path: &Path, pallet_name: &str) -> Option { - if let Some(mut workspace_toml) = find_workspace_toml(runtime_path) { +pub fn find_pallet_runtime_lib_path(pallet_path: &Path) -> Option { + if let Some(mut workspace_toml) = find_workspace_toml(pallet_path) { match Manifest::from_path(&workspace_toml) .ok() .map(|manifest| manifest.workspace.map(|workspace| workspace.members)) { Some(Some(members)) if members.contains(&"runtime".to_string()) => { - // Create the pallet config impl file workspace_toml.pop(); - let runtime_src_path = workspace_toml.join("runtime").join("src"); - let runtime_lib_path = runtime_src_path.join("lib.rs"); - let configs_rs_path = runtime_src_path.join("configs.rs"); - let configs_folder_path = runtime_src_path.join("configs"); - let configs_mod_path = configs_folder_path.join("mod.rs"); - let pallet_config_file = configs_folder_path.join(format!("{}.rs", pallet_name)); - match (configs_rs_path.exists(), configs_mod_path.exists()) { - // The runtime is using a configs module without the mod.rs sintax - (true, false) => { - let mut write_configs_rs = - std::fs::OpenOptions::new().append(true).open(configs_rs_path).ok()?; - writeln!(write_configs_rs, "{}", format!("mod {};", pallet_name)).ok()?; - std::fs::File::create(&pallet_config_file).ok()?; - Some(pallet_config_file) - }, - // The runtime is using a configs module with the mod.rs syntax - (false, true) => { - let mut write_configs_mod = - std::fs::OpenOptions::new().append(true).open(configs_mod_path).ok()?; - writeln!(write_configs_mod, "{}", format!("mod {};", pallet_name)).ok()?; - std::fs::File::create(&pallet_config_file).ok()?; - Some(pallet_config_file) - }, - // The runtime isn't using a configs module yet, we opt for the configs.rs - // convention - (false, false) => { - let mut write_configs_rs = std::fs::OpenOptions::new() - .create(true) - .write(true) - .open(configs_rs_path) - .ok()?; - writeln!(write_configs_rs, "{}", format!("mod {};", pallet_name)).ok()?; - std::fs::create_dir(configs_folder_path).ok()?; - std::fs::File::create(&pallet_config_file).ok()?; - rust_writer::add_mod_declarations( - &runtime_lib_path, - vec![parse_quote!( - pub mod configs; - )], - ) - .ok()?; - Some(pallet_config_file) - }, - // Both approaches at the sime time aren't supported by the compiler, so this is - // unreachable in a compiling project - (true, true) => unreachable!(), - } + Some(workspace_toml.join("runtime").join("src").join("lib.rs")) }, _ => None, } @@ -289,6 +247,52 @@ pub fn get_pallet_impl_path(runtime_path: &Path, pallet_name: &str) -> Option Result { + let runtime_src_path = runtime_path.join("src"); + let runtime_lib_path = runtime_src_path.join("lib.rs"); + let configs_rs_path = runtime_src_path.join("configs.rs"); + let configs_folder_path = runtime_src_path.join("configs"); + let configs_mod_path = configs_folder_path.join("mod.rs"); + let pallet_config_file = configs_folder_path.join(format!("{}.rs", pallet_name)); + match (configs_rs_path.exists(), configs_mod_path.exists()) { + // The runtime is using a configs module without the mod.rs sintax + (true, false) => { + let mut write_configs_rs = + std::fs::OpenOptions::new().append(true).open(configs_rs_path)?; + writeln!(write_configs_rs, "{}", format!("mod {};", pallet_name))?; + std::fs::File::create(&pallet_config_file)?; + Ok(pallet_config_file) + }, + // The runtime is using a configs module with the mod.rs syntax + (false, true) => { + let mut write_configs_mod = + std::fs::OpenOptions::new().append(true).open(configs_mod_path)?; + writeln!(write_configs_mod, "{}", format!("mod {};", pallet_name))?; + std::fs::File::create(&pallet_config_file)?; + Ok(pallet_config_file) + }, + // The runtime isn't using a configs module yet, we opt for the configs.rs + // convention + (false, false) => { + let mut write_configs_rs = + std::fs::OpenOptions::new().create(true).write(true).open(configs_rs_path)?; + writeln!(write_configs_rs, "{}", format!("mod {};", pallet_name))?; + std::fs::create_dir(configs_folder_path)?; + std::fs::File::create(&pallet_config_file)?; + rust_writer::add_mod_declarations( + &runtime_lib_path, + vec![parse_quote!( + pub mod configs; + )], + )?; + Ok(pallet_config_file) + }, + // Both approaches at the sime time aren't supported by the compiler, so this is + // unreachable in a compiling project + (true, true) => unreachable!(), + } +} + /// Adds a "production" profile to the Cargo.toml manifest if it doesn't already exist. /// /// # Arguments From 93c8e1a1d2a046efb6d3f94126b40ca51c6e5a32 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1s=20Senovilla=20Polo?= Date: Sun, 2 Feb 2025 13:07:26 +0100 Subject: [PATCH 32/46] pop new pallet adds configs in the appropriate path --- crates/pop-cli/src/commands/add/runtime_pallet.rs | 6 +++--- crates/pop-cli/src/commands/new/pallet.rs | 10 +++++----- crates/pop-common/src/lib.rs | 2 +- crates/pop-common/src/manifest.rs | 4 ++-- 4 files changed, 11 insertions(+), 11 deletions(-) diff --git a/crates/pop-cli/src/commands/add/runtime_pallet.rs b/crates/pop-cli/src/commands/add/runtime_pallet.rs index d929ef0bb..1c90843a0 100644 --- a/crates/pop-cli/src/commands/add/runtime_pallet.rs +++ b/crates/pop-cli/src/commands/add/runtime_pallet.rs @@ -130,9 +130,9 @@ impl AddPalletCommand { for handle in handles { let result = handle.join().expect("Unexpected error"); - if result.is_err(){ - return result; - } + if result.is_err() { + return result; + } } if let Some(mut workspace_toml) = find_workspace_toml(&runtime_path) { diff --git a/crates/pop-cli/src/commands/new/pallet.rs b/crates/pop-cli/src/commands/new/pallet.rs index bf7e44aad..491576363 100644 --- a/crates/pop-cli/src/commands/new/pallet.rs +++ b/crates/pop-cli/src/commands/new/pallet.rs @@ -8,7 +8,7 @@ use crate::{ use clap::{Args, Subcommand}; use cliclack::{confirm, input, multiselect, outro, outro_cancel}; use pop_common::{ - add_crate_to_workspace, find_crate_name, find_pallet_runtime_lib_path, find_workspace_toml, + add_crate_to_workspace, find_crate_name, find_pallet_runtime_path, find_workspace_toml, format_dir, get_pallet_impl_path, manifest::types::CrateDependencie, prefix_with_current_dir_if_needed, rust_writer, }; @@ -196,11 +196,11 @@ impl NewPalletCommand { let pallet_crate_name = find_crate_name(&pallet_path.join("Cargo.toml"))?; // Check if the pallet has to be included in a runtime and include it if so - if let Some(runtime_lib_path) = find_pallet_runtime_lib_path(&pallet_path) { + if let Some(runtime_path) = find_pallet_runtime_path(&pallet_path) { // If the pallet has been created inside a workspace containing a runtime, add the // pallet to that runtime. - - spinner.set_message("Adding the pallet to your runtime if needed..."); + spinner.set_message("Adding the pallet to your runtime..."); + let runtime_lib_path = runtime_path.join("src").join("lib.rs"); rust_writer::add_pallet_to_runtime_module( &pallet_crate_name, &runtime_lib_path, @@ -211,7 +211,7 @@ impl NewPalletCommand { impl_path.clone() } else { get_pallet_impl_path( - &pallet_path, + &runtime_path, &pallet_crate_name.splitn(2, '-').nth(1).unwrap_or("pallet").to_string(), )? }; diff --git a/crates/pop-common/src/lib.rs b/crates/pop-common/src/lib.rs index 47ade7caf..48245ec98 100644 --- a/crates/pop-common/src/lib.rs +++ b/crates/pop-common/src/lib.rs @@ -10,7 +10,7 @@ pub use helpers::{ replace_in_file, }; pub use manifest::{ - add_crate_to_workspace, find_crate_name, find_pallet_runtime_lib_path, find_workspace_toml, + add_crate_to_workspace, find_crate_name, find_pallet_runtime_path, find_workspace_toml, get_pallet_impl_path, }; pub use metadata::format_type; diff --git a/crates/pop-common/src/manifest.rs b/crates/pop-common/src/manifest.rs index 1bb8f4b8d..43c29f3cd 100644 --- a/crates/pop-common/src/manifest.rs +++ b/crates/pop-common/src/manifest.rs @@ -230,7 +230,7 @@ pub fn is_runtime_crate(path: &Path) -> bool { } } -pub fn find_pallet_runtime_lib_path(pallet_path: &Path) -> Option { +pub fn find_pallet_runtime_path(pallet_path: &Path) -> Option { if let Some(mut workspace_toml) = find_workspace_toml(pallet_path) { match Manifest::from_path(&workspace_toml) .ok() @@ -238,7 +238,7 @@ pub fn find_pallet_runtime_lib_path(pallet_path: &Path) -> Option { { Some(Some(members)) if members.contains(&"runtime".to_string()) => { workspace_toml.pop(); - Some(workspace_toml.join("runtime").join("src").join("lib.rs")) + Some(workspace_toml.join("runtime")) }, _ => None, } From 6b2c9601326960bc61d15be5e3209515e463a276 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1s=20Senovilla=20Polo?= Date: Sun, 2 Feb 2025 14:44:53 +0100 Subject: [PATCH 33/46] pop add-to pallet detects pallet directory + concurrency --- .../src/commands/add/pallet_config_type.rs | 189 ++++++++++++------ .../src/commands/add/runtime_pallet.rs | 13 +- crates/pop-cli/src/commands/new/pallet.rs | 8 +- crates/pop-common/src/lib.rs | 4 +- crates/pop-common/src/manifest.rs | 21 +- crates/pop-common/src/rust_writer.rs | 15 +- 6 files changed, 169 insertions(+), 81 deletions(-) diff --git a/crates/pop-cli/src/commands/add/pallet_config_type.rs b/crates/pop-cli/src/commands/add/pallet_config_type.rs index 182b8876b..eed688b9c 100644 --- a/crates/pop-cli/src/commands/add/pallet_config_type.rs +++ b/crates/pop-cli/src/commands/add/pallet_config_type.rs @@ -9,44 +9,63 @@ use crate::{ use clap::{error::ErrorKind, Args, Command}; use cliclack::multiselect; use pop_common::{ - capitalize_str, find_workspace_toml, format_dir, prefix_with_current_dir_if_needed, + capitalize_str, find_workspace_toml, format_dir, manifest, prefix_with_current_dir_if_needed, rust_writer::{self, types::*}, }; use proc_macro2::Span; -use std::{fs, path::PathBuf}; +use std::{ + env, fs, + path::PathBuf, + sync::{Arc, Mutex}, +}; use strum::{EnumMessage, IntoEnumIterator}; use syn::{parse_quote, Ident}; #[derive(Args, Debug, Clone)] pub struct AddConfigTypeCommand { - #[arg(short, long, required = true, help = "Specify the path to the pallet crate.")] - pub(crate) pallet_path: PathBuf, #[arg(short, long, value_enum, num_args(1..), required = false, help = "The types you want to include in your pallet.")] pub(crate) types: Vec, + #[arg( + short, + long, + help = "Pop-CLI will add the config type to the current directory lib if there's one. Use this argument to point to other path." + )] + pub(crate) pallet_path: Option, #[arg( long, - help = "If your pallet is included in a runtime, Pop-Cli will look for the impl block for your pallet's Config trait inside configs/mod.rs or lib.rs in the runtime crate by default in order to add the new type to the runtime. If your impl block is in another path, use this option to specify it." + help = "If your pallet is part of a workspace containing a runtime, Pop-Cli will look for the impl block in configs/your_pallet_name.rs or in the runtime lib file to add the new type. Use this argument to point to other path." )] - pub(crate) runtime_impl_path: Option, + pub(crate) pallet_impl_path: Option, } impl AddConfigTypeCommand { pub(crate) async fn execute(self) -> anyhow::Result<()> { Cli.intro("Add a new type to your pallet")?; let mut cmd = Command::new(""); - let pallet_path = prefix_with_current_dir_if_needed(self.pallet_path); + + let pallet_path = if let Some(path) = &self.pallet_path { + prefix_with_current_dir_if_needed(path.to_path_buf()) + } else { + // If not provided, use the working dir + let working_dir = match env::current_dir() { + Ok(working_dir) => working_dir, + _ => cmd.error(ErrorKind::Io, "Cannot modify the working crate").exit(), + }; + prefix_with_current_dir_if_needed(working_dir) + }; + let src = pallet_path.join("src"); // Check that the path correspond to a pallet using that the file lib.rs always contains the // line #[pallet::pallet]. - let lib_path = src.join("lib.rs"); - if !lib_path.is_file() { + let pallet_lib_path = src.join("lib.rs"); + if !pallet_lib_path.is_file() { cmd.error( ErrorKind::InvalidValue, "Make sure that the used path correspond to a pallet crate.", ) .exit(); } - let lib_content = fs::read_to_string(&lib_path)?; + let lib_content = fs::read_to_string(&pallet_lib_path)?; if !lib_content.contains("#[pallet::pallet]") { cmd.error( ErrorKind::InvalidValue, @@ -68,62 +87,108 @@ impl AddConfigTypeCommand { let using_default_config = lib_content.contains("pub mod config_preludes"); + let mut handles = Vec::new(); + // Mutex the memory shared accross threads + let mutex_pallet_path = Arc::new(Mutex::new(pallet_path.clone())); + let mutex_pallet_impl_path = Arc::new(Mutex::new(self.pallet_impl_path)); + let spinner = cliclack::spinner(); spinner.start("Updating pallet's config trait..."); for type_ in types { - rust_writer::add_use_statements(&lib_path, type_.get_needed_use_statements())?; - - rust_writer::add_composite_enums(&lib_path, type_.get_needed_composite_enums())?; - - let type_name_ident = Ident::new( - &capitalize_str(type_.get_message().unwrap_or_default()), - Span::call_site(), - ); - let default_config = if using_default_config { - type_.get_default_config() - } else { - // Here the inner element's irrelevant, so we place a simple type definition - DefaultConfigType::Default { type_default_impl: parse_quote! {type A = ();} } - }; - // Update the config trait in lib.rs - rust_writer::update_config_trait( - &lib_path, - type_name_ident.clone(), - type_.get_common_trait_bounds(), - &default_config, - )?; - - match default_config { - // Need to update default config - DefaultConfigType::Default { type_default_impl } | - DefaultConfigType::NoDefaultBounds { type_default_impl } - if using_default_config => - { - spinner.set_message( - "Adding your type's default value to the pallet's config preludes...", - ); - // If config_preludes is defined in its own file, we pass it to - // 'add_type_to_config_preludes", otherwise we pass lib.rs - let config_preludes_path = src.join("config_preludes.rs"); - let file_path = if config_preludes_path.is_file() { - &config_preludes_path - } else { - &lib_path - }; - - rust_writer::add_type_to_config_preludes(file_path, type_default_impl)?; - }, - // Need to update runtimes - _ => { - spinner.set_message("Adding your type to pallet's related runtimes..."); - rust_writer::add_type_to_runtimes( - &pallet_path, - type_name_ident, - type_.get_common_runtime_value(), - self.runtime_impl_path.as_deref(), - )?; - }, + let mutex_pallet_path = Arc::clone(&mutex_pallet_path); + let mutex_pallet_impl_path = Arc::clone(&mutex_pallet_impl_path); + handles.push(std::thread::spawn(move || -> Result<(), anyhow::Error> { + let pallet_impl_path = mutex_pallet_impl_path + .lock() + .map_err(|e| anyhow::Error::msg(format!("{}", e)))?; + let pallet_path = + mutex_pallet_path.lock().map_err(|e| anyhow::Error::msg(format!("{}", e)))?; + + let pallet_lib_path = pallet_path.join("src").join("lib.rs"); + let pallet_crate_name = manifest::find_crate_name(&pallet_path.join("Cargo.toml"))?; + let config_preludes_path = pallet_path.join("src").join("config_preludes.rs"); + let runtime_path = manifest::find_pallet_runtime_path(&pallet_path); + + rust_writer::add_use_statements( + &pallet_lib_path, + type_.get_needed_use_statements(), + )?; + + rust_writer::add_composite_enums( + &pallet_lib_path, + type_.get_needed_composite_enums(), + )?; + + let type_name_ident = Ident::new( + &capitalize_str(type_.get_message().unwrap_or_default()), + Span::call_site(), + ); + let default_config = if using_default_config { + type_.get_default_config() + } else { + // Here the inner element's irrelevant, so we place a simple type definition + DefaultConfigType::Default { type_default_impl: parse_quote! {type A = ();} } + }; + // Update the config trait in lib.rs + rust_writer::update_config_trait( + &pallet_lib_path, + type_name_ident.clone(), + type_.get_common_trait_bounds(), + &default_config, + )?; + + match default_config { + // Need to update default config + DefaultConfigType::Default { type_default_impl } | + DefaultConfigType::NoDefaultBounds { type_default_impl } + if using_default_config => + { + // If config_preludes is defined in its own file, we pass it to + // 'add_type_to_config_preludes", otherwise we pass lib.rs + let file_path = if config_preludes_path.is_file() { + &config_preludes_path + } else { + &pallet_lib_path + }; + + rust_writer::add_type_to_config_preludes(file_path, type_default_impl)?; + }, + // Need to update runtimes + _ => { + let pallet_impl_path = if let Some(runtime_path) = runtime_path { + match *pallet_impl_path { + Some(_) => pallet_impl_path.clone(), + _ => Some(manifest::get_pallet_impl_path( + &runtime_path, + &pallet_crate_name + .splitn(2, '-') + .nth(1) + .unwrap_or("pallet") + .to_owned(), + )?), + } + } else { + None + }; + + rust_writer::add_type_to_runtimes( + &pallet_path, + type_name_ident, + type_.get_common_runtime_value(), + pallet_impl_path, + )?; + }, + } + + Ok(()) + })); + } + + for handle in handles { + let result = handle.join().expect("Unexpected error"); + if result.is_err() { + return result; } } diff --git a/crates/pop-cli/src/commands/add/runtime_pallet.rs b/crates/pop-cli/src/commands/add/runtime_pallet.rs index 1c90843a0..512fb648b 100644 --- a/crates/pop-cli/src/commands/add/runtime_pallet.rs +++ b/crates/pop-cli/src/commands/add/runtime_pallet.rs @@ -26,7 +26,7 @@ pub struct AddPalletCommand { pub(crate) runtime_path: Option, #[arg( long, - help = "Pop-Cli will place the impl blocks for your pallets' Config traits inside a dedicated file under configs directory. Use this argument to point to another path." + help = "Pop-Cli will place the impl blocks for your pallets' Config traits inside a dedicated file under configs directory. Use this argument to point to other path." )] pub(crate) pallet_impl_path: Option, } @@ -88,10 +88,11 @@ impl AddPalletCommand { mutex_runtime_path.lock().map_err(|e| anyhow::Error::msg(format!("{}", e)))?; let runtime_lib_path = runtime_path.join("src").join("lib.rs"); - let pallet_impl_path = if pallet_impl_path.is_some() { - pallet_impl_path.clone().expect("The if statement ensures this is Some;qed;") - } else { - manifest::get_pallet_impl_path( + let pallet_impl_path = match *pallet_impl_path { + Some(_) => pallet_impl_path + .clone() + .expect("The match arm guarantees this is Some; qed;"), + None => manifest::compute_new_pallet_impl_path( &runtime_path, &pallet .get_crate_name() @@ -99,7 +100,7 @@ impl AddPalletCommand { .nth(1) .unwrap_or("pallet") .to_string(), - )? + )?, }; // Add the pallet to the crate and to the runtime module diff --git a/crates/pop-cli/src/commands/new/pallet.rs b/crates/pop-cli/src/commands/new/pallet.rs index 491576363..009e1dbee 100644 --- a/crates/pop-cli/src/commands/new/pallet.rs +++ b/crates/pop-cli/src/commands/new/pallet.rs @@ -8,8 +8,8 @@ use crate::{ use clap::{Args, Subcommand}; use cliclack::{confirm, input, multiselect, outro, outro_cancel}; use pop_common::{ - add_crate_to_workspace, find_crate_name, find_pallet_runtime_path, find_workspace_toml, - format_dir, get_pallet_impl_path, manifest::types::CrateDependencie, + add_crate_to_workspace, compute_new_pallet_impl_path, find_crate_name, + find_pallet_runtime_path, find_workspace_toml, format_dir, manifest::types::CrateDependencie, prefix_with_current_dir_if_needed, rust_writer, }; use pop_parachains::{ @@ -55,7 +55,7 @@ pub struct NewPalletCommand { pub(crate) description: Option, #[arg( long, - help = "If your pallet is created in a workspace containing a runtime, Pop-Cli will place the impl blocks for your pallets' Config traits inside a dedicated file under configs directory. Use this argument to point to another path." + help = "If your pallet is created in a workspace containing a runtime, Pop-Cli will place the impl blocks for your pallets' Config traits inside a dedicated file under configs directory. Use this argument to point to other path." )] pub(crate) pallet_impl_path: Option, #[command(subcommand)] @@ -210,7 +210,7 @@ impl NewPalletCommand { let pallet_impl_path = if let Some(impl_path) = self.pallet_impl_path { impl_path.clone() } else { - get_pallet_impl_path( + compute_new_pallet_impl_path( &runtime_path, &pallet_crate_name.splitn(2, '-').nth(1).unwrap_or("pallet").to_string(), )? diff --git a/crates/pop-common/src/lib.rs b/crates/pop-common/src/lib.rs index 48245ec98..e0944bfc5 100644 --- a/crates/pop-common/src/lib.rs +++ b/crates/pop-common/src/lib.rs @@ -10,8 +10,8 @@ pub use helpers::{ replace_in_file, }; pub use manifest::{ - add_crate_to_workspace, find_crate_name, find_pallet_runtime_path, find_workspace_toml, - get_pallet_impl_path, + add_crate_to_workspace, compute_new_pallet_impl_path, find_crate_name, + find_pallet_runtime_path, find_workspace_toml, }; pub use metadata::format_type; pub use signer::create_signer; diff --git a/crates/pop-common/src/manifest.rs b/crates/pop-common/src/manifest.rs index 43c29f3cd..d78c87bb7 100644 --- a/crates/pop-common/src/manifest.rs +++ b/crates/pop-common/src/manifest.rs @@ -247,7 +247,10 @@ pub fn find_pallet_runtime_path(pallet_path: &Path) -> Option { } } -pub fn get_pallet_impl_path(runtime_path: &Path, pallet_name: &str) -> Result { +pub fn compute_new_pallet_impl_path( + runtime_path: &Path, + pallet_name: &str, +) -> Result { let runtime_src_path = runtime_path.join("src"); let runtime_lib_path = runtime_src_path.join("lib.rs"); let configs_rs_path = runtime_src_path.join("configs.rs"); @@ -293,6 +296,22 @@ pub fn get_pallet_impl_path(runtime_path: &Path, pallet_name: &str) -> Result Result { + let pallet_config_path = + runtime_path.join("src").join("configs").join(format!("{}.rs", pallet_name)); + if pallet_config_path.exists() { + return Ok(pallet_config_path); + } + let runtime_lib_path = runtime_path.join("src").join("lib.rs"); + if read_to_string(&runtime_lib_path)?.contains(&format!("{} for Runtime", pallet_name)) { + return Ok(runtime_lib_path) + } + Err(Error::Descriptive(format!( + "Pop-CLI couldn't find the impl block for the pallet {}", + pallet_name + ))) +} + /// Adds a "production" profile to the Cargo.toml manifest if it doesn't already exist. /// /// # Arguments diff --git a/crates/pop-common/src/rust_writer.rs b/crates/pop-common/src/rust_writer.rs index 6109432b3..452ce870a 100644 --- a/crates/pop-common/src/rust_writer.rs +++ b/crates/pop-common/src/rust_writer.rs @@ -9,7 +9,10 @@ use crate::{ }; use prettyplease::unparse; use proc_macro2::Span; -use std::{fs, path::Path}; +use std::{ + fs, + path::{Path, PathBuf}, +}; use syn::{parse_str, Ident, ImplItem, ItemEnum, ItemMod, ItemUse, TraitBound, Type}; mod expand; @@ -45,7 +48,7 @@ pub fn add_type_to_runtimes( pallet_path: &Path, type_name: Ident, runtime_value: Type, - runtime_impl_path: Option<&Path>, + pallet_impl_path: Option, ) -> Result<(), Error> { fn do_add_type_to_runtime( file_content: &str, @@ -92,11 +95,11 @@ pub fn add_type_to_runtimes( )?; // If the pallet is contained inside a runtime add the type to that runtime as well - if let Some(runtime_impl_path) = runtime_impl_path.map(|inner| inner.to_path_buf()) { - let runtime_impl_content = fs::read_to_string(&runtime_impl_path)?; + if let Some(pallet_impl_path) = pallet_impl_path { + let pallet_impl_content = fs::read_to_string(&pallet_impl_path)?; do_add_type_to_runtime( - &runtime_impl_content, - &runtime_impl_path, + &pallet_impl_content, + &pallet_impl_path, &pallet_manifest_path, type_name, runtime_value, From 6471c31184cdeea180c02466e14eda6c080e6c95 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1s=20Senovilla=20Polo?= Date: Mon, 3 Feb 2025 20:07:37 +0100 Subject: [PATCH 34/46] Add rollback + finish preserver --- .../src/commands/add/pallet_config_type.rs | 36 ++++-- .../src/commands/add/runtime_pallet.rs | 103 +++++++++++----- crates/pop-cli/src/commands/new/pallet.rs | 66 +++++++++-- crates/pop-common/src/lib.rs | 2 + crates/pop-common/src/manifest.rs | 68 +++++++---- crates/pop-common/src/rollback.rs | 110 ++++++++++++++++++ crates/pop-common/src/rust_writer.rs | 54 ++++----- crates/pop-common/src/rust_writer/parse.rs | 11 +- .../pop-common/src/rust_writer/preserver.rs | 76 +++++++++--- 9 files changed, 394 insertions(+), 132 deletions(-) create mode 100644 crates/pop-common/src/rollback.rs diff --git a/crates/pop-cli/src/commands/add/pallet_config_type.rs b/crates/pop-cli/src/commands/add/pallet_config_type.rs index eed688b9c..afd48c029 100644 --- a/crates/pop-cli/src/commands/add/pallet_config_type.rs +++ b/crates/pop-cli/src/commands/add/pallet_config_type.rs @@ -11,6 +11,7 @@ use cliclack::multiselect; use pop_common::{ capitalize_str, find_workspace_toml, format_dir, manifest, prefix_with_current_dir_if_needed, rust_writer::{self, types::*}, + Rollback, }; use proc_macro2::Span; use std::{ @@ -109,14 +110,23 @@ impl AddConfigTypeCommand { let pallet_crate_name = manifest::find_crate_name(&pallet_path.join("Cargo.toml"))?; let config_preludes_path = pallet_path.join("src").join("config_preludes.rs"); let runtime_path = manifest::find_pallet_runtime_path(&pallet_path); + let pallet_mock_path = pallet_path.join("src").join("mock.rs"); + + let mut rollback = Rollback::with_capacity(3, 0, 0); + + let roll_pallet_lib_path = rollback.note_file(&pallet_lib_path)?; + let roll_pallet_mock_path = rollback.note_file(&pallet_mock_path)?; + // This may be Err as the file may not exist due to the config preludes may not be + // in a separate file. + let roll_config_preludes_path = rollback.note_file(&config_preludes_path); rust_writer::add_use_statements( - &pallet_lib_path, + &roll_pallet_lib_path, type_.get_needed_use_statements(), )?; rust_writer::add_composite_enums( - &pallet_lib_path, + &roll_pallet_lib_path, type_.get_needed_composite_enums(), )?; @@ -132,7 +142,7 @@ impl AddConfigTypeCommand { }; // Update the config trait in lib.rs rust_writer::update_config_trait( - &pallet_lib_path, + &roll_pallet_lib_path, type_name_ident.clone(), type_.get_common_trait_bounds(), &default_config, @@ -147,9 +157,11 @@ impl AddConfigTypeCommand { // If config_preludes is defined in its own file, we pass it to // 'add_type_to_config_preludes", otherwise we pass lib.rs let file_path = if config_preludes_path.is_file() { - &config_preludes_path + // As config_preludes_path is indeed a file, roll_config_preludes_path + // should be Ok + &roll_config_preludes_path? } else { - &pallet_lib_path + &roll_pallet_lib_path }; rust_writer::add_type_to_config_preludes(file_path, type_default_impl)?; @@ -172,15 +184,23 @@ impl AddConfigTypeCommand { None }; + let roll_pallet_impl_path = if let Some(impl_path) = pallet_impl_path { + rollback.note_file(&impl_path).ok() + } else { + None + }; + rust_writer::add_type_to_runtimes( - &pallet_path, type_name_ident, type_.get_common_runtime_value(), - pallet_impl_path, + roll_pallet_impl_path, + &roll_pallet_mock_path, + &pallet_crate_name, )?; }, } + rollback.commit(); Ok(()) })); } @@ -188,7 +208,7 @@ impl AddConfigTypeCommand { for handle in handles { let result = handle.join().expect("Unexpected error"); if result.is_err() { - return result; + Cli.warning("Some of the types weren't added to your pallet")?; } } diff --git a/crates/pop-cli/src/commands/add/runtime_pallet.rs b/crates/pop-cli/src/commands/add/runtime_pallet.rs index 512fb648b..71f67f9d8 100644 --- a/crates/pop-cli/src/commands/add/runtime_pallet.rs +++ b/crates/pop-cli/src/commands/add/runtime_pallet.rs @@ -8,6 +8,7 @@ use clap::{error::ErrorKind, Args, Command}; use cliclack::multiselect; use pop_common::{ find_workspace_toml, format_dir, manifest, prefix_with_current_dir_if_needed, rust_writer, + Rollback, }; use std::{ env, @@ -88,43 +89,83 @@ impl AddPalletCommand { mutex_runtime_path.lock().map_err(|e| anyhow::Error::msg(format!("{}", e)))?; let runtime_lib_path = runtime_path.join("src").join("lib.rs"); + let runtime_manifest = manifest::find_crate_manifest(&runtime_lib_path) + .expect("Runtime is a crate, so it contains a manifest; qed;"); + + let mut rollback; + let roll_runtime_lib_path; let pallet_impl_path = match *pallet_impl_path { - Some(_) => pallet_impl_path - .clone() - .expect("The match arm guarantees this is Some; qed;"), - None => manifest::compute_new_pallet_impl_path( - &runtime_path, - &pallet - .get_crate_name() - .splitn(2, '-') - .nth(1) - .unwrap_or("pallet") - .to_string(), - )?, + Some(_) => { + rollback = Rollback::with_capacity(3, 0, 0); + roll_runtime_lib_path = rollback.note_file(&runtime_lib_path)?; + pallet_impl_path + .clone() + .expect("The match arm guarantees this is Some; qed;") + }, + None => { + let (rollback_temp, runtime_lib_path_rolled) = + manifest::compute_new_pallet_impl_path( + &runtime_path, + &pallet + .get_crate_name() + .splitn(2, '-') + .nth(1) + .unwrap_or("pallet") + .to_string(), + )?; + rollback = rollback_temp; + + // The rollback created above may already contain a noted version of + // runtime_lib_path and a new file which corresponds to the pallet + // impl path + roll_runtime_lib_path = if runtime_lib_path_rolled { + rollback.noted_files().remove(0) + } else { + rollback.note_file(&runtime_lib_path)? + }; + rollback.new_files().remove(0) + }, }; + let roll_pallet_impl_path = rollback.note_file(&pallet_impl_path)?; + let roll_manifest = rollback.note_file(&runtime_manifest)?; + // Add the pallet to the crate and to the runtime module - rust_writer::add_pallet_to_runtime_module( - &pallet.get_crate_name(), - &runtime_lib_path, - manifest::types::CrateDependencie::External { version: pallet.get_version() }, - )?; + let (rollback, _) = + rollback.ok_or_rollback(rust_writer::add_pallet_to_runtime_module( + &pallet.get_crate_name(), + &roll_runtime_lib_path, + ))?; // Add the pallet impl block and its related use statements - rust_writer::add_use_statements( - &pallet_impl_path, + let (rollback, _) = rollback.ok_or_rollback(rust_writer::add_use_statements( + &roll_pallet_impl_path, pallet.get_impl_needed_use_statements(), - )?; - - rust_writer::add_pallet_impl_block_to_runtime( - &pallet.get_crate_name(), - &pallet_impl_path, - pallet.get_parameter_types(), - pallet.get_config_types(), - pallet.get_config_values(), - pallet.get_default_config(), - )?; - + ))?; + + let (rollback, _) = + rollback.ok_or_rollback(rust_writer::add_pallet_impl_block_to_runtime( + &pallet.get_crate_name(), + &roll_pallet_impl_path, + pallet.get_parameter_types(), + pallet.get_config_types(), + pallet.get_config_values(), + pallet.get_default_config(), + ))?; + + // Update the crate's manifest to add the pallet crate + let (rollback, _) = + rollback.ok_or_rollback(manifest::add_crate_to_dependencies( + &roll_manifest, + &runtime_manifest, + &pallet.get_crate_name(), + manifest::types::CrateDependencie::External { + version: pallet.get_version(), + }, + ))?; + + // At this point, we can commit the rollback + rollback.commit(); Ok(()) })); } @@ -132,7 +173,7 @@ impl AddPalletCommand { for handle in handles { let result = handle.join().expect("Unexpected error"); if result.is_err() { - return result; + Cli.warning("Some of the pallets weren't added to your runtime")?; } } diff --git a/crates/pop-cli/src/commands/new/pallet.rs b/crates/pop-cli/src/commands/new/pallet.rs index 009e1dbee..a0578ac62 100644 --- a/crates/pop-cli/src/commands/new/pallet.rs +++ b/crates/pop-cli/src/commands/new/pallet.rs @@ -9,8 +9,8 @@ use clap::{Args, Subcommand}; use cliclack::{confirm, input, multiselect, outro, outro_cancel}; use pop_common::{ add_crate_to_workspace, compute_new_pallet_impl_path, find_crate_name, - find_pallet_runtime_path, find_workspace_toml, format_dir, manifest::types::CrateDependencie, - prefix_with_current_dir_if_needed, rust_writer, + find_pallet_runtime_path, find_workspace_toml, format_dir, manifest, + manifest::types::CrateDependencie, prefix_with_current_dir_if_needed, rust_writer, Rollback, }; use pop_parachains::{ create_pallet_template, TemplatePalletConfig, TemplatePalletConfigCommonTypes, @@ -201,21 +201,50 @@ impl NewPalletCommand { // pallet to that runtime. spinner.set_message("Adding the pallet to your runtime..."); let runtime_lib_path = runtime_path.join("src").join("lib.rs"); - rust_writer::add_pallet_to_runtime_module( - &pallet_crate_name, - &runtime_lib_path, - CrateDependencie::Local { local_crate_path: pallet_path.to_path_buf() }, - )?; + let runtime_manifest = manifest::find_crate_manifest(&runtime_lib_path) + .expect("Runtime is a crate, so it contains a manifest; qed;"); + let mut rollback; + let roll_runtime_lib_path; let pallet_impl_path = if let Some(impl_path) = self.pallet_impl_path { + rollback = Rollback::with_capacity(3, 0, 0); + roll_runtime_lib_path = rollback.note_file(&runtime_lib_path)?; impl_path.clone() } else { - compute_new_pallet_impl_path( + let (rollback_temp, runtime_lib_path_rolled) = compute_new_pallet_impl_path( &runtime_path, &pallet_crate_name.splitn(2, '-').nth(1).unwrap_or("pallet").to_string(), - )? + )?; + + rollback = rollback_temp; + // The rollback created above may already contain a noted version of + // runtime_lib_path and a new file which corresponds to the pallet + // impl path + roll_runtime_lib_path = if runtime_lib_path_rolled { + rollback.noted_files().remove(0) + } else { + rollback.note_file(&runtime_lib_path)? + }; + rollback.new_files().remove(0) }; + let roll_pallet_impl_path = rollback.note_file(&pallet_impl_path)?; + let roll_runtime_manifest = rollback.note_file(&runtime_manifest)?; + + // Add pallet to runtime module + let add_pallet_to_runtime = rust_writer::add_pallet_to_runtime_module( + &pallet_crate_name, + &roll_runtime_lib_path, + ); + + // Update the crate's manifest to add the pallet crate + let add_crate_dependencies = manifest::add_crate_to_dependencies( + &roll_runtime_manifest, + &runtime_manifest, + &pallet_crate_name, + CrateDependencie::Local { local_crate_path: pallet_path.to_path_buf() }, + ); + // Add pallet's impl block let (types, values) = if pallet_default_config { (Vec::new(), Vec::new()) @@ -232,14 +261,27 @@ impl NewPalletCommand { (types, values) }; - rust_writer::add_pallet_impl_block_to_runtime( + let add_pallet_impl_block = rust_writer::add_pallet_impl_block_to_runtime( &pallet_crate_name, - &pallet_impl_path, + &roll_pallet_impl_path, Vec::new(), types, values, pallet_default_config, - )?; + ); + + // If some of these results are Err, that doesn't mean that everything went wrong, only + // that the pallet wasn't included into the runtime. But the pallet was indeed + // created, so we cannot return an error here + match (add_pallet_to_runtime, add_crate_dependencies, add_pallet_impl_block) { + (Ok(_), Ok(_), Ok(_)) => rollback.commit(), + _ => { + Cli.warning( + "Your pallet has been created but it couldn't be added to your runtime.", + )?; + rollback.rollback(); + }, + } } // If the pallet has been created inside a workspace, add it to that workspace diff --git a/crates/pop-common/src/lib.rs b/crates/pop-common/src/lib.rs index e0944bfc5..9867f1139 100644 --- a/crates/pop-common/src/lib.rs +++ b/crates/pop-common/src/lib.rs @@ -14,6 +14,7 @@ pub use manifest::{ find_pallet_runtime_path, find_workspace_toml, }; pub use metadata::format_type; +pub use rollback::Rollback; pub use signer::create_signer; pub use sourcing::set_executable_permission; pub use subxt::{Config, PolkadotConfig as DefaultConfig}; @@ -28,6 +29,7 @@ pub mod manifest; /// Provides functionality for formatting and resolving metadata types. pub mod metadata; pub mod polkadot_sdk; +mod rollback; pub mod rust_writer; /// Provides functionality for creating a signer from a secret URI. pub mod signer; diff --git a/crates/pop-common/src/manifest.rs b/crates/pop-common/src/manifest.rs index d78c87bb7..760ab5e7d 100644 --- a/crates/pop-common/src/manifest.rs +++ b/crates/pop-common/src/manifest.rs @@ -1,16 +1,17 @@ // SPDX-License-Identifier: GPL-3.0 pub mod types; -use crate::{rust_writer, Error}; +use crate::{rust_writer, Error, Rollback}; use anyhow; pub use cargo_toml::{Dependency, LtoSetting, Manifest, Profile, Profiles}; use pathdiff::diff_paths; +use proc_macro2::Span; use std::{ fs::{read_to_string, write}, io::Write, path::{Path, PathBuf}, }; -use syn::parse_quote; +use syn::{parse_quote, Ident}; use toml_edit::{value, Array, DocumentMut, InlineTable, Item, Table, Value}; /// Parses the contents of a `Cargo.toml` manifest. @@ -115,6 +116,7 @@ pub fn add_crate_to_workspace(workspace_toml: &Path, crate_path: &Path) -> anyho } pub fn add_crate_to_dependencies( + maybe_rolled_manifest_path: &Path, manifest_path: &Path, crate_name: &str, dependencie_format: types::CrateDependencie, @@ -160,7 +162,7 @@ pub fn add_crate_to_dependencies( { path } else { - return Err(Error::Config("Calling add_crate_to_dependencies with a internal crate whose path isn't valid.".to_string())); + return Err(Error::Config("Calling add_crate_to_dependencies with an internal crate whose path isn't valid.".to_string())); }; crate_declaration.insert( @@ -182,7 +184,7 @@ pub fn add_crate_to_dependencies( } Ok(()) } - let content = read_to_string(manifest_path)?; + let content = read_to_string(maybe_rolled_manifest_path)?; let mut doc = content.parse::()?; if let Some(Item::Table(dependencies)) = doc.get_mut("dependencies") { do_add_crate_to_dependencies(manifest_path, dependencies, crate_name, dependencie_format)?; @@ -197,7 +199,7 @@ pub fn add_crate_to_dependencies( doc.insert("dependencies", Item::Table(dependencies)); } - write(manifest_path, doc.to_string())?; + write(maybe_rolled_manifest_path, doc.to_string())?; Ok(()) } @@ -250,45 +252,63 @@ pub fn find_pallet_runtime_path(pallet_path: &Path) -> Option { pub fn compute_new_pallet_impl_path( runtime_path: &Path, pallet_name: &str, -) -> Result { +) -> Result<(Rollback, bool), Error> { let runtime_src_path = runtime_path.join("src"); let runtime_lib_path = runtime_src_path.join("lib.rs"); let configs_rs_path = runtime_src_path.join("configs.rs"); let configs_folder_path = runtime_src_path.join("configs"); let configs_mod_path = configs_folder_path.join("mod.rs"); let pallet_config_file = configs_folder_path.join(format!("{}.rs", pallet_name)); - match (configs_rs_path.exists(), configs_mod_path.exists()) { + let pallet_name_ident = Ident::new(pallet_name, Span::call_site()); + match (configs_rs_path.is_file(), configs_mod_path.is_file()) { // The runtime is using a configs module without the mod.rs sintax (true, false) => { - let mut write_configs_rs = - std::fs::OpenOptions::new().append(true).open(configs_rs_path)?; - writeln!(write_configs_rs, "{}", format!("mod {};", pallet_name))?; - std::fs::File::create(&pallet_config_file)?; - Ok(pallet_config_file) + let mut rollback = Rollback::with_capacity(1, 1, 0); + let roll_configs_rs_path = rollback.note_file(&configs_rs_path)?; + rust_writer::add_mod_declarations( + &roll_configs_rs_path, + vec![parse_quote!(mod #pallet_name_ident;)], + )?; + rollback.new_file(&pallet_config_file)?; + Ok((rollback, false)) }, // The runtime is using a configs module with the mod.rs syntax (false, true) => { - let mut write_configs_mod = - std::fs::OpenOptions::new().append(true).open(configs_mod_path)?; - writeln!(write_configs_mod, "{}", format!("mod {};", pallet_name))?; - std::fs::File::create(&pallet_config_file)?; - Ok(pallet_config_file) + let mut rollback = Rollback::with_capacity(1, 1, 0); + let roll_configs_mod_path = rollback.note_file(&configs_mod_path)?; + rust_writer::add_mod_declarations( + &roll_configs_mod_path, + vec![parse_quote!(mod #pallet_name_ident;)], + )?; + rollback.new_file(&pallet_config_file)?; + Ok((rollback, false)) }, // The runtime isn't using a configs module yet, we opt for the configs.rs // convention (false, false) => { - let mut write_configs_rs = - std::fs::OpenOptions::new().create(true).write(true).open(configs_rs_path)?; - writeln!(write_configs_rs, "{}", format!("mod {};", pallet_name))?; - std::fs::create_dir(configs_folder_path)?; - std::fs::File::create(&pallet_config_file)?; + let mut rollback = Rollback::with_capacity(1, 2, 1); + let roll_runtime_lib_path = rollback.note_file(&runtime_lib_path)?; rust_writer::add_mod_declarations( - &runtime_lib_path, + &roll_runtime_lib_path, vec![parse_quote!( pub mod configs; )], )?; - Ok(pallet_config_file) + + rollback.new_file(&configs_rs_path)?; + rollback.new_dir(&configs_folder_path)?; + rollback.new_file(&pallet_config_file)?; + + let (rollback, mut write_configs_rs) = rollback + .ok_or_rollback(std::fs::OpenOptions::new().write(true).open(configs_rs_path))?; + + let (rollback, _) = rollback.ok_or_rollback(writeln!( + write_configs_rs, + "{}", + format!("mod {};", pallet_name) + ))?; + + Ok((rollback, true)) }, // Both approaches at the sime time aren't supported by the compiler, so this is // unreachable in a compiling project diff --git a/crates/pop-common/src/rollback.rs b/crates/pop-common/src/rollback.rs new file mode 100644 index 000000000..922ebc1ad --- /dev/null +++ b/crates/pop-common/src/rollback.rs @@ -0,0 +1,110 @@ +// SPDX-License-Identifier: GPL-3.0 + +use crate::Error; +use std::{ + fs::File, + path::{Path, PathBuf}, +}; +use tempfile::NamedTempFile; + +#[derive(Debug)] +pub struct Rollback { + // Keep the temp_files inside the rollback struct, so they live until the Rollback dissapears + temp_files: Vec, + // A tuple of PathBuf representing the paths to the temporary file and the original file + noted: Vec<(PathBuf, PathBuf)>, + // A registry of new_files + new_files: Vec, + // A registry of new directories + new_dirs: Vec, +} + +impl Rollback { + pub fn new() -> Self { + Self { + temp_files: Vec::new(), + noted: Vec::new(), + new_files: Vec::new(), + new_dirs: Vec::new(), + } + } + + pub fn with_capacity( + note_capacity: usize, + new_files_capacity: usize, + new_dirs_capacity: usize, + ) -> Self { + Self { + temp_files: Vec::with_capacity(note_capacity), + noted: Vec::with_capacity(note_capacity), + new_files: Vec::with_capacity(new_files_capacity), + new_dirs: Vec::with_capacity(new_dirs_capacity), + } + } + + pub fn note_file(&mut self, original: &Path) -> Result { + let temp_file = NamedTempFile::new()?; + std::fs::write(&temp_file, &std::fs::read_to_string(original)?)?; + let temp_file_path = temp_file.path().to_path_buf(); + self.temp_files.push(temp_file); + self.noted.push((temp_file_path.clone(), original.to_path_buf())); + Ok(temp_file_path) + } + + pub fn new_file(&mut self, file: &Path) -> Result<(), Error> { + File::create(file)?; + self.new_files.push(file.to_path_buf()); + Ok(()) + } + + pub fn new_dir(&mut self, dir: &Path) -> Result<(), Error> { + std::fs::create_dir(dir)?; + self.new_dirs.push(dir.to_path_buf()); + Ok(()) + } + + pub fn noted_files(&self) -> Vec { + self.noted + .iter() + .map(|(_, original)| original.to_path_buf()) + .collect::>() + } + + pub fn new_files(&self) -> Vec { + self.new_files.clone() + } + + pub fn new_dirs(&self) -> Vec { + self.new_dirs.clone() + } + + pub fn commit(self) { + self.noted.into_iter().for_each(|(temp, original)| { + std::fs::write( + original, + std::fs::read_to_string(temp) + .expect("The temp file exists as long as Self exists; qed"), + ) + .expect("The original file exists; qed;") + }); + } + + pub fn rollback(self) { + self.new_files.into_iter().for_each(|file| { + std::fs::remove_file(&file).expect("The file exists cause it's in the rollback; qed;") + }); + self.new_dirs.into_iter().for_each(|dir| { + std::fs::remove_dir_all(&dir).expect("Thee dir exists cause it's in the rollback; qed;") + }); + } + + pub fn ok_or_rollback(self, result: Result) -> Result<(Self, S), E> { + match result { + Ok(result) => Ok((self, result)), + Err(err) => { + self.rollback(); + Err(err) + }, + } + } +} diff --git a/crates/pop-common/src/rust_writer.rs b/crates/pop-common/src/rust_writer.rs index 452ce870a..de7beecae 100644 --- a/crates/pop-common/src/rust_writer.rs +++ b/crates/pop-common/src/rust_writer.rs @@ -1,12 +1,6 @@ // SPDX-License-Identifier: GPL-3.0 -use crate::{ - capitalize_str, - manifest::{ - add_crate_to_dependencies, find_crate_manifest, find_crate_name, types::CrateDependencie, - }, - Error, -}; +use crate::{capitalize_str, Error}; use prettyplease::unparse; use proc_macro2::Span; use std::{ @@ -45,19 +39,20 @@ pub fn update_config_trait( } pub fn add_type_to_runtimes( - pallet_path: &Path, type_name: Ident, runtime_value: Type, pallet_impl_path: Option, + pallet_mock_path: &Path, + pallet_crate_name: &str, ) -> Result<(), Error> { fn do_add_type_to_runtime( file_content: &str, file_path: &Path, - pallet_manifest_path: &Path, type_name: Ident, runtime_value: Type, + pallet_crate_name: &str, ) -> Result<(), Error> { - let pallet_name = find_crate_name(pallet_manifest_path)?.replace("-", "_"); + let pallet_name = pallet_crate_name.replace("-", "_"); let preserver = types::Preserver::new(&format!("impl {}::Config", pallet_name)); let mut ast = preserver::preserve_and_parse(file_content.to_string(), vec![preserver])?; @@ -81,17 +76,14 @@ pub fn add_type_to_runtimes( Ok(()) } - let src = pallet_path.join("src"); - let pallet_manifest_path = pallet_path.join("Cargo.toml"); // All pallets should have a mock runtime, so we add the type to it. - let mock_path = src.join("mock.rs"); - let mock_content = fs::read_to_string(&mock_path)?; + let mock_content = fs::read_to_string(&pallet_mock_path)?; do_add_type_to_runtime( &mock_content, - &mock_path, - &pallet_manifest_path, + &pallet_mock_path, type_name.clone(), runtime_value.clone(), + pallet_crate_name, )?; // If the pallet is contained inside a runtime add the type to that runtime as well @@ -100,9 +92,9 @@ pub fn add_type_to_runtimes( do_add_type_to_runtime( &pallet_impl_content, &pallet_impl_path, - &pallet_manifest_path, type_name, runtime_value, + pallet_crate_name, )?; } Ok(()) @@ -173,7 +165,6 @@ pub fn add_type_to_config_preludes( pub fn add_pallet_to_runtime_module( pallet_name: &str, runtime_lib_path: &Path, - pallet_dependencie_type: CrateDependencie, ) -> Result<(), Error> { let preserver_construct_runtime = types::Preserver::new("construct_runtime!"); let preserver_mod_runtime = types::Preserver::new("mod runtime"); @@ -181,7 +172,6 @@ pub fn add_pallet_to_runtime_module( fs::read_to_string(runtime_lib_path)?, vec![preserver_construct_runtime, preserver_mod_runtime], )?; - // Parse the runtime to find which of the runtime macros is being used and the highest // pallet index used (if needed, otherwise 0). let used_macro = parse::find_used_runtime_macro(&ast)?; @@ -224,12 +214,6 @@ pub fn add_pallet_to_runtime_module( )) })?; - // Update the crate's manifest to add the pallet crate - let runtime_manifest = find_crate_manifest(runtime_lib_path) - .expect("Runtime is a crate, so it contains a manifest; qed;"); - - add_crate_to_dependencies(&runtime_manifest, pallet_name, pallet_dependencie_type)?; - Ok(()) } @@ -273,9 +257,13 @@ pub fn add_pallet_impl_block_to_runtime( } pub fn add_use_statements(file_path: &Path, use_statements: Vec) -> Result<(), Error> { - // Preserve the first use statement to insert the new one where they're - let preserver = types::Preserver::new("use"); - let mut ast = preserver::preserve_and_parse(fs::read_to_string(file_path)?, vec![preserver])?; + // Preserve the first use/pub use statement to insert the new one where they're + let preserver_use = types::Preserver::new("use"); + let preserver_pub_use = types::Preserver::new("pub use"); + let mut ast = preserver::preserve_and_parse( + fs::read_to_string(file_path)?, + vec![preserver_use, preserver_pub_use], + )?; use_statements.into_iter().for_each(|use_statement| { if !parse::find_use_statement(&ast, &use_statement) { @@ -293,9 +281,13 @@ pub fn add_use_statements(file_path: &Path, use_statements: Vec) -> Res } pub fn add_mod_declarations(file_path: &Path, mod_declarations: Vec) -> Result<(), Error> { - // Preserve the first mod declaration to insert the new one where they're - let preserver = types::Preserver::new("mod"); - let mut ast = preserver::preserve_and_parse(fs::read_to_string(file_path)?, vec![preserver])?; + // Preserve the first mod/pub mod declaration to insert the new one where they're + let preserver_mod = types::Preserver::new("mod"); + let preserver_pub_mod = types::Preserver::new("pub mod"); + let mut ast = preserver::preserve_and_parse( + fs::read_to_string(file_path)?, + vec![preserver_mod, preserver_pub_mod], + )?; mod_declarations .into_iter() diff --git a/crates/pop-common/src/rust_writer/parse.rs b/crates/pop-common/src/rust_writer/parse.rs index c940a9ff8..15a4195e7 100644 --- a/crates/pop-common/src/rust_writer/parse.rs +++ b/crates/pop-common/src/rust_writer/parse.rs @@ -76,16 +76,7 @@ pub(crate) fn find_highest_pallet_index(ast: &File) -> Result Result { for item in &ast.items { match item { - Item::Mod(ItemMod { ident, attrs, .. }) - if *ident == "runtime" && - attrs.iter().any(|attribute| { - if let Meta::Path(Path { segments, .. }) = &attribute.meta { - segments.iter().any(|segment| segment.ident == "runtime") - } else { - false - } - }) => - { + Item::Mod(ItemMod { ident, .. }) if *ident == "runtime" => { return Ok(RuntimeUsedMacro::Runtime); }, Item::Macro(ItemMacro { mac: Macro { path: Path { segments, .. }, .. }, .. }) diff --git a/crates/pop-common/src/rust_writer/preserver.rs b/crates/pop-common/src/rust_writer/preserver.rs index e3321e62c..d4219e5ad 100644 --- a/crates/pop-common/src/rust_writer/preserver.rs +++ b/crates/pop-common/src/rust_writer/preserver.rs @@ -16,22 +16,66 @@ pub(crate) fn preserve_and_parse(code: String, preservers: Vec) -> Re } pub(crate) fn resolve_preserved(code: String) -> String { - // Inside non-preserved declarative macros invocations, everything is a token so the doc - // comments became #[doc] in order to preserve them (tokens doesn't accept doc comments). - // ///TEMP_DOC comments became #[doc = "TEMP_DOC"] which are 4 tokens in the AST. When the - // AST is converted to a String, new line characters can appear in the middle of any of those - // tokens, so to properly convert them in a new line we can use regex. - // As the #[doc] attribute may be present anywhere, be sure to keep spaces before and after the - // comment to don't leave commented some lines of code. - let re = - Regex::new(r#"#\s*\[\s*doc\s*=\s*"TEMP_DOC(.*?)"\s*\]"#).expect("The regex is valid;qed;"); - let code = re.replace_all(&code, |caps: &Captures| format!("\n{}\n", &caps[1])).to_string(); - // Same happens with 'type temp_marker = ();'. This lines also delete them from everywhere, not - // just inside declarative macros - let re = Regex::new(r"type\s+temp_marker\s*=\s*\(\);\s*").expect("The regex is valid; qed;"); - let code = re.replace_all(&code, "\n").to_string(); - // Delete all TEMP_DOCS present in the rest of the code and return the result. - code.replace("///TEMP_DOC", "") + // Inside non-preserved declarative macros invocations, everything is a token and hence it + // should be managed carefully. We capture all the macro invocations and apply regex to those + // pieces of code to properly resolve them. + let mut delimiters_counts = DelimitersCount::new(); + let mut lines = code.lines(); + + // We'll reduce lines, so this capacity is a max bond on the result + let mut macro_cleaned_code: Vec = Vec::with_capacity(code.lines().count()); + let mut macro_content = String::new(); + + let macro_invocation_matcher = + Regex::new(r"\w+!\s*[\{\(\[]").expect("The regex is valid; qed;"); + + // Inside declarative macros, doc comments became #[doc] in order to preserve them (tokens + // doesn't accept doc comments). ///TEMP_DOC comments became #[doc = "TEMP_DOC(something)"] + // which are 4 tokens in the AST. When the AST is converted to a String, new line characters + // can appear in the middle of any of those tokens, so to properly convert them in a new line + // we can use regex. As the #[doc] attribute may be present anywhere, be sure to keep spaces + // before and after the comment to don't leave commented some lines of code. + let macro_docs_matcher = Regex::new(r#"#\s*\[\s*doc\s*=\s*"TEMP_DOC([\\t]*)(.*?)"\s*\]"#) + .expect("The regex is valid; qed;"); + // Same happens with 'type temp_marker = ();'. + let temp_marker_matcher = + Regex::new(r"type\s+temp_marker\s*=\s*\(\);\s*").expect("The regex is valid; qed;"); + + while let Some(line) = lines.next() { + // We're noting the content of a macro + if !macro_content.is_empty() && !delimiters_counts.is_complete() { + delimiters_counts.count(line); + macro_content.push_str(line); + macro_content.push_str("\n"); + // Start noting the content of a macro + } else if macro_invocation_matcher.is_match(&line) { + delimiters_counts.count(line); + macro_content.push_str(line); + macro_content.push_str("\n"); + // macro_content contains the whole macro, so we preserve it and push it, together with + // the new line to the cleaned code + } else if delimiters_counts.is_complete() { + let docs_resolved_code = macro_docs_matcher + .replace_all(¯o_content, |caps: &Captures| format!("\n{}\n", &caps[2])) + .to_string(); + + macro_cleaned_code + .push(temp_marker_matcher.replace_all(&docs_resolved_code, "\n").to_string()); + macro_cleaned_code.push(line.to_owned()); + macro_cleaned_code.push("\n".to_owned()); + + macro_content.clear(); + } else { + macro_cleaned_code.push(line.to_owned()); + macro_cleaned_code.push("\n".to_owned()); + } + } + + // Delete all TEMP_DOCS and temp_marker present in the rest of the code and return the result. + macro_cleaned_code + .join("") + .replace("///TEMP_DOC", "") + .replace("type temp_marker = ();\n", "") } fn apply_preservers(code: String, mut preservers: Vec) -> String { From fb68d9929f8d9c56e1375aa7358bda6a27cdbc09 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1s=20Senovilla=20Polo?= Date: Wed, 26 Mar 2025 19:22:41 +0100 Subject: [PATCH 35/46] Integrate functionality from new extern crates; Integration tests --- Cargo.lock | 394 ++++++---- Cargo.toml | 7 +- crates/pop-cli/Cargo.toml | 8 +- .../src/commands/add/pallet_config_type.rs | 360 +++++---- .../add/pallet_config_type/common_types.rs | 103 ++- .../src/commands/add/runtime_pallet.rs | 301 +++++--- .../add/runtime_pallet/common_pallets.rs | 83 +- crates/pop-cli/src/commands/new/contract.rs | 4 +- crates/pop-cli/src/commands/new/pallet.rs | 248 ++++-- .../new_pallet_added_to_existing_runtime.rs | 100 +++ .../tests/pop_add_to_pallet_config_type.rs | 229 ++++++ .../tests/pop_add_to_runtime_pallet.rs | 243 ++++++ crates/pop-common/Cargo.toml | 7 +- crates/pop-common/src/errors.rs | 6 +- crates/pop-common/src/helpers.rs | 55 +- crates/pop-common/src/lib.rs | 14 +- crates/pop-common/src/manifest.rs | 257 +------ crates/pop-common/src/manifest/types.rs | 10 - crates/pop-common/src/rollback.rs | 110 --- crates/pop-common/src/rust_writer.rs | 323 -------- crates/pop-common/src/rust_writer/expand.rs | 277 ------- .../src/rust_writer/expand/tests.rs | 713 ------------------ crates/pop-common/src/rust_writer/parse.rs | 134 ---- .../pop-common/src/rust_writer/preserver.rs | 148 ---- .../src/rust_writer/preserver/tests.rs | 3 - crates/pop-common/src/rust_writer/tests.rs | 3 - .../basic_pallet_with_composite_enum.rs | 36 - .../basic_pallet_with_config_preludes.rs | 85 --- .../sample_files/outer_config_preludes.rs | 55 -- .../src/rust_writer/tests/test_builder.rs | 47 -- crates/pop-common/src/rust_writer/types.rs | 77 -- crates/pop-common/src/rust_writer_helpers.rs | 249 ++++++ .../sample_files/basic_pallet.rs | 0 .../runtime_using_construct_runtime_macro.rs | 0 .../runtime_using_runtime_macro.rs | 0 .../parse => rust_writer_helpers}/tests.rs | 93 ++- 36 files changed, 1877 insertions(+), 2905 deletions(-) create mode 100644 crates/pop-cli/tests/new_pallet_added_to_existing_runtime.rs create mode 100644 crates/pop-cli/tests/pop_add_to_pallet_config_type.rs create mode 100644 crates/pop-cli/tests/pop_add_to_runtime_pallet.rs delete mode 100644 crates/pop-common/src/manifest/types.rs delete mode 100644 crates/pop-common/src/rollback.rs delete mode 100644 crates/pop-common/src/rust_writer.rs delete mode 100644 crates/pop-common/src/rust_writer/expand.rs delete mode 100644 crates/pop-common/src/rust_writer/expand/tests.rs delete mode 100644 crates/pop-common/src/rust_writer/parse.rs delete mode 100644 crates/pop-common/src/rust_writer/preserver.rs delete mode 100644 crates/pop-common/src/rust_writer/preserver/tests.rs delete mode 100644 crates/pop-common/src/rust_writer/tests.rs delete mode 100644 crates/pop-common/src/rust_writer/tests/sample_files/basic_pallet_with_composite_enum.rs delete mode 100644 crates/pop-common/src/rust_writer/tests/sample_files/basic_pallet_with_config_preludes.rs delete mode 100644 crates/pop-common/src/rust_writer/tests/sample_files/outer_config_preludes.rs delete mode 100644 crates/pop-common/src/rust_writer/tests/test_builder.rs delete mode 100644 crates/pop-common/src/rust_writer/types.rs create mode 100644 crates/pop-common/src/rust_writer_helpers.rs rename crates/pop-common/src/{rust_writer/tests => rust_writer_helpers}/sample_files/basic_pallet.rs (100%) rename crates/pop-common/src/{rust_writer/tests => rust_writer_helpers}/sample_files/runtime_using_construct_runtime_macro.rs (100%) rename crates/pop-common/src/{rust_writer/tests => rust_writer_helpers}/sample_files/runtime_using_runtime_macro.rs (100%) rename crates/pop-common/src/{rust_writer/parse => rust_writer_helpers}/tests.rs (60%) diff --git a/Cargo.lock b/Cargo.lock index 94043b18a..97d89f243 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -77,7 +77,7 @@ version = "0.7.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "891477e0c6a8957309ee5c45a6368af3ae14bb510732d2684ffa19af310920f9" dependencies = [ - "getrandom", + "getrandom 0.2.15", "once_cell", "version_check", ] @@ -89,7 +89,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011" dependencies = [ "cfg-if", - "getrandom", + "getrandom 0.2.15", "once_cell", "version_check", "zerocopy", @@ -152,7 +152,7 @@ dependencies = [ "proc-macro-error", "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.100", "syn-solidity", "tiny-keccak", ] @@ -268,7 +268,7 @@ dependencies = [ "proc-macro-error", "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.100", ] [[package]] @@ -652,7 +652,7 @@ dependencies = [ "proc-macro2", "quote", "serde", - "syn 2.0.90", + "syn 2.0.100", ] [[package]] @@ -889,7 +889,7 @@ checksum = "c7c24de15d275a1ecfd47a380fb4d5ec9bfe0933f309ed5e705b775596a3574d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.100", ] [[package]] @@ -906,7 +906,7 @@ checksum = "721cae7de5c34fbb2acd27e21e6d2cf7b886dce0c27388d46c4e6c47ea4318dd" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.100", ] [[package]] @@ -929,7 +929,7 @@ checksum = "3c87f3f15e7794432337fc718554eaa4dc8f04c9677a950ffe366f20a162ae42" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.100", ] [[package]] @@ -999,7 +999,7 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b62ddb9cb1ec0a098ad4bbf9344d0713fa193ae1a80af55febcff2627b6a00c1" dependencies = [ - "getrandom", + "getrandom 0.2.15", "instant", "rand", ] @@ -1258,7 +1258,7 @@ dependencies = [ "serde_json", "serde_repr", "serde_urlencoded", - "thiserror 2.0.8", + "thiserror 2.0.11", "tokio", "tokio-util", "tower-service", @@ -1297,7 +1297,7 @@ dependencies = [ "proc-macro-crate 3.2.0", "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.100", ] [[package]] @@ -1720,7 +1720,7 @@ dependencies = [ "semver 1.0.24", "serde", "serde_json", - "thiserror 2.0.8", + "thiserror 2.0.11", ] [[package]] @@ -1733,6 +1733,16 @@ dependencies = [ "toml 0.8.19", ] +[[package]] +name = "cargo_toml" +version = "0.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5fbd1fe9db3ebf71b89060adaf7b0504c2d6a425cf061313099547e382c2e472" +dependencies = [ + "serde", + "toml 0.8.19", +] + [[package]] name = "cc" version = "1.2.4" @@ -1837,7 +1847,7 @@ dependencies = [ "heck 0.5.0", "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.100", ] [[package]] @@ -1958,7 +1968,7 @@ version = "0.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f9d839f2a20b0aee515dc581a6172f2321f96cab76c1a38a4c584a194955390e" dependencies = [ - "getrandom", + "getrandom 0.2.15", "once_cell", "tiny-keccak", ] @@ -2113,7 +2123,7 @@ dependencies = [ "serde", "serde_json", "strsim 0.11.1", - "thiserror 2.0.8", + "thiserror 2.0.11", "tracing", ] @@ -2477,7 +2487,7 @@ dependencies = [ "proc-macro-crate 3.2.0", "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.100", ] [[package]] @@ -2722,7 +2732,7 @@ checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.100", ] [[package]] @@ -2750,7 +2760,7 @@ dependencies = [ "proc-macro2", "quote", "scratch", - "syn 2.0.90", + "syn 2.0.100", ] [[package]] @@ -2763,7 +2773,7 @@ dependencies = [ "codespan-reporting", "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.100", ] [[package]] @@ -2781,7 +2791,7 @@ dependencies = [ "proc-macro2", "quote", "rustversion", - "syn 2.0.90", + "syn 2.0.100", ] [[package]] @@ -2829,7 +2839,7 @@ dependencies = [ "proc-macro2", "quote", "strsim 0.11.1", - "syn 2.0.90", + "syn 2.0.100", ] [[package]] @@ -2851,7 +2861,7 @@ checksum = "d336a2a514f6ccccaa3e09b02d41d35330c07ddf03a62165fcec10bb561c7806" dependencies = [ "darling_core 0.20.10", "quote", - "syn 2.0.90", + "syn 2.0.100", ] [[package]] @@ -2919,7 +2929,7 @@ checksum = "d65d7ce8132b7c0e54497a4d9a55a1c2a0912a0d786cf894472ba818fba45762" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.100", ] [[package]] @@ -2930,7 +2940,7 @@ checksum = "62d671cc41a825ebabc75757b62d3d168c577f9149b2d49ece1dad1f72119d25" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.100", ] [[package]] @@ -2941,7 +2951,7 @@ checksum = "30542c1ad912e0e3d22a1935c290e12e8a29d704a420177a31faad4a601a0800" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.100", ] [[package]] @@ -2954,7 +2964,7 @@ dependencies = [ "proc-macro2", "quote", "rustc_version 0.4.1", - "syn 2.0.90", + "syn 2.0.100", ] [[package]] @@ -2974,7 +2984,7 @@ checksum = "cb7330aeadfbe296029522e6c40f315320aba36fc43a5b3632f3795348f3bd22" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.100", "unicode-xid", ] @@ -3067,7 +3077,7 @@ checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.100", ] [[package]] @@ -3097,7 +3107,7 @@ dependencies = [ "proc-macro2", "quote", "regex", - "syn 2.0.90", + "syn 2.0.100", "termcolor", "toml 0.8.19", "walkdir", @@ -3281,7 +3291,7 @@ checksum = "de0d48a183585823424a4ce1aa132d174a6a81bd540895822eb4c8373a8e49e8" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.100", ] [[package]] @@ -3292,7 +3302,7 @@ checksum = "2f9ed6b3789237c8a0c1c505af1c7eb2c560df6186f01b098c3a1064ea532f38" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.100", ] [[package]] @@ -3433,7 +3443,7 @@ dependencies = [ "prettyplease", "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.100", ] [[package]] @@ -3562,6 +3572,15 @@ dependencies = [ "miniz_oxide", ] +[[package]] +name = "float-cmp" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "98de4bbd547a563b716d8dfa9aad1cb19bfab00f4fa09a6a4ed21dbcf44ce9c4" +dependencies = [ + "num-traits", +] + [[package]] name = "fnv" version = "1.0.7" @@ -3661,7 +3680,7 @@ dependencies = [ "proc-macro-crate 3.2.0", "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.100", ] [[package]] @@ -3799,7 +3818,7 @@ dependencies = [ "proc-macro2", "quote", "sp-crypto-hashing", - "syn 2.0.90", + "syn 2.0.100", ] [[package]] @@ -3812,7 +3831,7 @@ dependencies = [ "proc-macro-crate 3.2.0", "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.100", ] [[package]] @@ -3823,7 +3842,7 @@ checksum = "ed971c6435503a099bdac99fe4c5bea08981709e5b5a0a8535a1856f48561191" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.100", ] [[package]] @@ -3894,6 +3913,17 @@ dependencies = [ "autocfg", ] +[[package]] +name = "fs_rollback" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3de930156615ed4eb3165da0bd81c0e5079d4e14a8a965bc56cfd7400f94f718" +dependencies = [ + "rustilities 1.1.0", + "tempfile", + "thiserror 2.0.11", +] + [[package]] name = "funty" version = "2.0.0" @@ -3970,7 +4000,7 @@ checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.100", ] [[package]] @@ -4037,7 +4067,19 @@ checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" dependencies = [ "cfg-if", "libc", - "wasi", + "wasi 0.11.0+wasi-snapshot-preview1", +] + +[[package]] +name = "getrandom" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43a49c392881ce6d5c3b8cb70f98717b7c07aabbdff06687b9030dbfbe2725f8" +dependencies = [ + "cfg-if", + "libc", + "wasi 0.13.3+wasi-0.2.2", + "windows-targets 0.52.6", ] [[package]] @@ -4732,7 +4774,7 @@ checksum = "1ec89e9337638ecdc08744df490b221a7399bf8d164eb52a665454e60e075ad6" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.100", ] [[package]] @@ -4815,7 +4857,7 @@ checksum = "a0eb5a3343abf848c0984fe4604b2b105da9539376e24fc0a3b0007411ae4fd9" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.100", ] [[package]] @@ -5444,7 +5486,7 @@ dependencies = [ "either", "futures", "futures-timer", - "getrandom", + "getrandom 0.2.15", "instant", "libp2p-allow-block-list", "libp2p-connection-limits", @@ -5659,7 +5701,7 @@ checksum = "edbe595006d355eaf9ae11db92707d4338cd2384d16866131cc1afdbdd35d8d9" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.100", ] [[package]] @@ -5741,7 +5783,7 @@ dependencies = [ "macro_magic_core", "macro_magic_macros", "quote", - "syn 2.0.90", + "syn 2.0.100", ] [[package]] @@ -5755,7 +5797,7 @@ dependencies = [ "macro_magic_core_macros", "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.100", ] [[package]] @@ -5766,7 +5808,7 @@ checksum = "b02abfe41815b5bd98dbd4260173db2c116dda171dc0fe7838cb206333b83308" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.100", ] [[package]] @@ -5777,7 +5819,7 @@ checksum = "73ea28ee64b88876bf45277ed9a5817c1817df061a74f2b988971a12570e5869" dependencies = [ "macro_magic_core", "quote", - "syn 2.0.90", + "syn 2.0.100", ] [[package]] @@ -5898,7 +5940,7 @@ checksum = "2886843bf800fba2e3377cff24abf6379b4c4d5c6681eaf9ea5b0d15090450bd" dependencies = [ "libc", "log", - "wasi", + "wasi 0.11.0+wasi-snapshot-preview1", "windows-sys 0.52.0", ] @@ -6064,6 +6106,12 @@ dependencies = [ "nom", ] +[[package]] +name = "normalize-line-endings" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61807f77802ff30975e01f4f071c8ba10c022052f98b3294119f3e615d13e5be" + [[package]] name = "nu-ansi-term" version = "0.46.0" @@ -6107,7 +6155,7 @@ checksum = "ed3955f1a9c7c0c15e092f9c887db08b1fc683305fdf6eb6684f22555355e202" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.100", ] [[package]] @@ -6242,7 +6290,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.100", ] [[package]] @@ -6894,7 +6942,7 @@ checksum = "94226cbd48516b7c310eb5dae8d50798c1ce73a7421dc0977c55b7fc2237a283" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.100", ] [[package]] @@ -7724,7 +7772,7 @@ checksum = "0cc16d1f7cee6a1ee6e8cd710e16230d59fb4935316c1704cf770e4d2335f8d4" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.100", ] [[package]] @@ -8507,7 +8555,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b7cafe60d6cf8e62e1b9b2ea516a089c008945bb5a275416789e7db0bc199dc" dependencies = [ "memchr", - "thiserror 2.0.8", + "thiserror 2.0.11", "ucd-trie", ] @@ -8531,7 +8579,7 @@ dependencies = [ "pest_meta", "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.100", ] [[package]] @@ -8562,7 +8610,7 @@ checksum = "3c0f5fad0874fc7abcd4d750e76917eaebbecaa2c20bde22e1dbeeba8beb758c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.100", ] [[package]] @@ -9156,7 +9204,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6380dbe1fb03ecc74ad55d841cfc75480222d153ba69ddcb00977866cbdabdb8" dependencies = [ "polkavm-derive-impl 0.5.0", - "syn 2.0.90", + "syn 2.0.100", ] [[package]] @@ -9195,7 +9243,7 @@ dependencies = [ "polkavm-common 0.5.0", "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.100", ] [[package]] @@ -9207,7 +9255,7 @@ dependencies = [ "polkavm-common 0.8.0", "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.100", ] [[package]] @@ -9219,7 +9267,7 @@ dependencies = [ "polkavm-common 0.9.0", "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.100", ] [[package]] @@ -9231,7 +9279,7 @@ dependencies = [ "polkavm-common 0.10.0", "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.100", ] [[package]] @@ -9241,7 +9289,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "15e85319a0d5129dc9f021c62607e0804f5fb777a05cdda44d750ac0732def66" dependencies = [ "polkavm-derive-impl 0.8.0", - "syn 2.0.90", + "syn 2.0.100", ] [[package]] @@ -9251,7 +9299,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8ba81f7b5faac81e528eb6158a6f3c9e0bb1008e0ffa19653bc8dea925ecb429" dependencies = [ "polkavm-derive-impl 0.9.0", - "syn 2.0.90", + "syn 2.0.100", ] [[package]] @@ -9261,7 +9309,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9324fe036de37c17829af233b46ef6b5562d4a0c09bb7fdb9f8378856dee30cf" dependencies = [ "polkavm-derive-impl 0.10.0", - "syn 2.0.90", + "syn 2.0.100", ] [[package]] @@ -9358,24 +9406,30 @@ dependencies = [ "dirs", "duct", "env_logger 0.11.5", + "fs_rollback", "git2", "open", "os_info", + "pathdiff", "pop-common", "pop-contracts", "pop-parachains", "pop-telemetry", + "predicates", "proc-macro2", "reqwest 0.12.9", + "rust_writer", + "rustilities 2.2.0", "serde", "serde_json", + "similar", "sp-core 32.0.0", "sp-weights", "strum 0.26.3", "strum_macros 0.26.4", "subxt", "subxt-signer", - "syn 2.0.90", + "syn 2.0.100", "tempfile", "tokio", "tower-http 0.6.2", @@ -9387,20 +9441,21 @@ name = "pop-common" version = "0.6.0" dependencies = [ "anyhow", - "cargo_toml", + "cargo_toml 0.20.5", "contract-build", "contract-extrinsics", "duct", "flate2", + "fs_rollback", "git2", "git2_credentials", "ink_env", "mockito", - "pathdiff", - "prettyplease", "proc-macro2", "regex", "reqwest 0.12.9", + "rust_writer", + "rustilities 2.2.0", "scale-info", "serde", "serde_json", @@ -9408,13 +9463,13 @@ dependencies = [ "strum_macros 0.26.4", "subxt", "subxt-signer", - "syn 2.0.90", + "syn 2.0.100", "tar", "tempfile", "thiserror 1.0.69", "tokio", "toml 0.5.11", - "toml_edit 0.22.22", + "toml_edit 0.22.24", "url", ] @@ -9465,13 +9520,13 @@ dependencies = [ "subxt", "subxt-signer", "symlink", - "syn 2.0.90", + "syn 2.0.100", "tar", "tempfile", "thiserror 1.0.69", "tokio", "tokio-test", - "toml_edit 0.22.22", + "toml_edit 0.22.24", "url", "walkdir", "zombienet-sdk", @@ -9522,7 +9577,10 @@ checksum = "7e9086cc7640c29a356d1a29fd134380bee9d8f79a17410aa76e7ad295f42c97" dependencies = [ "anstyle", "difflib", + "float-cmp", + "normalize-line-endings", "predicates-core", + "regex", ] [[package]] @@ -9543,12 +9601,12 @@ dependencies = [ [[package]] name = "prettyplease" -version = "0.2.25" +version = "0.2.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64d1ec885c64d0457d564db4ec299b2dae3f9c02808b8ad9c3a089c591b18033" +checksum = "5316f57387668042f561aae71480de936257848f9c43ce528e311d89a07cadeb" dependencies = [ "proc-macro2", - "syn 2.0.90", + "syn 2.0.100", ] [[package]] @@ -9594,7 +9652,7 @@ version = "3.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8ecf48c7ca261d60b74ab1a7b20da18bede46776b2e55535cb958eb595c5fa7b" dependencies = [ - "toml_edit 0.22.22", + "toml_edit 0.22.24", ] [[package]] @@ -9640,7 +9698,7 @@ dependencies = [ "proc-macro-error-attr2", "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.100", ] [[package]] @@ -9651,14 +9709,14 @@ checksum = "834da187cfe638ae8abb0203f0b33e5ccdb02a28e7199f2f47b3e2754f50edca" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.100", ] [[package]] name = "proc-macro2" -version = "1.0.92" +version = "1.0.94" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37d3544b3f2748c54e147655edb5025752e2303145b5aefb3c3ea2c78b973bb0" +checksum = "a31971752e70b8b2686d7e46ec17fb38dad4051d94024c88df49b667caea9c84" dependencies = [ "unicode-ident", ] @@ -9729,9 +9787,9 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.37" +version = "1.0.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" +checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d" dependencies = [ "proc-macro2", ] @@ -9775,7 +9833,7 @@ version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" dependencies = [ - "getrandom", + "getrandom 0.2.15", ] [[package]] @@ -9828,7 +9886,7 @@ version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ba009ff324d1fc1b900bd1fdb31564febe58a8ccc8a6fdbb93b543d33b13ca43" dependencies = [ - "getrandom", + "getrandom 0.2.15", "libredox", "thiserror 1.0.69", ] @@ -9850,7 +9908,7 @@ checksum = "bcc303e793d3734489387d205e9b186fac9c6cfacedd98cbb2e8a5943595f3e6" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.100", ] [[package]] @@ -10032,7 +10090,7 @@ checksum = "c17fa4cb658e3583423e915b9f3acc01cceaee1860e33d59ebae66adc3a2dc0d" dependencies = [ "cc", "cfg-if", - "getrandom", + "getrandom 0.2.15", "libc", "spin", "untrusted", @@ -10149,6 +10207,33 @@ dependencies = [ "serde_json", ] +[[package]] +name = "rust_writer" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf4bb56f2de882403080044bd15dbafbdceb5437580638da25d257de8fbd86e" +dependencies = [ + "prettyplease", + "proc-macro2", + "regex", + "rust_writer_proc", + "rustilities 2.2.0", + "syn 2.0.100", + "thiserror 2.0.11", +] + +[[package]] +name = "rust_writer_proc" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "54abd3b6b8f7e68143a45c862405827fc453433e46c5d892d59421607bea8074" +dependencies = [ + "proc-macro2", + "quote", + "rustilities 2.2.0", + "syn 2.0.100", +] + [[package]] name = "rustc-demangle" version = "0.1.24" @@ -10200,6 +10285,28 @@ dependencies = [ "semver 1.0.24", ] +[[package]] +name = "rustilities" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bfbd7c1a4f912953f84295e1a6119d3800d87a3555454241fbdaa1f48cfe344" +dependencies = [ + "thiserror 2.0.11", +] + +[[package]] +name = "rustilities" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d049a83871f271465eba32e54bc8b9342795ac9675015dd9891938e6fec7f75" +dependencies = [ + "cargo_toml 0.21.0", + "proc-macro2", + "syn 2.0.100", + "thiserror 2.0.11", + "toml_edit 0.22.24", +] + [[package]] name = "rustix" version = "0.36.17" @@ -10585,7 +10692,7 @@ dependencies = [ "darling 0.20.10", "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.100", ] [[package]] @@ -10639,7 +10746,7 @@ dependencies = [ "proc-macro-crate 3.2.0", "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.100", ] [[package]] @@ -10666,7 +10773,7 @@ dependencies = [ "proc-macro-crate 3.2.0", "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.100", ] [[package]] @@ -10697,7 +10804,7 @@ dependencies = [ "proc-macro2", "quote", "scale-info", - "syn 2.0.90", + "syn 2.0.100", "thiserror 1.0.69", ] @@ -10751,7 +10858,7 @@ dependencies = [ "proc-macro2", "quote", "serde_derive_internals", - "syn 2.0.90", + "syn 2.0.100", ] [[package]] @@ -11016,7 +11123,7 @@ checksum = "46f859dbbf73865c6627ed570e78961cd3ac92407a2d117204c49232485da55e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.100", ] [[package]] @@ -11027,7 +11134,7 @@ checksum = "18d26a20a969b9e3fdf2fc2d9f21eda6c40e2de84c9408bb5d3b05d499aae711" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.100", ] [[package]] @@ -11061,7 +11168,7 @@ checksum = "6c64451ba24fc7a6a2d60fc75dd9c83c90903b19028d4eff35e88fc1e86564e9" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.100", ] [[package]] @@ -11262,9 +11369,9 @@ checksum = "e3a9fe34e3e7a50316060351f37187a3f546bce95496156754b601a5fa71b76e" [[package]] name = "similar" -version = "2.6.0" +version = "2.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1de1d4f81173b03af4c0cbed3c898f6bff5b870e4a7f5d6f4057d62a7a4b686e" +checksum = "bbbb5d9659141646ae647b42fe094daf6c6192d1620870b449d9557f748b2daa" [[package]] name = "simple-mermaid" @@ -11808,7 +11915,7 @@ dependencies = [ "proc-macro-crate 3.2.0", "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.100", ] [[package]] @@ -12171,7 +12278,7 @@ checksum = "b85d0f1f1e44bd8617eb2a48203ee854981229e3e79e6f468c7175d5fd37489b" dependencies = [ "quote", "sp-crypto-hashing", - "syn 2.0.90", + "syn 2.0.100", ] [[package]] @@ -12182,7 +12289,7 @@ checksum = "48d09fa0a5f7299fb81ee25ae3853d26200f7a348148aed6de76be905c007dbe" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.100", ] [[package]] @@ -12545,7 +12652,7 @@ dependencies = [ "proc-macro-crate 3.2.0", "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.100", ] [[package]] @@ -12829,7 +12936,7 @@ dependencies = [ "parity-scale-codec", "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.100", ] [[package]] @@ -13098,7 +13205,7 @@ dependencies = [ "proc-macro2", "quote", "rustversion", - "syn 2.0.90", + "syn 2.0.100", ] [[package]] @@ -13204,7 +13311,7 @@ dependencies = [ "scale-info", "scale-typegen", "subxt-metadata", - "syn 2.0.90", + "syn 2.0.100", "thiserror 1.0.69", ] @@ -13267,7 +13374,7 @@ dependencies = [ "scale-typegen", "subxt-codegen", "subxt-utils-fetchmetadata", - "syn 2.0.90", + "syn 2.0.100", ] [[package]] @@ -13341,9 +13448,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.90" +version = "2.0.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "919d3b74a5dd0ccd15aeb8f93e7006bd9e14c295087c9896a110f490752bcf31" +checksum = "b09a44accad81e1ba1cd74a32461ba89dee89095ba17b32f5d03683b1b1fc2a0" dependencies = [ "proc-macro2", "quote", @@ -13359,7 +13466,7 @@ dependencies = [ "paste", "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.100", ] [[package]] @@ -13397,7 +13504,7 @@ checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.100", ] [[package]] @@ -13467,12 +13574,13 @@ checksum = "61c41af27dd6d1e27b1b16b489db798443478cef1f06a660c96db617ba5de3b1" [[package]] name = "tempfile" -version = "3.14.0" +version = "3.17.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28cce251fcbc87fac86a866eeb0d6c2d536fc16d06f184bb61aeae11aa4cee0c" +checksum = "22e5a0acb1f3f55f65cc4a866c361b2fb2a0ff6366785ae6fbb5f85df07ba230" dependencies = [ "cfg-if", "fastrand", + "getrandom 0.3.1", "once_cell", "rustix 0.38.42", "windows-sys 0.59.0", @@ -13541,11 +13649,11 @@ dependencies = [ [[package]] name = "thiserror" -version = "2.0.8" +version = "2.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08f5383f3e0071702bf93ab5ee99b52d26936be9dedd9413067cbdcddcb6141a" +checksum = "d452f284b73e6d76dd36758a0c8684b1d5be31f92b89d07fd5822175732206fc" dependencies = [ - "thiserror-impl 2.0.8", + "thiserror-impl 2.0.11", ] [[package]] @@ -13556,18 +13664,18 @@ checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.100", ] [[package]] name = "thiserror-impl" -version = "2.0.8" +version = "2.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2f357fcec90b3caef6623a099691be676d033b40a058ac95d2a6ade6fa0c943" +checksum = "26afc1baea8a989337eeb52b6e72a039780ce45c3edfcc9c5b9d112feeb173c2" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.100", ] [[package]] @@ -13681,7 +13789,7 @@ checksum = "693d596312e88961bc67d7f1f97af8a70227d9f90c31bba5806eec004978d752" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.100", ] [[package]] @@ -13795,7 +13903,7 @@ dependencies = [ "serde", "serde_spanned", "toml_datetime", - "toml_edit 0.22.22", + "toml_edit 0.22.24", ] [[package]] @@ -13822,15 +13930,15 @@ dependencies = [ [[package]] name = "toml_edit" -version = "0.22.22" +version = "0.22.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ae48d6208a266e853d946088ed816055e556cc6028c5e8e2b84d9fa5dd7c7f5" +checksum = "17b4795ff5edd201c7cd6dca065ae59972ce77d1b80fa0a84d94950ece7d1474" dependencies = [ "indexmap 2.7.0", "serde", "serde_spanned", "toml_datetime", - "winnow 0.6.20", + "winnow 0.7.4", ] [[package]] @@ -13944,7 +14052,7 @@ checksum = "395ae124c09f9e6918a2310af6038fba074bcf474ac352496d5910dd59a2226d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.100", ] [[package]] @@ -14276,7 +14384,7 @@ version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f8c5f0a0af699448548ad1a2fbf920fb4bee257eae39953ba95cb84891a0446a" dependencies = [ - "getrandom", + "getrandom 0.2.15", ] [[package]] @@ -14371,6 +14479,15 @@ version = "0.11.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" +[[package]] +name = "wasi" +version = "0.13.3+wasi-0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26816d2e1a4a36a2940b96c5296ce403917633dff8f3440e9b236ed6f6bacad2" +dependencies = [ + "wit-bindgen-rt", +] + [[package]] name = "wasm-bindgen" version = "0.2.99" @@ -14392,7 +14509,7 @@ dependencies = [ "log", "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.100", "wasm-bindgen-shared", ] @@ -14427,7 +14544,7 @@ checksum = "30d7a95b763d3c45903ed6c81f156801839e5ee968bb07e534c44df0fcd330c2" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.100", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -15128,9 +15245,9 @@ dependencies = [ [[package]] name = "winnow" -version = "0.6.20" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "36c1fec1a2bb5866f07c25f68c26e565c4c200aebb96d7e55710c19d3e8ac49b" +checksum = "0e97b544156e9bebe1a0ffbc03484fc1ffe3100cbce3ffb17eac35f7cdd7ab36" dependencies = [ "memchr", ] @@ -15151,6 +15268,15 @@ version = "0.0.19" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d135d17ab770252ad95e9a872d365cf3090e3be864a34ab46f48555993efc904" +[[package]] +name = "wit-bindgen-rt" +version = "0.33.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3268f3d866458b787f390cf61f4bbb563b922d091359f9608842999eaee3943c" +dependencies = [ + "bitflags 2.6.0", +] + [[package]] name = "write16" version = "1.0.0" @@ -15204,7 +15330,7 @@ dependencies = [ "Inflector", "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.100", ] [[package]] @@ -15216,7 +15342,7 @@ dependencies = [ "Inflector", "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.100", ] [[package]] @@ -15289,7 +15415,7 @@ checksum = "2380878cad4ac9aac1e2435f3eb4020e8374b5f13c296cb75b4620ff8e229154" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.100", "synstructure 0.13.1", ] @@ -15311,7 +15437,7 @@ checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.100", ] [[package]] @@ -15331,7 +15457,7 @@ checksum = "595eed982f7d355beb85837f651fa22e90b3c044842dc7f2c2842c086f295808" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.100", "synstructure 0.13.1", ] @@ -15352,7 +15478,7 @@ checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.100", ] [[package]] @@ -15374,7 +15500,7 @@ checksum = "6eafa6dfb17584ea3e2bd6e76e0cc15ad7af12b09abdd1ca55961bed9b1063c6" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.100", ] [[package]] @@ -15389,7 +15515,7 @@ dependencies = [ "displaydoc", "indexmap 2.7.0", "memchr", - "thiserror 2.0.8", + "thiserror 2.0.11", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index 6e8bd322f..f48539ae0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -28,19 +28,20 @@ dirs = "5.0" duct = "0.13" env_logger = "0.11.1" flate2 = "1.0.30" +fs_rollback = "2.0.0" git2 = { version = "0.18", features = ["vendored-openssl"] } glob = "0.3.1" log = "0.4.20" mockito = "1.4.0" pathdiff = "0.2.1" -predicates = "3.1.0" -prettyplease = "0.2.22" proc-macro2 = "1.0.86" +rustilities = "2.1.0" +rust_writer = "1.0.4" +syn = "2.0.100" tar = "0.4.40" tempfile = "3.10" thiserror = "1.0.58" tokio-test = "0.4.4" -syn = { version = "2.0.77", features = ["full", "extra-traits"]} toml = "0.5.0" # networking diff --git a/crates/pop-cli/Cargo.toml b/crates/pop-cli/Cargo.toml index c40afe14d..b88309fee 100644 --- a/crates/pop-cli/Cargo.toml +++ b/crates/pop-cli/Cargo.toml @@ -16,12 +16,16 @@ path = "src/main.rs" anyhow.workspace = true duct.workspace = true env_logger.workspace = true +fs_rollback.workspace = true os_info.workspace = true +pathdiff.workspace = true proc-macro2.workspace = true reqwest.workspace = true +rustilities = { workspace = true, features = ["paths", "fmt", "manifest"]} +rust_writer.workspace = true serde = { workspace = true, features = ["derive"] } serde_json.workspace = true -syn.workspace = true +syn = { workspace = true, features = ["parsing"] } tempfile.workspace = true tokio.workspace = true url.workspace = true @@ -60,6 +64,8 @@ contract-extrinsics.workspace = true subxt.workspace = true subxt-signer.workspace = true sp-weights.workspace = true +similar = "2.7.0" +predicates = "3.0.3" [features] default = ["contract", "parachain", "telemetry"] diff --git a/crates/pop-cli/src/commands/add/pallet_config_type.rs b/crates/pop-cli/src/commands/add/pallet_config_type.rs index afd48c029..6a79fe5ee 100644 --- a/crates/pop-cli/src/commands/add/pallet_config_type.rs +++ b/crates/pop-cli/src/commands/add/pallet_config_type.rs @@ -8,19 +8,26 @@ use crate::{ }; use clap::{error::ErrorKind, Args, Command}; use cliclack::multiselect; -use pop_common::{ - capitalize_str, find_workspace_toml, format_dir, manifest, prefix_with_current_dir_if_needed, - rust_writer::{self, types::*}, - Rollback, -}; -use proc_macro2::Span; -use std::{ - env, fs, - path::PathBuf, - sync::{Arc, Mutex}, +use fs_rollback::Rollback; +use pop_common::{manifest, rust_writer_helpers::DefaultConfigType}; +use rust_writer::{ + ast::{ + finder, + finder::{Finder, ToFind}, + implementors::{ItemToFile, ItemToImpl, ItemToMod, ItemToTrait}, + mutator, + mutator::{Mutator, ToMutate}, + }, + preserver::Preserver, }; +use std::{env, fs, path::PathBuf}; use strum::{EnumMessage, IntoEnumIterator}; -use syn::{parse_quote, Ident}; +use syn::{parse_quote, visit_mut::VisitMut}; + +#[mutator(ItemToImpl<'a>, ItemToImpl<'a>, ItemToImpl<'a>, ItemToImpl<'a>)] +#[finder(ItemToImpl<'a>, ItemToImpl<'a>, ItemToImpl<'a>, ItemToImpl<'a>)] +#[impl_from] +struct DefaultConfigsImplementor; #[derive(Args, Debug, Clone)] pub struct AddConfigTypeCommand { @@ -45,14 +52,14 @@ impl AddConfigTypeCommand { let mut cmd = Command::new(""); let pallet_path = if let Some(path) = &self.pallet_path { - prefix_with_current_dir_if_needed(path.to_path_buf()) + rustilities::paths::prefix_with_current_dir(path) } else { // If not provided, use the working dir let working_dir = match env::current_dir() { Ok(working_dir) => working_dir, _ => cmd.error(ErrorKind::Io, "Cannot modify the working crate").exit(), }; - prefix_with_current_dir_if_needed(working_dir) + rustilities::paths::prefix_with_current_dir(working_dir) }; let src = pallet_path.join("src"); @@ -87,138 +94,229 @@ impl AddConfigTypeCommand { types = common_types::complete_dependencies(types); let using_default_config = lib_content.contains("pub mod config_preludes"); - - let mut handles = Vec::new(); - // Mutex the memory shared accross threads - let mutex_pallet_path = Arc::new(Mutex::new(pallet_path.clone())); - let mutex_pallet_impl_path = Arc::new(Mutex::new(self.pallet_impl_path)); + let pallet_crate_name = + rustilities::manifest::find_crate_name(&pallet_path.join("Cargo.toml")) + .ok_or(anyhow::anyhow!("Couldn't determine the pallet's crate name"))?; + let config_preludes_path = pallet_path.join("src").join("config_preludes.rs"); + let runtime_path = manifest::find_pallet_runtime_path(&pallet_path); + let pallet_mock_path = pallet_path.join("src").join("mock.rs"); let spinner = cliclack::spinner(); spinner.start("Updating pallet's config trait..."); + let pallet_impl_path = if let Some(ref runtime_path) = runtime_path { + match self.pallet_impl_path { + Some(_) => self.pallet_impl_path.clone(), + _ => Some(manifest::get_pallet_impl_path( + &runtime_path, + &pallet_crate_name.splitn(2, '-').nth(1).unwrap_or("pallet").to_owned(), + )?), + } + } else { + None + }; + + let mut rollback = Rollback::with_capacity(4, 0, 0); + + rollback.note_file(&pallet_lib_path)?; + rollback.note_file(&pallet_mock_path)?; + // This may be Err cause the config preludes file may not exist. And it's perfect + let _ = rollback.note_file(&config_preludes_path); + // Note pallet_impl_path if needed + if let Some(ref pallet_impl_path) = pallet_impl_path { + rollback.note_file(&pallet_impl_path)?; + } + + let roll_pallet_lib_path = rollback + .get_noted_file(&pallet_lib_path) + .expect("The file has been noted above; qed;"); + let roll_pallet_mock_path = rollback + .get_noted_file(&pallet_mock_path) + .expect("The file has been noted above; qed;"); + for type_ in types { - let mutex_pallet_path = Arc::clone(&mutex_pallet_path); - let mutex_pallet_impl_path = Arc::clone(&mutex_pallet_impl_path); - handles.push(std::thread::spawn(move || -> Result<(), anyhow::Error> { - let pallet_impl_path = mutex_pallet_impl_path - .lock() - .map_err(|e| anyhow::Error::msg(format!("{}", e)))?; - let pallet_path = - mutex_pallet_path.lock().map_err(|e| anyhow::Error::msg(format!("{}", e)))?; - - let pallet_lib_path = pallet_path.join("src").join("lib.rs"); - let pallet_crate_name = manifest::find_crate_name(&pallet_path.join("Cargo.toml"))?; - let config_preludes_path = pallet_path.join("src").join("config_preludes.rs"); - let runtime_path = manifest::find_pallet_runtime_path(&pallet_path); - let pallet_mock_path = pallet_path.join("src").join("mock.rs"); - - let mut rollback = Rollback::with_capacity(3, 0, 0); - - let roll_pallet_lib_path = rollback.note_file(&pallet_lib_path)?; - let roll_pallet_mock_path = rollback.note_file(&pallet_mock_path)?; - // This may be Err as the file may not exist due to the config preludes may not be - // in a separate file. - let roll_config_preludes_path = rollback.note_file(&config_preludes_path); - - rust_writer::add_use_statements( - &roll_pallet_lib_path, - type_.get_needed_use_statements(), - )?; - - rust_writer::add_composite_enums( - &roll_pallet_lib_path, - type_.get_needed_composite_enums(), - )?; - - let type_name_ident = Ident::new( - &capitalize_str(type_.get_message().unwrap_or_default()), - Span::call_site(), - ); - let default_config = if using_default_config { - type_.get_default_config() - } else { - // Here the inner element's irrelevant, so we place a simple type definition - DefaultConfigType::Default { type_default_impl: parse_quote! {type A = ();} } - }; - // Update the config trait in lib.rs - rust_writer::update_config_trait( - &roll_pallet_lib_path, - type_name_ident.clone(), - type_.get_common_trait_bounds(), - &default_config, - )?; - - match default_config { - // Need to update default config - DefaultConfigType::Default { type_default_impl } | - DefaultConfigType::NoDefaultBounds { type_default_impl } - if using_default_config => - { - // If config_preludes is defined in its own file, we pass it to - // 'add_type_to_config_preludes", otherwise we pass lib.rs - let file_path = if config_preludes_path.is_file() { - // As config_preludes_path is indeed a file, roll_config_preludes_path - // should be Ok - &roll_config_preludes_path? - } else { - &roll_pallet_lib_path - }; - - rust_writer::add_type_to_config_preludes(file_path, type_default_impl)?; - }, - // Need to update runtimes - _ => { - let pallet_impl_path = if let Some(runtime_path) = runtime_path { - match *pallet_impl_path { - Some(_) => pallet_impl_path.clone(), - _ => Some(manifest::get_pallet_impl_path( - &runtime_path, - &pallet_crate_name - .splitn(2, '-') - .nth(1) - .unwrap_or("pallet") - .to_owned(), - )?), - } - } else { - None - }; - - let roll_pallet_impl_path = if let Some(impl_path) = pallet_impl_path { - rollback.note_file(&impl_path).ok() - } else { - None - }; - - rust_writer::add_type_to_runtimes( - type_name_ident, - type_.get_common_runtime_value(), - roll_pallet_impl_path, - &roll_pallet_mock_path, - &pallet_crate_name, - )?; - }, + let use_preserver = Preserver::new("use"); + let pub_use_preserver = Preserver::new("pub use"); + let mut mod_pallet_and_config_trait_preserver = Preserver::new("pub mod pallet"); + mod_pallet_and_config_trait_preserver.add_inners(&["pub trait Config"]); + + let mut preserved_ast = rust_writer::preserver::preserve_and_parse( + roll_pallet_lib_path, + &[&use_preserver, &pub_use_preserver, &mod_pallet_and_config_trait_preserver], + )?; + + for use_statement in type_.get_needed_use_statements() { + let use_statement: ItemToFile = use_statement.into(); + let mut finder = Finder::default().to_find(&use_statement); + let use_statement_used = finder.find(&preserved_ast); + if !use_statement_used { + let mut mutator = Mutator::default().to_mutate(&use_statement); + mutator.mutate(&mut preserved_ast)?; } + } - rollback.commit(); - Ok(()) - })); - } + for composite_enum in type_.get_needed_composite_enums() { + let composite_enum_implementor: ItemToMod = ("pallet", composite_enum).into(); + let mut finder = Finder::default().to_find(&composite_enum_implementor); + let composite_enum_used = finder.find(&preserved_ast); + if !composite_enum_used { + let mut mutator = Mutator::default().to_mutate(&composite_enum_implementor); + mutator.mutate(&mut preserved_ast)?; + } + } + + let default_config = if using_default_config { + type_.get_default_config() + } else { + // Here the inner element's irrelevant, so we place a simple type definition + DefaultConfigType::Default { type_default_impl: parse_quote! {type marker = ();} } + }; + + let type_implementor: ItemToTrait = + ("Config", type_.get_type_definition(default_config.clone())).into(); + let mut finder = Finder::default().to_find(&type_implementor); + let type_already_used = finder.find(&preserved_ast); - for handle in handles { - let result = handle.join().expect("Unexpected error"); - if result.is_err() { - Cli.warning("Some of the types weren't added to your pallet")?; + if !type_already_used { + let mut mutator = Mutator::default().to_mutate(&type_implementor); + mutator.mutate(&mut preserved_ast)?; + } else { + return Err(anyhow::anyhow!(format!( + "{} is already in use.", + type_.get_message().expect("Message defined for all types; qed;") + ))); + } + + rust_writer::preserver::resolve_preserved(&preserved_ast, roll_pallet_lib_path)?; + + match default_config { + // Need to update default config + DefaultConfigType::Default { type_default_impl } | + DefaultConfigType::NoDefaultBounds { type_default_impl } + if using_default_config => + { + // If config_preludes isn't defined in its own file, we use the lib file. + let file_path = if config_preludes_path.is_file() { + rollback + .get_noted_file(&config_preludes_path) + .expect("config_preludes_path is file, so it's well noted; qed") + } else { + roll_pallet_lib_path + }; + + // Define preservers for the most common used struct names for default config. + let preserver_testchain_config = + Preserver::new("impl DefaultConfig for TestDefaultConfig"); + + let preserver_solochain_config = + Preserver::new("impl DefaultConfig for SolochainDefaultConfig"); + + let preserver_relaychain_config = + Preserver::new("impl DefaultConfig for RelayChainDefaultConfig"); + + let preserver_parachain_config = + Preserver::new("impl DefaultConfig for ParaChainDefaultConfig"); + + let mut preserved_ast = rust_writer::preserver::preserve_and_parse( + file_path, + &[ + &preserver_testchain_config, + &preserver_solochain_config, + &preserver_relaychain_config, + &preserver_parachain_config, + ], + )?; + + let default_config_implementor: DefaultConfigsImplementor = ( + (Some("DefaultConfig"), "TestDefaultConfig", type_default_impl.clone()) + .into(), + (Some("DefaultConfig"), "TestDefaultConfig", type_default_impl.clone()) + .into(), + (Some("DefaultConfig"), "TestDefaultConfig", type_default_impl.clone()) + .into(), + (Some("DefaultConfig"), "TestDefaultConfig", type_default_impl.clone()) + .into(), + ) + .into(); + + let mut finder: DefaultConfigsImplementorFinderWrapper = + Finder::default().to_find(&default_config_implementor).into(); + finder.find(&preserved_ast, None); + let missing_indexes = finder.get_missing_indexes(); + if missing_indexes.is_some() { + let mut mutator: DefaultConfigsImplementorMutatorWrapper = + Mutator::default().to_mutate(&default_config_implementor).into(); + mutator.mutate(&mut preserved_ast, missing_indexes.as_deref())?; + rust_writer::preserver::resolve_preserved(&preserved_ast, file_path)?; + } + }, + // Need to update runtimes + _ => { + let pallet_name = pallet_crate_name.replace("-", "_"); + let pallet_config_trait_impl = format!("impl {}::Config", pallet_name); + let pallet_impl_preserver = Preserver::new(&pallet_config_trait_impl); + + let runtime_value_implementor: ItemToImpl = + (Some("Config"), "Runtime", type_.get_common_runtime_value()).into(); + + let mock_runtime_value_implementor: ItemToImpl = + (Some("Config"), "Test", type_.get_common_runtime_value()).into(); + + if let Some(ref impl_path) = pallet_impl_path { + let roll_impl_path = rollback + .get_noted_file(impl_path) + .expect("The file has been noted above; qed;"); + + let mut preserved_ast = rust_writer::preserver::preserve_and_parse( + roll_impl_path, + &[&pallet_impl_preserver], + )?; + + let mut finder = Finder::default().to_find(&runtime_value_implementor); + let runtime_value_already_used = finder.find(&preserved_ast); + if !runtime_value_already_used { + let mut mutator = + Mutator::default().to_mutate(&runtime_value_implementor); + mutator.mutate(&mut preserved_ast)?; + rust_writer::preserver::resolve_preserved( + &preserved_ast, + roll_impl_path, + )?; + } + } + + let mut preserved_ast = rust_writer::preserver::preserve_and_parse( + roll_pallet_mock_path, + &[&pallet_impl_preserver], + )?; + + let mut finder = Finder::default().to_find(&mock_runtime_value_implementor); + let runtime_value_already_used = finder.find(&preserved_ast); + if !runtime_value_already_used { + let mut mutator = + Mutator::default().to_mutate(&mock_runtime_value_implementor); + mutator.mutate(&mut preserved_ast)?; + rust_writer::preserver::resolve_preserved( + &preserved_ast, + roll_pallet_mock_path, + )?; + } + }, } } - if let Some(mut workspace_toml) = find_workspace_toml(&pallet_path) { + rollback.commit()?; + + if let Some(mut workspace_toml) = + rustilities::manifest::find_workspace_manifest(&pallet_path) + { workspace_toml.pop(); - format_dir(&workspace_toml)?; + rustilities::fmt::format_dir(&workspace_toml)?; } else { - format_dir(&pallet_path)?; + rustilities::fmt::format_dir(&pallet_path)?; } - spinner.stop("Your type is ready to be used in your pallet 🚀"); + + spinner.stop("Your types are ready to be used in your pallet 🚀"); Ok(()) } } diff --git a/crates/pop-cli/src/commands/add/pallet_config_type/common_types.rs b/crates/pop-cli/src/commands/add/pallet_config_type/common_types.rs index 821006f38..c971c69bf 100644 --- a/crates/pop-cli/src/commands/add/pallet_config_type/common_types.rs +++ b/crates/pop-cli/src/commands/add/pallet_config_type/common_types.rs @@ -1,8 +1,8 @@ // SPDX-License-Identifier: GPL-3.0 use clap::ValueEnum; -use pop_common::rust_writer::types::DefaultConfigType; +use pop_common::rust_writer_helpers::DefaultConfigType; use strum_macros::{EnumIter, EnumMessage}; -use syn::{parse_quote, ImplItem, ItemEnum, ItemUse, TraitBound, Type}; +use syn::{parse_quote, ImplItem, Item, TraitItem}; /// This enum is used to register from the CLI which types that are kind of usual in config traits /// are included in the pallet @@ -43,33 +43,81 @@ pub enum CommonTypes { } impl CommonTypes { - pub fn get_common_trait_bounds(&self) -> Vec { - match self { - CommonTypes::RuntimeEvent => vec![ - parse_quote! {From>}, - parse_quote! {IsType<::RuntimeEvent>}, - ], - CommonTypes::RuntimeOrigin => vec![parse_quote! {From>}], - CommonTypes::RuntimeHoldReason => vec![parse_quote! {From}], - CommonTypes::RuntimeFreezeReason => vec![parse_quote! {VariantCount}], - CommonTypes::Fungibles => vec![ - parse_quote! {fungible::Inspect}, - parse_quote! {fungible::Mutate}, - parse_quote! {fungible::hold::Inspect}, - parse_quote! {fungible::hold::Mutate}, - parse_quote! {fungible::freeze::Inspect}, - parse_quote! {fungible::freeze::Mutate}, - ], + pub fn get_type_definition(&self, default_config: DefaultConfigType) -> TraitItem { + match (self, default_config) { + (CommonTypes::RuntimeEvent, DefaultConfigType::NoDefaultBounds { .. }) => + parse_quote! { + /// The aggregated event type of the runtime. + #[pallet::no_default_bounds] + type RuntimeEvent: From> + IsType<::RuntimeEvent>; + }, + (CommonTypes::RuntimeEvent, DefaultConfigType::Default { .. }) => parse_quote! { + /// The aggregated event type of the runtime. + type RuntimeEvent: From> + IsType<::RuntimeEvent>; + }, + (CommonTypes::RuntimeOrigin, DefaultConfigType::NoDefaultBounds { .. }) => + parse_quote! { + /// The aggregated origin type of the runtime. + #[pallet::no_default_bounds] + type RuntimeOrigin: From>; + }, + (CommonTypes::RuntimeOrigin, DefaultConfigType::Default { .. }) => parse_quote! { + /// The aggregated origin type of the runtime. + type RuntimeOrigin: From>; + }, + (CommonTypes::RuntimeHoldReason, DefaultConfigType::NoDefaultBounds { .. }) => + parse_quote! { + /// A reason for placing a hold on funds + #[pallet::no_default_bounds] + type RuntimeHoldReason: From; + }, + (CommonTypes::RuntimeHoldReason, DefaultConfigType::Default { .. }) => parse_quote! { + /// A reason for placing a hold on funds + type RuntimeHoldReason: From; + }, + (CommonTypes::RuntimeFreezeReason, DefaultConfigType::NoDefaultBounds { .. }) => + parse_quote! { + /// A reason for placing a freeze on funds + #[pallet::no_default_bounds] + type RuntimeFreezeReason: VariantCount; + }, + (CommonTypes::RuntimeFreezeReason, DefaultConfigType::Default { .. }) => parse_quote! { + /// A reason for placing a freeze on funds + type RuntimeFreezeReason: VariantCount; + }, + (CommonTypes::Fungibles, DefaultConfigType::NoDefault) => parse_quote! { + #[pallet::no_default] + type Fungibles: + fungible::Inspect + + fungible::Mutate + + fungible::hold::Inspect + + fungible::hold::Mutate + + fungible::freeze::Inspect + + fungible::freeze::Mutate; + }, + (CommonTypes::Fungibles, DefaultConfigType::Default { .. }) => parse_quote! { + type Fungibles: + fungible::Inspect + + fungible::Mutate + + fungible::hold::Inspect + + fungible::hold::Mutate + + fungible::freeze::Inspect + + fungible::freeze::Mutate; + }, + // By construction this case shouldn't occur. + _ => parse_quote! {}, } } - pub fn get_common_runtime_value(&self) -> Type { + pub fn get_common_runtime_value(&self) -> ImplItem { match self { - CommonTypes::RuntimeEvent => parse_quote! {RuntimeEvent}, - CommonTypes::RuntimeOrigin => parse_quote! {RuntimeOrigin}, - CommonTypes::RuntimeHoldReason => parse_quote! {RuntimeHoldReason}, - CommonTypes::RuntimeFreezeReason => parse_quote! {RuntimeFreezeReason}, - CommonTypes::Fungibles => parse_quote! {Balances}, + CommonTypes::RuntimeEvent => parse_quote! {type RuntimeEvent = RuntimeEvent;}, + CommonTypes::RuntimeOrigin => parse_quote! {type RuntimeOrigin = RuntimeOrigin;}, + CommonTypes::RuntimeHoldReason => + parse_quote! {type RuntimeHoldReason = RuntimeHoldReason;}, + CommonTypes::RuntimeFreezeReason => + parse_quote! {type RuntimeFreezeReason = RuntimeFreezeReason;}, + CommonTypes::Fungibles => parse_quote! {type Fungibles = Balances;}, } } @@ -103,7 +151,7 @@ impl CommonTypes { } } - pub fn get_needed_use_statements(&self) -> Vec { + pub fn get_needed_use_statements(&self) -> Vec { match self { CommonTypes::RuntimeEvent => Vec::new(), CommonTypes::RuntimeOrigin => Vec::new(), @@ -114,12 +162,11 @@ impl CommonTypes { } } - pub fn get_needed_composite_enums(&self) -> Vec { + pub fn get_needed_composite_enums(&self) -> Vec { match self { CommonTypes::RuntimeEvent => Vec::new(), CommonTypes::RuntimeOrigin => Vec::new(), CommonTypes::RuntimeHoldReason => vec![parse_quote! { - ///TEMP_DOC /// A reason for the pallet placing a hold on funds. #[pallet::composite_enum] pub enum HoldReason { diff --git a/crates/pop-cli/src/commands/add/runtime_pallet.rs b/crates/pop-cli/src/commands/add/runtime_pallet.rs index 71f67f9d8..5f4b38a73 100644 --- a/crates/pop-cli/src/commands/add/runtime_pallet.rs +++ b/crates/pop-cli/src/commands/add/runtime_pallet.rs @@ -6,19 +6,33 @@ use crate::{ }; use clap::{error::ErrorKind, Args, Command}; use cliclack::multiselect; +use fs_rollback::Rollback; use pop_common::{ - find_workspace_toml, format_dir, manifest, prefix_with_current_dir_if_needed, rust_writer, - Rollback, + manifest, + rust_writer_helpers::{self, RuntimeUsedMacro}, }; -use std::{ - env, - path::PathBuf, - sync::{Arc, Mutex}, +use rust_writer::{ + ast::{ + finder, + finder::{Finder, ToFind}, + implementors::{ItemToFile, ItemToMod, TokenStreamToMacro}, + mutator, + mutator::{Mutator, ToMutate}, + }, + preserver::Preserver, }; +use rustilities::manifest::{ManifestDependencyConfig, ManifestDependencyOrigin}; +use std::{env, path::PathBuf}; use strum::{EnumMessage, IntoEnumIterator}; +use syn::{parse_quote, visit_mut::VisitMut}; mod common_pallets; +#[mutator(ItemToFile, ItemToFile)] +#[finder(ItemToFile, ItemToFile)] +#[impl_from] +struct PalletImplBlockImplementor; + #[derive(Args, Debug, Clone)] pub struct AddPalletCommand { #[arg(short, long, value_enum, num_args(1..), required = false, help = "The pallets you want to include to your runtime.")] @@ -38,7 +52,7 @@ impl AddPalletCommand { let mut cmd = Command::new(""); let runtime_path = if let Some(path) = &self.runtime_path { - prefix_with_current_dir_if_needed(path.to_path_buf()) + rustilities::paths::prefix_with_current_dir(path) } else { let working_dir = match env::current_dir() { Ok(working_dir) => working_dir, @@ -47,9 +61,9 @@ impl AddPalletCommand { // Give the chance to use the command either from a workspace containing a runtime or // from a runtime crate if path not specified if working_dir.join("runtime").exists() { - prefix_with_current_dir_if_needed(working_dir.join("runtime")) + rustilities::paths::prefix_with_current_dir(working_dir.join("runtime")) } else { - prefix_with_current_dir_if_needed(working_dir) + rustilities::paths::prefix_with_current_dir(working_dir) } }; @@ -73,115 +87,180 @@ impl AddPalletCommand { self.pallets }; - let mut handles = Vec::new(); - // Mutex over the memory shared across threads - let mutex_pallet_impl_path = Arc::new(Mutex::new(self.pallet_impl_path)); - let mutex_runtime_path = Arc::new(Mutex::new(runtime_path.clone())); - - for pallet in pallets { - let mutex_pallet_impl_path = Arc::clone(&mutex_pallet_impl_path); - let mutex_runtime_path = Arc::clone(&mutex_runtime_path); - handles.push(std::thread::spawn(move || -> Result<(), anyhow::Error> { - let pallet_impl_path = mutex_pallet_impl_path - .lock() - .map_err(|e| anyhow::Error::msg(format!("{}", e)))?; - let runtime_path = - mutex_runtime_path.lock().map_err(|e| anyhow::Error::msg(format!("{}", e)))?; - - let runtime_lib_path = runtime_path.join("src").join("lib.rs"); - let runtime_manifest = manifest::find_crate_manifest(&runtime_lib_path) - .expect("Runtime is a crate, so it contains a manifest; qed;"); - - let mut rollback; - let roll_runtime_lib_path; - let pallet_impl_path = match *pallet_impl_path { - Some(_) => { - rollback = Rollback::with_capacity(3, 0, 0); - roll_runtime_lib_path = rollback.note_file(&runtime_lib_path)?; - pallet_impl_path - .clone() - .expect("The match arm guarantees this is Some; qed;") - }, - None => { - let (rollback_temp, runtime_lib_path_rolled) = - manifest::compute_new_pallet_impl_path( - &runtime_path, - &pallet - .get_crate_name() - .splitn(2, '-') - .nth(1) - .unwrap_or("pallet") - .to_string(), - )?; - rollback = rollback_temp; - - // The rollback created above may already contain a noted version of - // runtime_lib_path and a new file which corresponds to the pallet - // impl path - roll_runtime_lib_path = if runtime_lib_path_rolled { - rollback.noted_files().remove(0) - } else { - rollback.note_file(&runtime_lib_path)? - }; - rollback.new_files().remove(0) - }, - }; - - let roll_pallet_impl_path = rollback.note_file(&pallet_impl_path)?; - let roll_manifest = rollback.note_file(&runtime_manifest)?; - - // Add the pallet to the crate and to the runtime module - let (rollback, _) = - rollback.ok_or_rollback(rust_writer::add_pallet_to_runtime_module( - &pallet.get_crate_name(), - &roll_runtime_lib_path, - ))?; - - // Add the pallet impl block and its related use statements - let (rollback, _) = rollback.ok_or_rollback(rust_writer::add_use_statements( - &roll_pallet_impl_path, - pallet.get_impl_needed_use_statements(), - ))?; - - let (rollback, _) = - rollback.ok_or_rollback(rust_writer::add_pallet_impl_block_to_runtime( - &pallet.get_crate_name(), - &roll_pallet_impl_path, - pallet.get_parameter_types(), - pallet.get_config_types(), - pallet.get_config_values(), - pallet.get_default_config(), - ))?; - - // Update the crate's manifest to add the pallet crate - let (rollback, _) = - rollback.ok_or_rollback(manifest::add_crate_to_dependencies( - &roll_manifest, - &runtime_manifest, - &pallet.get_crate_name(), - manifest::types::CrateDependencie::External { - version: pallet.get_version(), - }, - ))?; - - // At this point, we can commit the rollback - rollback.commit(); - Ok(()) - })); + let mut rollback = Rollback::default(); + + let mut precomputed_pallet_config_paths = Vec::with_capacity(pallets.len()); + + let (runtime_lib_path, configs_rs_path, configs_folder_path, configs_mod_path) = + rust_writer_helpers::compute_pallet_related_paths(&runtime_path); + + let runtime_manifest = rustilities::manifest::find_innermost_manifest(&runtime_path) + .expect("Runtime is a crate, so it contains a manifest; qed;"); + + for pallet in pallets.iter() { + let pallet_name = + pallet.get_crate_name().splitn(2, '-').nth(1).unwrap_or("pallet").to_string(); + precomputed_pallet_config_paths + .push(configs_folder_path.join(format!("{}.rs", pallet_name))); + } + + rollback.note_file(&runtime_lib_path)?; + rollback.note_file(&runtime_manifest)?; + if let Some(ref pallet_impl_path) = self.pallet_impl_path { + rollback.note_file(pallet_impl_path)?; } - for handle in handles { - let result = handle.join().expect("Unexpected error"); - if result.is_err() { - Cli.warning("Some of the pallets weren't added to your runtime")?; + for (index, pallet) in pallets.iter().enumerate() { + let pallet_name = + pallet.get_crate_name().splitn(2, '-').nth(1).unwrap_or("pallet").to_string(); + + let pallet_config_path = &precomputed_pallet_config_paths[index]; + + let roll_pallet_impl_path = match self.pallet_impl_path { + Some(ref pallet_impl_path) => rollback + .get_noted_file(pallet_impl_path) + .expect("The file has been noted above;qed;"), + None => { + rollback = rust_writer_helpers::compute_new_pallet_impl_path( + rollback, + &runtime_lib_path, + &configs_rs_path, + &configs_folder_path, + &configs_mod_path, + &pallet_config_path, + &pallet_name, + )?; + + rollback + .get_new_file(&pallet_config_path) + .expect("compute_new_pallet_impl_path noted this file; qed;") + }, + }; + + let roll_runtime_lib_path = rollback + .get_noted_file(&runtime_lib_path) + .expect("This file is noted by the rollback; qed;"); + let roll_manifest = rollback + .get_noted_file(&runtime_manifest) + .expect("This file is noted by the rollback; qed;"); + + // Add the pallet to the runtime module + let construct_runtime_preserver = Preserver::new("construct_runtime!"); + let mod_runtime_preserver = Preserver::new("mod runtime"); + let mut preserved_ast = rust_writer::preserver::preserve_and_parse( + roll_runtime_lib_path, + &[&construct_runtime_preserver, &mod_runtime_preserver], + )?; + + // Parse the runtime to find which of the runtime macros is being used and the highest + // pallet index used (if needed, otherwise 0). + let used_macro = rust_writer_helpers::find_used_runtime_macro(&preserved_ast)?; + match used_macro { + RuntimeUsedMacro::Runtime => { + let highest_index = + rust_writer_helpers::find_highest_pallet_index(&preserved_ast)?; + let pallet_to_runtime_implementor: ItemToMod = + ("runtime", pallet.get_pallet_declaration_runtime_module(highest_index)) + .into(); + + let mut finder = Finder::default().to_find(&pallet_to_runtime_implementor); + let pallet_already_present = finder.find(&preserved_ast); + if pallet_already_present { + return Err(anyhow::anyhow!(format!( + "{} is already in use.", + pallet.get_crate_name() + ))); + } else { + let mut mutator = + Mutator::default().to_mutate(&pallet_to_runtime_implementor); + mutator.mutate(&mut preserved_ast)?; + rust_writer::preserver::resolve_preserved( + &preserved_ast, + roll_runtime_lib_path, + )?; + } + }, + RuntimeUsedMacro::ConstructRuntime => { + let pallet_to_construct_runtime_implementor: TokenStreamToMacro = ( + parse_quote!(construct_runtime), + Some(parse_quote!(Runtime)), + pallet.get_pallet_declaration_construct_runtime(), + ) + .into(); + let mut finder = + Finder::default().to_find(&pallet_to_construct_runtime_implementor); + let pallet_already_present = finder.find(&preserved_ast); + if pallet_already_present { + return Err(anyhow::anyhow!(format!( + "{} is already in use.", + pallet.get_crate_name() + ))); + } else { + let mut mutator = + Mutator::default().to_mutate(&pallet_to_construct_runtime_implementor); + mutator.mutate(&mut preserved_ast)?; + rust_writer::preserver::resolve_preserved( + &preserved_ast, + roll_runtime_lib_path, + )?; + } + }, } + + // Add the pallet impl block and its related use statements + let use_preserver = Preserver::new("use"); + let pub_use_preserver = Preserver::new("pub use"); + + let mut preserved_ast = rust_writer::preserver::preserve_and_parse( + roll_pallet_impl_path, + &[&use_preserver, &pub_use_preserver], + )?; + + for use_statement in pallet.get_impl_needed_use_statements() { + let use_statement: ItemToFile = use_statement.into(); + let mut finder = Finder::default().to_find(&use_statement); + let use_statement_used = finder.find(&preserved_ast); + if !use_statement_used { + let mut mutator = Mutator::default().to_mutate(&use_statement); + mutator.mutate(&mut preserved_ast)?; + } + } + + let pallet_impl_block_implementor: PalletImplBlockImplementor = ( + ItemToFile { item: pallet.get_needed_parameter_types() }, + ItemToFile { item: pallet.get_needed_impl_block() }, + ) + .into(); + + let mut mutator: PalletImplBlockImplementorMutatorWrapper = + Mutator::default().to_mutate(&pallet_impl_block_implementor).into(); + + mutator.mutate(&mut preserved_ast, None)?; + + rust_writer::preserver::resolve_preserved(&preserved_ast, roll_pallet_impl_path)?; + + // Update the crate's manifest to add the pallet crate + rustilities::manifest::add_crate_to_dependencies( + roll_manifest, + &pallet.get_crate_name(), + ManifestDependencyConfig::new( + ManifestDependencyOrigin::crates_io(&pallet.get_version()), + false, + vec![], + false, + ), + )?; } - if let Some(mut workspace_toml) = find_workspace_toml(&runtime_path) { + rollback.commit()?; + + if let Some(mut workspace_toml) = + rustilities::manifest::find_workspace_manifest(&runtime_path) + { workspace_toml.pop(); - format_dir(&workspace_toml)?; + rustilities::fmt::format_dir(&workspace_toml)?; } else { - format_dir(&runtime_path)?; + rustilities::fmt::format_dir(&runtime_path)?; } spinner.stop("Your runtime has been updated and it's ready to use 🚀"); diff --git a/crates/pop-cli/src/commands/add/runtime_pallet/common_pallets.rs b/crates/pop-cli/src/commands/add/runtime_pallet/common_pallets.rs index b0d68c8bf..aa28d2541 100644 --- a/crates/pop-cli/src/commands/add/runtime_pallet/common_pallets.rs +++ b/crates/pop-cli/src/commands/add/runtime_pallet/common_pallets.rs @@ -1,9 +1,8 @@ // SPDX-License-Identifier: GPL-3.0 use clap::ValueEnum; -use pop_common::rust_writer::types::ParameterTypes; -use proc_macro2::Span; +use proc_macro2::{Literal, TokenStream}; use strum_macros::{EnumIter, EnumMessage}; -use syn::{parse_quote, Ident, ItemUse, Type}; +use syn::{parse_quote, Item}; #[derive(Debug, Copy, Clone, PartialEq, EnumIter, EnumMessage, ValueEnum)] pub enum CommonPallets { @@ -23,25 +22,36 @@ impl CommonPallets { } } - pub fn get_version(&self) -> String { + pub fn get_pallet_declaration_construct_runtime(&self) -> TokenStream { match self { - CommonPallets::Balances => "39.0.0".to_string(), - CommonPallets::Contracts => "27.0.0".to_string(), + CommonPallets::Balances => parse_quote! { Balances: pallet_balances, }, + CommonPallets::Contracts => parse_quote! { Contracts: pallet_contracts, }, + } + } + + pub fn get_pallet_declaration_runtime_module(&self, highest_index: Literal) -> Item { + match self { + CommonPallets::Balances => parse_quote! { + ///TEMP_DOC + #[runtime::pallet_index(#highest_index)] + pub type Balances = pallet_balances; + }, + CommonPallets::Contracts => parse_quote! { + ///TEMP_DOC + #[runtime::pallet_index(#highest_index)] + pub type Contracts = pallet_contracts; + }, } } - pub fn get_parameter_types(&self) -> Vec { + pub fn get_version(&self) -> String { match self { - CommonPallets::Balances => Vec::new(), - CommonPallets::Contracts => vec![ParameterTypes { - ident: Ident::new("Schedule", Span::call_site()), - type_: parse_quote! {pallet_contracts::Schedule}, - value: parse_quote! {Default::default()}, - }], + CommonPallets::Balances => "39.0.0".to_string(), + CommonPallets::Contracts => "27.0.0".to_string(), } } - pub fn get_impl_needed_use_statements(&self) -> Vec { + pub fn get_impl_needed_use_statements(&self) -> Vec { match self { CommonPallets::Balances => vec![parse_quote!( use crate::System; @@ -52,36 +62,35 @@ impl CommonPallets { } } - pub fn get_config_types(&self) -> Vec { + pub fn get_needed_parameter_types(&self) -> Item { match self { - CommonPallets::Balances => vec![Ident::new("AccountStore", Span::call_site())], - CommonPallets::Contracts => vec![ - Ident::new("Currency", Span::call_site()), - Ident::new("Schedule", Span::call_site()), - Ident::new("CallStack", Span::call_site()), - ], + CommonPallets::Balances => parse_quote!(), + CommonPallets::Contracts => parse_quote! { + parameter_types!{ + pub Schedule: pallet_contracts::Schedule = Default::default(); + } + }, } } - pub fn get_config_values(&self) -> Vec { + pub fn get_needed_impl_block(&self) -> Item { match self { - CommonPallets::Balances => { - vec![parse_quote! {System}] + CommonPallets::Balances => parse_quote! { + ///TEMP_DOC + #[derive_impl(pallet_balances::config_preludes::TestDefaultConfig)] + impl pallet_balances::Config for Runtime{ + type AccountStore = System; + } }, - CommonPallets::Contracts => { - vec![ - parse_quote! {Balances}, - parse_quote! {[pallet_contracts::Frame; 5]}, - parse_quote! {Schedule}, - ] + CommonPallets::Contracts => parse_quote! { + ///TEMP_DOC + #[derive_impl(pallet_contracts::config_preludes::TestDefaultConfig)] + impl pallet_contracts::Config for Runtime{ + type Currency = Balances; + type Schedule = [pallet_contracts::Frame; 5]; + type CallStack = Schedule; + } }, } } - - pub fn get_default_config(&self) -> bool { - match self { - CommonPallets::Balances => true, - CommonPallets::Contracts => true, - } - } } diff --git a/crates/pop-cli/src/commands/new/contract.rs b/crates/pop-cli/src/commands/new/contract.rs index 35a9132c6..f714b4ca0 100644 --- a/crates/pop-cli/src/commands/new/contract.rs +++ b/crates/pop-cli/src/commands/new/contract.rs @@ -4,7 +4,7 @@ use crate::cli::{ traits::{Cli as _, Confirm as _}, Cli, }; -use pop_common::manifest::{add_crate_to_workspace, find_workspace_toml}; +use pop_common::manifest::add_crate_to_workspace; use anyhow::Result; use clap::{ @@ -75,7 +75,7 @@ impl NewContractCommand { generate_contract_from_template(name, path, &template)?; // If the contract is part of a workspace, add it to that workspace - if let Some(workspace_toml) = find_workspace_toml(path) { + if let Some(workspace_toml) = rustilities::manifest::find_workspace_manifest(path) { add_crate_to_workspace(&workspace_toml, path)?; } diff --git a/crates/pop-cli/src/commands/new/pallet.rs b/crates/pop-cli/src/commands/new/pallet.rs index a0578ac62..db0fb8a30 100644 --- a/crates/pop-cli/src/commands/new/pallet.rs +++ b/crates/pop-cli/src/commands/new/pallet.rs @@ -7,19 +7,28 @@ use crate::{ use clap::{Args, Subcommand}; use cliclack::{confirm, input, multiselect, outro, outro_cancel}; +use fs_rollback::Rollback; use pop_common::{ - add_crate_to_workspace, compute_new_pallet_impl_path, find_crate_name, - find_pallet_runtime_path, find_workspace_toml, format_dir, manifest, - manifest::types::CrateDependencie, prefix_with_current_dir_if_needed, rust_writer, Rollback, + capitalize_str, find_pallet_runtime_path, rust_writer_helpers, + rust_writer_helpers::RuntimeUsedMacro, }; use pop_parachains::{ create_pallet_template, TemplatePalletConfig, TemplatePalletConfigCommonTypes, TemplatePalletOptions, TemplatePalletStorageTypes, }; use proc_macro2::Span; +use rust_writer::{ + ast::{ + finder::{Finder, ToFind}, + implementors::{ItemToFile, ItemToMod, TokenStreamToMacro}, + mutator::{Mutator, ToMutate}, + }, + preserver::Preserver, +}; +use rustilities::manifest::{ManifestDependencyConfig, ManifestDependencyOrigin}; use std::{fs, path::PathBuf}; use strum::{EnumMessage, IntoEnumIterator}; -use syn::{Ident, Type}; +use syn::{parse_quote, parse_str, Ident, Type}; fn after_help_simple() -> &'static str { r#"Examples: @@ -157,10 +166,10 @@ impl NewPalletCommand { // If the user has introduced something like pallets/my_pallet, probably it refers to // ./pallets/my_pallet. We need to transform this path, as otherwise the Cargo.toml won't be // detected and the pallet won't be added to the workspace. - let pallet_path = prefix_with_current_dir_if_needed(pallet_path); + let pallet_path = rustilities::paths::prefix_with_current_dir(pallet_path); // Determine if the pallet is being created inside a workspace - let workspace_toml = find_workspace_toml(&pallet_path); + let workspace_toml = rustilities::manifest::find_workspace_manifest(&pallet_path); if pallet_path.exists() { if !confirm(format!( @@ -193,59 +202,165 @@ impl NewPalletCommand { pallet_custom_origin, }, )?; - let pallet_crate_name = find_crate_name(&pallet_path.join("Cargo.toml"))?; - // Check if the pallet has to be included in a runtime and include it if so + // If the pallet has been created inside a workspace containing a runtime, add the + // pallet to that runtime. if let Some(runtime_path) = find_pallet_runtime_path(&pallet_path) { - // If the pallet has been created inside a workspace containing a runtime, add the - // pallet to that runtime. spinner.set_message("Adding the pallet to your runtime..."); + + let pallet_crate_name = + rustilities::manifest::find_crate_name(&pallet_path.join("Cargo.toml")) + .unwrap_or("pallet".to_owned()); + let runtime_lib_path = runtime_path.join("src").join("lib.rs"); - let runtime_manifest = manifest::find_crate_manifest(&runtime_lib_path) - .expect("Runtime is a crate, so it contains a manifest; qed;"); - - let mut rollback; - let roll_runtime_lib_path; - let pallet_impl_path = if let Some(impl_path) = self.pallet_impl_path { - rollback = Rollback::with_capacity(3, 0, 0); - roll_runtime_lib_path = rollback.note_file(&runtime_lib_path)?; - impl_path.clone() - } else { - let (rollback_temp, runtime_lib_path_rolled) = compute_new_pallet_impl_path( - &runtime_path, - &pallet_crate_name.splitn(2, '-').nth(1).unwrap_or("pallet").to_string(), - )?; - - rollback = rollback_temp; - // The rollback created above may already contain a noted version of - // runtime_lib_path and a new file which corresponds to the pallet - // impl path - roll_runtime_lib_path = if runtime_lib_path_rolled { - rollback.noted_files().remove(0) - } else { - rollback.note_file(&runtime_lib_path)? - }; - rollback.new_files().remove(0) + let runtime_manifest = + rustilities::manifest::find_innermost_manifest(&runtime_lib_path) + .expect("Runtime is a crate, so it contains a manifest; qed;"); + + let pallet_ident = Ident::new( + &capitalize_str( + &pallet_crate_name + .split("pallet-") + .last() + .ok_or(anyhow::anyhow! { + "Pallet crates are supposed to be called pallet-something."})? + .replace("-", ""), + ), + Span::call_site(), + ); + let pallet_type = parse_str::(&pallet_crate_name.replace("-", "_"))?; + + let pallet_name = + pallet_crate_name.splitn(2, '-').nth(1).unwrap_or("pallet").to_string(); + + let (runtime_lib_path, configs_rs_path, configs_folder_path, configs_mod_path) = + rust_writer_helpers::compute_pallet_related_paths(&runtime_path); + let pallet_config_path = configs_folder_path.join(format!("{}.rs", pallet_name)); + + let mut rollback = Rollback::default(); + + if let Some(ref pallet_impl_path) = self.pallet_impl_path { + rollback.note_file(pallet_impl_path)?; + } + + rollback.note_file(&runtime_manifest)?; + rollback.note_file(&runtime_lib_path)?; + + let roll_pallet_impl_path = match self.pallet_impl_path { + Some(ref pallet_impl_path) => rollback + .get_noted_file(&pallet_impl_path) + .expect("The file has been noted above;qed;"), + None => { + rollback = rust_writer_helpers::compute_new_pallet_impl_path( + rollback, + &runtime_lib_path, + &configs_rs_path, + &configs_folder_path, + &configs_mod_path, + &pallet_config_path, + &pallet_name, + )?; + + rollback + .get_new_file(&pallet_config_path) + .expect("compute_new_pallet_impl_path noted this file; qed;") + }, }; - let roll_pallet_impl_path = rollback.note_file(&pallet_impl_path)?; - let roll_runtime_manifest = rollback.note_file(&runtime_manifest)?; + let roll_runtime_lib_path = rollback + .get_noted_file(&runtime_lib_path) + .expect("This file is noted by the rollback; qed;"); + let roll_manifest = rollback + .get_noted_file(&runtime_manifest) + .expect("This file is noted by the rollback; qed;"); - // Add pallet to runtime module - let add_pallet_to_runtime = rust_writer::add_pallet_to_runtime_module( - &pallet_crate_name, - &roll_runtime_lib_path, - ); + // Add the pallet to the runtime module + let construct_runtime_preserver = Preserver::new("construct_runtime!"); + let mod_runtime_preserver = Preserver::new("mod runtime"); + let mut preserved_ast = rust_writer::preserver::preserve_and_parse( + roll_runtime_lib_path, + &[&construct_runtime_preserver, &mod_runtime_preserver], + )?; + + // Parse the runtime to find which of the runtime macros is being used and the highest + // pallet index used (if needed, otherwise 0). + let used_macro = rust_writer_helpers::find_used_runtime_macro(&preserved_ast)?; + + let pallet_added_to_runtime = match used_macro { + RuntimeUsedMacro::Runtime => { + let highest_index = + rust_writer_helpers::find_highest_pallet_index(&preserved_ast)?; + let pallet_to_runtime_implementor: ItemToMod = ( + "runtime", + parse_quote! { + ///TEMP_DOC + #[runtime::pallet_index(#highest_index)] + pub type #pallet_ident = #pallet_type; + }, + ) + .into(); + + let mut finder = Finder::default().to_find(&pallet_to_runtime_implementor); + let pallet_already_present = finder.find(&preserved_ast); + if !pallet_already_present { + let mut mutator = + Mutator::default().to_mutate(&pallet_to_runtime_implementor); + mutator.mutate(&mut preserved_ast)?; + rust_writer::preserver::resolve_preserved( + &preserved_ast, + roll_runtime_lib_path, + ) + } else { + Ok(()) + } + }, + RuntimeUsedMacro::ConstructRuntime => { + let pallet_to_construct_runtime_implementor: TokenStreamToMacro = ( + parse_quote!(construct_runtime), + Some(parse_quote!(Runtime)), + parse_quote!(#pallet_ident: #pallet_type,), + ) + .into(); + let mut finder = + Finder::default().to_find(&pallet_to_construct_runtime_implementor); + let pallet_already_present = finder.find(&preserved_ast); + if !pallet_already_present { + let mut mutator = + Mutator::default().to_mutate(&pallet_to_construct_runtime_implementor); + mutator.mutate(&mut preserved_ast)?; + rust_writer::preserver::resolve_preserved( + &preserved_ast, + roll_runtime_lib_path, + ) + } else { + Ok(()) + } + }, + }; // Update the crate's manifest to add the pallet crate - let add_crate_dependencies = manifest::add_crate_to_dependencies( - &roll_runtime_manifest, - &runtime_manifest, + let relative_local_path = pathdiff::diff_paths( + &pallet_path, + &runtime_manifest + .parent() + .expect("A file's always contained inside a directory; qed;"), + ) + .unwrap_or(pallet_path.clone()); + let crate_added_to_dependencies = rustilities::manifest::add_crate_to_dependencies( + roll_manifest, &pallet_crate_name, - CrateDependencie::Local { local_crate_path: pallet_path.to_path_buf() }, + ManifestDependencyConfig::new( + ManifestDependencyOrigin::local(&relative_local_path), + false, + vec![], + false, + ), ); // Add pallet's impl block + let mut preserved_ast = + rust_writer::preserver::preserve_and_parse(roll_pallet_impl_path, &[])?; + let (types, values) = if pallet_default_config { (Vec::new(), Vec::new()) } else { @@ -261,38 +376,45 @@ impl NewPalletCommand { (types, values) }; - let add_pallet_impl_block = rust_writer::add_pallet_impl_block_to_runtime( - &pallet_crate_name, - &roll_pallet_impl_path, - Vec::new(), - types, - values, - pallet_default_config, - ); + let pallet_impl_block_implementor = ItemToFile { + item: parse_quote! { + ///TEMP_DOC + impl #pallet_type::Config for Runtime{ + #( + type #types = #values; + )* + } + }, + }; + + let mut mutator = Mutator::default().to_mutate(&pallet_impl_block_implementor); + + let pallet_impl_block_added = mutator.mutate(&mut preserved_ast); + + rust_writer::preserver::resolve_preserved(&preserved_ast, roll_pallet_impl_path)?; // If some of these results are Err, that doesn't mean that everything went wrong, only // that the pallet wasn't included into the runtime. But the pallet was indeed // created, so we cannot return an error here - match (add_pallet_to_runtime, add_crate_dependencies, add_pallet_impl_block) { - (Ok(_), Ok(_), Ok(_)) => rollback.commit(), + match (pallet_added_to_runtime, crate_added_to_dependencies, pallet_impl_block_added) { + (Ok(_), Ok(_), Ok(_)) => rollback.commit()?, _ => { Cli.warning( "Your pallet has been created but it couldn't be added to your runtime.", )?; - rollback.rollback(); }, } } // If the pallet has been created inside a workspace, add it to that workspace - if let Some(mut workspace_toml) = workspace_toml { - add_crate_to_workspace(&workspace_toml, &pallet_path)?; - // Format the whole workspace + if let Some(mut workspace_toml) = + rustilities::manifest::find_workspace_manifest(&pallet_path) + { + pop_common::add_crate_to_workspace(&workspace_toml, &pallet_path)?; workspace_toml.pop(); - format_dir(&workspace_toml)?; + rustilities::fmt::format_dir(&workspace_toml)?; } else { - // Format the pallet dir - format_dir(&pallet_path)?; + rustilities::fmt::format_dir(&pallet_path)?; } spinner.stop("Generation complete"); diff --git a/crates/pop-cli/tests/new_pallet_added_to_existing_runtime.rs b/crates/pop-cli/tests/new_pallet_added_to_existing_runtime.rs new file mode 100644 index 000000000..6280e081b --- /dev/null +++ b/crates/pop-cli/tests/new_pallet_added_to_existing_runtime.rs @@ -0,0 +1,100 @@ +// SPDX-License-Identifier: GPL-3.0 + +use assert_cmd::Command; +use similar::{ChangeTag, TextDiff}; + +#[test] +fn pop_new_pallet_modifies_runtime() { + let temp = tempfile::tempdir().unwrap(); + let tempdir = temp.path(); + + Command::cargo_bin("pop") + .unwrap() + .current_dir(&tempdir) + .args(&["new", "parachain", "test_parachain", "-t", "standard"]) + .assert() + .success(); + + let test_parachain = tempdir.join("test_parachain"); + + let workspace_manifest_path = test_parachain.join("Cargo.toml"); + + let runtime_path = test_parachain.join("runtime"); + let runtime_lib_path = runtime_path.join("src").join("lib.rs"); + let configs_path = runtime_path.join("src").join("configs"); + let configs_mod_path = configs_path.join("mod.rs"); + let configs_pallet_path = configs_path.join("template.rs"); + + let workspace_content_before = std::fs::read_to_string(&workspace_manifest_path).unwrap(); + let runtime_lib_content_before = std::fs::read_to_string(&runtime_lib_path).unwrap(); + let configs_mod_content_before = std::fs::read_to_string(&configs_mod_path).unwrap(); + + assert!(!configs_pallet_path.exists()); + + Command::cargo_bin("pop") + .unwrap() + .current_dir(&test_parachain) + .args(&["new", "pallet", "template", "advanced", "-c", "runtime-event", "-d"]) + .assert() + .success(); + + let workspace_content_after = std::fs::read_to_string(&workspace_manifest_path).unwrap(); + let runtime_lib_content_after = std::fs::read_to_string(&runtime_lib_path).unwrap(); + let configs_mod_content_after = std::fs::read_to_string(&configs_mod_path).unwrap(); + let configs_pallet_content = std::fs::read_to_string(&configs_pallet_path).unwrap(); + + let runtime_lib_diff = + TextDiff::from_lines(&runtime_lib_content_before, &runtime_lib_content_after); + let workspace_diff = TextDiff::from_lines(&workspace_content_before, &workspace_content_after); + let configs_mod_diff = + TextDiff::from_lines(&configs_mod_content_before, &configs_mod_content_after); + + let expected_runtime_lib_inserted_lines = vec![ + "\n", + " #[runtime::pallet_index(34)]\n", + " pub type Template = pallet_template;\n", + ]; + + let expected_workspace_inserted_lines = + vec!["members = [\"node\", \"runtime\", \"template\"]\n"]; + + let expected_workspace_deleted_lines = vec!["members = [\"node\", \"runtime\"]\n"]; + + let expected_configs_mod_inserted_lines = vec!["mod template;\n"]; + + let mut runtime_lib_inserted_lines = Vec::with_capacity(3); + let mut workspace_inserted_lines = Vec::with_capacity(1); + let mut workspace_deleted_lines = Vec::with_capacity(1); + let mut configs_mod_inserted_lines = Vec::with_capacity(1); + + for change in runtime_lib_diff.iter_all_changes() { + match change.tag() { + ChangeTag::Delete => panic!("No deletions in lib expected"), + ChangeTag::Insert => runtime_lib_inserted_lines.push(change.value()), + _ => (), + } + } + + for change in workspace_diff.iter_all_changes() { + match change.tag() { + ChangeTag::Delete => workspace_deleted_lines.push(change.value()), + ChangeTag::Insert => workspace_inserted_lines.push(change.value()), + _ => (), + } + } + + for change in configs_mod_diff.iter_all_changes() { + match change.tag() { + ChangeTag::Delete => panic!("No deletions expected"), + ChangeTag::Insert => configs_mod_inserted_lines.push(change.value()), + _ => (), + } + } + + assert_eq!(expected_runtime_lib_inserted_lines, runtime_lib_inserted_lines); + assert_eq!(expected_workspace_inserted_lines, workspace_inserted_lines); + assert_eq!(expected_workspace_deleted_lines, workspace_deleted_lines); + assert_eq!(expected_configs_mod_inserted_lines, configs_mod_inserted_lines); + + assert_eq!(configs_pallet_content, "impl pallet_template::Config for Runtime {}\n"); +} diff --git a/crates/pop-cli/tests/pop_add_to_pallet_config_type.rs b/crates/pop-cli/tests/pop_add_to_pallet_config_type.rs new file mode 100644 index 000000000..9841dc013 --- /dev/null +++ b/crates/pop-cli/tests/pop_add_to_pallet_config_type.rs @@ -0,0 +1,229 @@ +// SPDX-License-Identifier: GPL-3.0 + +use assert_cmd::Command; +use similar::{ChangeTag, TextDiff}; + +#[test] +fn pop_add_to_pallet_config_type_works() { + let temp = tempfile::tempdir().unwrap(); + let tempdir = temp.path(); + + Command::cargo_bin("pop") + .unwrap() + .current_dir(&tempdir) + .args(&["new", "parachain", "test_parachain", "-t", "standard"]) + .assert() + .success(); + + let test_parachain = tempdir.join("test_parachain"); + + Command::cargo_bin("pop") + .unwrap() + .current_dir(&test_parachain) + .args(&["new", "pallet", "template", "advanced", "-c", "runtime-event", "-d"]) + .assert() + .success(); + + let pallet_path = test_parachain.join("template"); + let pallet_lib_path = pallet_path.join("src").join("lib.rs"); + let pallet_mock_path = pallet_path.join("src").join("mock.rs"); + let pallet_impl_path = + test_parachain.join("runtime").join("src").join("configs").join("template.rs"); + let config_preludes_path = pallet_path.join("src").join("config_preludes.rs"); + + let lib_content_before_new_type = std::fs::read_to_string(&pallet_lib_path).unwrap(); + let mock_content_before_new_type = std::fs::read_to_string(&pallet_mock_path).unwrap(); + let pallet_impl_content_before_new_type = std::fs::read_to_string(&pallet_impl_path).unwrap(); + let config_preludes_path_content_before_new_type = + std::fs::read_to_string(&config_preludes_path).unwrap(); + + Command::cargo_bin("pop") + .unwrap() + .current_dir(&pallet_path) + .args(&["add-to", "pallet", "config-type", "-t", "fungibles"]) + .assert() + .success(); + + let lib_content_after_new_type = std::fs::read_to_string(&pallet_lib_path).unwrap(); + let mock_content_after_new_type = std::fs::read_to_string(&pallet_mock_path).unwrap(); + let pallet_impl_content_after_new_type = std::fs::read_to_string(&pallet_impl_path).unwrap(); + let config_preludes_path_content_after_new_type = + std::fs::read_to_string(&config_preludes_path).unwrap(); + + let lib_diff = TextDiff::from_lines(&lib_content_before_new_type, &lib_content_after_new_type); + let mock_diff = + TextDiff::from_lines(&mock_content_before_new_type, &mock_content_after_new_type); + let pallet_impl_diff = TextDiff::from_lines( + &pallet_impl_content_before_new_type, + &pallet_impl_content_after_new_type, + ); + let config_preludes_diff = TextDiff::from_lines( + &config_preludes_path_content_before_new_type, + &config_preludes_path_content_after_new_type, + ); + + let expected_lib_inserted_lines = vec![ + " #[pallet::no_default]\n", + " type Fungibles: fungible::Inspect\n", + " + fungible::Mutate\n", + " + fungible::hold::Inspect\n", + " + fungible::hold::Mutate\n", + " + fungible::freeze::Inspect\n", + " + fungible::freeze::Mutate;\n", + " /// A reason for placing a hold on funds\n", + " #[pallet::no_default_bounds]\n", + " type RuntimeHoldReason: From;\n", + " /// A reason for placing a freeze on funds\n", + " #[pallet::no_default_bounds]\n", + " type RuntimeFreezeReason: VariantCount;\n", + " /// A reason for the pallet placing a hold on funds.\n", + " #[pallet::composite_enum]\n", + " pub enum HoldReason {\n", + " /// Some hold reason\n", + " #[codec(index = 0)]\n", + " SomeHoldReason,\n", + " }\n", + "use frame::traits::fungible;\n", + "use frame::traits::VariantCount;\n", + ]; + + let expected_mock_inserted_lines = vec![ + "impl pallet_template::Config for Test {\n", + " type Fungibles = Balances;\n", + "}\n", + ]; + + let expected_mock_deleted_lines = vec!["impl pallet_template::Config for Test {}\n"]; + + let expected_impl_type_inserted_lines = vec![ + "impl pallet_template::Config for Runtime {\n", + " type Fungibles = Balances;\n", + "}\n", + ]; + + let expected_impl_type_deleted_lines = vec!["impl pallet_template::Config for Runtime {}\n"]; + + // There's 4 default configs (Testchain, solochain, relaychain, parachain), so the changes are + // applied four times each. + let expected_config_preludes_inserted_lines = vec![ + " #[inject_runtime_type]\n", + " type RuntimeHoldReason = ();\n", + " #[inject_runtime_type]\n", + " type RuntimeHoldReason = ();\n", + " #[inject_runtime_type]\n", + " type RuntimeHoldReason = ();\n", + " #[inject_runtime_type]\n", + " type RuntimeHoldReason = ();\n", + " #[inject_runtime_type]\n", + " type RuntimeFreezeReason = ();\n", + " #[inject_runtime_type]\n", + " type RuntimeFreezeReason = ();\n", + " #[inject_runtime_type]\n", + " type RuntimeFreezeReason = ();\n", + " #[inject_runtime_type]\n", + " type RuntimeFreezeReason = ();\n", + ]; + + let mut lib_inserted_lines = Vec::with_capacity(18); + let mut mock_inserted_lines = Vec::with_capacity(1); + let mut mock_deleted_lines = Vec::with_capacity(3); + let mut pallet_impl_inserted_lines = Vec::with_capacity(1); + let mut pallet_impl_deleted_lines = Vec::with_capacity(3); + let mut config_preludes_inserted_lines = Vec::with_capacity(16); + + for change in lib_diff.iter_all_changes() { + match change.tag() { + ChangeTag::Delete => panic!("No deletions in lib expected"), + ChangeTag::Insert => lib_inserted_lines.push(change.value()), + _ => (), + } + } + + for change in mock_diff.iter_all_changes() { + match change.tag() { + ChangeTag::Delete => mock_deleted_lines.push(change.value()), + ChangeTag::Insert => mock_inserted_lines.push(change.value()), + _ => (), + } + } + + for change in pallet_impl_diff.iter_all_changes() { + match change.tag() { + ChangeTag::Delete => pallet_impl_deleted_lines.push(change.value()), + ChangeTag::Insert => pallet_impl_inserted_lines.push(change.value()), + _ => (), + } + } + + for change in config_preludes_diff.iter_all_changes() { + match change.tag() { + ChangeTag::Delete => panic!("No deletions in lib expected"), + ChangeTag::Insert => config_preludes_inserted_lines.push(change.value()), + _ => (), + } + } + + assert_eq!(expected_lib_inserted_lines, lib_inserted_lines); + assert_eq!(expected_mock_inserted_lines, mock_inserted_lines); + assert_eq!(expected_mock_deleted_lines, mock_deleted_lines); + assert_eq!(expected_impl_type_inserted_lines, pallet_impl_inserted_lines); + assert_eq!(expected_impl_type_deleted_lines, pallet_impl_deleted_lines); + assert_eq!(expected_config_preludes_inserted_lines, config_preludes_inserted_lines); +} + +#[test] +fn pop_add_to_pallet_config_type_doesnt_modify_on_fail() { + let temp = tempfile::tempdir().unwrap(); + let tempdir = temp.path(); + + Command::cargo_bin("pop") + .unwrap() + .current_dir(&tempdir) + .args(&["new", "parachain", "test_parachain", "-t", "standard"]) + .assert() + .success(); + + let test_parachain = tempdir.join("test_parachain"); + + Command::cargo_bin("pop") + .unwrap() + .current_dir(&test_parachain) + .args(&["new", "pallet", "template", "advanced", "-c", "runtime-event", "-d"]) + .assert() + .success(); + + let pallet_path = test_parachain.join("template"); + let pallet_lib_path = pallet_path.join("src").join("lib.rs"); + let pallet_mock_path = pallet_path.join("src").join("mock.rs"); + let pallet_impl_path = + test_parachain.join("runtime").join("src").join("configs").join("template.rs"); + let config_preludes_path = pallet_path.join("src").join("config_preludes.rs"); + + let lib_content_before_new_type = std::fs::read_to_string(&pallet_lib_path).unwrap(); + let mock_content_before_new_type = std::fs::read_to_string(&pallet_mock_path).unwrap(); + let pallet_impl_content_before_new_type = std::fs::read_to_string(&pallet_impl_path).unwrap(); + let config_preludes_path_content_before_new_type = + std::fs::read_to_string(&config_preludes_path).unwrap(); + + Command::cargo_bin("pop") + .unwrap() + .current_dir(&pallet_path) + .args(&["add-to", "pallet", "config-type", "-t", "fungibles", "runtime-event"]) + .assert() + .failure() + .stderr(predicates::str::contains("Error: RuntimeEvent is already in use.")); + + let lib_content_after_new_type = std::fs::read_to_string(&pallet_lib_path).unwrap(); + let mock_content_after_new_type = std::fs::read_to_string(&pallet_mock_path).unwrap(); + let pallet_impl_content_after_new_type = std::fs::read_to_string(&pallet_impl_path).unwrap(); + let config_preludes_path_content_after_new_type = + std::fs::read_to_string(&config_preludes_path).unwrap(); + + assert_eq!(lib_content_before_new_type, lib_content_after_new_type); + assert_eq!(mock_content_before_new_type, mock_content_after_new_type); + assert_eq!(pallet_impl_content_before_new_type, pallet_impl_content_after_new_type); + assert_eq!( + config_preludes_path_content_before_new_type, + config_preludes_path_content_after_new_type + ); +} diff --git a/crates/pop-cli/tests/pop_add_to_runtime_pallet.rs b/crates/pop-cli/tests/pop_add_to_runtime_pallet.rs new file mode 100644 index 000000000..29dffc6c6 --- /dev/null +++ b/crates/pop-cli/tests/pop_add_to_runtime_pallet.rs @@ -0,0 +1,243 @@ +// SPDX-License-Identifier: GPL-3.0 + +use assert_cmd::Command; +use similar::{ChangeTag, TextDiff}; + +#[test] +fn pop_add_to_runtime_pallet_runtime_macro_v2_works() { + let temp = tempfile::tempdir().unwrap(); + let tempdir = temp.path(); + + Command::cargo_bin("pop") + .unwrap() + .current_dir(&tempdir) + .args(&["new", "parachain", "test_parachain", "-t", "standard"]) + .assert() + .success(); + + let test_parachain = tempdir.join("test_parachain"); + let runtime_path = test_parachain.join("runtime"); + + let manifest_path = runtime_path.join("Cargo.toml"); + let runtime_lib_path = runtime_path.join("src").join("lib.rs"); + let pallet_configs_path = runtime_path.join("src").join("configs"); + let pallet_configs_mod_path = pallet_configs_path.join("mod.rs"); + let contracts_pallet_config_path = pallet_configs_path.join("contracts.rs"); + + assert!(!contracts_pallet_config_path.exists()); + + let runtime_lib_content_before = std::fs::read_to_string(&runtime_lib_path).unwrap(); + let pallet_configs_mod_content_before = + std::fs::read_to_string(&pallet_configs_mod_path).unwrap(); + let manifest_content_before = std::fs::read_to_string(&manifest_path).unwrap(); + + Command::cargo_bin("pop") + .unwrap() + .current_dir(&test_parachain) + .args(&["add-to", "runtime", "pallet", "-p", "contracts"]) + .assert() + .success(); + + let runtime_lib_content_after = std::fs::read_to_string(&runtime_lib_path).unwrap(); + let pallet_configs_mod_content_after = + std::fs::read_to_string(&pallet_configs_mod_path).unwrap(); + let manifest_content_after = std::fs::read_to_string(&manifest_path).unwrap(); + let contracts_pallet_config_content = + std::fs::read_to_string(&contracts_pallet_config_path).unwrap(); + + let runtime_lib_diff = + TextDiff::from_lines(&runtime_lib_content_before, &runtime_lib_content_after); + let pallet_configs_mod_diff = + TextDiff::from_lines(&pallet_configs_mod_content_before, &pallet_configs_mod_content_after); + let manifest_diff = TextDiff::from_lines(&manifest_content_before, &manifest_content_after); + + let expected_inserted_lines_runtime_lib = vec![ + "\n", + " #[runtime::pallet_index(34)]\n", + " pub type Contracts = pallet_contracts;\n", + ]; + let expected_inserted_lines_configs_mod = vec!["mod contracts;\n"]; + let expected_inserted_lines_manifest = + vec!["pallet-contracts = { version = \"27.0.0\", default-features = false }\n"]; + + let mut inserted_lines_runtime_lib = Vec::with_capacity(3); + let mut inserted_lines_configs_mod = Vec::with_capacity(1); + let mut inserted_lines_manifest = Vec::with_capacity(1); + + for change in runtime_lib_diff.iter_all_changes() { + match change.tag() { + ChangeTag::Delete => panic!("no deletion expected"), + ChangeTag::Insert => inserted_lines_runtime_lib.push(change.value()), + _ => (), + } + } + + for change in pallet_configs_mod_diff.iter_all_changes() { + match change.tag() { + ChangeTag::Delete => panic!("no deletion expected"), + ChangeTag::Insert => inserted_lines_configs_mod.push(change.value()), + _ => (), + } + } + + for change in manifest_diff.iter_all_changes() { + match change.tag() { + ChangeTag::Delete => panic!("no deletion expected"), + ChangeTag::Insert => inserted_lines_manifest.push(change.value()), + _ => (), + } + } + + assert_eq!(expected_inserted_lines_runtime_lib, inserted_lines_runtime_lib); + assert_eq!(expected_inserted_lines_configs_mod, inserted_lines_configs_mod); + assert_eq!(expected_inserted_lines_manifest, inserted_lines_manifest); + + assert_eq!( + contracts_pallet_config_content, + r#"use crate::Balances; +parameter_types! { + pub Schedule : pallet_contracts::Schedule < Runtime > = Default::default(); +} + +#[derive_impl(pallet_contracts::config_preludes::TestDefaultConfig)] +impl pallet_contracts::Config for Runtime { + type Currency = Balances; + type Schedule = [pallet_contracts::Frame; 5]; + type CallStack = Schedule; +} +"# + ); +} + +#[test] +fn pop_add_to_runtime_pallet_construct_runtime_specified_impl_path_works() { + let temp = tempfile::tempdir().unwrap(); + let tempdir = temp.path(); + + Command::cargo_bin("pop") + .unwrap() + .current_dir(&tempdir) + .args(&[ + "new", + "parachain", + "test_parachain2", + "openzeppelin", + "-t", + "openzeppelin/generic-template", + "-r", + "v2.0.3", + ]) + .assert() + .success(); + + let test_parachain = tempdir.join("test_parachain2"); + let runtime_path = test_parachain.join("runtime"); + + let manifest_path = runtime_path.join("Cargo.toml"); + let runtime_lib_path = runtime_path.join("src").join("lib.rs"); + + let runtime_lib_content_before = std::fs::read_to_string(&runtime_lib_path).unwrap(); + let manifest_content_before = std::fs::read_to_string(&manifest_path).unwrap(); + + Command::cargo_bin("pop") + .unwrap() + .current_dir(&test_parachain) + .args(&[ + "add-to", + "runtime", + "pallet", + "-p", + "contracts", + "--pallet-impl-path", + runtime_lib_path.to_str().unwrap(), + ]) + .assert() + .success(); + + let runtime_lib_content_after = std::fs::read_to_string(&runtime_lib_path).unwrap(); + let manifest_content_after = std::fs::read_to_string(&manifest_path).unwrap(); + + let runtime_lib_diff = + TextDiff::from_lines(&runtime_lib_content_before, &runtime_lib_content_after); + let manifest_diff = TextDiff::from_lines(&manifest_content_before, &manifest_content_after); + + let expected_inserted_lines_runtime_lib = vec![ + "use crate::Balances;\n", + "parameter_types! {\n", + " pub Schedule : pallet_contracts::Schedule < Runtime > = Default::default();\n", + "}\n", + "\n", + "#[derive_impl(pallet_contracts::config_preludes::TestDefaultConfig)]\n", + "impl pallet_contracts::Config for Runtime {\n", + " type CallStack = Schedule;\n", + " type Currency = Balances;\n", + " type Schedule = [pallet_contracts::Frame; 5];\n", + "}\n", + ]; + let expected_inserted_lines_manifest = + vec!["pallet-contracts = { version = \"27.0.0\", default-features = false }\n"]; + + let mut inserted_lines_runtime_lib = Vec::with_capacity(3); + let mut inserted_lines_manifest = Vec::with_capacity(1); + + for change in runtime_lib_diff.iter_all_changes() { + match change.tag() { + ChangeTag::Delete => panic!("no deletion expected"), + ChangeTag::Insert => inserted_lines_runtime_lib.push(change.value()), + _ => (), + } + } + + for change in manifest_diff.iter_all_changes() { + match change.tag() { + ChangeTag::Delete => panic!("no deletion expected"), + ChangeTag::Insert => inserted_lines_manifest.push(change.value()), + _ => (), + } + } + + assert_eq!(expected_inserted_lines_runtime_lib, inserted_lines_runtime_lib); + assert_eq!(expected_inserted_lines_manifest, inserted_lines_manifest); +} + +#[test] +fn pop_add_to_runtime_pallet_doesnt_modify_on_failure() { + let temp = tempfile::tempdir().unwrap(); + let tempdir = temp.path(); + + Command::cargo_bin("pop") + .unwrap() + .current_dir(&tempdir) + .args(&["new", "parachain", "test_parachain3", "-t", "contracts"]) + .assert() + .success(); + + let test_parachain = tempdir.join("test_parachain3"); + let runtime_path = test_parachain.join("runtime"); + + let manifest_path = runtime_path.join("Cargo.toml"); + let runtime_lib_path = runtime_path.join("src").join("lib.rs"); + let pallet_configs_mod_path = runtime_path.join("src").join("configs").join("mod.rs"); + + let runtime_lib_content_before = std::fs::read_to_string(&runtime_lib_path).unwrap(); + let pallet_configs_mod_content_before = + std::fs::read_to_string(&pallet_configs_mod_path).unwrap(); + let manifest_content_before = std::fs::read_to_string(&manifest_path).unwrap(); + + Command::cargo_bin("pop") + .unwrap() + .current_dir(&test_parachain) + .args(&["add-to", "runtime", "pallet", "-p", "contracts"]) + .assert() + .failure() + .stderr(predicates::str::contains("Error: contracts is already in use.")); + + let runtime_lib_content_after = std::fs::read_to_string(&runtime_lib_path).unwrap(); + let pallet_configs_mod_content_after = + std::fs::read_to_string(&pallet_configs_mod_path).unwrap(); + let manifest_content_after = std::fs::read_to_string(&manifest_path).unwrap(); + + assert_eq!(runtime_lib_content_before, runtime_lib_content_after); + assert_eq!(pallet_configs_mod_content_before, pallet_configs_mod_content_after); + assert_eq!(manifest_content_before, manifest_content_after); +} diff --git a/crates/pop-common/Cargo.toml b/crates/pop-common/Cargo.toml index 49e0b6421..a0a718cce 100644 --- a/crates/pop-common/Cargo.toml +++ b/crates/pop-common/Cargo.toml @@ -14,14 +14,15 @@ contract-build.workspace = true contract-extrinsics.workspace = true duct.workspace = true flate2.workspace = true +fs_rollback.workspace = true git2.workspace = true git2_credentials.workspace = true -pathdiff.workspace = true -proc-macro2.workspace = true -prettyplease.workspace = true ink_env.workspace = true +proc-macro2.workspace = true regex.workspace = true reqwest.workspace = true +rustilities = { workspace = true, features = ["manifest"] } +rust_writer.workspace = true scale-info.workspace = true serde_json.workspace = true serde.workspace = true diff --git a/crates/pop-common/src/errors.rs b/crates/pop-common/src/errors.rs index dad42ec8b..f3cf0aa11 100644 --- a/crates/pop-common/src/errors.rs +++ b/crates/pop-common/src/errors.rs @@ -29,10 +29,12 @@ pub enum Error { /// An error occurred while parsing the provided secret URI. #[error("Failed to parse secret URI: {0}")] ParseSecretURI(String), + #[error("{0}")] + RollbackError(#[from] fs_rollback::Error), + #[error("Failed to update files: {0}")] + RustWriterError(#[from] rust_writer::Error), #[error("SourceError error: {0}")] SourceError(#[from] sourcing::Error), - #[error("Syn parse error: {0}. Pop CLI has to parse your code in order to expand it. To preserve its structure while parsing, some temporal type markers may be added in the target part of your code. If declaring a type in that part of the code is invalid Rust code, that may be the origin of this error. Please review the code you're modifying to solve this. Example: If you're modifying an Enum likee the following one, it'll fail as types cannot be defined inside enums\npub enum Enum{{\n\t//This is the painful comment\n\tA,\n\tB\n}}")] - SynError(#[from] syn::Error), #[error("TemplateError error: {0}")] TemplateError(#[from] templates::Error), #[error("TomlError: {0}")] diff --git a/crates/pop-common/src/helpers.rs b/crates/pop-common/src/helpers.rs index 528d4b652..7fd1f51ce 100644 --- a/crates/pop-common/src/helpers.rs +++ b/crates/pop-common/src/helpers.rs @@ -5,8 +5,7 @@ use std::{ collections::HashMap, fs, io::{Read, Write}, - path::{Component, Path, PathBuf}, - process::{Command, Output}, + path::{Path, PathBuf}, }; /// Replaces occurrences of specified strings in a file with new values. @@ -41,31 +40,6 @@ pub fn get_project_name_from_path<'a>(path: &'a Path, default: &'a str) -> &'a s path.file_name().and_then(|name| name.to_str()).unwrap_or(default) } -/// Transforms a path without prefix into a relative path starting at the current directory. -/// -/// # Arguments -/// * `path` - The path to be prefixed if needed. -pub fn prefix_with_current_dir_if_needed(path: PathBuf) -> PathBuf { - let components = &path.components().collect::>(); - if !components.is_empty() { - // If the first component is a normal component, we prefix the path with the current dir - if let Component::Normal(_) = components[0] { - return as AsRef>::as_ref(&Component::CurDir).join(path); - } - } - path -} - -pub fn format_dir(path: &Path) -> Result { - Command::new("cargo") - .arg("+nightly") - .arg("fmt") - .arg("--all") - .current_dir(path) - .output() - .or(Command::new("cargo").arg("fmt").arg("--all").current_dir(path).output()) -} - pub fn capitalize_str(input: &str) -> String { if input.is_empty() { return String::new(); @@ -110,31 +84,4 @@ mod tests { assert_eq!(get_project_name_from_path(path, "my-contract"), "my-contract"); Ok(()) } - - #[test] - fn prefix_with_current_dir_if_needed_works_well() { - let no_prefixed_path = PathBuf::from("my/path".to_string()); - let current_dir_prefixed_path = PathBuf::from("./my/path".to_string()); - let parent_dir_prefixed_path = PathBuf::from("../my/path".to_string()); - let root_dir_prefixed_path = PathBuf::from("/my/path".to_string()); - let empty_path = PathBuf::from("".to_string()); - - assert_eq!( - prefix_with_current_dir_if_needed(no_prefixed_path), - PathBuf::from("./my/path/".to_string()) - ); - assert_eq!( - prefix_with_current_dir_if_needed(current_dir_prefixed_path), - PathBuf::from("./my/path/".to_string()) - ); - assert_eq!( - prefix_with_current_dir_if_needed(parent_dir_prefixed_path), - PathBuf::from("../my/path/".to_string()) - ); - assert_eq!( - prefix_with_current_dir_if_needed(root_dir_prefixed_path), - PathBuf::from("/my/path/".to_string()) - ); - assert_eq!(prefix_with_current_dir_if_needed(empty_path), PathBuf::from("".to_string())); - } } diff --git a/crates/pop-common/src/lib.rs b/crates/pop-common/src/lib.rs index 9867f1139..f2c1eb1dd 100644 --- a/crates/pop-common/src/lib.rs +++ b/crates/pop-common/src/lib.rs @@ -5,16 +5,9 @@ use std::net::TcpListener; pub use build::Profile; pub use errors::Error; pub use git::{Git, GitHub, Release}; -pub use helpers::{ - capitalize_str, format_dir, get_project_name_from_path, prefix_with_current_dir_if_needed, - replace_in_file, -}; -pub use manifest::{ - add_crate_to_workspace, compute_new_pallet_impl_path, find_crate_name, - find_pallet_runtime_path, find_workspace_toml, -}; +pub use helpers::{capitalize_str, get_project_name_from_path, replace_in_file}; +pub use manifest::{add_crate_to_workspace, find_pallet_runtime_path}; pub use metadata::format_type; -pub use rollback::Rollback; pub use signer::create_signer; pub use sourcing::set_executable_permission; pub use subxt::{Config, PolkadotConfig as DefaultConfig}; @@ -29,8 +22,7 @@ pub mod manifest; /// Provides functionality for formatting and resolving metadata types. pub mod metadata; pub mod polkadot_sdk; -mod rollback; -pub mod rust_writer; +pub mod rust_writer_helpers; /// Provides functionality for creating a signer from a secret URI. pub mod signer; pub mod sourcing; diff --git a/crates/pop-common/src/manifest.rs b/crates/pop-common/src/manifest.rs index 760ab5e7d..9b9ad3cde 100644 --- a/crates/pop-common/src/manifest.rs +++ b/crates/pop-common/src/manifest.rs @@ -1,18 +1,13 @@ // SPDX-License-Identifier: GPL-3.0 -pub mod types; -use crate::{rust_writer, Error, Rollback}; +use crate::Error; use anyhow; pub use cargo_toml::{Dependency, LtoSetting, Manifest, Profile, Profiles}; -use pathdiff::diff_paths; -use proc_macro2::Span; use std::{ fs::{read_to_string, write}, - io::Write, path::{Path, PathBuf}, }; -use syn::{parse_quote, Ident}; -use toml_edit::{value, Array, DocumentMut, InlineTable, Item, Table, Value}; +use toml_edit::{value, Array, DocumentMut, Item, Value}; /// Parses the contents of a `Cargo.toml` manifest. /// @@ -34,45 +29,6 @@ pub fn from_path(path: Option<&Path>) -> Result { Ok(Manifest::from_path(path.canonicalize()?)?) } -/// This function is used to determine if a Path is contained inside a workspace, and returns a -/// PathBuf to the workspace Cargo.toml if found. -/// -/// # Arguments -/// * `target_dir` - A directory that may be contained inside a workspace -pub fn find_workspace_toml(target_dir: &Path) -> Option { - let mut dir = target_dir; - while let Some(parent) = dir.parent() { - // This condition is necessary to avoid that calling the function from a workspace using a - // path which isn't contained in a workspace returns `Some(Cargo.toml)` refering the - // workspace from where the function has been called instead of the expected `None`. - if parent.to_str() == Some("") { - return None; - } - let cargo_toml = parent.join("Cargo.toml"); - if cargo_toml.exists() { - if let Ok(contents) = read_to_string(&cargo_toml) { - if contents.contains("[workspace]") { - return Some(cargo_toml); - } - } - } - dir = parent; - } - None -} - -pub fn find_crate_manifest(target_dir: &Path) -> Option { - let mut dir = target_dir; - while let Some(parent) = dir.parent() { - let cargo_toml = parent.join("Cargo.toml"); - if cargo_toml.exists() { - return Some(cargo_toml); - } - dir = parent; - } - None -} - /// This function is used to add a crate to a workspace. /// # Arguments /// @@ -115,104 +71,9 @@ pub fn add_crate_to_workspace(workspace_toml: &Path, crate_path: &Path) -> anyho Ok(()) } -pub fn add_crate_to_dependencies( - maybe_rolled_manifest_path: &Path, - manifest_path: &Path, - crate_name: &str, - dependencie_format: types::CrateDependencie, -) -> Result<(), Error> { - fn do_add_crate_to_dependencies( - manifest_path: &Path, - dependencies: &mut Table, - crate_name: &str, - dependencie_format: types::CrateDependencie, - ) -> Result<(), Error> { - match dependencie_format { - types::CrateDependencie::Workspace => { - let mut crate_declaration = Table::new(); - crate_declaration.set_dotted(true); - crate_declaration.insert("workspace", value(true)); - dependencies.insert(crate_name, Item::Table(crate_declaration)); - }, - types::CrateDependencie::External { version } => { - let mut crate_declaration = InlineTable::new(); - crate_declaration.insert( - "version", - value(version) - .as_value() - .expect("version is String, so value(version) is Value::String; qed;") - .clone(), - ); - crate_declaration.insert( - "default-features", - value(false) - .as_value() - .expect("false is bool so value(false) is Value::Boolean; qed;") - .clone(), - ); - dependencies.insert(crate_name, value(crate_declaration)); - }, - types::CrateDependencie::Local { local_crate_path } => { - let mut crate_declaration = InlineTable::new(); - let relative_path = if let Some(path) = diff_paths( - &local_crate_path, - manifest_path.parent().expect("A file's always contained in a directory;qed;"), - ) - .and_then(|path| path.to_str().map(|path| path.to_string())) - { - path - } else { - return Err(Error::Config("Calling add_crate_to_dependencies with an internal crate whose path isn't valid.".to_string())); - }; - - crate_declaration.insert( - "path", - value(&relative_path) - .as_value() - .expect("version is String, so value(version) is Value::String; qed;") - .clone(), - ); - crate_declaration.insert( - "default-features", - value(false) - .as_value() - .expect("false is bool so value(false) is Value::Boolean; qed;") - .clone(), - ); - dependencies.insert(crate_name, value(crate_declaration)); - }, - } - Ok(()) - } - let content = read_to_string(maybe_rolled_manifest_path)?; - let mut doc = content.parse::()?; - if let Some(Item::Table(dependencies)) = doc.get_mut("dependencies") { - do_add_crate_to_dependencies(manifest_path, dependencies, crate_name, dependencie_format)?; - } else { - let mut dependencies = Table::new(); - do_add_crate_to_dependencies( - manifest_path, - &mut dependencies, - crate_name, - dependencie_format, - )?; - doc.insert("dependencies", Item::Table(dependencies)); - } - - write(maybe_rolled_manifest_path, doc.to_string())?; - Ok(()) -} - -pub fn find_crate_name(manifest_path: &Path) -> Result { - Ok(Manifest::from_path(manifest_path)? - .package - .ok_or(cargo_toml::Error::Other("Package not found in Cargo.toml")) - .map(|package| package.name)?) -} - pub fn is_runtime_crate(path: &Path) -> bool { // Ideally the runtime would be contained inside a workspace - if let Some(workspace_toml) = find_workspace_toml(path) { + if let Some(workspace_toml) = rustilities::manifest::find_workspace_manifest(path) { match Manifest::from_path(&workspace_toml) .ok() .map(|manifest| manifest.workspace.map(|workspace| workspace.members)) @@ -233,7 +94,7 @@ pub fn is_runtime_crate(path: &Path) -> bool { } pub fn find_pallet_runtime_path(pallet_path: &Path) -> Option { - if let Some(mut workspace_toml) = find_workspace_toml(pallet_path) { + if let Some(mut workspace_toml) = rustilities::manifest::find_workspace_manifest(pallet_path) { match Manifest::from_path(&workspace_toml) .ok() .map(|manifest| manifest.workspace.map(|workspace| workspace.members)) @@ -249,73 +110,6 @@ pub fn find_pallet_runtime_path(pallet_path: &Path) -> Option { } } -pub fn compute_new_pallet_impl_path( - runtime_path: &Path, - pallet_name: &str, -) -> Result<(Rollback, bool), Error> { - let runtime_src_path = runtime_path.join("src"); - let runtime_lib_path = runtime_src_path.join("lib.rs"); - let configs_rs_path = runtime_src_path.join("configs.rs"); - let configs_folder_path = runtime_src_path.join("configs"); - let configs_mod_path = configs_folder_path.join("mod.rs"); - let pallet_config_file = configs_folder_path.join(format!("{}.rs", pallet_name)); - let pallet_name_ident = Ident::new(pallet_name, Span::call_site()); - match (configs_rs_path.is_file(), configs_mod_path.is_file()) { - // The runtime is using a configs module without the mod.rs sintax - (true, false) => { - let mut rollback = Rollback::with_capacity(1, 1, 0); - let roll_configs_rs_path = rollback.note_file(&configs_rs_path)?; - rust_writer::add_mod_declarations( - &roll_configs_rs_path, - vec![parse_quote!(mod #pallet_name_ident;)], - )?; - rollback.new_file(&pallet_config_file)?; - Ok((rollback, false)) - }, - // The runtime is using a configs module with the mod.rs syntax - (false, true) => { - let mut rollback = Rollback::with_capacity(1, 1, 0); - let roll_configs_mod_path = rollback.note_file(&configs_mod_path)?; - rust_writer::add_mod_declarations( - &roll_configs_mod_path, - vec![parse_quote!(mod #pallet_name_ident;)], - )?; - rollback.new_file(&pallet_config_file)?; - Ok((rollback, false)) - }, - // The runtime isn't using a configs module yet, we opt for the configs.rs - // convention - (false, false) => { - let mut rollback = Rollback::with_capacity(1, 2, 1); - let roll_runtime_lib_path = rollback.note_file(&runtime_lib_path)?; - rust_writer::add_mod_declarations( - &roll_runtime_lib_path, - vec![parse_quote!( - pub mod configs; - )], - )?; - - rollback.new_file(&configs_rs_path)?; - rollback.new_dir(&configs_folder_path)?; - rollback.new_file(&pallet_config_file)?; - - let (rollback, mut write_configs_rs) = rollback - .ok_or_rollback(std::fs::OpenOptions::new().write(true).open(configs_rs_path))?; - - let (rollback, _) = rollback.ok_or_rollback(writeln!( - write_configs_rs, - "{}", - format!("mod {};", pallet_name) - ))?; - - Ok((rollback, true)) - }, - // Both approaches at the sime time aren't supported by the compiler, so this is - // unreachable in a compiling project - (true, true) => unreachable!(), - } -} - pub fn get_pallet_impl_path(runtime_path: &Path, pallet_name: &str) -> Result { let pallet_config_path = runtime_path.join("src").join("configs").join(format!("{}.rs", pallet_name)); @@ -452,49 +246,6 @@ mod tests { Ok(()) } - #[test] - fn find_workspace_toml_works_well() { - let test_builder = TestBuilder::default() - .add_workspace() - .add_inside_workspace_dir() - .add_workspace_cargo_toml( - r#"[workspace] - resolver = "2" - members = ["member1"] - "#, - ) - .add_outside_workspace_dir(); - assert!(find_workspace_toml( - test_builder - .inside_workspace_dir - .as_ref() - .expect("Inside workspace dir should exist") - .path() - ) - .is_some()); - assert_eq!( - find_workspace_toml( - test_builder - .inside_workspace_dir - .as_ref() - .expect("Inside workspace dir should exist") - .path() - ) - .expect("The Cargo.toml should exist at this point"), - test_builder.workspace_cargo_toml.expect("Cargo.toml should exist") - ); - assert!(find_workspace_toml( - test_builder - .outside_workspace_dir - .as_ref() - .expect("Outside workspace dir should exist") - .path() - ) - .is_none()); - // Calling the function from a relative path which parent is "" returns None - assert!(find_workspace_toml(&PathBuf::from("..")).is_none()); - } - #[test] fn add_crate_to_workspace_works_well_if_members_exists() { let test_builder = TestBuilder::default() diff --git a/crates/pop-common/src/manifest/types.rs b/crates/pop-common/src/manifest/types.rs deleted file mode 100644 index ce714ab26..000000000 --- a/crates/pop-common/src/manifest/types.rs +++ /dev/null @@ -1,10 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0 - -use std::path::PathBuf; - -#[derive(Debug, Clone, PartialEq)] -pub enum CrateDependencie { - External { version: String }, - Local { local_crate_path: PathBuf }, - Workspace, -} diff --git a/crates/pop-common/src/rollback.rs b/crates/pop-common/src/rollback.rs deleted file mode 100644 index 922ebc1ad..000000000 --- a/crates/pop-common/src/rollback.rs +++ /dev/null @@ -1,110 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0 - -use crate::Error; -use std::{ - fs::File, - path::{Path, PathBuf}, -}; -use tempfile::NamedTempFile; - -#[derive(Debug)] -pub struct Rollback { - // Keep the temp_files inside the rollback struct, so they live until the Rollback dissapears - temp_files: Vec, - // A tuple of PathBuf representing the paths to the temporary file and the original file - noted: Vec<(PathBuf, PathBuf)>, - // A registry of new_files - new_files: Vec, - // A registry of new directories - new_dirs: Vec, -} - -impl Rollback { - pub fn new() -> Self { - Self { - temp_files: Vec::new(), - noted: Vec::new(), - new_files: Vec::new(), - new_dirs: Vec::new(), - } - } - - pub fn with_capacity( - note_capacity: usize, - new_files_capacity: usize, - new_dirs_capacity: usize, - ) -> Self { - Self { - temp_files: Vec::with_capacity(note_capacity), - noted: Vec::with_capacity(note_capacity), - new_files: Vec::with_capacity(new_files_capacity), - new_dirs: Vec::with_capacity(new_dirs_capacity), - } - } - - pub fn note_file(&mut self, original: &Path) -> Result { - let temp_file = NamedTempFile::new()?; - std::fs::write(&temp_file, &std::fs::read_to_string(original)?)?; - let temp_file_path = temp_file.path().to_path_buf(); - self.temp_files.push(temp_file); - self.noted.push((temp_file_path.clone(), original.to_path_buf())); - Ok(temp_file_path) - } - - pub fn new_file(&mut self, file: &Path) -> Result<(), Error> { - File::create(file)?; - self.new_files.push(file.to_path_buf()); - Ok(()) - } - - pub fn new_dir(&mut self, dir: &Path) -> Result<(), Error> { - std::fs::create_dir(dir)?; - self.new_dirs.push(dir.to_path_buf()); - Ok(()) - } - - pub fn noted_files(&self) -> Vec { - self.noted - .iter() - .map(|(_, original)| original.to_path_buf()) - .collect::>() - } - - pub fn new_files(&self) -> Vec { - self.new_files.clone() - } - - pub fn new_dirs(&self) -> Vec { - self.new_dirs.clone() - } - - pub fn commit(self) { - self.noted.into_iter().for_each(|(temp, original)| { - std::fs::write( - original, - std::fs::read_to_string(temp) - .expect("The temp file exists as long as Self exists; qed"), - ) - .expect("The original file exists; qed;") - }); - } - - pub fn rollback(self) { - self.new_files.into_iter().for_each(|file| { - std::fs::remove_file(&file).expect("The file exists cause it's in the rollback; qed;") - }); - self.new_dirs.into_iter().for_each(|dir| { - std::fs::remove_dir_all(&dir).expect("Thee dir exists cause it's in the rollback; qed;") - }); - } - - pub fn ok_or_rollback(self, result: Result) -> Result<(Self, S), E> { - match result { - Ok(result) => Ok((self, result)), - Err(err) => { - self.rollback(); - Err(err) - }, - } - } -} diff --git a/crates/pop-common/src/rust_writer.rs b/crates/pop-common/src/rust_writer.rs deleted file mode 100644 index de7beecae..000000000 --- a/crates/pop-common/src/rust_writer.rs +++ /dev/null @@ -1,323 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0 - -use crate::{capitalize_str, Error}; -use prettyplease::unparse; -use proc_macro2::Span; -use std::{ - fs, - path::{Path, PathBuf}, -}; -use syn::{parse_str, Ident, ImplItem, ItemEnum, ItemMod, ItemUse, TraitBound, Type}; - -mod expand; -mod parse; -mod preserver; -#[cfg(test)] -mod tests; -pub mod types; - -pub fn update_config_trait( - file_path: &Path, - type_name: Ident, - trait_bounds: Vec, - default_config: &types::DefaultConfigType, -) -> Result<(), Error> { - let mut preserver = types::Preserver::new("pub mod pallet"); - preserver.add_inners(vec!["pub trait Config"]); - - let mut ast = preserver::preserve_and_parse(fs::read_to_string(file_path)?, vec![preserver])?; - - // Expand the config trait - expand::expand_pallet_config_trait(&mut ast, default_config, type_name, trait_bounds); - let generated_code = preserver::resolve_preserved(unparse(&ast)); - - fs::write(file_path, &generated_code).map_err(|_| { - Error::WriteError(format!("Path :{}", file_path.to_str().unwrap_or("Invalid UTF-8 path"))) - })?; - - Ok(()) -} - -pub fn add_type_to_runtimes( - type_name: Ident, - runtime_value: Type, - pallet_impl_path: Option, - pallet_mock_path: &Path, - pallet_crate_name: &str, -) -> Result<(), Error> { - fn do_add_type_to_runtime( - file_content: &str, - file_path: &Path, - type_name: Ident, - runtime_value: Type, - pallet_crate_name: &str, - ) -> Result<(), Error> { - let pallet_name = pallet_crate_name.replace("-", "_"); - let preserver = types::Preserver::new(&format!("impl {}::Config", pallet_name)); - - let mut ast = preserver::preserve_and_parse(file_content.to_string(), vec![preserver])?; - - expand::expand_runtime_add_type_to_impl_block( - &mut ast, - type_name, - runtime_value, - &pallet_name, - ); - - let generated_code = preserver::resolve_preserved(unparse(&ast)); - - fs::write(file_path, generated_code).map_err(|_| { - Error::WriteError(format!( - "Path :{}", - file_path.to_str().unwrap_or("Invalid UTF-8 path") - )) - })?; - - Ok(()) - } - - // All pallets should have a mock runtime, so we add the type to it. - let mock_content = fs::read_to_string(&pallet_mock_path)?; - do_add_type_to_runtime( - &mock_content, - &pallet_mock_path, - type_name.clone(), - runtime_value.clone(), - pallet_crate_name, - )?; - - // If the pallet is contained inside a runtime add the type to that runtime as well - if let Some(pallet_impl_path) = pallet_impl_path { - let pallet_impl_content = fs::read_to_string(&pallet_impl_path)?; - do_add_type_to_runtime( - &pallet_impl_content, - &pallet_impl_path, - type_name, - runtime_value, - pallet_crate_name, - )?; - } - Ok(()) -} - -pub fn add_type_to_config_preludes( - file_path: &Path, - type_default_impl: ImplItem, -) -> Result<(), Error> { - // Define preservers for the most common used struct names for default config. Both for - // independent module file and module contained inside pallet - let preserver_testchain_config = - types::Preserver::new("impl DefaultConfig for TestDefaultConfig"); - let mut preserver_testchain_config_inside_pallet_mod = types::Preserver::new("pub mod pallet"); - preserver_testchain_config_inside_pallet_mod - .add_inners(vec!["pub mod config_preludes", "impl DefaultConfig for TestDefaultConfig"]); - - let preserver_solochain_config = - types::Preserver::new("impl DefaultConfig for SolochainDefaultConfig"); - let mut preserver_solochain_config_inside_pallet_mod = types::Preserver::new("pub mod pallet"); - preserver_solochain_config_inside_pallet_mod.add_inners(vec![ - "pub mod config_preludes", - "impl DefaultConfig for SolochainDefaultConfig", - ]); - - let preserver_relaychain_config = - types::Preserver::new("impl DefaultConfig for RelayChainDefaultConfig"); - let mut preserver_relaychain_config_inside_pallet_mod = types::Preserver::new("pub mod pallet"); - preserver_relaychain_config_inside_pallet_mod.add_inners(vec![ - "pub mod config_preludes", - "impl DefaultConfig for RelayChainDefaultConfig", - ]); - - let preserver_parachain_config = - types::Preserver::new("impl DefaultConfig for ParaChainDefaultConfig"); - let mut preserver_parachain_config_inside_pallet_mod = types::Preserver::new("pub mod pallet"); - preserver_parachain_config_inside_pallet_mod.add_inners(vec![ - "pub mod config_preludes", - "impl DefaultConfig for ParaChainDefaultConfig", - ]); - - let mut ast = preserver::preserve_and_parse( - fs::read_to_string(file_path)?, - vec![ - preserver_testchain_config, - preserver_testchain_config_inside_pallet_mod, - preserver_solochain_config, - preserver_solochain_config_inside_pallet_mod, - preserver_relaychain_config, - preserver_relaychain_config_inside_pallet_mod, - preserver_parachain_config, - preserver_parachain_config_inside_pallet_mod, - ], - )?; - - // Expand the config_preludes - expand::expand_pallet_config_preludes(&mut ast, type_default_impl); - - let generated_code = preserver::resolve_preserved(unparse(&ast)); - - fs::write(file_path, generated_code).map_err(|_| { - Error::WriteError(format!("Path :{}", file_path.to_str().unwrap_or("Invalid UTF-8 path"))) - })?; - - Ok(()) -} - -pub fn add_pallet_to_runtime_module( - pallet_name: &str, - runtime_lib_path: &Path, -) -> Result<(), Error> { - let preserver_construct_runtime = types::Preserver::new("construct_runtime!"); - let preserver_mod_runtime = types::Preserver::new("mod runtime"); - let mut ast = preserver::preserve_and_parse( - fs::read_to_string(runtime_lib_path)?, - vec![preserver_construct_runtime, preserver_mod_runtime], - )?; - // Parse the runtime to find which of the runtime macros is being used and the highest - // pallet index used (if needed, otherwise 0). - let used_macro = parse::find_used_runtime_macro(&ast)?; - let mut highest_index = 0; - if let types::RuntimeUsedMacro::Runtime = used_macro { - highest_index = parse::find_highest_pallet_index(&ast)?; - } - - // Find the pallet name and the pallet item to be added to the runtime. If the pallet_name is - // behind the form pallet-some-thing, pallet_item becomes Something. - let pallet_item = Ident::new( - &capitalize_str( - &pallet_name - .split("pallet-") - .last() - .ok_or(Error::Config( - "Pallet crates are supposed to be called pallet-something.".to_string(), - ))? - .replace("-", ""), - ), - Span::call_site(), - ); - let pallet_name_type = parse_str::(&pallet_name.replace("-", "_"))?; - - // Expand the ast with the new pallet. pallet-some-thing becomes pallet_some_thing in the code - expand::expand_runtime_add_pallet( - &mut ast, - highest_index, - used_macro, - pallet_name_type, - pallet_item, - ); - - let generated_code = preserver::resolve_preserved(unparse(&ast)); - - fs::write(runtime_lib_path, generated_code).map_err(|_| { - Error::WriteError(format!( - "Path :{}", - runtime_lib_path.to_str().unwrap_or("Invalid UTF-8 path") - )) - })?; - - Ok(()) -} - -pub fn add_pallet_impl_block_to_runtime( - pallet_name: &str, - pallet_impl_path: &Path, - parameter_types: Vec, - types: Vec, - values: Vec, - default_config: bool, -) -> Result<(), Error> { - // Nothing to preserve in this ast as this is a new impl block - let mut ast = preserver::preserve_and_parse(fs::read_to_string(pallet_impl_path)?, vec![])?; - let pallet_name_ident = Ident::new(&pallet_name.replace("-", "_"), Span::call_site()); - // Expand the runtime to add the impl_block - expand::expand_runtime_add_impl_block( - &mut ast, - pallet_name_ident, - parameter_types, - default_config, - ); - // Expand the block to add the types - types.into_iter().zip(values).for_each(|(type_, value)| { - expand::expand_runtime_add_type_to_impl_block( - &mut ast, - type_, - value, - &pallet_name.replace("-", "_"), - ) - }); - - let generated_code = preserver::resolve_preserved(unparse(&ast)); - - fs::write(pallet_impl_path, generated_code).map_err(|_| { - Error::WriteError(format!( - "Path :{}", - pallet_impl_path.to_str().unwrap_or("Invalid UTF-8 path") - )) - })?; - Ok(()) -} - -pub fn add_use_statements(file_path: &Path, use_statements: Vec) -> Result<(), Error> { - // Preserve the first use/pub use statement to insert the new one where they're - let preserver_use = types::Preserver::new("use"); - let preserver_pub_use = types::Preserver::new("pub use"); - let mut ast = preserver::preserve_and_parse( - fs::read_to_string(file_path)?, - vec![preserver_use, preserver_pub_use], - )?; - - use_statements.into_iter().for_each(|use_statement| { - if !parse::find_use_statement(&ast, &use_statement) { - expand::expand_add_use_statement(&mut ast, use_statement) - } - }); - - let generated_code = preserver::resolve_preserved(unparse(&ast)); - - fs::write(file_path, &generated_code).map_err(|_| { - Error::WriteError(format!("Path :{}", file_path.to_str().unwrap_or("Invalid UTF-8 path"))) - })?; - - Ok(()) -} - -pub fn add_mod_declarations(file_path: &Path, mod_declarations: Vec) -> Result<(), Error> { - // Preserve the first mod/pub mod declaration to insert the new one where they're - let preserver_mod = types::Preserver::new("mod"); - let preserver_pub_mod = types::Preserver::new("pub mod"); - let mut ast = preserver::preserve_and_parse( - fs::read_to_string(file_path)?, - vec![preserver_mod, preserver_pub_mod], - )?; - - mod_declarations - .into_iter() - .for_each(|mod_declaration| expand::expand_add_mod(&mut ast, mod_declaration)); - - let generated_code = preserver::resolve_preserved(unparse(&ast)); - - fs::write(file_path, &generated_code).map_err(|_| { - Error::WriteError(format!("Path :{}", file_path.to_str().unwrap_or("Invalid UTF-8 path"))) - })?; - - Ok(()) -} - -pub fn add_composite_enums(file_path: &Path, composite_enums: Vec) -> Result<(), Error> { - let mut preserver = types::Preserver::new("pub mod pallet"); - preserver.add_inners(vec!["pub struct Pallet"]); - let mut ast = preserver::preserve_and_parse(fs::read_to_string(file_path)?, vec![preserver])?; - - composite_enums.into_iter().for_each(|composite_enum| { - if !parse::find_composite_enum(&ast, &composite_enum) { - expand::expand_pallet_add_composite_enum(&mut ast, composite_enum); - } - }); - - let generated_code = preserver::resolve_preserved(unparse(&ast)); - - fs::write(file_path, &generated_code).map_err(|_| { - Error::WriteError(format!("Path :{}", file_path.to_str().unwrap_or("Invalid UTF-8 path"))) - })?; - - Ok(()) -} diff --git a/crates/pop-common/src/rust_writer/expand.rs b/crates/pop-common/src/rust_writer/expand.rs deleted file mode 100644 index 45ef7f054..000000000 --- a/crates/pop-common/src/rust_writer/expand.rs +++ /dev/null @@ -1,277 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0 - -#[cfg(test)] -mod tests; - -use crate::rust_writer::types::*; -use proc_macro2::{Group, Literal, TokenStream, TokenTree}; -use syn::{ - parse_quote, Expr, File, Ident, ImplItem, Item, ItemEnum, ItemImpl, ItemMacro, ItemMod, - ItemStruct, ItemTrait, ItemUse, Macro, Meta, MetaList, TraitBound, TraitItem, Type, -}; - -pub(crate) fn expand_pallet_config_trait( - ast: &mut File, - default_config: &DefaultConfigType, - type_name: Ident, - trait_bounds: Vec, -) { - for item in &mut ast.items { - match item { - Item::Mod(ItemMod { ident, content, .. }) - if *ident == "pallet" && content.is_some() => - { - let (_, items) = - content.as_mut().expect("content is always Some thanks to the match guard"); - for item in items { - match item { - Item::Trait(ItemTrait { ident, items, .. }) if *ident == "Config" => { - items.push(match default_config { - DefaultConfigType::Default { .. } => - TraitItem::Type(parse_quote! { - ///TEMP_DOC - type #type_name: #(#trait_bounds +)*; - }), - DefaultConfigType::NoDefault => TraitItem::Type(parse_quote! { - ///TEMP_DOC - #[pallet::no_default] - type #type_name: #(#trait_bounds +)*; - }), - DefaultConfigType::NoDefaultBounds { .. } => { - TraitItem::Type(parse_quote! { - ///TEMP_DOC - #[pallet::no_default_bounds] - type #type_name: #(#trait_bounds +)*; - }) - }, - }); - }, - _ => continue, - } - } - }, - _ => continue, - } - } -} - -pub(crate) fn expand_pallet_config_preludes(ast: &mut File, type_default_impl: ImplItem) { - for item in &mut ast.items { - match item { - // In case ast points to lib.rs, config_preludes is contained inside pallet mod in - // lib.rs so we have to look for that module and the impl blocks for structs defined - // inside it, equivalently impl blocks using the register_default_impl macro - Item::Mod(ItemMod { ident, content, .. }) - if *ident == "pallet" && content.is_some() => - { - let (_, items) = - content.as_mut().expect("content is always Some thanks to the match guard"); - for item in items { - match item { - Item::Mod(ItemMod { ident, content, .. }) - if *ident == "config_preludes" && content.is_some() => - { - let (_, items) = content - .as_mut() - .expect("content is always Some thanks to the match guard"); - for item in items { - match item { - Item::Impl(ItemImpl { attrs, items, .. }) - if attrs.iter().any(|attribute| { - if let Meta::List(MetaList { - path: syn::Path { segments, .. }, - .. - }) = &attribute.meta - { - segments.iter().any(|segment| { - segment.ident == "register_default_impl" - }) - } else { - false - } - }) => - items.push(type_default_impl.clone()), - _ => continue, - } - } - }, - _ => continue, - } - } - }, - // In case ast points to config_preludes.rs, we have to look for the impl blocks - // for structs defined inside the file. - Item::Impl(ItemImpl { attrs, items, .. }) - if attrs.iter().any(|attribute| { - if let Meta::List(MetaList { path: syn::Path { segments, .. }, .. }) = - &attribute.meta - { - segments.iter().any(|segment| segment.ident == "register_default_impl") - } else { - false - } - }) => - items.push(type_default_impl.clone()), - _ => continue, - } - } -} - -pub(crate) fn expand_runtime_add_pallet( - ast: &mut File, - highest_index: u8, - used_macro: RuntimeUsedMacro, - pallet_name: Type, - pallet_item: Ident, -) { - match used_macro { - RuntimeUsedMacro::Runtime => { - // Convert the highest_index in Ident - let highest_index = Literal::u8_unsuffixed(highest_index.saturating_add(1)); - for item in &mut ast.items { - match item { - Item::Mod(ItemMod { ident, content, .. }) - if *ident == "runtime" && content.is_some() => - { - let (_, items) = content - .as_mut() - .expect("content is always Some thanks to the match guard"); - items.push(Item::Type(parse_quote! { - #[runtime::pallet_index(#highest_index)] - pub type #pallet_item = #pallet_name; - })); - }, - _ => continue, - } - } - }, - RuntimeUsedMacro::ConstructRuntime => { - for item in &mut ast.items { - match item { - Item::Macro(ItemMacro { - mac: Macro { path: syn::Path { segments, .. }, tokens, .. }, - .. - }) if segments.iter().any(|segment| segment.ident == "construct_runtime") => { - // construct_runtime! contains the definition of either a struct or an - // enum whose variants/items are the pallets, so basically the pallets - // are containedd inside a TokenTree::Group and we can suppose that - // there's nothing else inside construct_runtime, so it's enough with - // finding a group. - let mut token_tree: Vec = tokens.clone().into_iter().collect(); - for token in token_tree.iter_mut() { - if let TokenTree::Group(group) = token { - let mut stream = group.stream(); - stream.extend::(parse_quote! { - #pallet_item: #pallet_name, - }); - let new_group = Group::new(group.delimiter(), stream); - *token = TokenTree::Group(new_group); - } - } - *tokens = TokenStream::from_iter(token_tree); - }, - _ => continue, - } - } - }, - } -} - -pub(crate) fn expand_runtime_add_impl_block( - ast: &mut File, - pallet_name: Ident, - parameter_types: Vec, - default_config: bool, -) { - let items = &mut ast.items; - - if !parameter_types.is_empty() { - let parameter_idents: Vec<&Ident> = - parameter_types.iter().map(|item| &item.ident).collect(); - let parameter_types_types: Vec<&Type> = - parameter_types.iter().map(|item| &item.type_).collect(); - let parameter_values: Vec<&Expr> = parameter_types.iter().map(|item| &item.value).collect(); - - items.push(Item::Macro(parse_quote! { - ///TEMP_DOC - parameter_types!{ - #( - pub #parameter_idents: #parameter_types_types = #parameter_values; - )* - } - })); - } - - if default_config { - items.push(Item::Impl(parse_quote! { - ///TEMP_DOC - #[derive_impl(#pallet_name::config_preludes::TestDefaultConfig)] - impl #pallet_name::Config for Runtime{} - })); - } else { - items.push(Item::Impl(parse_quote! { - ///TEMP_DOC - impl #pallet_name::Config for Runtime{} - })); - } -} - -pub(crate) fn expand_runtime_add_type_to_impl_block( - ast: &mut File, - type_name: Ident, - runtime_value: Type, - pallet_name: &str, -) { - for item in &mut ast.items { - match item { - Item::Impl(ItemImpl { - trait_: Some((_, syn::Path { segments, .. }, _)), - items, - .. - }) if segments.iter().any(|segment| segment.ident == pallet_name) => - items.push(ImplItem::Type(parse_quote! { - type #type_name = #runtime_value; - })), - _ => continue, - } - } -} - -pub(crate) fn expand_add_use_statement(ast: &mut File, use_statement: ItemUse) { - let items = &mut ast.items; - // Find the first use statement - let position = items.iter().position(|item| matches!(item, Item::Use(_))).unwrap_or(0); - // Insert the use statement where needed - items.insert(position.saturating_add(1), Item::Use(use_statement)); -} - -pub(crate) fn expand_add_mod(ast: &mut File, mod_: ItemMod) { - let items = &mut ast.items; - // Find the first mod - let position = items.iter().position(|item| matches!(item, Item::Mod(_))).unwrap_or(0); - // Insert the mod where needed - items.insert(position.saturating_add(1), Item::Mod(mod_)); -} - -pub(crate) fn expand_pallet_add_composite_enum(ast: &mut File, composite_enum: ItemEnum) { - for item in &mut ast.items { - match item { - Item::Mod(ItemMod { ident, content, .. }) - if *ident == "pallet" && content.is_some() => - { - let (_, items) = - content.as_mut().expect("content is always Some thanks to the match guard"); - // Find the Pallet struct position - let position = items - .iter() - .position( - |item| matches!(item, Item::Struct(ItemStruct { ident, .. }) if *ident == "Pallet"), - ) - .unwrap_or(0); - // Insert the composite_enum just after the Pallet struct - items.insert(position.saturating_add(1), Item::Enum(composite_enum.clone())); - }, - _ => continue, - } - } -} diff --git a/crates/pop-common/src/rust_writer/expand/tests.rs b/crates/pop-common/src/rust_writer/expand/tests.rs deleted file mode 100644 index 97ee319b1..000000000 --- a/crates/pop-common/src/rust_writer/expand/tests.rs +++ /dev/null @@ -1,713 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0 - -use super::*; -use crate::rust_writer::tests::test_builder::TestBuilder; -use proc_macro2::Span; -use syn::parse_str; - -impl TestBuilder { - fn assert_item_in_config_trait(&self, contains: bool, checked_item: TraitItem) { - let mut assert_happened = false; - for item in &self.ast.items { - match item { - Item::Mod(ItemMod { ident, content, .. }) - if *ident == "pallet" && content.is_some() => - { - let (_, items) = - content.as_ref().expect("content is always Some thanks to the match guard"); - for item in items { - match item { - Item::Trait(ItemTrait { ident, items, .. }) if *ident == "Config" => { - assert_eq!(items.contains(&checked_item), contains); - assert_happened = true; - }, - _ => continue, - } - } - }, - _ => continue, - } - } - assert!(assert_happened); - } - - fn assert_type_added_to_config_preludes(&self, contains: bool, type_: ImplItem) { - let mut assert_happened = false; - for item in &self.ast.items { - match item { - // In case ast using inner config_preludes - Item::Mod(ItemMod { ident, content, .. }) - if *ident == "pallet" && content.is_some() => - { - let (_, items) = - content.as_ref().expect("content is always Some thanks to the match guard"); - for item in items { - match item { - Item::Mod(ItemMod { ident, content, .. }) - if *ident == "config_preludes" && content.is_some() => - { - let (_, items) = content - .as_ref() - .expect("content is always Some thanks to the match guard"); - for item in items { - match item { - Item::Impl(ItemImpl { attrs, items, .. }) - if attrs.iter().any(|attribute| { - if let Meta::List(MetaList { - path: syn::Path { segments, .. }, - .. - }) = &attribute.meta - { - segments.iter().any(|segment| { - segment.ident == "register_default_impl" - }) - } else { - false - } - }) => - { - assert_eq!(items.contains(&type_), contains); - assert_happened = true; - }, - _ => continue, - } - } - }, - _ => continue, - } - } - }, - // In case ast using an outer config preludes - Item::Impl(ItemImpl { attrs, items, .. }) - if attrs.iter().any(|attribute| { - if let Meta::List(MetaList { path: syn::Path { segments, .. }, .. }) = - &attribute.meta - { - segments.iter().any(|segment| segment.ident == "register_default_impl") - } else { - false - } - }) => - { - assert_eq!(items.contains(&type_), contains); - assert_happened = true; - }, - _ => continue, - } - } - assert!(assert_happened); - } - - fn assert_pallet_in_runtime( - &self, - contains: bool, - expected_index: Literal, - used_macro: RuntimeUsedMacro, - pallet_name: Type, - pallet_item: Ident, - ) { - let mut assert_happened = false; - match used_macro { - RuntimeUsedMacro::Runtime => - for item in &self.ast.items { - match item { - Item::Mod(ItemMod { ident, content, .. }) - if *ident == "runtime" && content.is_some() => - { - let (_, items) = content - .as_ref() - .expect("content is always Some thanks to the match guard"); - - assert_eq!( - items.contains(&Item::Type(parse_quote! { - #[runtime::pallet_index(#expected_index)] - pub type #pallet_item = #pallet_name; - })), - contains - ); - assert_happened = true; - }, - _ => continue, - } - }, - RuntimeUsedMacro::ConstructRuntime => - for item in &self.ast.items { - match item { - Item::Macro(ItemMacro { - mac: Macro { path: syn::Path { segments, .. }, tokens, .. }, - .. - }) if segments - .iter() - .any(|segment| segment.ident == "construct_runtime") => - { - let mut token_tree: Vec = - tokens.clone().into_iter().collect(); - for token in token_tree.iter_mut() { - if let TokenTree::Group(group) = token { - let new_pallet_token_stream: TokenStream = parse_quote! { - #pallet_item:#pallet_name, - }; - assert_eq!( - group - .stream() - .to_string() - .contains(&new_pallet_token_stream.to_string()), - contains - ); - assert_happened = true; - } - } - }, - _ => continue, - } - }, - } - assert!(assert_happened); - } - - fn assert_impl_block_contained( - &self, - contains: bool, - pallet_name: Ident, - parameter_types: Vec, - using_default_config: bool, - ) { - if !parameter_types.is_empty() { - let parameter_idents: Vec<&Ident> = - parameter_types.iter().map(|item| &item.ident).collect(); - let parameter_types_types: Vec<&Type> = - parameter_types.iter().map(|item| &item.type_).collect(); - let parameter_values: Vec<&Expr> = - parameter_types.iter().map(|item| &item.value).collect(); - - assert_eq!( - self.ast.items.contains(&Item::Macro(parse_quote! { - ///TEMP_DOC - parameter_types!{ - #( - pub #parameter_idents: #parameter_types_types = #parameter_values; - )* - } - })), - contains - ); - } - - if using_default_config { - assert_eq!( - self.ast.items.contains(&Item::Impl(parse_quote! { - ///TEMP_DOC - #[derive_impl(#pallet_name::config_preludes::TestDefaultConfig)] - impl #pallet_name::Config for Runtime{} - })), - contains - ); - } else { - assert_eq!( - self.ast.items.contains(&Item::Impl(parse_quote! { - ///TEMP_DOC - impl #pallet_name::Config for Runtime{} - })), - contains - ); - } - } - - fn assert_type_in_impl_block( - &self, - contains: bool, - type_name: Ident, - runtime_value: Type, - pallet_name: &str, - ) { - let mut assert_happened = false; - for item in &self.ast.items { - match item { - Item::Impl(ItemImpl { - trait_: Some((_, syn::Path { segments, .. }, _)), - items, - .. - }) if segments.iter().any(|segment| segment.ident == pallet_name) => { - assert_eq!( - items.contains(&ImplItem::Type(parse_quote! { - type #type_name = #runtime_value; - })), - contains - ); - assert_happened = true; - }, - _ => continue, - } - } - assert!(assert_happened); - } - - fn assert_use_statement_included(&self, contains: bool, use_statement: ItemUse) { - // Find the first use statement - let position = - self.ast.items.iter().position(|item| matches!(item, Item::Use(_))).unwrap_or(0); - // The use statement has been added together with other use statements - if let Some(item) = self.ast.items.get(position.saturating_add(1)) { - assert_eq!(item == &Item::Use(use_statement), contains); - } else { - assert!(false); - } - } - - fn assert_mod_included(&self, contains: bool, mod_: ItemMod) { - // Find the first mod declaration - let position = - self.ast.items.iter().position(|item| matches!(item, Item::Mod(_))).unwrap_or(0); - // The mod has been added together with other mod declarations - if let Some(item) = self.ast.items.get(position.saturating_add(1)) { - assert_eq!(item == &Item::Mod(mod_), contains); - } else { - assert!(false); - } - } - - fn assert_composite_enum_in_pallet(&self, contains: bool, composite_enum: ItemEnum) { - let mut assert_happened = false; - for item in &self.ast.items { - match item { - Item::Mod(ItemMod { ident, content, .. }) - if *ident == "pallet" && content.is_some() => - { - let (_, items) = - content.as_ref().expect("content is always Some thanks to the match guard"); - // Find the Pallet struct position - let position = items - .iter() - .position( - |item| matches!(item, Item::Struct(ItemStruct { ident, .. }) if *ident == "Pallet"), - ) - .unwrap_or(0); - // The composite enum has been added just after the Pallet struct - if let Some(item) = items.get(position.saturating_add(1)) { - assert_eq!(item == &Item::Enum(composite_enum.clone()), contains); - assert_happened = true; - } - }, - _ => continue, - } - } - assert!(assert_happened); - } -} - -#[test] -fn expand_pallet_config_trait_works_well_test() { - let mut test_builder = TestBuilder::default(); - //This test modifies the config trait of the pallet, so the ast contained in the builder is - //the basic pallet's ast. - test_builder.add_basic_pallet_ast(); - - //A helper type to pass to expand_pallet_config_trait. - let mut default_config_type = - DefaultConfigType::Default { type_default_impl: parse_quote! {type whatever = ();} }; - - //Check that the config trait doesn't include ```MyDefaultType```. - test_builder.assert_item_in_config_trait( - false, - TraitItem::Type(parse_quote! { - ///TEMP_DOC - type MyDefaultType: Bound1 + From +; - }), - ); - - //Expand the pallet config trait with our type. - expand_pallet_config_trait( - &mut test_builder.ast, - &default_config_type, - Ident::new("MyDefaultType", Span::call_site()), - vec![parse_quote! {Bound1}, parse_quote! {From}], - ); - - //Now ```MyDefaultType``` is part of the ast. - test_builder.assert_item_in_config_trait( - true, - TraitItem::Type(parse_quote! { - ///TEMP_DOC - type MyDefaultType: Bound1 + From +; - }), - ); - - test_builder.assert_item_in_config_trait( - false, - TraitItem::Type(parse_quote! { - ///TEMP_DOC - #[pallet::no_default] - type MyNoDefaultType: Bound1 + From +; - }), - ); - - default_config_type = DefaultConfigType::NoDefault; - expand_pallet_config_trait( - &mut test_builder.ast, - &default_config_type, - Ident::new("MyNoDefaultType", Span::call_site()), - vec![parse_quote! {Bound1}, parse_quote! {From}], - ); - - test_builder.assert_item_in_config_trait( - true, - TraitItem::Type(parse_quote! { - ///TEMP_DOC - #[pallet::no_default] - type MyNoDefaultType: Bound1 + From +; - }), - ); - - test_builder.assert_item_in_config_trait( - false, - TraitItem::Type(parse_quote! { - ///TEMP_DOC - #[pallet::no_default_bounds] - type MyNoDefaultBoundsType: Bound1 + From +; - }), - ); - - default_config_type = DefaultConfigType::NoDefaultBounds { - type_default_impl: parse_quote! {type whatever = ();}, - }; - expand_pallet_config_trait( - &mut test_builder.ast, - &default_config_type, - Ident::new("MyNoDefaultBoundsType", Span::call_site()), - vec![parse_quote! {Bound1}, parse_quote! {From}], - ); - - test_builder.assert_item_in_config_trait( - true, - TraitItem::Type(parse_quote! { - ///TEMP_DOC - #[pallet::no_default_bounds] - type MyNoDefaultBoundsType: Bound1 + From +; - }), - ); -} - -#[test] -fn expand_pallet_config_preludes_inner_module_works_well_test() { - let mut test_builder = TestBuilder::default(); - //This test uses a pallet lib containing config_preludes. - test_builder.add_basic_pallet_with_config_preludes_ast(); - - // Type to add - let my_type = ImplItem::Type(parse_quote! { - type MyType = (); - }); - - //Check that the config type's not included. - test_builder.assert_type_added_to_config_preludes(false, my_type.clone()); - - //Expand the pallet's config_preludes. - expand_pallet_config_preludes(&mut test_builder.ast, my_type.clone()); - - //Check that the config type's included. - test_builder.assert_type_added_to_config_preludes(true, my_type.clone()); -} - -#[test] -fn expand_pallet_config_preludes_outer_file_works_well_test() { - let mut test_builder = TestBuilder::default(); - //This test uses a pallet lib containing config_preludes. - test_builder.add_outer_config_preludes_ast(); - - // Type to add - let my_type = ImplItem::Type(parse_quote! { - type MyType = (); - }); - - //Check that the config type's not included. - test_builder.assert_type_added_to_config_preludes(false, my_type.clone()); - - //Expand the pallet's config_preludes. - expand_pallet_config_preludes(&mut test_builder.ast, my_type.clone()); - - //Check that the config type's included. - test_builder.assert_type_added_to_config_preludes(true, my_type.clone()); -} - -#[test] -fn expand_runtime_add_pallet_using_runtime_macro_works_well_test() { - let mut test_builder = TestBuilder::default(); - test_builder.add_runtime_using_runtime_macro_ast(); - - // Arbitrary highest index to pass to expand_runtime_add_pallet - let highest_index = 11u8; - // Expected index as syn::literal - let expected_index = Literal::u8_unsuffixed(highest_index.saturating_add(1)); - - let pallet_item = Ident::new("Test", Span::call_site()); - let pallet_name: Type = parse_str("pallet_test").expect( - "Error parsing pallet_test in add_pallet_to_runtime_using_runtime_macro_works_well_test", - ); - - test_builder.assert_pallet_in_runtime( - false, - expected_index.clone(), - RuntimeUsedMacro::Runtime, - pallet_name.clone(), - pallet_item.clone(), - ); - - expand_runtime_add_pallet( - &mut test_builder.ast, - highest_index, - RuntimeUsedMacro::Runtime, - pallet_name.clone(), - pallet_item.clone(), - ); - - test_builder.assert_pallet_in_runtime( - true, - expected_index, - RuntimeUsedMacro::Runtime, - pallet_name, - pallet_item, - ); -} - -#[test] -fn expand_runtime_add_pallet_using_construct_runtime_macro_works_well_test() { - let mut test_builder = TestBuilder::default(); - test_builder.add_runtime_using_construct_runtime_macro_ast(); - - // Expected index as syn::literal, needed for assert_pallet_in_runtime but not relevant in this - // case - let expected_index = Literal::u8_unsuffixed(0u8); - - let pallet_item = Ident::new("Test", Span::call_site()); - let pallet_name: Type = parse_str("pallet_test").expect( - "Error parsing pallet_test in add_pallet_to_runtime_using_runtime_macro_works_well_test", - ); - - test_builder.assert_pallet_in_runtime( - false, - expected_index.clone(), - RuntimeUsedMacro::ConstructRuntime, - pallet_name.clone(), - pallet_item.clone(), - ); - - expand_runtime_add_pallet( - &mut test_builder.ast, - 0u8, - RuntimeUsedMacro::ConstructRuntime, - pallet_name.clone(), - pallet_item.clone(), - ); - - test_builder.assert_pallet_in_runtime( - true, - expected_index, - RuntimeUsedMacro::ConstructRuntime, - pallet_name, - pallet_item, - ); -} - -#[test] -fn expand_runtime_add_impl_block_without_default_config_works_well_test() { - let mut test_builder = TestBuilder::default(); - test_builder.add_runtime_using_runtime_macro_ast(); - - let parameter_types = Vec::new(); - let pallet_name = Ident::new("Test", Span::call_site()); - - // Impl pallet without defautl config not added - test_builder.assert_impl_block_contained( - false, - pallet_name.clone(), - parameter_types.clone(), - false, - ); - - // Add it - expand_runtime_add_impl_block( - &mut test_builder.ast, - pallet_name.clone(), - parameter_types.clone(), - false, - ); - - // Impl pallet without default config added. - test_builder.assert_impl_block_contained( - true, - pallet_name.clone(), - parameter_types.clone(), - false, - ); -} - -#[test] -fn expand_runtime_add_impl_block_with_default_config_works_well_test() { - let mut test_builder = TestBuilder::default(); - test_builder.add_runtime_using_runtime_macro_ast(); - - let pallet_name = Ident::new("Test", Span::call_site()); - let parameter_types = Vec::new(); - - // Impl pallet with default config not added - test_builder.assert_impl_block_contained( - false, - pallet_name.clone(), - parameter_types.clone(), - true, - ); - - // Add it - expand_runtime_add_impl_block( - &mut test_builder.ast, - pallet_name.clone(), - parameter_types.clone(), - true, - ); - - //Impl pallet with default config added - test_builder.assert_impl_block_contained( - true, - pallet_name.clone(), - parameter_types.clone(), - true, - ); -} - -#[test] -fn expand_runtime_add_impl_block_using_parameter_types_works_well_test() { - let mut test_builder = TestBuilder::default(); - test_builder.add_runtime_using_runtime_macro_ast(); - - let pallet_name = Ident::new("Test", Span::call_site()); - let parameter_types = vec![ - ParameterTypes { - ident: Ident::new("MyType1", Span::call_site()), - type_: parse_quote! {Type}, - value: parse_quote! {Default::default()}, - }, - ParameterTypes { - ident: Ident::new("MyType2", Span::call_site()), - type_: parse_quote! {Type}, - value: parse_quote! {Default::default()}, - }, - ]; - - // Impl pallet block + parameter_types block not added - test_builder.assert_impl_block_contained( - false, - pallet_name.clone(), - parameter_types.clone(), - true, - ); - - // Add them - expand_runtime_add_impl_block( - &mut test_builder.ast, - pallet_name.clone(), - parameter_types.clone(), - true, - ); - - //Impl pallet block + parameter_types block not added - test_builder.assert_impl_block_contained( - true, - pallet_name.clone(), - parameter_types.clone(), - true, - ); -} - -#[test] -fn expand_runtime_add_type_to_impl_block_works_well_test() { - let mut test_builder = TestBuilder::default(); - test_builder.add_runtime_using_runtime_macro_ast(); - - let pallet_name = "Test"; - let type_name = Ident::new("MyType", Span::call_site()); - let runtime_value: Type = parse_quote! {Type}; - let parameter_types = Vec::new(); - - expand_runtime_add_impl_block( - &mut test_builder.ast, - Ident::new(pallet_name, Span::call_site()), - parameter_types, - false, - ); - - // The pallet impl block doesn't include the type - test_builder.assert_type_in_impl_block( - false, - type_name.clone(), - runtime_value.clone(), - pallet_name, - ); - - // Add it - expand_runtime_add_type_to_impl_block( - &mut test_builder.ast, - type_name.clone(), - runtime_value.clone(), - pallet_name, - ); - - // Now it's included in the ast - test_builder.assert_type_in_impl_block( - true, - type_name.clone(), - runtime_value.clone(), - pallet_name, - ); -} - -#[test] -fn expand_add_use_statement_works_well_test() { - let mut test_builder = TestBuilder::default(); - test_builder.add_basic_pallet_ast(); - - let use_statement: ItemUse = parse_quote! { - use some_crate::some_module::some_function; - }; - - test_builder.assert_use_statement_included(false, use_statement.clone()); - - expand_add_use_statement(&mut test_builder.ast, use_statement.clone()); - - test_builder.assert_use_statement_included(true, use_statement); -} - -#[test] -fn expand_add_mod_works_well_test() { - let mut test_builder = TestBuilder::default(); - test_builder.add_basic_pallet_ast(); - - let mod_: ItemMod = parse_quote! { - mod some_mod; - }; - - test_builder.assert_mod_included(false, mod_.clone()); - - expand_add_mod(&mut test_builder.ast, mod_.clone()); - - test_builder.assert_mod_included(true, mod_); -} - -#[test] -fn expand_pallet_add_composite_enum_works_well_test() { - let mut test_builder = TestBuilder::default(); - test_builder.add_basic_pallet_ast(); - - let composite_enum: ItemEnum = parse_quote! { - #[pallet::composite_enum] - pub enum Enum { - #[codec(index = 0)] - SomeVariant, - #[codec(index=1)] - OtherVariant - } - }; - - test_builder.assert_composite_enum_in_pallet(false, composite_enum.clone()); - expand_pallet_add_composite_enum(&mut test_builder.ast, composite_enum.clone()); - test_builder.assert_composite_enum_in_pallet(true, composite_enum); -} diff --git a/crates/pop-common/src/rust_writer/parse.rs b/crates/pop-common/src/rust_writer/parse.rs deleted file mode 100644 index 15a4195e7..000000000 --- a/crates/pop-common/src/rust_writer/parse.rs +++ /dev/null @@ -1,134 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0 - -use crate::{rust_writer::types::RuntimeUsedMacro, Error}; -use std::cmp; -use syn::{ - File, Item, ItemEnum, ItemMacro, ItemMod, ItemType, ItemUse, Macro, Meta, MetaList, Path, -}; - -#[cfg(test)] -mod tests; - -// Not more than 256 pallets are included in a runtime -type PalletIndex = u8; - -/// Find the highest implemented pallet index in the outer enum if using the macro -/// #[runtime]. -pub(crate) fn find_highest_pallet_index(ast: &File) -> Result { - let mut highest_index: PalletIndex = 0; - let mut found = false; - for item in &ast.items { - match item { - Item::Mod(ItemMod { ident, content, .. }) - if *ident == "runtime" && content.is_some() => - { - let (_, items) = - content.as_ref().expect("content is always Some thanks to the match guard"); - for item in items { - if let Item::Type(ItemType { attrs, .. }) = item { - if let Some(pallet_index_attribute) = attrs.iter().find(|attribute| { - if let Meta::List(MetaList { path: Path { segments, .. }, .. }) = - &attribute.meta - { - segments.iter().any(|segment| segment.ident == "pallet_index") - } else { - false - } - }) { - // As the attribute at this point is for sure - // #[runtime::pallet_index(n)], so meta is a MetaList where tokens - // is a TokenStream of exactly one element: the literal n. - let mut pallet_index = 0u8; - if let Meta::List(MetaList { tokens, .. }) = - &pallet_index_attribute.meta - { - pallet_index = tokens - .clone() - .into_iter() - .next() - .expect("This iterator has one element due to the attribute shape; qed;") - .to_string() - .parse::() - .expect("The macro #[runtime::pallet_index(n)] is only valid if n is a valid number, so we can parse it to PalletIndex; qed;"); - } - // Despite the pallets will likely be ordered by call_index in the - // runtime, that's not necessarily true, so we keep the highest index in - // order to give the added pallet the next index - highest_index = cmp::max(highest_index, pallet_index); - found = true; - } - } - } - }, - _ => continue, - } - } - - if !found { - return Err(Error::Descriptive( - format! {"Unable to find the highest pallet index in runtime file"}, - )) - } - Ok(highest_index) -} - -/// Determine whether a runtime's ast uses the construct_runtime! macro or the #[runtime] macro. -pub(crate) fn find_used_runtime_macro(ast: &File) -> Result { - for item in &ast.items { - match item { - Item::Mod(ItemMod { ident, .. }) if *ident == "runtime" => { - return Ok(RuntimeUsedMacro::Runtime); - }, - Item::Macro(ItemMacro { mac: Macro { path: Path { segments, .. }, .. }, .. }) - if segments.iter().any(|segment| segment.ident == "construct_runtime") => - { - return Ok(RuntimeUsedMacro::ConstructRuntime); - }, - _ => (), - } - } - return Err(Error::Descriptive(format!("Unable to find a runtime declaration in runtime file"))); -} - -pub(crate) fn find_use_statement(ast: &File, use_statement: &ItemUse) -> bool { - for item in &ast.items { - match item { - Item::Use(item_use) if item_use == use_statement => return true, - _ => continue, - } - } - false -} - -pub(crate) fn find_composite_enum(ast: &File, composite_enum: &ItemEnum) -> bool { - for item in &ast.items { - match item { - Item::Mod(ItemMod { ident, content, .. }) - if *ident == "pallet" && content.is_some() => - { - let (_, items) = - content.as_ref().expect("content is always Some thanks to the match guard"); - for item in items { - match item { - Item::Enum(ItemEnum { ident, attrs, .. }) - if *ident == composite_enum.ident && - attrs.iter().any(|attribute| { - if let Meta::Path(Path { segments, .. }) = &attribute.meta { - // It's enough checking than composite_enum is in the path - segments - .iter() - .any(|segment| segment.ident == "composite_enum") - } else { - false - } - }) => - return true, - _ => continue, - } - } - }, - _ => continue, - } - } - false -} diff --git a/crates/pop-common/src/rust_writer/preserver.rs b/crates/pop-common/src/rust_writer/preserver.rs deleted file mode 100644 index d4219e5ad..000000000 --- a/crates/pop-common/src/rust_writer/preserver.rs +++ /dev/null @@ -1,148 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0 - -use crate::{ - rust_writer::types::{DelimitersCount, Preserver}, - Error, -}; -use regex::{Captures, Regex}; -use syn::{parse_file, File}; - -#[cfg(test)] -mod tests; - -pub(crate) fn preserve_and_parse(code: String, preservers: Vec) -> Result { - let preserved_code = apply_preservers(code, preservers); - Ok(parse_file(&preserved_code)?) -} - -pub(crate) fn resolve_preserved(code: String) -> String { - // Inside non-preserved declarative macros invocations, everything is a token and hence it - // should be managed carefully. We capture all the macro invocations and apply regex to those - // pieces of code to properly resolve them. - let mut delimiters_counts = DelimitersCount::new(); - let mut lines = code.lines(); - - // We'll reduce lines, so this capacity is a max bond on the result - let mut macro_cleaned_code: Vec = Vec::with_capacity(code.lines().count()); - let mut macro_content = String::new(); - - let macro_invocation_matcher = - Regex::new(r"\w+!\s*[\{\(\[]").expect("The regex is valid; qed;"); - - // Inside declarative macros, doc comments became #[doc] in order to preserve them (tokens - // doesn't accept doc comments). ///TEMP_DOC comments became #[doc = "TEMP_DOC(something)"] - // which are 4 tokens in the AST. When the AST is converted to a String, new line characters - // can appear in the middle of any of those tokens, so to properly convert them in a new line - // we can use regex. As the #[doc] attribute may be present anywhere, be sure to keep spaces - // before and after the comment to don't leave commented some lines of code. - let macro_docs_matcher = Regex::new(r#"#\s*\[\s*doc\s*=\s*"TEMP_DOC([\\t]*)(.*?)"\s*\]"#) - .expect("The regex is valid; qed;"); - // Same happens with 'type temp_marker = ();'. - let temp_marker_matcher = - Regex::new(r"type\s+temp_marker\s*=\s*\(\);\s*").expect("The regex is valid; qed;"); - - while let Some(line) = lines.next() { - // We're noting the content of a macro - if !macro_content.is_empty() && !delimiters_counts.is_complete() { - delimiters_counts.count(line); - macro_content.push_str(line); - macro_content.push_str("\n"); - // Start noting the content of a macro - } else if macro_invocation_matcher.is_match(&line) { - delimiters_counts.count(line); - macro_content.push_str(line); - macro_content.push_str("\n"); - // macro_content contains the whole macro, so we preserve it and push it, together with - // the new line to the cleaned code - } else if delimiters_counts.is_complete() { - let docs_resolved_code = macro_docs_matcher - .replace_all(¯o_content, |caps: &Captures| format!("\n{}\n", &caps[2])) - .to_string(); - - macro_cleaned_code - .push(temp_marker_matcher.replace_all(&docs_resolved_code, "\n").to_string()); - macro_cleaned_code.push(line.to_owned()); - macro_cleaned_code.push("\n".to_owned()); - - macro_content.clear(); - } else { - macro_cleaned_code.push(line.to_owned()); - macro_cleaned_code.push("\n".to_owned()); - } - } - - // Delete all TEMP_DOCS and temp_marker present in the rest of the code and return the result. - macro_cleaned_code - .join("") - .replace("///TEMP_DOC", "") - .replace("type temp_marker = ();\n", "") -} - -fn apply_preservers(code: String, mut preservers: Vec) -> String { - let mut delimiters_counts = DelimitersCount::new(); - - let mut lines = code.lines(); - - // Non-preserved lines are pushed to the Vec together with a new line character, so the bound - // #lines * 2 is an upper bound of the final capacity - let mut result: Vec = Vec::with_capacity(code.lines().count() * 2); - - while let Some(line) = lines.next() { - let trimmed_line = line.trim_start(); - if let Some(index) = preservers - .iter_mut() - .position(|preserver| trimmed_line.starts_with(preserver.lookup())) - { - delimiters_counts.count(line); - result.push(line.to_owned()); - result.push("\n".to_owned()); - - let mut preserver = preservers.swap_remove(index); - let inner_preserver = preserver.take_inner(); - - if let Some(inner_preserver_pointer) = inner_preserver { - let mut inner_code = String::new(); - while let Some(line) = lines.next() { - delimiters_counts.count(line); - - if delimiters_counts.is_complete() { - result.push(apply_preservers(inner_code, vec![*inner_preserver_pointer])); - result.push(line.to_owned()); - result.push("\n".to_owned()); - break; - } else { - inner_code.push_str(line); - inner_code.push_str("\n"); - } - } - } - } else { - if delimiters_counts.is_complete() { - result.push(format!("///TEMP_DOC{}\n", line)); - } else { - if (trimmed_line.starts_with("//") && - !trimmed_line.starts_with("///") && - !trimmed_line.starts_with("//!")) || - trimmed_line.starts_with("#![") - { - // Preserve comments and global attributes. - // Global attributes may be hard to parse with syn, so we comment them to solve - // potential issues related to them. - result.push(format!("///TEMP_DOC{}\ntype temp_marker = ();", line)); - } else if trimmed_line.is_empty() { - // Preserve empty lines inside a non-preserved block - result.push("///TEMP_DOC\ntype temp_marker = ();".to_owned()); - } else { - result.push(line.to_owned()); - result.push("\n".to_owned()); - } - - delimiters_counts.count(line); - } - } - } - - result.push("type temp_marker = ();".to_owned()); - - result.join("") -} diff --git a/crates/pop-common/src/rust_writer/preserver/tests.rs b/crates/pop-common/src/rust_writer/preserver/tests.rs deleted file mode 100644 index 1e5d375f1..000000000 --- a/crates/pop-common/src/rust_writer/preserver/tests.rs +++ /dev/null @@ -1,3 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0 - -use super::*; diff --git a/crates/pop-common/src/rust_writer/tests.rs b/crates/pop-common/src/rust_writer/tests.rs deleted file mode 100644 index 1b5261bb9..000000000 --- a/crates/pop-common/src/rust_writer/tests.rs +++ /dev/null @@ -1,3 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0 - -pub(crate) mod test_builder; diff --git a/crates/pop-common/src/rust_writer/tests/sample_files/basic_pallet_with_composite_enum.rs b/crates/pop-common/src/rust_writer/tests/sample_files/basic_pallet_with_composite_enum.rs deleted file mode 100644 index 0e31e07d8..000000000 --- a/crates/pop-common/src/rust_writer/tests/sample_files/basic_pallet_with_composite_enum.rs +++ /dev/null @@ -1,36 +0,0 @@ -#![cfg_attr(not(feature = "std"), no_std)] - -use frame::prelude::*; - -use frame::traits::{fungible, VariantCount}; - -pub use pallet::*; - -#[cfg(test)] -mod mock; - -#[cfg(test)] -mod tests; - -#[cfg(feature = "runtime-benchmarks")] -mod benchmarking; - -#[frame::pallet] -pub mod pallet { - use super::*; - - #[pallet::composite_enum] - pub enum SomeEnum { - #[codec(index = 0)] - Something, - } - - #[pallet::pallet] - pub struct Pallet(_); - - #[pallet::config] - pub trait Config: frame_system::Config {} - - #[pallet::call] - impl Pallet {} -} diff --git a/crates/pop-common/src/rust_writer/tests/sample_files/basic_pallet_with_config_preludes.rs b/crates/pop-common/src/rust_writer/tests/sample_files/basic_pallet_with_config_preludes.rs deleted file mode 100644 index d78a169bf..000000000 --- a/crates/pop-common/src/rust_writer/tests/sample_files/basic_pallet_with_config_preludes.rs +++ /dev/null @@ -1,85 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0 - -#![cfg_attr(not(feature = "std"), no_std)] - -use frame::prelude::*; - -pub use pallet::*; - -#[cfg(test)] -mod mock; - -#[cfg(test)] -mod tests; - -#[cfg(feature = "runtime-benchmarks")] -mod benchmarking; - -#[frame::pallet] -pub mod pallet { - use super::*; - - pub mod config_preludes{ - use super::*; - use frame::runtime::prelude::derive_impl; - /// Provides a viable default config that can be used with - /// [`derive_impl`] to derive a testing pallet config - /// based on this one. - pub struct TestDefaultConfig; - - #[derive_impl(frame_system::config_preludes::TestDefaultConfig, no_aggregated_types)] - impl frame::deps::frame_system::DefaultConfig for TestDefaultConfig {} - - #[register_default_impl(TestDefaultConfig)] - impl DefaultConfig for TestDefaultConfig { - } - - /// Default configurations of this pallet in a solochain environment. - pub struct SolochainDefaultConfig; - - #[derive_impl( - frame_system::config_preludes::SolochainDefaultConfig, - no_aggregated_types - )] - impl frame::deps::frame_system::DefaultConfig for SolochainDefaultConfig {} - - #[register_default_impl(SolochainDefaultConfig)] - impl DefaultConfig for SolochainDefaultConfig { - } - - /// Default configurations of this pallet in a solochain environment. - pub struct RelayChainDefaultConfig; - - #[derive_impl( - frame_system::config_preludes::RelayChainDefaultConfig, - no_aggregated_types - )] - impl frame::deps::frame_system::DefaultConfig for RelayChainDefaultConfig {} - - #[register_default_impl(RelayChainDefaultConfig)] - impl DefaultConfig for RelayChainDefaultConfig { - } - - /// Default configurations of this pallet in a solochain environment. - pub struct ParaChainDefaultConfig; - - #[derive_impl( - frame_system::config_preludes::ParaChainDefaultConfig, - no_aggregated_types - )] - impl frame::deps::frame_system::DefaultConfig for ParaChainDefaultConfig {} - - #[register_default_impl(ParaChainDefaultConfig)] - impl DefaultConfig for ParaChainDefaultConfig { - } - } - - #[pallet::pallet] - pub struct Pallet(_); - - #[pallet::config(with_default)] - pub trait Config: frame_system::Config {} - - #[pallet::call] - impl Pallet {} -} diff --git a/crates/pop-common/src/rust_writer/tests/sample_files/outer_config_preludes.rs b/crates/pop-common/src/rust_writer/tests/sample_files/outer_config_preludes.rs deleted file mode 100644 index d4285ecbb..000000000 --- a/crates/pop-common/src/rust_writer/tests/sample_files/outer_config_preludes.rs +++ /dev/null @@ -1,55 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0 - -use super::*; -use frame::runtime::prelude::derive_impl; - -/// Provides a viable default config that can be used with -/// [`derive_impl`] to derive a testing pallet config -/// based on this one. -pub struct TestDefaultConfig; - -#[derive_impl(frame_system::config_preludes::TestDefaultConfig, no_aggregated_types)] -impl frame::deps::frame_system::DefaultConfig for TestDefaultConfig {} - -#[register_default_impl(TestDefaultConfig)] -impl DefaultConfig for TestDefaultConfig { -} - -/// Default configurations of this pallet in a solochain environment. -pub struct SolochainDefaultConfig; - -#[derive_impl( - frame_system::config_preludes::SolochainDefaultConfig, - no_aggregated_types -)] -impl frame::deps::frame_system::DefaultConfig for SolochainDefaultConfig {} - -#[register_default_impl(SolochainDefaultConfig)] -impl DefaultConfig for SolochainDefaultConfig { -} - -/// Default configurations of this pallet in a solochain environment. -pub struct RelayChainDefaultConfig; - -#[derive_impl( - frame_system::config_preludes::RelayChainDefaultConfig, - no_aggregated_types -)] -impl frame::deps::frame_system::DefaultConfig for RelayChainDefaultConfig {} - -#[register_default_impl(RelayChainDefaultConfig)] -impl DefaultConfig for RelayChainDefaultConfig { -} - -/// Default configurations of this pallet in a solochain environment. -pub struct ParaChainDefaultConfig; - -#[derive_impl( - frame_system::config_preludes::ParaChainDefaultConfig, - no_aggregated_types -)] -impl frame::deps::frame_system::DefaultConfig for ParaChainDefaultConfig {} - -#[register_default_impl(ParaChainDefaultConfig)] -impl DefaultConfig for ParaChainDefaultConfig { -} diff --git a/crates/pop-common/src/rust_writer/tests/test_builder.rs b/crates/pop-common/src/rust_writer/tests/test_builder.rs deleted file mode 100644 index fb7576190..000000000 --- a/crates/pop-common/src/rust_writer/tests/test_builder.rs +++ /dev/null @@ -1,47 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0 - -use std::{fs, path::PathBuf}; -use syn::{parse_file, parse_quote, File}; - -pub(crate) struct TestBuilder { - test_files: PathBuf, - pub(crate) ast: File, -} - -impl Default for TestBuilder { - fn default() -> Self { - Self { - test_files: PathBuf::from(env!("CARGO_MANIFEST_DIR")) - .join("src") - .join("rust_writer") - .join("tests") - .join("sample_files"), - ast: parse_quote! {}, - } - } -} - -macro_rules! add_ast_to_builder_no_preserve{ - ($([$name: ident, $file: literal]),*) => { - $( - pub(crate) fn $name(&mut self){ - self.ast = parse_file( - &fs::read_to_string(self.test_files.join($file)) - .expect(concat!{"Error reading file in ", stringify!($name)}), - ) - .expect(concat!{"Error parsing file in ", stringify!($name)}); - } - )* - }; -} - -impl TestBuilder { - add_ast_to_builder_no_preserve! { - [add_basic_pallet_ast, "basic_pallet.rs"], - [add_basic_pallet_with_config_preludes_ast, "basic_pallet_with_config_preludes.rs"], - [add_basic_pallet_with_composite_enum_ast, "basic_pallet_with_composite_enum.rs"], - [add_outer_config_preludes_ast, "outer_config_preludes.rs"], - [add_runtime_using_runtime_macro_ast, "runtime_using_runtime_macro.rs"], - [add_runtime_using_construct_runtime_macro_ast, "runtime_using_construct_runtime_macro.rs"] - } -} diff --git a/crates/pop-common/src/rust_writer/types.rs b/crates/pop-common/src/rust_writer/types.rs deleted file mode 100644 index 122b9d23a..000000000 --- a/crates/pop-common/src/rust_writer/types.rs +++ /dev/null @@ -1,77 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0 - -use syn::{Expr, Ident, ImplItem, Type}; - -#[derive(Debug, Clone, PartialEq)] -pub enum DefaultConfigType { - Default { type_default_impl: ImplItem }, - NoDefault, - NoDefaultBounds { type_default_impl: ImplItem }, -} - -#[derive(Debug, Clone, PartialEq)] -pub(crate) enum RuntimeUsedMacro { - Runtime, - ConstructRuntime, -} - -#[derive(Debug, Clone, PartialEq)] -pub struct ParameterTypes { - pub ident: Ident, - pub type_: Type, - pub value: Expr, -} - -#[derive(Debug, Clone, PartialEq)] -pub(crate) struct Preserver { - lookup: String, - inner: Option>, -} - -impl Preserver { - pub(crate) fn new(lookup: &str) -> Self { - Self { lookup: lookup.to_owned(), inner: None } - } - - pub(crate) fn add_inners(&mut self, lookups: Vec<&str>) { - let mut current = self; - for lookup in lookups { - current.inner = Some(Box::new(Self::new(lookup))); - current = current.inner.as_mut().expect("Inner is Some due to the previous line; qed"); - } - } - - pub(crate) fn lookup(&self) -> &str { - &self.lookup - } - - pub(crate) fn take_inner(&mut self) -> Option> { - self.inner.take() - } -} - -#[derive(Debug, Clone, PartialEq)] -pub(crate) struct DelimitersCount { - counts: [u8; 6], -} - -impl DelimitersCount { - pub(crate) fn new() -> Self { - Self { counts: [0; 6] } - } - - pub(crate) fn is_complete(&self) -> bool { - self.counts[0] == self.counts[1] && // `{` and `}` - self.counts[2] == self.counts[3] && // `(` and `)` - self.counts[4] == self.counts[5] // `[` and `]` - } - - pub(crate) fn count(&mut self, line: &str) { - self.counts[0] += line.matches('{').count() as u8; - self.counts[1] += line.matches('}').count() as u8; - self.counts[2] += line.matches('(').count() as u8; - self.counts[3] += line.matches(')').count() as u8; - self.counts[4] += line.matches('[').count() as u8; - self.counts[5] += line.matches(']').count() as u8; - } -} diff --git a/crates/pop-common/src/rust_writer_helpers.rs b/crates/pop-common/src/rust_writer_helpers.rs new file mode 100644 index 000000000..958479ce9 --- /dev/null +++ b/crates/pop-common/src/rust_writer_helpers.rs @@ -0,0 +1,249 @@ +// SPDX-License-Identifier: GPL-3.0 + +use crate::Error; +use fs_rollback::Rollback; +use proc_macro2::{Literal, Span}; +use rust_writer::{ + ast::{ + finder::{Finder, ToFind}, + implementors::ItemToFile, + mutator::{Mutator, ToMutate}, + }, + preserver::Preserver, +}; +use std::{ + cmp, + path::{Path, PathBuf}, +}; +use syn::{ + parse_quote, File, Ident, ImplItem, Item, ItemMacro, ItemMod, ItemType, Macro, Meta, MetaList, + Path as syn_Path, +}; + +#[cfg(test)] +mod tests; + +#[derive(Debug, Clone, PartialEq)] +pub enum DefaultConfigType { + Default { type_default_impl: ImplItem }, + NoDefault, + NoDefaultBounds { type_default_impl: ImplItem }, +} + +#[derive(Debug, Clone, PartialEq)] +pub enum RuntimeUsedMacro { + Runtime, + ConstructRuntime, +} + +// Not more than 256 pallets are included in a runtime +pub type PalletIndex = u8; + +/// Find the highest implemented pallet index in the outer enum if using the macro +/// #[runtime]. +pub fn find_highest_pallet_index(ast: &File) -> Result { + let mut highest_index: PalletIndex = 0; + let mut found = false; + for item in &ast.items { + match item { + Item::Mod(ItemMod { ident, content, .. }) + if *ident == "runtime" && content.is_some() => + { + let (_, items) = + content.as_ref().expect("content is always Some thanks to the match guard"); + for item in items { + if let Item::Type(ItemType { attrs, .. }) = item { + if let Some(pallet_index_attribute) = attrs.iter().find(|attribute| { + if let Meta::List(MetaList { + path: syn_Path { segments, .. }, .. + }) = &attribute.meta + { + segments.iter().any(|segment| segment.ident == "pallet_index") + } else { + false + } + }) { + // As the attribute at this point is for sure + // #[runtime::pallet_index(n)], so meta is a MetaList where tokens + // is a TokenStream of exactly one element: the literal n. + let mut pallet_index = 0u8; + if let Meta::List(MetaList { tokens, .. }) = + &pallet_index_attribute.meta + { + pallet_index = tokens + .clone() + .into_iter() + .next() + .expect("This iterator has one element due to the attribute shape; qed;") + .to_string() + .parse::() + .expect("The macro #[runtime::pallet_index(n)] is only valid if n is a valid number, so we can parse it to PalletIndex; qed;"); + } + // Despite the pallets will likely be ordered by call_index in the + // runtime, that's not necessarily true, so we keep the highest index in + // order to give the added pallet the next index + highest_index = cmp::max(highest_index, pallet_index); + found = true; + } + } + } + }, + _ => continue, + } + } + + if !found { + return Err(Error::Descriptive( + format! {"Unable to find the highest pallet index in runtime file"}, + )) + } + Ok(Literal::u8_unsuffixed(highest_index.saturating_add(1))) +} + +/// Determine whether a runtime's ast uses the construct_runtime! macro or the #[runtime] macro. +pub fn find_used_runtime_macro(ast: &File) -> Result { + for item in &ast.items { + match item { + Item::Mod(ItemMod { ident, .. }) if *ident == "runtime" => { + return Ok(RuntimeUsedMacro::Runtime); + }, + Item::Macro(ItemMacro { + mac: Macro { path: syn_Path { segments, .. }, .. }, .. + }) if segments.iter().any(|segment| segment.ident == "construct_runtime") => { + return Ok(RuntimeUsedMacro::ConstructRuntime); + }, + _ => (), + } + } + return Err(Error::Descriptive(format!("Unable to find a runtime declaration in runtime file"))); +} + +pub fn compute_pallet_related_paths(runtime_path: &Path) -> (PathBuf, PathBuf, PathBuf, PathBuf) { + let runtime_src_path = runtime_path.join("src"); + let runtime_lib_path = runtime_src_path.join("lib.rs"); + let configs_rs_path = runtime_src_path.join("configs.rs"); + let configs_folder_path = runtime_src_path.join("configs"); + let configs_mod_path = configs_folder_path.join("mod.rs"); + (runtime_lib_path, configs_rs_path, configs_folder_path, configs_mod_path) +} + +pub fn compute_new_pallet_impl_path<'a>( + mut rollback: Rollback<'a>, + runtime_lib_path: &'a Path, + configs_rs_path: &'a Path, + configs_folder_path: &'a Path, + configs_mod_path: &'a Path, + pallet_config_path: &'a Path, + pallet_name: &str, +) -> Result, Error> { + let pallet_name_ident = Ident::new(pallet_name, Span::call_site()); + + let mod_preserver = Preserver::new("mod"); + let pub_mod_preserver = Preserver::new("pub mod"); + + let pallet_mod_implementor = ItemToFile { item: parse_quote!(mod #pallet_name_ident;) }; + + match (configs_rs_path.is_file(), configs_mod_path.is_file()) { + // The runtime is using a configs module without the mod.rs sintax + (true, false) => { + if rollback.get_noted_file(&configs_rs_path).is_none() { + rollback.note_file(&configs_rs_path)?; + } + + let roll_configs_rs_path = rollback + .get_noted_file(&configs_rs_path) + .expect("This file has been noted above; qed;"); + let mut preserved_ast = rust_writer::preserver::preserve_and_parse( + roll_configs_rs_path, + &[&mod_preserver, &pub_mod_preserver], + )?; + + let mut finder = Finder::default().to_find(&pallet_mod_implementor); + let pallet_already_declared = finder.find(&preserved_ast); + if !pallet_already_declared { + let mut mutator = Mutator::default().to_mutate(&pallet_mod_implementor); + mutator.mutate(&mut preserved_ast)?; + rust_writer::preserver::resolve_preserved(&preserved_ast, roll_configs_rs_path)?; + } else { + return Err(Error::Descriptive(format!("{pallet_name} is already in use."))); + } + + rollback.new_file(&pallet_config_path)?; + Ok(rollback) + }, + // The runtime is using a configs module with the mod.rs syntax + (false, true) => { + if rollback.get_noted_file(&configs_mod_path).is_none() { + rollback.note_file(&configs_mod_path)?; + } + + let roll_configs_mod_path = rollback + .get_noted_file(&configs_mod_path) + .expect("This file has been noted above; qed;"); + let mut preserved_ast = rust_writer::preserver::preserve_and_parse( + roll_configs_mod_path, + &[&mod_preserver, &pub_mod_preserver], + )?; + + let mut finder = Finder::default().to_find(&pallet_mod_implementor); + let pallet_already_declared = finder.find(&preserved_ast); + if !pallet_already_declared { + let mut mutator = Mutator::default().to_mutate(&pallet_mod_implementor); + mutator.mutate(&mut preserved_ast)?; + rust_writer::preserver::resolve_preserved(&preserved_ast, roll_configs_mod_path)?; + } else { + return Err(Error::Descriptive(format!("{pallet_name} is already in use."))); + } + + rollback.new_file(&pallet_config_path)?; + Ok(rollback) + }, + // The runtime isn't using a configs module yet, we opt for the configs.rs + // convention + (false, false) => { + let configs_mod_implementor = ItemToFile { + item: parse_quote!( + pub mod configs; + ), + }; + if rollback.get_noted_file(&runtime_lib_path).is_none() { + rollback.note_file(&runtime_lib_path)?; + } + + let roll_runtime_lib_path = rollback + .get_noted_file(&runtime_lib_path) + .expect("This file has been noted above; qed;"); + let mut preserved_ast = rust_writer::preserver::preserve_and_parse( + roll_runtime_lib_path, + &[&mod_preserver, &pub_mod_preserver], + )?; + + let mut finder = Finder::default().to_find(&configs_mod_implementor); + let configs_already_declared = finder.find(&preserved_ast); + if !configs_already_declared { + let mut mutator = Mutator::default().to_mutate(&configs_mod_implementor); + mutator.mutate(&mut preserved_ast)?; + rust_writer::preserver::resolve_preserved(&preserved_ast, roll_runtime_lib_path)?; + } + + rollback.new_file(&configs_rs_path)?; + rollback.new_dir(&configs_folder_path)?; + rollback.new_file(&pallet_config_path)?; + + let roll_configs_rs_path = rollback + .get_new_file(&configs_rs_path) + .expect("The new file has been noted above; qed"); + + // New file so we can mutate it directly. + let mut ast = rust_writer::preserver::preserve_and_parse(roll_configs_rs_path, &[])?; + let mut mutator = Mutator::default().to_mutate(&pallet_mod_implementor); + mutator.mutate(&mut ast)?; + rust_writer::preserver::resolve_preserved(&ast, roll_configs_rs_path)?; + + Ok(rollback) + }, + // Both approaches at the sime time aren't supported by the compiler, so this is + // unreachable in a compiling project + (true, true) => unreachable!(), + } +} diff --git a/crates/pop-common/src/rust_writer/tests/sample_files/basic_pallet.rs b/crates/pop-common/src/rust_writer_helpers/sample_files/basic_pallet.rs similarity index 100% rename from crates/pop-common/src/rust_writer/tests/sample_files/basic_pallet.rs rename to crates/pop-common/src/rust_writer_helpers/sample_files/basic_pallet.rs diff --git a/crates/pop-common/src/rust_writer/tests/sample_files/runtime_using_construct_runtime_macro.rs b/crates/pop-common/src/rust_writer_helpers/sample_files/runtime_using_construct_runtime_macro.rs similarity index 100% rename from crates/pop-common/src/rust_writer/tests/sample_files/runtime_using_construct_runtime_macro.rs rename to crates/pop-common/src/rust_writer_helpers/sample_files/runtime_using_construct_runtime_macro.rs diff --git a/crates/pop-common/src/rust_writer/tests/sample_files/runtime_using_runtime_macro.rs b/crates/pop-common/src/rust_writer_helpers/sample_files/runtime_using_runtime_macro.rs similarity index 100% rename from crates/pop-common/src/rust_writer/tests/sample_files/runtime_using_runtime_macro.rs rename to crates/pop-common/src/rust_writer_helpers/sample_files/runtime_using_runtime_macro.rs diff --git a/crates/pop-common/src/rust_writer/parse/tests.rs b/crates/pop-common/src/rust_writer_helpers/tests.rs similarity index 60% rename from crates/pop-common/src/rust_writer/parse/tests.rs rename to crates/pop-common/src/rust_writer_helpers/tests.rs index b2f84fd3e..907ed707e 100644 --- a/crates/pop-common/src/rust_writer/parse/tests.rs +++ b/crates/pop-common/src/rust_writer_helpers/tests.rs @@ -1,8 +1,47 @@ // SPDX-License-Identifier: GPL-3.0 use super::*; -use crate::rust_writer::tests::test_builder::TestBuilder; -use syn::parse_quote; +use std::{fs, path::PathBuf}; +use syn::{parse_file, parse_quote, File}; + +struct TestBuilder { + test_files: PathBuf, + pub(crate) ast: File, +} + +impl Default for TestBuilder { + fn default() -> Self { + Self { + test_files: PathBuf::from(env!("CARGO_MANIFEST_DIR")) + .join("src") + .join("rust_writer_helpers") + .join("sample_files"), + ast: parse_quote! {}, + } + } +} + +macro_rules! add_ast_to_builder_no_preserve{ + ($([$name: ident, $file: literal]),*) => { + $( + fn $name(&mut self){ + self.ast = parse_file( + &fs::read_to_string(self.test_files.join($file)) + .expect(concat!{"Error reading file in ", stringify!($name)}), + ) + .expect(concat!{"Error parsing file in ", stringify!($name)}); + } + )* + }; +} + +impl TestBuilder { + add_ast_to_builder_no_preserve! { + [add_basic_pallet_ast, "basic_pallet.rs"], + [add_runtime_using_runtime_macro_ast, "runtime_using_runtime_macro.rs"], + [add_runtime_using_construct_runtime_macro_ast, "runtime_using_construct_runtime_macro.rs"] + } +} #[test] fn find_highest_pallet_index_works_well() { @@ -15,7 +54,7 @@ fn find_highest_pallet_index_works_well() { .expect("find_highest_pallet_index is supposed to be Ok"); // The highest index in the sample pallet is 11 - assert_eq!(highest_index, 11); + assert_eq!(highest_index.to_string(), "12"); } #[test] @@ -77,51 +116,3 @@ fn find_used_runtime_macro_fails_if_input_isnt_runtime_file() { panic!("find_used_runtime_macro should return only Error::Descriptive") } } - -#[test] -fn find_use_statement_works_well() { - let mut test_builder = TestBuilder::default(); - - test_builder.add_basic_pallet_ast(); - - //Basic pallet has the use statement pub use pallet::*; - let valid_use_statement: ItemUse = parse_quote! {pub use pallet::*;}; - let invalid_use_statement: ItemUse = parse_quote! {use std::path::Path;}; - - assert!(find_use_statement(&test_builder.ast, &valid_use_statement)); - assert!(!find_use_statement(&test_builder.ast, &invalid_use_statement)); -} - -#[test] -fn find_composite_enum_works_well() { - let mut test_builder = TestBuilder::default(); - - test_builder.add_basic_pallet_with_composite_enum_ast(); - - // This enum appears in the sample file basic_pallet_with_composite_enum - let composite_enum: ItemEnum = parse_quote! { - #[pallet::composite_enum] - pub enum SomeEnum { - #[codec(index = 0)] - Something, - } - }; - - // This enum doesn't appear in the sample file basic_pallet_with_composite_enum - let bad_composite_enum: ItemEnum = parse_quote! { - #[pallet::composite_enum] - pub enum OtherEnum{ - #[codec(index=0)] - Something, - } - }; - - assert!(find_composite_enum(&test_builder.ast, &composite_enum)); - assert!(!find_composite_enum(&test_builder.ast, &bad_composite_enum)); - - // basic pallet contains an enum called SomeEnum but it's not annotated as composite_enum - let mut test_builder = TestBuilder::default(); - - test_builder.add_basic_pallet_ast(); - assert!(!find_composite_enum(&test_builder.ast, &composite_enum)); -} From 9904563b215f2557ed5830f0b7df45d48781d7e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1s=20Senovilla=20Polo?= Date: Wed, 26 Mar 2025 21:57:24 +0100 Subject: [PATCH 36/46] Adding rustls-webpki explicitly to Cargo.toml --- Cargo.toml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Cargo.toml b/Cargo.toml index eeb3607a1..a6f02dde2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -96,3 +96,6 @@ strum_macros = "0.26" axum = "0.7.9" open = "5.3.1" tower-http = "0.6.2" + +[patch.crates-io] +rustls-webpki = "0.102" From 2ff6209ef944b63dca733314a3225b86e5abafc3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1s=20Senovilla=20Polo?= Date: Wed, 26 Mar 2025 22:00:14 +0100 Subject: [PATCH 37/46] Adding rustls-webpki explicitly to Cargo.toml --- Cargo.toml | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index a6f02dde2..ffaa52208 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -36,6 +36,7 @@ mockito = "1.4.0" pathdiff = "0.2.1" proc-macro2 = "1.0.86" rustilities = "2.1.0" +rustls-webpki = "0.102" rust_writer = "1.0.4" syn = "2.0.100" tar = "0.4.40" @@ -96,6 +97,3 @@ strum_macros = "0.26" axum = "0.7.9" open = "5.3.1" tower-http = "0.6.2" - -[patch.crates-io] -rustls-webpki = "0.102" From 5560343cecfdba4648ae4d0c500ad2f6322db7c2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1s=20Senovilla=20Polo?= Date: Thu, 27 Mar 2025 11:23:50 +0100 Subject: [PATCH 38/46] Pin deranged 0.4.0 => https://github.com/jhpratt/deranged/issues/18 --- Cargo.lock | 1425 +++++++++++++++++------------- Cargo.toml | 7 +- crates/pop-cli/Cargo.toml | 2 + crates/pop-common/Cargo.toml | 2 + crates/pop-contracts/Cargo.toml | 4 +- crates/pop-parachains/Cargo.toml | 2 + crates/pop-telemetry/Cargo.toml | 4 +- 7 files changed, 822 insertions(+), 624 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 5c7c2026f..9dc94ee21 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -166,19 +166,20 @@ dependencies = [ [[package]] name = "anstyle-wincon" -version = "3.0.6" +version = "3.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2109dbce0e72be3ec00bed26e6a7479ca384ad226efdd66db8fa2e3a38c83125" +checksum = "ca3534e77181a9cc07539ad51f2141fe32f6c3ffd4df76db8ad92346b003ae4e" dependencies = [ "anstyle", + "once_cell", "windows-sys 0.59.0", ] [[package]] name = "anyhow" -version = "1.0.94" +version = "1.0.97" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1fd03a028ef38ba2276dce7e33fcd6369c158a1bca17946c4b1b701891c1ff7" +checksum = "dcfed56ad506cb2c684a14971b8861fdc3baaaae314b9e5f9bb532cbe3ba7a4f" [[package]] name = "approx" @@ -440,7 +441,7 @@ dependencies = [ "nom", "num-traits", "rusticata-macros", - "thiserror 2.0.11", + "thiserror 2.0.12", "time", ] @@ -510,7 +511,7 @@ dependencies = [ "bstr", "doc-comment", "libc", - "predicates 3.1.2", + "predicates 3.1.3", "predicates-core", "predicates-tree", "wait-timeout", @@ -576,7 +577,7 @@ dependencies = [ "futures-lite", "parking", "polling", - "rustix 0.38.42", + "rustix 0.38.44", "slab", "tracing", "windows-sys 0.59.0", @@ -588,7 +589,7 @@ version = "3.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ff6e472cdea888a4bd64f342f09b3f50e1886d32afe8df3d663c01140b811b18" dependencies = [ - "event-listener 5.3.1", + "event-listener 5.4.0", "event-listener-strategy", "pin-project-lite", ] @@ -617,9 +618,9 @@ dependencies = [ "async-task", "blocking", "cfg-if", - "event-listener 5.3.1", + "event-listener 5.4.0", "futures-lite", - "rustix 0.38.42", + "rustix 0.38.44", "tracing", ] @@ -635,7 +636,7 @@ dependencies = [ "cfg-if", "futures-core", "futures-io", - "rustix 0.38.42", + "rustix 0.38.44", "signal-hook-registry", "slab", "windows-sys 0.59.0", @@ -671,9 +672,9 @@ checksum = "8b75356056920673b02621b35afd0f7dda9306d03c79a30f5c56c44cf256e3de" [[package]] name = "async-trait" -version = "0.1.83" +version = "0.1.88" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "721cae7de5c34fbb2acd27e21e6d2cf7b886dce0c27388d46c4e6c47ea4318dd" +checksum = "e539d3fca749fcee5236ab05e93a52867dd549cc157c8cb7f99595f3cedffdb5" dependencies = [ "proc-macro2", "quote", @@ -732,10 +733,10 @@ dependencies = [ "axum-core", "bytes", "futures-util", - "http 1.2.0", + "http 1.3.1", "http-body 1.0.1", "http-body-util", - "hyper 1.5.2", + "hyper 1.6.0", "hyper-util", "itoa", "matchit", @@ -765,7 +766,7 @@ dependencies = [ "async-trait", "bytes", "futures-util", - "http 1.2.0", + "http 1.3.1", "http-body 1.0.1", "http-body-util", "mime", @@ -798,7 +799,7 @@ dependencies = [ "cfg-if", "libc", "miniz_oxide", - "object 0.36.5", + "object 0.36.7", "rustc-demangle", "windows-targets 0.52.6", ] @@ -841,15 +842,15 @@ checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" [[package]] name = "base64ct" -version = "1.6.0" +version = "1.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" +checksum = "89e25b6adfb930f02d1981565a6e5d9c547ac15a96606256d3b59040e5cd4ca3" [[package]] name = "basic-toml" -version = "0.1.9" +version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "823388e228f614e9558c6804262db37960ec8821856535f5c3f59913140558f8" +checksum = "ba62675e8242a4c4e806d12f11d136e626e6c8361d6b829310732241652a178a" dependencies = [ "serde", ] @@ -972,9 +973,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.6.0" +version = "2.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" +checksum = "5c8214115b7bf84099f1309324e63141d4c5d7cc26862f97a0a857dbefe165bd" [[package]] name = "bitvec" @@ -1022,9 +1023,9 @@ dependencies = [ [[package]] name = "blake2b_simd" -version = "1.0.2" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23285ad32269793932e830392f2fe2f83e26488fd3ec778883a93c8323735780" +checksum = "06e903a20b159e944f91ec8499fe1e55651480c541ea0a584f5d967c49ad9d99" dependencies = [ "arrayref", "arrayvec 0.7.6", @@ -1098,9 +1099,9 @@ dependencies = [ "futures-core", "futures-util", "hex", - "http 1.2.0", + "http 1.3.1", "http-body-util", - "hyper 1.5.2", + "hyper 1.6.0", "hyper-named-pipe", "hyper-util", "hyperlocal", @@ -1111,7 +1112,7 @@ dependencies = [ "serde_json", "serde_repr", "serde_urlencoded", - "thiserror 2.0.11", + "thiserror 2.0.12", "tokio", "tokio-util", "tower-service", @@ -1132,9 +1133,9 @@ dependencies = [ [[package]] name = "borsh" -version = "1.5.3" +version = "1.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2506947f73ad44e344215ccd6403ac2ae18cd8e046e581a441bf8d199f257f03" +checksum = "ad8646f98db542e39fc66e68a20b2144f6a732636df7c2354e74645faaa433ce" dependencies = [ "borsh-derive", "cfg_aliases 0.2.1", @@ -1142,12 +1143,12 @@ dependencies = [ [[package]] name = "borsh-derive" -version = "1.5.3" +version = "1.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2593a3b8b938bd68373196c9832f516be11fa487ef4ae745eb282e6a56a7244" +checksum = "fdd1d3c0c2f5833f22386f252fe8ed005c7f59fdcddeef025c01b4c3b9fd9ac3" dependencies = [ "once_cell", - "proc-macro-crate 3.2.0", + "proc-macro-crate 3.3.0", "proc-macro2", "quote", "syn 2.0.100", @@ -1155,9 +1156,9 @@ dependencies = [ [[package]] name = "bounded-collections" -version = "0.2.2" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d077619e9c237a5d1875166f5e8033e8f6bff0c96f8caf81e1c2d7738c431bf" +checksum = "64ad8a0bed7827f0b07a5d23cec2e58cc02038a99e4ca81616cb2bb2025f804d" dependencies = [ "log", "parity-scale-codec", @@ -1195,9 +1196,9 @@ dependencies = [ [[package]] name = "bstr" -version = "1.11.1" +version = "1.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "786a307d683a5bf92e6fd5fd69a7eb613751668d1d8d67d802846dfe367c62c8" +checksum = "531a9155a481e2ee699d4f98f43c0ca4ff8ee1bfd55c31e9e98fb29d2b176fe0" dependencies = [ "memchr", "regex-automata 0.4.9", @@ -1206,15 +1207,15 @@ dependencies = [ [[package]] name = "bumpalo" -version = "3.16.0" +version = "3.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" +checksum = "1628fb46dfa0b37568d12e5edd512553eccf6a22a78e8bde00bb4aed84d5bdbf" [[package]] name = "byte-slice-cast" -version = "1.2.2" +version = "1.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3ac9f8b63eca6fd385229b3675f6cc0dc5c8a5c8a54a59d4f52ffd670d87b0c" +checksum = "7575182f7272186991736b70173b0ea045398f984bf5ebbb3804736ce1330c9d" [[package]] name = "byte-tools" @@ -1246,9 +1247,9 @@ dependencies = [ [[package]] name = "bytemuck" -version = "1.20.0" +version = "1.22.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b37c88a63ffd85d15b406896cc343916d7cf57838a847b3a6f2ca5d39a5695a" +checksum = "b6b1fc10dbac614ebc03540c9dbd60e83887fda27794998c6528f1782047d540" [[package]] name = "byteorder" @@ -1258,9 +1259,9 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "bytes" -version = "1.9.0" +version = "1.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "325918d6fe32f23b19878fe4b34794ae41fc19ddbe53b10571a4874d44ffd39b" +checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a" [[package]] name = "bzip2-sys" @@ -1302,16 +1303,16 @@ dependencies = [ [[package]] name = "cargo_metadata" -version = "0.19.1" +version = "0.19.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8769706aad5d996120af43197bf46ef6ad0fda35216b4505f926a365a232d924" +checksum = "dd5eb614ed4c27c5d706420e4320fbe3216ab31fa1c33cd8246ac36dae4479ba" dependencies = [ "camino", "cargo-platform", "semver", "serde", "serde_json", - "thiserror 2.0.11", + "thiserror 2.0.12", ] [[package]] @@ -1321,7 +1322,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "88da5a13c620b4ca0078845707ea9c3faf11edbc3ffd8497d11d686211cd1ac0" dependencies = [ "serde", - "toml 0.8.19", + "toml 0.8.20", ] [[package]] @@ -1331,14 +1332,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5fbd1fe9db3ebf71b89060adaf7b0504c2d6a425cf061313099547e382c2e472" dependencies = [ "serde", - "toml 0.8.19", + "toml 0.8.20", ] [[package]] name = "cc" -version = "1.2.4" +version = "1.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9157bbaa6b165880c27a4293a474c91cdcf265cc68cc829bf10be0964a391caf" +checksum = "1fcb57c740ae1daf453ae85f16e37396f672b039e00d9d866e07ddb24e328e3a" dependencies = [ "jobserver", "libc", @@ -1423,9 +1424,9 @@ dependencies = [ [[package]] name = "chrono" -version = "0.4.39" +version = "0.4.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e36cc9d416881d2e24f9a963be5fb1cd90966419ac844274161d10488b3e825" +checksum = "1a7964611d71df112cb1730f2ee67324fcf4d0fc6606acbbe9bfe06df124637c" dependencies = [ "android-tzdata", "iana-time-zone", @@ -1433,7 +1434,7 @@ dependencies = [ "num-traits", "serde", "wasm-bindgen", - "windows-targets 0.52.6", + "windows-link", ] [[package]] @@ -1495,9 +1496,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.23" +version = "4.5.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3135e7ec2ef7b10c6ed8950f0f792ed96ee093fa088608f1c76e569722700c84" +checksum = "e958897981290da2a852763fe9cdb89cd36977a5d729023127095fa94d95e2ff" dependencies = [ "clap_builder", "clap_derive", @@ -1505,9 +1506,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.23" +version = "4.5.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30582fc632330df2bd26877bde0c1f4470d57c582bbc070376afcd04d8cb4838" +checksum = "83b0f35019843db2160b5bb19ae09b4e6411ac33fc6a712003c33e03090e2489" dependencies = [ "anstream", "anstyle", @@ -1518,9 +1519,9 @@ dependencies = [ [[package]] name = "clap_derive" -version = "4.5.18" +version = "4.5.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ac6a0c7b1a9e9a5186361f67dfa1b88213572f427fb9ab038efb2bd8c582dab" +checksum = "09176aae279615badda0765c0c0b3f6ed53f4709118af73cf4655d85d1530cd7" dependencies = [ "heck 0.5.0", "proc-macro2", @@ -1561,12 +1562,13 @@ dependencies = [ [[package]] name = "codespan-reporting" -version = "0.11.1" +version = "0.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3538270d33cc669650c4b093848450d380def10c331d38c768e34cac80576e6e" +checksum = "fe6d2e5af09e8c8ad56c969f2157a3d4238cebc7c55f0a517728c38f7b200f81" dependencies = [ + "serde", "termcolor", - "unicode-width 0.1.14", + "unicode-width", ] [[package]] @@ -1585,6 +1587,15 @@ dependencies = [ "windows-sys 0.59.0", ] +[[package]] +name = "colored" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fde0e0ec90c9dfb3b4b1a0891a7dcd0e2bffde2f7efed5fe7c9bb00e5bfb915e" +dependencies = [ + "windows-sys 0.59.0", +] + [[package]] name = "combine" version = "4.6.7" @@ -1602,7 +1613,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4a65ebfec4fb190b6f90e944a817d60499ee0744e582530e2c9900a22e591d9a" dependencies = [ "unicode-segmentation", - "unicode-width 0.2.0", + "unicode-width", ] [[package]] @@ -1622,14 +1633,14 @@ dependencies = [ [[package]] name = "console" -version = "0.15.10" +version = "0.15.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea3c6ecd8059b57859df5c69830340ed3c41d30e3da0c1cbed90a96ac853041b" +checksum = "054ccb5b10f9f2cbf51eb355ca1d05c2d279ce1804688d0db74b4733a5aeafd8" dependencies = [ "encode_unicode", "libc", "once_cell", - "unicode-width 0.2.0", + "unicode-width", "windows-sys 0.59.0", ] @@ -1679,6 +1690,26 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "const_format" +version = "0.2.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "126f97965c8ad46d6d9163268ff28432e8f6a1196a55578867832e3049df63dd" +dependencies = [ + "const_format_proc_macros", +] + +[[package]] +name = "const_format_proc_macros" +version = "0.2.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d57c2eccfb16dbac1f4e61e206105db5820c9d26c3c472bc17c774259ef7744" +dependencies = [ + "proc-macro2", + "quote", + "unicode-xid", +] + [[package]] name = "constant_time_eq" version = "0.1.5" @@ -1699,16 +1730,16 @@ checksum = "cd7e35aee659887cbfb97aaf227ac12cad1a9d7c71e55ff3376839ed4e282d08" [[package]] name = "contract-build" -version = "5.0.2" +version = "5.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b014fa89030235ecd8bdeb061ec97df326281b484f89ad3e17a79f08759c2f52" +checksum = "6e661897ab30bc0290628b2ea3ce18463c766a1264687a76aa8f5a36b6e75e78" dependencies = [ "anyhow", "blake2 0.10.6", "bollard", "cargo_metadata", "clap", - "colored", + "colored 2.2.0", "contract-metadata", "crossterm", "duct", @@ -1726,27 +1757,27 @@ dependencies = [ "term_size", "tokio", "tokio-stream", - "toml 0.8.19", + "toml 0.8.20", "tracing", "url", "uzers", "walkdir", "wasm-encoder", "wasm-opt", - "wasmparser 0.220.0", + "wasmparser 0.220.1", "which", "zip", ] [[package]] name = "contract-extrinsics" -version = "5.0.2" +version = "5.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67d0c91349c31caec4d5e3c544b4bc4fcc7c0468dc49ee84a96a24f915464401" +checksum = "f21e03420806389aa620e4aa6c01085478f0b5024e7bdefa26c41af26379ffcf" dependencies = [ "anyhow", "blake2 0.10.6", - "colored", + "colored 2.2.0", "contract-build", "contract-metadata", "contract-transcode", @@ -1765,7 +1796,7 @@ dependencies = [ "sp-core 32.0.0", "sp-runtime 35.0.0", "sp-weights", - "subxt 0.38.0", + "subxt 0.38.1", "tokio", "tracing", "url", @@ -1773,9 +1804,9 @@ dependencies = [ [[package]] name = "contract-metadata" -version = "5.0.2" +version = "5.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83ae8bcb5f7c5ea033d05fa0bbffa4e762a5b69c0ce96e4188fb15385a01998b" +checksum = "3ce11bf540c9b154aca38e9d828ae7ea93ec7b4486c5dea87d553016b28af175" dependencies = [ "anyhow", "impl-serde 0.5.0", @@ -1787,9 +1818,9 @@ dependencies = [ [[package]] name = "contract-transcode" -version = "5.0.2" +version = "5.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baca96dc859fd180eba5f15e468f59dc8c932a6b72f6b76f91b571b6743a9e7d" +checksum = "b315857697f467045d8c1bcf2bce7c9eb0a6e32d94554afd0d2892e772ecad0c" dependencies = [ "anyhow", "base58", @@ -1809,7 +1840,7 @@ dependencies = [ "serde", "serde_json", "strsim 0.11.1", - "thiserror 2.0.11", + "thiserror 2.0.12", "tracing", ] @@ -1865,9 +1896,9 @@ dependencies = [ [[package]] name = "cpufeatures" -version = "0.2.16" +version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16b80225097f2e5ae4e7179dd2266824648f3e2f49d9134d584b76389d31c4c3" +checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280" dependencies = [ "libc", ] @@ -2019,11 +2050,11 @@ version = "0.28.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "829d955a0bb380ef178a640b91779e3987da38c9aea133b20614cfed8cdea9c6" dependencies = [ - "bitflags 2.6.0", + "bitflags 2.9.0", "crossterm_winapi", "mio", "parking_lot 0.12.3", - "rustix 0.38.42", + "rustix 0.38.44", "signal-hook", "signal-hook-mio", "winapi", @@ -2040,9 +2071,9 @@ dependencies = [ [[package]] name = "crunchy" -version = "0.2.2" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" +checksum = "43da5946c66ffcc7745f48db692ffbb10a83bfe0afd96235c5c2a4fb23994929" [[package]] name = "crypto-bigint" @@ -2197,7 +2228,7 @@ dependencies = [ "async-trait", "cumulus-primitives-core", "futures", - "jsonrpsee-core 0.24.7", + "jsonrpsee-core 0.24.9", "parity-scale-codec", "polkadot-overseer", "sc-client-api", @@ -2264,9 +2295,9 @@ dependencies = [ [[package]] name = "cxx" -version = "1.0.135" +version = "1.0.151" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d44ff199ff93242c3afe480ab588d544dd08d72e92885e152ffebc670f076ad" +checksum = "fdb3e596b379180315d2f934231e233a2fc745041f88231807774093d8de45f2" dependencies = [ "cc", "cxxbridge-cmd", @@ -2278,9 +2309,9 @@ dependencies = [ [[package]] name = "cxx-build" -version = "1.0.135" +version = "1.0.151" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "66fd8f17ad454fc1e4f4ab83abffcc88a532e90350d3ffddcb73030220fcbd52" +checksum = "3743fae7f47620cd34ec23bab819db9ee52da93166a058f87ab0ad99d777dc9b" dependencies = [ "cc", "codespan-reporting", @@ -2292,9 +2323,9 @@ dependencies = [ [[package]] name = "cxxbridge-cmd" -version = "1.0.135" +version = "1.0.151" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4717c9c806a9e07fdcb34c84965a414ea40fafe57667187052cf1eb7f5e8a8a9" +checksum = "aaea0273c049b126a3918df88a1670c9c0168e0738df9370a988ff69070d4fff" dependencies = [ "clap", "codespan-reporting", @@ -2305,15 +2336,15 @@ dependencies = [ [[package]] name = "cxxbridge-flags" -version = "1.0.135" +version = "1.0.151" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f6515329bf3d98f4073101c7866ff2bec4e635a13acb82e3f3753fff0bf43cb" +checksum = "020a9a3d6b792aab7f30f6e323893ad7f45052e572cde5d014c47fe67c89495f" [[package]] name = "cxxbridge-macro" -version = "1.0.135" +version = "1.0.151" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb93e6a7ce8ec985c02bbb758237a31598b340acbbc3c19c5a4fa6adaaac92ab" +checksum = "ee54cd01f94db0328c4c73036d38bd8c3bb88927e953d05ffefe743edbf4eb68" dependencies = [ "proc-macro2", "quote", @@ -2406,15 +2437,15 @@ dependencies = [ [[package]] name = "data-encoding" -version = "2.6.0" +version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8566979429cf69b49a5c740c60791108e86440e8be149bbea4fe54d2c32d6e2" +checksum = "575f75dfd25738df5b91b8e43e14d44bda14637a58fae779fd2b064f8bf3e010" [[package]] name = "data-encoding-macro" -version = "0.1.15" +version = "0.1.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1559b6cba622276d6d63706db152618eeb15b89b3e4041446b05876e352e639" +checksum = "9f9724adfcf41f45bf652b3995837669d73c4d49a1b5ac1ff82905ac7d9b5558" dependencies = [ "data-encoding", "data-encoding-macro-internal", @@ -2422,12 +2453,12 @@ dependencies = [ [[package]] name = "data-encoding-macro-internal" -version = "0.1.13" +version = "0.1.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "332d754c0af53bc87c108fed664d121ecf59207ec4196041f04d6ab9002ad33f" +checksum = "18e4fdb82bd54a12e42fb58a800dcae6b9e13982238ce2296dc3570b92148e1f" dependencies = [ "data-encoding", - "syn 1.0.109", + "syn 2.0.100", ] [[package]] @@ -2470,9 +2501,9 @@ dependencies = [ [[package]] name = "deranged" -version = "0.3.11" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4" +checksum = "9c9e6a11ca8224451684bc0d7d5a7adbf8f2fd6887261a1cfc3c0432f9d4068e" dependencies = [ "powerfmt", "serde", @@ -2524,9 +2555,9 @@ dependencies = [ [[package]] name = "derive_more" -version = "0.99.18" +version = "0.99.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f33878137e4dafd7fa914ad4e259e18a4e8e532b9617a2d0150262bf53abfce" +checksum = "3da29a38df43d6f156149c9b43ded5e018ddff2a855cf2cfd62e8cd7d079c69f" dependencies = [ "convert_case", "proc-macro2", @@ -2695,7 +2726,7 @@ dependencies = [ "regex", "syn 2.0.100", "termcolor", - "toml 0.8.19", + "toml 0.8.20", "walkdir", ] @@ -2731,9 +2762,9 @@ dependencies = [ [[package]] name = "dyn-clonable" -version = "0.9.0" +version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e9232f0e607a262ceb9bd5141a3dfb3e4db6994b31989bbfd845878cba59fd4" +checksum = "a36efbb9bfd58e1723780aa04b61aba95ace6a05d9ffabfdb0b43672552f0805" dependencies = [ "dyn-clonable-impl", "dyn-clone", @@ -2741,20 +2772,20 @@ dependencies = [ [[package]] name = "dyn-clonable-impl" -version = "0.9.0" +version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "558e40ea573c374cf53507fd240b7ee2f5477df7cfebdb97323ec61c719399c5" +checksum = "7e8671d54058979a37a26f3511fbf8d198ba1aa35ffb202c42587d918d77213a" dependencies = [ "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.100", ] [[package]] name = "dyn-clone" -version = "1.0.17" +version = "1.0.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d6ef0072f8a535281e4876be788938b528e9a1d43900b82c2569af7da799125" +checksum = "1c7a8fb8a9fbf66c1f703fe16184d10ca0ee9d23be5b4436400408ba54a95005" [[package]] name = "ecdsa" @@ -2827,9 +2858,9 @@ dependencies = [ [[package]] name = "either" -version = "1.13.0" +version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" +checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" [[package]] name = "elliptic-curve" @@ -2892,14 +2923,20 @@ dependencies = [ [[package]] name = "env_filter" -version = "0.1.2" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f2c92ceda6ceec50f43169f9ee8424fe2db276791afde7b2cd8bc084cb376ab" +checksum = "186e05a59d4c50738528153b83b0b0194d3a29507dfec16eccd4b342903397d0" dependencies = [ "log", "regex", ] +[[package]] +name = "env_home" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7f84e12ccf0a7ddc17a6c41c93326024c42920d7ee630d04950e6926645c0fe" + [[package]] name = "env_logger" version = "0.10.2" @@ -2934,9 +2971,9 @@ checksum = "e48c92028aaa870e83d51c64e5d4e0b6981b360c522198c23959f219a4e1b15b" [[package]] name = "equivalent" -version = "1.0.1" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" [[package]] name = "errno" @@ -2972,9 +3009,9 @@ dependencies = [ [[package]] name = "event-listener" -version = "5.3.1" +version = "5.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6032be9bd27023a771701cc49f9f053c751055f71efb2e0ae5c15809093675ba" +checksum = "3492acde4c3fc54c845eaab3eed8bd00c7a7d881f78bfc801e43a93dec1331ae" dependencies = [ "concurrent-queue", "parking", @@ -2987,7 +3024,7 @@ version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3c3e4e0dd3673c1139bf041f3008816d9cf2946bbfac2945c09e523b8d7b05b2" dependencies = [ - "event-listener 5.3.1", + "event-listener 5.4.0", "pin-project-lite", ] @@ -3045,7 +3082,7 @@ checksum = "eb42427514b063d97ce21d5199f36c0c307d981434a6be32582bc79fe5bd2303" dependencies = [ "expander", "indexmap 2.8.0", - "proc-macro-crate 3.2.0", + "proc-macro-crate 3.3.0", "proc-macro2", "quote", "syn 2.0.100", @@ -3063,9 +3100,9 @@ dependencies = [ [[package]] name = "ff" -version = "0.13.0" +version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ded41244b729663b1e574f1b4fb731469f69f79c17667b5d776b16cda0479449" +checksum = "c0b50bfb653653f9ca9095b427bed08ab8d75a137839d9ad64eb11810d5b6393" dependencies = [ "rand_core 0.6.4", "subtle 2.6.1", @@ -3111,9 +3148,9 @@ dependencies = [ [[package]] name = "finality-grandpa" -version = "0.16.2" +version = "0.16.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "36530797b9bf31cd4ff126dcfee8170f86b00cfdcea3269d73133cc0415945c3" +checksum = "b4f8f43dc520133541781ec03a8cab158ae8b7f7169cdf22e9050aa6cf0fbdfc" dependencies = [ "either", "futures", @@ -3161,9 +3198,9 @@ checksum = "1d674e81391d1e1ab681a28d99df07927c6d4aa5b027d7da16ba32d1d21ecd99" [[package]] name = "flate2" -version = "1.0.35" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c936bfdafb507ebbf50b8074c54fa31c5be9a1e7e5f467dd659697041407d07c" +checksum = "11faaf5a5236997af9848be0bef4db95824b1d534ebc64d0f0c6cf3e67bd38dc" dependencies = [ "crc32fast", "miniz_oxide", @@ -3178,6 +3215,15 @@ dependencies = [ "num-traits", ] +[[package]] +name = "float-cmp" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b09cf3155332e944990140d967ff5eceb70df778b34f77d8075db46e4704e6d8" +dependencies = [ + "num-traits", +] + [[package]] name = "fnv" version = "1.0.7" @@ -3186,9 +3232,9 @@ checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" [[package]] name = "foldhash" -version = "0.1.3" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f81ec6369c545a7d40e4589b5597581fa1c441fe1cce96dd1de43159910a36a2" +checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" [[package]] name = "foreign-types" @@ -3329,9 +3375,9 @@ dependencies = [ [[package]] name = "frame-decode" -version = "0.5.0" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02d3379df61ff3dd871e2dde7d1bcdc0263e613c21c7579b149fd4f0ad9b1dc2" +checksum = "6027a409bac4fe95b4d107f965fcdbc252fc89d884a360d076b3070b6128c094" dependencies = [ "frame-metadata 17.0.0", "parity-scale-codec", @@ -3446,7 +3492,7 @@ dependencies = [ "frame-support-procedural-tools", "itertools 0.11.0", "macro_magic", - "proc-macro-warning 1.0.2", + "proc-macro-warning 1.84.1", "proc-macro2", "quote", "sp-crypto-hashing", @@ -3460,7 +3506,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "81a088fd6fda5f53ff0c17fc7551ce8bd0ead14ba742228443c8196296a7369b" dependencies = [ "frame-support-procedural-tools-derive", - "proc-macro-crate 3.2.0", + "proc-macro-crate 3.3.0", "proc-macro2", "quote", "syn 2.0.100", @@ -3525,7 +3571,7 @@ checksum = "3de930156615ed4eb3165da0bd81c0e5079d4e14a8a965bc56cfd7400f94f718" dependencies = [ "rustilities 1.1.0", "tempfile", - "thiserror 2.0.11", + "thiserror 2.0.12", ] [[package]] @@ -3595,9 +3641,9 @@ checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" [[package]] name = "futures-lite" -version = "2.5.0" +version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cef40d21ae2c515b51041df9ed313ed21e572df340ea58a922a0aefe7e8891a1" +checksum = "f5edaec856126859abb19ed65f39e90fea3a9574b9707f13539acf4abf7eb532" dependencies = [ "fastrand", "futures-core", @@ -3715,14 +3761,14 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.3.1" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43a49c392881ce6d5c3b8cb70f98717b7c07aabbdff06687b9030dbfbe2725f8" +checksum = "73fea8450eea4bac3940448fb7ae50d91f034f941199fcd9d909a5a07aa455f0" dependencies = [ "cfg-if", "libc", - "wasi 0.13.3+wasi-0.2.2", - "windows-targets 0.52.6", + "r-efi", + "wasi 0.14.2+wasi-0.2.4", ] [[package]] @@ -3768,7 +3814,7 @@ version = "0.18.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "232e6a7bfe35766bf715e55a88b39a700596c0ccfd88cd3680b4cdb40d66ef70" dependencies = [ - "bitflags 2.6.0", + "bitflags 2.9.0", "libc", "libgit2-sys", "log", @@ -3793,9 +3839,9 @@ dependencies = [ [[package]] name = "glob" -version = "0.3.1" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" +checksum = "a8d1add55171497b4705a648c6b583acafb01d58050a51727785f0b2c8e0a2b2" [[package]] name = "glob-match" @@ -3855,16 +3901,16 @@ dependencies = [ [[package]] name = "h2" -version = "0.4.7" +version = "0.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ccae279728d634d083c00f6099cb58f01cc99c145b84b8be2f6c74618d79922e" +checksum = "5017294ff4bb30944501348f6f8e42e6ad28f42c8bbef7a74029aff064a4e3c2" dependencies = [ "atomic-waker", "bytes", "fnv", "futures-core", "futures-sink", - "http 1.2.0", + "http 1.3.1", "indexmap 2.8.0", "slab", "tokio", @@ -3974,6 +4020,12 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fbf6a919d6cf397374f7dfeeea91d974c7c0a7221d0d0f4f20d859d329e53fcc" +[[package]] +name = "hermit-abi" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fbd780fe5cc30f81464441920d82ac8740e2e46b29a6fad543ddd075229ce37e" + [[package]] name = "hex" version = "0.4.3" @@ -4118,9 +4170,9 @@ dependencies = [ [[package]] name = "http" -version = "1.2.0" +version = "1.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f16ca2af56261c99fba8bac40a10251ce8188205a4c448fbb745a2e4daa76fea" +checksum = "f4a85d31aea989eead29a3aaf9e1115a180df8282431156e533de47660892565" dependencies = [ "bytes", "fnv", @@ -4145,18 +4197,18 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" dependencies = [ "bytes", - "http 1.2.0", + "http 1.3.1", ] [[package]] name = "http-body-util" -version = "0.1.2" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "793429d76616a256bcb62c2a2ec2bed781c8307e797e2598c50010f2bee2544f" +checksum = "b021d93e26becf5dc7e1b75b1bed1fd93124b374ceb73f43d4d4eafec896a64a" dependencies = [ "bytes", - "futures-util", - "http 1.2.0", + "futures-core", + "http 1.3.1", "http-body 1.0.1", "pin-project-lite", ] @@ -4175,9 +4227,9 @@ checksum = "9171a2ea8a68358193d15dd5d70c1c10a2afc3e7e4c5bc92bc9f025cebd7359c" [[package]] name = "httparse" -version = "1.9.5" +version = "1.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d71d3574edd2771538b901e6549113b4006ece66150fb69c0fb6d9a2adae946" +checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87" [[package]] name = "httpdate" @@ -4196,9 +4248,9 @@ dependencies = [ [[package]] name = "humantime" -version = "2.1.0" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" +checksum = "9b112acc8b3adf4b107a8ec20977da0273a8c386765a3ec0229bd500a1443f9f" [[package]] name = "hyper" @@ -4226,15 +4278,15 @@ dependencies = [ [[package]] name = "hyper" -version = "1.5.2" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "256fb8d4bd6413123cc9d91832d78325c48ff41677595be797d90f42969beae0" +checksum = "cc2b571658e38e0c01b1fdca3bbbe93c00d3d71693ff2770043f8c29bc7d6f80" dependencies = [ "bytes", "futures-channel", "futures-util", - "h2 0.4.7", - "http 1.2.0", + "h2 0.4.8", + "http 1.3.1", "http-body 1.0.1", "httparse", "httpdate", @@ -4252,7 +4304,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "73b7d8abf35697b81a825e386fc151e0d503e8cb5fcb93cc8669c376dfd6f278" dependencies = [ "hex", - "hyper 1.5.2", + "hyper 1.6.0", "hyper-util", "pin-project-lite", "tokio", @@ -4278,18 +4330,18 @@ dependencies = [ [[package]] name = "hyper-rustls" -version = "0.27.4" +version = "0.27.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6884a48c6826ec44f524c7456b163cebe9e55a18d7b5e307cb4f100371cc767" +checksum = "2d191583f3da1305256f22463b9bb0471acad48a4e534a5218b9963e9c1f59b2" dependencies = [ "futures-util", - "http 1.2.0", - "hyper 1.5.2", + "http 1.3.1", + "hyper 1.6.0", "hyper-util", "rustls 0.23.25", "rustls-pki-types", "tokio", - "tokio-rustls 0.26.1", + "tokio-rustls 0.26.2", "tower-service", ] @@ -4313,7 +4365,7 @@ checksum = "70206fc6890eaca9fde8a0bf71caa2ddfc9fe045ac9e5c70df101a7dbde866e0" dependencies = [ "bytes", "http-body-util", - "hyper 1.5.2", + "hyper 1.6.0", "hyper-util", "native-tls", "tokio", @@ -4330,9 +4382,9 @@ dependencies = [ "bytes", "futures-channel", "futures-util", - "http 1.2.0", + "http 1.3.1", "http-body 1.0.1", - "hyper 1.5.2", + "hyper 1.6.0", "pin-project-lite", "socket2 0.5.8", "tokio", @@ -4348,7 +4400,7 @@ checksum = "986c5ce3b994526b3cd75578e62554abd09f0899d6206de48b3e96ab34ccc8c7" dependencies = [ "hex", "http-body-util", - "hyper 1.5.2", + "hyper 1.6.0", "hyper-util", "pin-project-lite", "tokio", @@ -4357,14 +4409,15 @@ dependencies = [ [[package]] name = "iana-time-zone" -version = "0.1.61" +version = "0.1.62" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "235e081f3925a06703c2d0117ea8b91f042756fd6e7a6e5d901e8ca1a996b220" +checksum = "b2fd658b06e56721792c5df4475705b6cda790e9298d19d2f8af083457bcd127" dependencies = [ "android_system_properties", "core-foundation-sys", "iana-time-zone-haiku", "js-sys", + "log", "wasm-bindgen", "windows-core 0.52.0", ] @@ -4419,9 +4472,9 @@ dependencies = [ [[package]] name = "icu_locid_transform_data" -version = "1.5.0" +version = "1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fdc8ff3388f852bede6b579ad4e978ab004f139284d7b28715f773507b946f6e" +checksum = "7515e6d781098bf9f7205ab3fc7e9709d34554ae0b21ddbcb5febfa4bc7df11d" [[package]] name = "icu_normalizer" @@ -4443,9 +4496,9 @@ dependencies = [ [[package]] name = "icu_normalizer_data" -version = "1.5.0" +version = "1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8cafbf7aa791e9b22bec55a167906f9e1215fd475cd22adfcf660e03e989516" +checksum = "c5e8338228bdc8ab83303f16b797e177953730f601a96c25d10cb3ab0daa0cb7" [[package]] name = "icu_properties" @@ -4464,9 +4517,9 @@ dependencies = [ [[package]] name = "icu_properties_data" -version = "1.5.0" +version = "1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67a8effbc3dd3e4ba1afa8ad918d5684b8868b3b26500753effea8d2eed19569" +checksum = "85fb8799753b75aee8d2a21d7c14d9f38921b54b3dbda10f5a3c7a7b82dba5e2" [[package]] name = "icu_provider" @@ -4607,9 +4660,9 @@ dependencies = [ [[package]] name = "impl-codec" -version = "0.7.0" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b67aa010c1e3da95bf151bd8b4c059b2ed7e75387cdb969b4f8f2723a43f9941" +checksum = "2d40b9d5e17727407e55028eafc22b2dc68781786e6d7eb8a21103f5058e3a14" dependencies = [ "parity-scale-codec", ] @@ -4709,14 +4762,14 @@ checksum = "8e04e2fd2b8188ea827b32ef11de88377086d690286ab35747ef7f9bf3ccb590" [[package]] name = "indicatif" -version = "0.17.9" +version = "0.17.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cbf675b85ed934d3c67b5c5469701eec7db22689d0a2139d856e0925fa28b281" +checksum = "183b3088984b400f4cfac3620d5e076c84da5364016b4f49473de574b2586235" dependencies = [ "console", "number_prefix", "portable-atomic", - "unicode-width 0.2.0", + "unicode-width", "web-time", ] @@ -4832,9 +4885,9 @@ dependencies = [ [[package]] name = "inout" -version = "0.1.3" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a0c10553d664a4d0bcff9f4215d0aac67a639cc68ef660840afe309b807bc9f5" +checksum = "879f10e63c20629ecabbb64a8010319738c66a5cd0c29b02d63d272b03751d01" dependencies = [ "generic-array 0.14.7", ] @@ -4888,9 +4941,9 @@ dependencies = [ [[package]] name = "ipnet" -version = "2.10.1" +version = "2.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ddc24109865250148c2e0f3d25d4f0f479571723792d3802153c60922a4fb708" +checksum = "469fb0b9cefa57e3ef31275ee7cacb78f2fdca44e4765491884a2b119d4eb130" [[package]] name = "is-docker" @@ -4903,13 +4956,13 @@ dependencies = [ [[package]] name = "is-terminal" -version = "0.4.13" +version = "0.4.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "261f68e344040fbd0edea105bef17c66edf46f984ddb1115b775ce31be948f4b" +checksum = "e04d7f318608d35d4b61ddd75cbdaee86b023ebe2bd5a66ee0915f0bf93095a9" dependencies = [ - "hermit-abi 0.4.0", + "hermit-abi 0.5.0", "libc", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -4964,11 +5017,20 @@ dependencies = [ "either", ] +[[package]] +name = "itertools" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b192c782037fadd9cfa75548310488aabdbf3d2da73885b31bd0abd03351285" +dependencies = [ + "either", +] + [[package]] name = "itoa" -version = "1.0.14" +version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d75a2a4b1b190afb6f5425f10f6a8f959d2ea0b9c2b1d79553551850539e4674" +checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" [[package]] name = "jiff" @@ -5008,6 +5070,22 @@ dependencies = [ "walkdir", ] +[[package]] +name = "jni" +version = "0.21.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a87aa2bb7d2af34197c04845522473242e1aa17c12f4935d5856491a7fb8c97" +dependencies = [ + "cesu8", + "cfg-if", + "combine", + "jni-sys", + "log", + "thiserror 1.0.69", + "walkdir", + "windows-sys 0.45.0", +] + [[package]] name = "jni-sys" version = "0.3.0" @@ -5031,9 +5109,9 @@ checksum = "72167d68f5fce3b8655487b8038691a3c9984ee769590f93f2a631f4ad64e4f5" [[package]] name = "js-sys" -version = "0.3.76" +version = "0.3.77" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6717b6b5b077764fb5966237269cb3c64edddde4b14ce42647430a78ced9e7b7" +checksum = "1cfaf33c695fc6e08064efbc1f72ec937429614f25eef83af942d0e227c3a28f" dependencies = [ "once_cell", "wasm-bindgen", @@ -5088,16 +5166,16 @@ dependencies = [ [[package]] name = "jsonrpsee" -version = "0.24.7" +version = "0.24.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5c71d8c1a731cc4227c2f698d377e7848ca12c8a48866fc5e6951c43a4db843" +checksum = "37b26c20e2178756451cfeb0661fb74c47dd5988cb7e3939de7e9241fd604d42" dependencies = [ - "jsonrpsee-client-transport 0.24.7", - "jsonrpsee-core 0.24.7", + "jsonrpsee-client-transport 0.24.9", + "jsonrpsee-core 0.24.9", "jsonrpsee-proc-macros", "jsonrpsee-server", - "jsonrpsee-types 0.24.7", - "jsonrpsee-ws-client 0.24.7", + "jsonrpsee-types 0.24.9", + "jsonrpsee-ws-client 0.24.9", "tokio", "tracing", ] @@ -5131,16 +5209,16 @@ checksum = "08163edd8bcc466c33d79e10f695cdc98c00d1e6ddfb95cec41b6b0279dd5432" dependencies = [ "base64 0.22.1", "futures-util", - "http 1.2.0", + "http 1.3.1", "jsonrpsee-core 0.23.2", "pin-project", "rustls 0.23.25", "rustls-pki-types", - "rustls-platform-verifier", + "rustls-platform-verifier 0.3.4", "soketto 0.8.1", "thiserror 1.0.69", "tokio", - "tokio-rustls 0.26.1", + "tokio-rustls 0.26.2", "tokio-util", "tracing", "url", @@ -5148,22 +5226,22 @@ dependencies = [ [[package]] name = "jsonrpsee-client-transport" -version = "0.24.7" +version = "0.24.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "548125b159ba1314104f5bb5f38519e03a41862786aa3925cf349aae9cdd546e" +checksum = "bacb85abf4117092455e1573625e21b8f8ef4dec8aff13361140b2dc266cdff2" dependencies = [ "base64 0.22.1", "futures-util", - "http 1.2.0", - "jsonrpsee-core 0.24.7", + "http 1.3.1", + "jsonrpsee-core 0.24.9", "pin-project", "rustls 0.23.25", "rustls-pki-types", - "rustls-platform-verifier", + "rustls-platform-verifier 0.5.1", "soketto 0.8.1", "thiserror 1.0.69", "tokio", - "tokio-rustls 0.26.1", + "tokio-rustls 0.26.2", "tokio-util", "tracing", "url", @@ -5216,22 +5294,22 @@ dependencies = [ [[package]] name = "jsonrpsee-core" -version = "0.24.7" +version = "0.24.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2882f6f8acb9fdaec7cefc4fd607119a9bd709831df7d7672a1d3b644628280" +checksum = "456196007ca3a14db478346f58c7238028d55ee15c1df15115596e411ff27925" dependencies = [ "async-trait", "bytes", "futures-timer", "futures-util", - "http 1.2.0", + "http 1.3.1", "http-body 1.0.1", "http-body-util", - "jsonrpsee-types 0.24.7", + "jsonrpsee-types 0.24.9", "parking_lot 0.12.3", "pin-project", "rand 0.8.5", - "rustc-hash 2.1.0", + "rustc-hash 2.1.1", "serde", "serde_json", "thiserror 1.0.69", @@ -5267,7 +5345,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5e65763c942dfc9358146571911b0cd1c361c2d63e2d2305622d40d36376ca80" dependencies = [ "heck 0.5.0", - "proc-macro-crate 3.2.0", + "proc-macro-crate 3.3.0", "proc-macro2", "quote", "syn 2.0.100", @@ -5275,18 +5353,18 @@ dependencies = [ [[package]] name = "jsonrpsee-server" -version = "0.24.8" +version = "0.24.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "66b7a3df90a1a60c3ed68e7ca63916b53e9afa928e33531e87f61a9c8e9ae87b" +checksum = "55e363146da18e50ad2b51a0a7925fc423137a0b1371af8235b1c231a0647328" dependencies = [ "futures-util", - "http 1.2.0", + "http 1.3.1", "http-body 1.0.1", "http-body-util", - "hyper 1.5.2", + "hyper 1.6.0", "hyper-util", - "jsonrpsee-core 0.24.7", - "jsonrpsee-types 0.24.7", + "jsonrpsee-core 0.24.9", + "jsonrpsee-types 0.24.9", "pin-project", "route-recognizer", "serde", @@ -5320,7 +5398,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d9c465fbe385238e861fdc4d1c85e04ada6c1fd246161d26385c1b311724d2af" dependencies = [ "beef", - "http 1.2.0", + "http 1.3.1", "serde", "serde_json", "thiserror 1.0.69", @@ -5328,11 +5406,11 @@ dependencies = [ [[package]] name = "jsonrpsee-types" -version = "0.24.7" +version = "0.24.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a178c60086f24cc35bb82f57c651d0d25d99c4742b4d335de04e97fa1f08a8a1" +checksum = "08a8e70baf945b6b5752fc8eb38c918a48f1234daf11355e07106d963f860089" dependencies = [ - "http 1.2.0", + "http 1.3.1", "serde", "serde_json", "thiserror 1.0.69", @@ -5344,7 +5422,7 @@ version = "0.23.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1c28759775f5cb2f1ea9667672d3fe2b0e701d1f4b7b67954e60afe7fd058b5e" dependencies = [ - "http 1.2.0", + "http 1.3.1", "jsonrpsee-client-transport 0.23.2", "jsonrpsee-core 0.23.2", "jsonrpsee-types 0.23.2", @@ -5353,14 +5431,14 @@ dependencies = [ [[package]] name = "jsonrpsee-ws-client" -version = "0.24.7" +version = "0.24.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fe322e0896d0955a3ebdd5bf813571c53fea29edd713bc315b76620b327e86d" +checksum = "01b3323d890aa384f12148e8d2a1fd18eb66e9e7e825f9de4fa53bcc19b93eef" dependencies = [ - "http 1.2.0", - "jsonrpsee-client-transport 0.24.7", - "jsonrpsee-core 0.24.7", - "jsonrpsee-types 0.24.7", + "http 1.3.1", + "jsonrpsee-client-transport 0.24.9", + "jsonrpsee-core 0.24.9", + "jsonrpsee-types 0.24.9", "url", ] @@ -5459,7 +5537,7 @@ dependencies = [ "jsonpath-rust", "k8s-openapi", "kube-core", - "pem 3.0.4", + "pem 3.0.5", "pin-project", "rand 0.8.5", "rustls 0.21.12", @@ -5573,9 +5651,9 @@ checksum = "884e2677b40cc8c339eaefcb701c32ef1fd2493d71118dc0ca4b6a736c93bd67" [[package]] name = "libc" -version = "0.2.169" +version = "0.2.171" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5aba8db14291edd000dfcc4d620c7ebfb122c613afb886ca8803fa4e128a20a" +checksum = "c19937216e9d3aa9956d9bb8dfc0b0c8beb6058fc4f7a4dc4d850edf86a237d6" [[package]] name = "libgit2-sys" @@ -6143,9 +6221,9 @@ version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d" dependencies = [ - "bitflags 2.6.0", + "bitflags 2.9.0", "libc", - "redox_syscall 0.5.8", + "redox_syscall 0.5.10", ] [[package]] @@ -6165,12 +6243,12 @@ dependencies = [ [[package]] name = "libsecp256k1" -version = "0.7.1" +version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95b09eff1b35ed3b33b877ced3a691fc7a481919c7e29c53c906226fcf55e2a1" +checksum = "e79019718125edc905a079a70cfa5f3820bc76139fc91d6f9abc27ea2a887139" dependencies = [ "arrayref", - "base64 0.13.1", + "base64 0.22.1", "digest 0.9.0", "hmac-drbg", "libsecp256k1-core", @@ -6213,9 +6291,9 @@ dependencies = [ [[package]] name = "libssh2-sys" -version = "0.3.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dc8a030b787e2119a731f1951d6a773e2280c660f8ec4b0f5e1505a386e71ee" +checksum = "220e4f05ad4a218192533b300327f5150e809b54c4ec83b5a1d91833601811b9" dependencies = [ "cc", "libc", @@ -6227,9 +6305,9 @@ dependencies = [ [[package]] name = "libz-sys" -version = "1.1.20" +version = "1.1.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2d16453e800a8cf6dd2fc3eb4bc99b786a9b90c663b8559a5b1a041bf89e472" +checksum = "8b70e7a7df205e92a1a4cd9aaae7898dac0aa555503cc0a649494d0d60e7651d" dependencies = [ "cc", "libc", @@ -6239,9 +6317,9 @@ dependencies = [ [[package]] name = "link-cplusplus" -version = "1.0.9" +version = "1.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d240c6f7e1ba3a28b0249f774e6a9dd0175054b52dfbb61b16eb8505c3785c9" +checksum = "4a6f6da007f968f9def0d65a05b187e2960183de70c160204ecfccf0ee330212" dependencies = [ "cc", ] @@ -6263,18 +6341,18 @@ dependencies = [ [[package]] name = "linkme" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "566336154b9e58a4f055f6dd4cbab62c7dc0826ce3c0a04e63b2d2ecd784cdae" +checksum = "22d227772b5999ddc0690e733f734f95ca05387e329c4084fe65678c51198ffe" dependencies = [ "linkme-impl", ] [[package]] name = "linkme-impl" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "edbe595006d355eaf9ae11db92707d4338cd2384d16866131cc1afdbdd35d8d9" +checksum = "71a98813fa0073a317ed6a8055dcd4722a49d9b862af828ee68449adb799b6be" dependencies = [ "proc-macro2", "quote", @@ -6298,9 +6376,9 @@ checksum = "f051f77a7c8e6957c0696eac88f26b0117e54f52d3fc682ab19397a8812846a4" [[package]] name = "linux-raw-sys" -version = "0.4.14" +version = "0.4.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" +checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab" [[package]] name = "linux-raw-sys" @@ -6322,9 +6400,9 @@ dependencies = [ [[package]] name = "litemap" -version = "0.7.4" +version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ee93343901ab17bd981295f2cf0026d4ad018c7c31ba84549a4ddbb47a45104" +checksum = "23fb14cb19457329c82206317a5663005a4d404783dc74f4252769b0d5f42856" [[package]] name = "litep2p" @@ -6361,7 +6439,7 @@ dependencies = [ "smallvec", "snow", "socket2 0.5.8", - "thiserror 2.0.11", + "thiserror 2.0.12", "tokio", "tokio-stream", "tokio-tungstenite 0.26.2", @@ -6530,7 +6608,7 @@ version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b2cffa4ad52c6f791f4f8b15f0c05f9824b2ced1160e88cc393d64fff9a8ac64" dependencies = [ - "rustix 0.38.42", + "rustix 0.38.44", ] [[package]] @@ -6605,9 +6683,9 @@ checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" [[package]] name = "miniz_oxide" -version = "0.8.2" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ffbe83022cedc1d264172192511ae958937694cd57ce297164951b8b3568394" +checksum = "8e3e04debbb59698c15bacbb6d93584a8c0ca9cc3213cb423d31f760d8843ce5" dependencies = [ "adler2", ] @@ -6674,7 +6752,7 @@ dependencies = [ "downcast", "fragile", "mockall_derive 0.13.1", - "predicates 3.1.2", + "predicates 3.1.3", "predicates-tree", ] @@ -6704,21 +6782,21 @@ dependencies = [ [[package]] name = "mockito" -version = "1.6.1" +version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "652cd6d169a36eaf9d1e6bce1a221130439a966d7f27858af66a33a66e9c4ee2" +checksum = "7760e0e418d9b7e5777c0374009ca4c93861b9066f18cb334a20ce50ab63aa48" dependencies = [ "assert-json-diff", "bytes", - "colored", + "colored 3.0.0", "futures-util", - "http 1.2.0", + "http 1.3.1", "http-body 1.0.1", "http-body-util", - "hyper 1.5.2", + "hyper 1.6.0", "hyper-util", "log", - "rand 0.8.5", + "rand 0.9.0", "regex", "serde_json", "serde_urlencoded", @@ -6891,9 +6969,9 @@ checksum = "6a51313c5820b0b02bd422f4b44776fbf47961755c74ce64afc73bfad10226c3" [[package]] name = "native-tls" -version = "0.2.12" +version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8614eb2c83d59d1c8cc974dd3f920198647674a0a035e1af1fa58707e317466" +checksum = "87de3442987e9dbec73158d5c715e7ad9072fda936bb03d19d7fa10e00520f0e" dependencies = [ "libc", "log", @@ -6954,7 +7032,7 @@ dependencies = [ "log", "netlink-packet-core", "netlink-sys", - "thiserror 2.0.11", + "thiserror 2.0.12", ] [[package]] @@ -6999,7 +7077,7 @@ version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "71e2746dc3a24dd78b3cfcb7be93368c6de9963d30f43a6a73998a9cf4b17b46" dependencies = [ - "bitflags 2.6.0", + "bitflags 2.9.0", "cfg-if", "cfg_aliases 0.2.1", "libc", @@ -7186,9 +7264,9 @@ dependencies = [ [[package]] name = "object" -version = "0.36.5" +version = "0.36.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aedf0a2d09c573ed1d8d85b30c119153926a2b36dce0ab28322c09a117a4683e" +checksum = "62948e14d923ea95ea2c7c86c71013138b66525b86bdc08d2dcc262bdb497b87" dependencies = [ "memchr", ] @@ -7213,9 +7291,9 @@ dependencies = [ [[package]] name = "once_cell" -version = "1.20.2" +version = "1.21.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775" +checksum = "d75b0bedcc4fe52caa0e03d9f1151a323e4aa5e2d78ba3580400cd3c9e2bc4bc" [[package]] name = "opaque-debug" @@ -7231,9 +7309,9 @@ checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381" [[package]] name = "open" -version = "5.3.1" +version = "5.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ecd52f0b8d15c40ce4820aa251ed5de032e5d91fab27f7db2f40d42a8bdf69c" +checksum = "e2483562e62ea94312f3576a7aca397306df7990b8d89033e18766744377ef95" dependencies = [ "is-wsl", "libc", @@ -7242,11 +7320,11 @@ dependencies = [ [[package]] name = "openssl" -version = "0.10.68" +version = "0.10.71" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6174bc48f102d208783c2c84bf931bb75927a617866870de8a4ea85597f871f5" +checksum = "5e14130c6a98cd258fdcb0fb6d744152343ff729cbfcb28c656a9d12b999fbcd" dependencies = [ - "bitflags 2.6.0", + "bitflags 2.9.0", "cfg-if", "foreign-types", "libc", @@ -7268,24 +7346,24 @@ dependencies = [ [[package]] name = "openssl-probe" -version = "0.1.5" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" +checksum = "d05e27ee213611ffe7d6348b942e8f942b37114c00cc03cec254295a4a17852e" [[package]] name = "openssl-src" -version = "300.4.1+3.4.0" +version = "300.4.2+3.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "faa4eac4138c62414b5622d1b31c5c304f34b406b013c079c2bbc652fdd6678c" +checksum = "168ce4e058f975fe43e89d9ccf78ca668601887ae736090aacc23ae353c298e2" dependencies = [ "cc", ] [[package]] name = "openssl-sys" -version = "0.9.104" +version = "0.9.106" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "45abf306cbf99debc8195b66b7346498d7b10c210de50418b5ccd7ceba08c741" +checksum = "8bb61ea9811cc39e3c2069f40b8b8e2e70d8569b361f879786cc7ed48b777cdd" dependencies = [ "cc", "libc", @@ -7327,7 +7405,7 @@ dependencies = [ "indexmap 2.8.0", "itertools 0.11.0", "petgraph 0.6.5", - "proc-macro-crate 3.2.0", + "proc-macro-crate 3.3.0", "proc-macro2", "quote", "syn 1.0.109", @@ -7344,9 +7422,9 @@ dependencies = [ [[package]] name = "os_info" -version = "3.9.0" +version = "3.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5ca711d8b83edbb00b44d504503cd247c9c0bd8b0fa2694f2a1a3d8165379ce" +checksum = "2a604e53c24761286860eba4e2c8b23a0161526476b1de520139d69cdb85a6b5" dependencies = [ "log", "windows-sys 0.52.0", @@ -7428,29 +7506,31 @@ dependencies = [ [[package]] name = "parity-scale-codec" -version = "3.6.12" +version = "3.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "306800abfa29c7f16596b5970a588435e3d5b3149683d00c12b699cc19f895ee" +checksum = "c9fde3d0718baf5bc92f577d652001da0f8d54cd03a7974e118d04fc888dc23d" dependencies = [ "arrayvec 0.7.6", "bitvec", "byte-slice-cast", "bytes", + "const_format", "impl-trait-for-tuples", "parity-scale-codec-derive", + "rustversion", "serde", ] [[package]] name = "parity-scale-codec-derive" -version = "3.6.12" +version = "3.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d830939c76d294956402033aee57a6da7b438f2294eb94864c37b0569053a42c" +checksum = "581c837bb6b9541ce7faa9377c20616e4fb7650f6b0f68bc93c827ee504fb7b3" dependencies = [ - "proc-macro-crate 3.2.0", + "proc-macro-crate 3.3.0", "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.100", ] [[package]] @@ -7508,7 +7588,7 @@ checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" dependencies = [ "cfg-if", "libc", - "redox_syscall 0.5.8", + "redox_syscall 0.5.10", "smallvec", "windows-targets 0.52.6", ] @@ -7570,9 +7650,9 @@ dependencies = [ [[package]] name = "pem" -version = "3.0.4" +version = "3.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e459365e590736a54c3fa561947c84837534b8e9af6fc5bf781307e82658fae" +checksum = "38af38e8470ac9dee3ce1bae1af9c1671fffc44ddfd8bd1d0a3445bf349a8ef3" dependencies = [ "base64 0.22.1", "serde", @@ -7586,20 +7666,20 @@ checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" [[package]] name = "pest" -version = "2.7.15" +version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b7cafe60d6cf8e62e1b9b2ea516a089c008945bb5a275416789e7db0bc199dc" +checksum = "198db74531d58c70a361c42201efde7e2591e976d518caf7662a47dc5720e7b6" dependencies = [ "memchr", - "thiserror 2.0.11", + "thiserror 2.0.12", "ucd-trie", ] [[package]] name = "pest_derive" -version = "2.7.15" +version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "816518421cfc6887a0d62bf441b6ffb4536fcc926395a69e1a85852d4363f57e" +checksum = "d725d9cfd79e87dccc9341a2ef39d1b6f6353d68c4b33c177febbe1a402c97c5" dependencies = [ "pest", "pest_generator", @@ -7607,9 +7687,9 @@ dependencies = [ [[package]] name = "pest_generator" -version = "2.7.15" +version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d1396fd3a870fc7838768d171b4616d5c91f6cc25e377b673d714567d99377b" +checksum = "db7d01726be8ab66ab32f9df467ae8b1148906685bbe75c82d1e65d7f5b3f841" dependencies = [ "pest", "pest_meta", @@ -7620,9 +7700,9 @@ dependencies = [ [[package]] name = "pest_meta" -version = "2.7.15" +version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1e58089ea25d717bfd31fb534e4f3afcc2cc569c70de3e239778991ea3b7dea" +checksum = "7f9f832470494906d1fca5329f8ab5791cc60beb230c74815dff541cbd2b5ca0" dependencies = [ "once_cell", "pest", @@ -7651,18 +7731,18 @@ dependencies = [ [[package]] name = "pin-project" -version = "1.1.7" +version = "1.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be57f64e946e500c8ee36ef6331845d40a93055567ec57e8fae13efd33759b95" +checksum = "677f1add503faace112b9f1373e43e9e054bfdd22ff1a63c1bc485eaec6a6a8a" dependencies = [ "pin-project-internal", ] [[package]] name = "pin-project-internal" -version = "1.1.7" +version = "1.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c0f5fad0874fc7abcd4d750e76917eaebbecaa2c20bde22e1dbeeba8beb758c" +checksum = "6e918e4ff8c4549eb882f14b3a4bc8c8bc93de829416eacf579f1207a8fbf861" dependencies = [ "proc-macro2", "quote", @@ -7671,9 +7751,9 @@ dependencies = [ [[package]] name = "pin-project-lite" -version = "0.2.15" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "915a1e146535de9163f3987b8944ed8cf49a18bb0056bcebcdcece385cece4ff" +checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" [[package]] name = "pin-utils" @@ -7704,9 +7784,9 @@ dependencies = [ [[package]] name = "pkg-config" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "953ec861398dccce10c670dfeaf3ec4911ca479e9c02154b3a215178c5f566f2" +checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c" [[package]] name = "polkadot-core-primitives" @@ -7749,7 +7829,7 @@ dependencies = [ "async-channel 1.9.0", "async-trait", "bitvec", - "derive_more 0.99.18", + "derive_more 0.99.19", "fatality", "futures", "hex", @@ -7801,7 +7881,7 @@ checksum = "7193b889dc5b82a4aa0022eb26ef3528ac7a0d08dd3749b037b8ab79c1b2f3a0" dependencies = [ "async-trait", "bitvec", - "derive_more 0.99.18", + "derive_more 0.99.19", "fatality", "futures", "orchestra", @@ -7853,7 +7933,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1d10a3da595ecd419e526a9cfcc013cd00bcd9a2c962991d6efb312df8307eaf" dependencies = [ "bounded-collections", - "derive_more 0.99.18", + "derive_more 0.99.19", "parity-scale-codec", "polkadot-core-primitives", "scale-info", @@ -8019,7 +8099,7 @@ dependencies = [ "concurrent-queue", "hermit-abi 0.4.0", "pin-project-lite", - "rustix 0.38.42", + "rustix 0.38.44", "tracing", "windows-sys 0.59.0", ] @@ -8058,6 +8138,7 @@ dependencies = [ "cliclack", "console", "contract-extrinsics", + "deranged", "dirs", "duct", "env_logger 0.11.7", @@ -8071,7 +8152,7 @@ dependencies = [ "pop-contracts", "pop-parachains", "pop-telemetry", - "predicates 3.1.2", + "predicates 3.1.3", "proc-macro2", "reqwest", "rust_writer", @@ -8083,8 +8164,8 @@ dependencies = [ "sp-weights", "strum 0.26.3", "strum_macros 0.26.4", - "subxt 0.38.0", - "subxt-signer 0.38.0", + "subxt 0.38.1", + "subxt-signer 0.38.1", "syn 2.0.100", "tempfile", "tokio", @@ -8102,6 +8183,7 @@ dependencies = [ "cargo_toml 0.20.5", "contract-build", "contract-extrinsics", + "deranged", "duct", "flate2", "fs_rollback", @@ -8119,8 +8201,8 @@ dependencies = [ "serde_json", "strum 0.26.3", "strum_macros 0.26.4", - "subxt 0.38.0", - "subxt-signer 0.38.0", + "subxt 0.38.1", + "subxt-signer 0.38.1", "syn 2.0.100", "tar", "tempfile", @@ -8139,6 +8221,7 @@ dependencies = [ "contract-build", "contract-extrinsics", "contract-transcode", + "deranged", "duct", "heck 0.5.0", "ink_env", @@ -8149,8 +8232,8 @@ dependencies = [ "sp-weights", "strum 0.26.3", "strum_macros 0.26.4", - "subxt 0.38.0", - "subxt-signer 0.38.0", + "subxt 0.38.1", + "subxt-signer 0.38.1", "tempfile", "thiserror 1.0.69", "tokio", @@ -8166,6 +8249,7 @@ dependencies = [ "askama", "clap", "cumulus-primitives-proof-size-hostfunction 0.10.0", + "deranged", "duct", "frame-benchmarking-cli", "glob", @@ -8183,8 +8267,8 @@ dependencies = [ "srtool-lib", "strum 0.26.3", "strum_macros 0.26.4", - "subxt 0.38.0", - "subxt-signer 0.38.0", + "subxt 0.38.1", + "subxt-signer 0.38.1", "symlink", "syn 2.0.100", "tar", @@ -8202,6 +8286,7 @@ dependencies = [ name = "pop-telemetry" version = "0.6.0" dependencies = [ + "deranged", "dirs", "env_logger 0.11.7", "log", @@ -8216,9 +8301,9 @@ dependencies = [ [[package]] name = "portable-atomic" -version = "1.10.0" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "280dc24453071f1b63954171985a0b0d30058d287960968b9b2aca264c8d4ee6" +checksum = "350e9b48cbc6b0e028b0473b114454c6316e57336ee184ceab6e53f72c178b3e" [[package]] name = "portable-atomic-util" @@ -8237,11 +8322,11 @@ checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" [[package]] name = "ppv-lite86" -version = "0.2.20" +version = "0.2.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04" +checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" dependencies = [ - "zerocopy 0.7.35", + "zerocopy 0.8.24", ] [[package]] @@ -8251,7 +8336,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "59230a63c37f3e18569bdb90e4a89cbf5bf8b06fea0b84e65ea10cc4df47addd" dependencies = [ "difflib", - "float-cmp", + "float-cmp 0.9.0", "itertools 0.10.5", "normalize-line-endings", "predicates-core", @@ -8260,13 +8345,13 @@ dependencies = [ [[package]] name = "predicates" -version = "3.1.2" +version = "3.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e9086cc7640c29a356d1a29fd134380bee9d8f79a17410aa76e7ad295f42c97" +checksum = "a5d19ee57562043d37e82899fade9a22ebab7be9cef5026b07fda9cdd4293573" dependencies = [ "anstyle", "difflib", - "float-cmp", + "float-cmp 0.10.0", "normalize-line-endings", "predicates-core", "regex", @@ -8274,15 +8359,15 @@ dependencies = [ [[package]] name = "predicates-core" -version = "1.0.8" +version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae8177bee8e75d6846599c6b9ff679ed51e882816914eec639944d7c9aa11931" +checksum = "727e462b119fe9c93fd0eb1429a5f7647394014cf3c04ab2c0350eeb09095ffa" [[package]] name = "predicates-tree" -version = "1.0.11" +version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41b740d195ed3166cd147c8047ec98db0e22ec019eb8eeb76d343b795304fb13" +checksum = "72dd2d6d381dfb73a193c7fca536518d7caee39fc8503f74e7dc0be0531b425c" dependencies = [ "predicates-core", "termtree", @@ -8318,7 +8403,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d15600a7d856470b7d278b3fe0e311fe28c2526348549f8ef2ff7db3299c87f5" dependencies = [ "fixed-hash", - "impl-codec 0.7.0", + "impl-codec 0.7.1", "impl-num-traits", "impl-serde 0.5.0", "scale-info", @@ -8333,7 +8418,7 @@ checksum = "a172e6cc603231f2cf004232eabcecccc0da53ba576ab286ef7baa0cfc7927ad" dependencies = [ "coarsetime", "crossbeam-queue", - "derive_more 0.99.18", + "derive_more 0.99.19", "futures", "futures-timer", "nanorand", @@ -8353,9 +8438,9 @@ dependencies = [ [[package]] name = "proc-macro-crate" -version = "3.2.0" +version = "3.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ecf48c7ca261d60b74ab1a7b20da18bede46776b2e55535cb958eb595c5fa7b" +checksum = "edce586971a4dfaa28950c6f18ed55e0406c1ab88bbce2c6f6293a7aaba73d35" dependencies = [ "toml_edit", ] @@ -8419,9 +8504,9 @@ dependencies = [ [[package]] name = "proc-macro-warning" -version = "1.0.2" +version = "1.84.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "834da187cfe638ae8abb0203f0b33e5ccdb02a28e7199f2f47b3e2754f50edca" +checksum = "75eea531cfcd120e0851a3f8aed42c4841f78c889eefafd96339c72677ae42c3" dependencies = [ "proc-macro2", "quote", @@ -8501,7 +8586,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "be769465445e8c1474e9c5dac2018218498557af32d9ed057325ec9a41ae81bf" dependencies = [ "heck 0.5.0", - "itertools 0.13.0", + "itertools 0.14.0", "log", "multimap", "once_cell", @@ -8521,7 +8606,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "81bddcdb20abf9501610992b6759a4c888aef7d1a7247ef75e2404275ac24af1" dependencies = [ "anyhow", - "itertools 0.11.0", + "itertools 0.12.1", "proc-macro2", "quote", "syn 2.0.100", @@ -8534,7 +8619,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8a56d757972c98b346a9b766e3f02746cde6dd1cd1d1d563472929fdd74bec4d" dependencies = [ "anyhow", - "itertools 0.13.0", + "itertools 0.14.0", "proc-macro2", "quote", "syn 2.0.100", @@ -8551,9 +8636,9 @@ dependencies = [ [[package]] name = "psm" -version = "0.1.24" +version = "0.1.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "200b9ff220857e53e184257720a14553b2f4aa02577d2ed9842d45d4b9654810" +checksum = "f58e5423e24c18cc840e1c98370b3993c6649cd1678b4d24318bcf0a083cbe88" dependencies = [ "cc", ] @@ -8672,6 +8757,12 @@ dependencies = [ "proc-macro2", ] +[[package]] +name = "r-efi" +version = "5.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74765f6d916ee2faa39bc8e68e4f3ed8949b48cccdac59983d287a7cb71ce9c5" + [[package]] name = "radium" version = "0.7.0" @@ -8741,7 +8832,7 @@ version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38" dependencies = [ - "getrandom 0.3.1", + "getrandom 0.3.2", ] [[package]] @@ -8769,7 +8860,7 @@ version = "11.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c6df7ab838ed27997ba19a4664507e6f82b41fe6e20be42929332156e5e85146" dependencies = [ - "bitflags 2.6.0", + "bitflags 2.9.0", ] [[package]] @@ -8837,11 +8928,11 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.5.8" +version = "0.5.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03a862b389f93e68874fbf580b9de08dd02facb9a788ebadaf4a3fd33cf58834" +checksum = "0b8c0c260b63a8219631167be35e6a988e9554dbd323f8bd08439c8ed1302bd1" dependencies = [ - "bitflags 2.6.0", + "bitflags 2.9.0", ] [[package]] @@ -8857,18 +8948,18 @@ dependencies = [ [[package]] name = "ref-cast" -version = "1.0.23" +version = "1.0.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ccf0a6f84d5f1d581da8b41b47ec8600871962f2a528115b542b362d4b744931" +checksum = "4a0ae411dbe946a674d89546582cea4ba2bb8defac896622d6496f14c23ba5cf" dependencies = [ "ref-cast-impl", ] [[package]] name = "ref-cast-impl" -version = "1.0.23" +version = "1.0.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bcc303e793d3734489387d205e9b186fac9c6cfacedd98cbb2e8a5943595f3e6" +checksum = "1165225c21bff1f3bbce98f5a1f889949bc902d3575308cc7b0de30b4f6d27c7" dependencies = [ "proc-macro2", "quote", @@ -8942,21 +9033,21 @@ dependencies = [ [[package]] name = "reqwest" -version = "0.12.9" +version = "0.12.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a77c62af46e79de0a562e1a9849205ffcb7fc1238876e9bd743357570e04046f" +checksum = "d19c46a6fdd48bc4dab94b6103fccc55d34c67cc0ad04653aad4ea2a07cd7bbb" dependencies = [ "base64 0.22.1", "bytes", "encoding_rs", "futures-core", "futures-util", - "h2 0.4.7", - "http 1.2.0", + "h2 0.4.8", + "http 1.3.1", "http-body 1.0.1", "http-body-util", - "hyper 1.5.2", - "hyper-rustls 0.27.4", + "hyper 1.6.0", + "hyper-rustls 0.27.5", "hyper-tls", "hyper-util", "ipnet", @@ -8975,6 +9066,7 @@ dependencies = [ "system-configuration", "tokio", "tokio-native-tls", + "tower 0.5.2", "tower-service", "url", "wasm-bindgen", @@ -9019,15 +9111,14 @@ dependencies = [ [[package]] name = "ring" -version = "0.17.8" +version = "0.17.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c17fa4cb658e3583423e915b9f3acc01cceaee1860e33d59ebae66adc3a2dc0d" +checksum = "a4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7" dependencies = [ "cc", "cfg-if", "getrandom 0.2.15", "libc", - "spin 0.9.8", "untrusted 0.9.0", "windows-sys 0.52.0", ] @@ -9133,9 +9224,9 @@ dependencies = [ [[package]] name = "rust_decimal" -version = "1.36.0" +version = "1.37.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b082d80e3e3cc52b2ed634388d436fe1f4de6af5786cc2de9ba9737527bdf555" +checksum = "faa7de2ba56ac291bd90c6b9bece784a52ae1411f9506544b3eae36dd2356d50" dependencies = [ "arrayvec 0.7.6", "borsh", @@ -9159,7 +9250,7 @@ dependencies = [ "rust_writer_proc", "rustilities 2.2.0", "syn 2.0.100", - "thiserror 2.0.11", + "thiserror 2.0.12", ] [[package]] @@ -9188,9 +9279,9 @@ checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" [[package]] name = "rustc-hash" -version = "2.1.0" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7fb8039b3032c191086b10f11f319a6e99e1e82889c5cc6046f515c9db1d497" +checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d" [[package]] name = "rustc-hex" @@ -9222,7 +9313,7 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1bfbd7c1a4f912953f84295e1a6119d3800d87a3555454241fbdaa1f48cfe344" dependencies = [ - "thiserror 2.0.11", + "thiserror 2.0.12", ] [[package]] @@ -9234,7 +9325,7 @@ dependencies = [ "cargo_toml 0.21.0", "proc-macro2", "syn 2.0.100", - "thiserror 2.0.11", + "thiserror 2.0.12", "toml_edit", ] @@ -9254,14 +9345,14 @@ dependencies = [ [[package]] name = "rustix" -version = "0.38.42" +version = "0.38.44" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f93dc38ecbab2eb790ff964bb77fa94faf256fd3e73285fd7ba0903b76bedb85" +checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154" dependencies = [ - "bitflags 2.6.0", + "bitflags 2.9.0", "errno", "libc", - "linux-raw-sys 0.4.14", + "linux-raw-sys 0.4.15", "windows-sys 0.59.0", ] @@ -9271,7 +9362,7 @@ version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e56a18552996ac8d29ecc3b190b4fdbb2d91ca4ec396de7bbffaf43f3d637e96" dependencies = [ - "bitflags 2.6.0", + "bitflags 2.9.0", "errno", "libc", "linux-raw-sys 0.9.3", @@ -9296,7 +9387,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f56a14d1f48b391359b22f731fd4bd7e43c97f3c50eee276f3aa09c94784d3e" dependencies = [ "log", - "ring 0.17.8", + "ring 0.17.14", "rustls-webpki 0.101.7", "sct", ] @@ -9308,7 +9399,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bf4ef73721ac7bcd79b2b315da7779d8fc09718c6b3d2d1b2d94850eb8c18432" dependencies = [ "log", - "ring 0.17.8", + "ring 0.17.14", "rustls-pki-types", "rustls-webpki 0.102.8", "subtle 2.6.1", @@ -9323,7 +9414,7 @@ checksum = "822ee9188ac4ec04a2f0531e55d035fb2de73f18b41a63c70c2712503b6fb13c" dependencies = [ "log", "once_cell", - "ring 0.17.8", + "ring 0.17.14", "rustls-pki-types", "rustls-webpki 0.103.1", "subtle 2.6.1", @@ -9399,7 +9490,7 @@ checksum = "afbb878bdfdf63a336a5e63561b1835e7a8c91524f51621db870169eac84b490" dependencies = [ "core-foundation 0.9.4", "core-foundation-sys", - "jni", + "jni 0.19.0", "log", "once_cell", "rustls 0.23.25", @@ -9412,6 +9503,27 @@ dependencies = [ "winapi", ] +[[package]] +name = "rustls-platform-verifier" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a5467026f437b4cb2a533865eaa73eb840019a0916f4b9ec563c6e617e086c9" +dependencies = [ + "core-foundation 0.10.0", + "core-foundation-sys", + "jni 0.21.1", + "log", + "once_cell", + "rustls 0.23.25", + "rustls-native-certs 0.8.1", + "rustls-platform-verifier-android", + "rustls-webpki 0.103.1", + "security-framework 3.2.0", + "security-framework-sys", + "webpki-root-certs", + "windows-sys 0.59.0", +] + [[package]] name = "rustls-platform-verifier-android" version = "0.1.1" @@ -9424,7 +9536,7 @@ version = "0.101.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b6275d1ee7a1cd780b64aca7726599a1dbc893b1e64144529e55c3c2f745765" dependencies = [ - "ring 0.17.8", + "ring 0.17.14", "untrusted 0.9.0", ] @@ -9434,7 +9546,7 @@ version = "0.102.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "64ca1bc8749bd4cf37b5ce386cc146580777b4e8572c7b97baf22c83f444bee9" dependencies = [ - "ring 0.17.8", + "ring 0.17.14", "rustls-pki-types", "untrusted 0.9.0", ] @@ -9445,16 +9557,16 @@ version = "0.103.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fef8b8769aaccf73098557a87cd1816b4f9c7c16811c9c77142aa695c16f2c03" dependencies = [ - "ring 0.17.8", + "ring 0.17.14", "rustls-pki-types", "untrusted 0.9.0", ] [[package]] name = "rustversion" -version = "1.0.18" +version = "1.0.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e819f2bc632f285be6d7cd36e25940d45b2391dd6d9b939e79de557f7014248" +checksum = "eded382c5f5f786b989652c49544c4877d9f015cc22e145a5ea8ea66c2921cd2" [[package]] name = "ruzstd" @@ -9463,7 +9575,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "58c4eb8a81997cf040a091d1f7e1938aeab6749d3a0dfa73af43cdc32393483d" dependencies = [ "byteorder", - "derive_more 0.99.18", + "derive_more 0.99.19", "twox-hash", ] @@ -9474,7 +9586,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5174a470eeb535a721ae9fdd6e291c2411a906b96592182d05217591d5c5cf7b" dependencies = [ "byteorder", - "derive_more 0.99.18", + "derive_more 0.99.19", ] [[package]] @@ -9490,15 +9602,15 @@ dependencies = [ [[package]] name = "ryu" -version = "1.0.18" +version = "1.0.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" +checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" [[package]] name = "safe_arch" -version = "0.7.2" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3460605018fdc9612bce72735cba0d27efbcd9904780d44c7e3a9948f96148a" +checksum = "96b02de82ddbe1b636e6170c21be622223aea188ef2e139be0a5b219ec215323" dependencies = [ "bytemuck", ] @@ -9614,7 +9726,7 @@ version = "12.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b18cef11d2c69703e0d7c3528202ef4ed1cd2b47a6f063e9e17cad8255b1fa94" dependencies = [ - "proc-macro-crate 3.2.0", + "proc-macro-crate 3.3.0", "proc-macro2", "quote", "syn 2.0.100", @@ -10050,7 +10162,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "58ac6a01eb88a5ea7e2ed7e6348f332548262fd00247c263f5b081dff3d1432b" dependencies = [ "futures", - "jsonrpsee 0.24.7", + "jsonrpsee 0.24.9", "log", "parity-scale-codec", "parking_lot 0.12.3", @@ -10082,7 +10194,7 @@ version = "0.47.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a5a45ebf7365e369bea319018dd2706929d4d8d8807829a1989dfaf3f1c7125d" dependencies = [ - "jsonrpsee 0.24.7", + "jsonrpsee 0.24.9", "parity-scale-codec", "sc-chain-spec", "sc-mixnet", @@ -10107,11 +10219,11 @@ dependencies = [ "forwarded-header-value", "futures", "governor", - "http 1.2.0", + "http 1.3.1", "http-body-util", - "hyper 1.5.2", + "hyper 1.6.0", "ip_network", - "jsonrpsee 0.24.7", + "jsonrpsee 0.24.9", "log", "sc-rpc-api", "serde", @@ -10133,7 +10245,7 @@ dependencies = [ "futures-util", "hex", "itertools 0.11.0", - "jsonrpsee 0.24.7", + "jsonrpsee 0.24.9", "log", "parity-scale-codec", "parking_lot 0.12.3", @@ -10166,7 +10278,7 @@ dependencies = [ "exit-future", "futures", "futures-timer", - "jsonrpsee 0.24.7", + "jsonrpsee 0.24.9", "log", "parity-scale-codec", "parking_lot 0.12.3", @@ -10238,7 +10350,7 @@ version = "41.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0e636383d99aa72ab948ea0939df12273a5b0cfe977e71c09ab6cc0379c051c2" dependencies = [ - "derive_more 0.99.18", + "derive_more 0.99.19", "futures", "libc", "log", @@ -10310,7 +10422,7 @@ version = "11.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "151cdf86d79abf22cf2a240a7ca95041c908dbd96c2ae9a818073042aa210964" dependencies = [ - "proc-macro-crate 3.2.0", + "proc-macro-crate 3.3.0", "proc-macro2", "quote", "syn 2.0.100", @@ -10408,7 +10520,7 @@ version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "afc79ba56a1c742f5aeeed1f1801f3edf51f7e818f0a54582cac6f131364ea7b" dependencies = [ - "derive_more 0.99.18", + "derive_more 0.99.19", "parity-scale-codec", "scale-bits 0.5.0", "scale-decode-derive 0.11.1", @@ -10422,7 +10534,7 @@ version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e98f3262c250d90e700bb802eb704e1f841e03331c2eb815e46516c4edbf5b27" dependencies = [ - "derive_more 0.99.18", + "derive_more 0.99.19", "parity-scale-codec", "primitive-types 0.12.2", "scale-bits 0.6.0", @@ -10488,7 +10600,7 @@ version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "628800925a33794fb5387781b883b5e14d130fece9af5a63613867b8de07c5c7" dependencies = [ - "derive_more 0.99.18", + "derive_more 0.99.19", "parity-scale-codec", "scale-encode-derive 0.6.0", "scale-type-resolver 0.1.1", @@ -10501,7 +10613,7 @@ version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "528464e6ae6c8f98e2b79633bf79ef939552e795e316579dab09c61670d56602" dependencies = [ - "derive_more 0.99.18", + "derive_more 0.99.19", "parity-scale-codec", "primitive-types 0.12.2", "scale-bits 0.6.0", @@ -10545,7 +10657,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bef2618f123c88da9cd8853b69d766068f1eddc7692146d7dfe9b89e25ce2efd" dependencies = [ "darling 0.20.10", - "proc-macro-crate 3.2.0", + "proc-macro-crate 3.3.0", "proc-macro2", "quote", "syn 2.0.100", @@ -10558,7 +10670,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "102fbc6236de6c53906c0b262f12c7aa69c2bdc604862c12728f5f4d370bc137" dependencies = [ "darling 0.20.10", - "proc-macro-crate 3.2.0", + "proc-macro-crate 3.3.0", "proc-macro2", "quote", "syn 2.0.100", @@ -10585,7 +10697,7 @@ version = "2.11.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c6630024bf739e2179b91fb424b28898baf819414262c5d376677dbff1fe7ebf" dependencies = [ - "proc-macro-crate 3.2.0", + "proc-macro-crate 3.3.0", "proc-macro2", "quote", "syn 2.0.100", @@ -10644,7 +10756,7 @@ checksum = "8cd6ab090d823e75cfdb258aad5fe92e13f2af7d04b43a55d607d25fcc38c811" dependencies = [ "base58", "blake2 0.10.6", - "derive_more 0.99.18", + "derive_more 0.99.19", "either", "frame-metadata 15.1.0", "parity-scale-codec", @@ -10688,9 +10800,9 @@ dependencies = [ [[package]] name = "schemars" -version = "0.8.21" +version = "0.8.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09c024468a378b7e36765cd36702b7a90cc3cba11654f6685c8f233408e89e92" +checksum = "3fbf2ae1b8bc8e02df939598064d22402220cd5bbcca1c76f7d6a310974d5615" dependencies = [ "dyn-clone", "schemars_derive", @@ -10700,9 +10812,9 @@ dependencies = [ [[package]] name = "schemars_derive" -version = "0.8.21" +version = "0.8.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1eee588578aff73f856ab961cd2f79e36bc45d7ded33a7562adba4667aecc0e" +checksum = "32e265784ad618884abaea0600a9adf15393368d840e0222d101a072f3f7534d" dependencies = [ "proc-macro2", "quote", @@ -10712,9 +10824,9 @@ dependencies = [ [[package]] name = "schnellru" -version = "0.2.3" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c9a8ef13a93c54d20580de1e5c413e624e53121d42fc7e2c11d10ef7f8b02367" +checksum = "356285bbf17bea63d9e52e96bd18f039672ac92b55b8cb997d6162a2a37d1649" dependencies = [ "ahash 0.8.11", "cfg-if", @@ -10748,9 +10860,9 @@ checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" [[package]] name = "scratch" -version = "1.0.7" +version = "1.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3cf7c11c38cb994f3d40e8a8cde3bbd1f72a435e4c49e85d6553d8312306152" +checksum = "9f6280af86e5f559536da57a45ebc84948833b3bee313a7dd25232e09c878a52" [[package]] name = "scrypt" @@ -10770,7 +10882,7 @@ version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "da046153aa2352493d6cb7da4b6e5c0c057d8a1d0a9aa8560baffdd945acd414" dependencies = [ - "ring 0.17.8", + "ring 0.17.14", "untrusted 0.9.0", ] @@ -10876,7 +10988,7 @@ version = "2.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02" dependencies = [ - "bitflags 2.6.0", + "bitflags 2.9.0", "core-foundation 0.9.4", "core-foundation-sys", "libc", @@ -10890,7 +11002,7 @@ version = "3.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "271720403f46ca04f7ba6f55d438f8bd878d6b8ca0a1046e8228c4145bcbb316" dependencies = [ - "bitflags 2.6.0", + "bitflags 2.9.0", "core-foundation 0.10.0", "core-foundation-sys", "libc", @@ -10909,9 +11021,9 @@ dependencies = [ [[package]] name = "semver" -version = "1.0.24" +version = "1.0.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3cb6eb87a131f756572d7fb904f6e7b68633f09cca868c5df1c4b8d1a694bbba" +checksum = "56e6fa9c48d24d85fb3de5ad847117517440f6beceb7798af16b4a87d616b8d0" dependencies = [ "serde", ] @@ -10924,9 +11036,9 @@ checksum = "cd0b0ec5f1c1ca621c432a25813d8d60c88abe6d3e08a3eb9cf37d97a0fe3d73" [[package]] name = "serde" -version = "1.0.216" +version = "1.0.219" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b9781016e935a97e8beecf0c933758c97a5520d32930e460142b4cd80c6338e" +checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6" dependencies = [ "serde_derive", ] @@ -10943,18 +11055,18 @@ dependencies = [ [[package]] name = "serde_bytes" -version = "0.11.15" +version = "0.11.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "387cc504cb06bb40a96c8e04e951fe01854cf6bc921053c954e4a606d9675c6a" +checksum = "8437fd221bde2d4ca316d61b90e337e9e702b3820b87d63caa9ba6c02bd06d96" dependencies = [ "serde", ] [[package]] name = "serde_derive" -version = "1.0.216" +version = "1.0.219" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46f859dbbf73865c6627ed570e78961cd3ac92407a2d117204c49232485da55e" +checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00" dependencies = [ "proc-macro2", "quote", @@ -10987,9 +11099,9 @@ dependencies = [ [[package]] name = "serde_path_to_error" -version = "0.1.16" +version = "0.1.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af99884400da37c88f5e9146b7f1fd0fbcae8f6eec4e9da38b67d05486f814a6" +checksum = "59fab13f937fa393d08645bf3a84bdfe86e296747b506ada67bb15f10f218b2a" dependencies = [ "itoa", "serde", @@ -10997,9 +11109,9 @@ dependencies = [ [[package]] name = "serde_repr" -version = "0.1.19" +version = "0.1.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c64451ba24fc7a6a2d60fc75dd9c83c90903b19028d4eff35e88fc1e86564e9" +checksum = "175ee3e80ae9982737ca543e96133087cbd9a485eecc3bc4de9c1a37b47ea59c" dependencies = [ "proc-macro2", "quote", @@ -11029,9 +11141,9 @@ dependencies = [ [[package]] name = "serde_with" -version = "3.11.0" +version = "3.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e28bdad6db2b8340e449f7108f020b3b092e8583a9e3fb82713e1d4e71fe817" +checksum = "d6b6f7f2fcb69f747921f79f3926bd1e203fce4fef62c268dd3abfb6d86029aa" dependencies = [ "base64 0.22.1", "chrono", @@ -11227,7 +11339,7 @@ version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dee851d0e5e7af3721faea1843e8015e820a234f81fda3dea9247e15bac9a86a" dependencies = [ - "bitflags 2.6.0", + "bitflags 2.9.0", ] [[package]] @@ -11265,9 +11377,9 @@ checksum = "826167069c09b99d56f31e9ae5c99049e932a98c9dc2dac47645b08dbbf76ba7" [[package]] name = "smallvec" -version = "1.13.2" +version = "1.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" +checksum = "7fcf8323ef1faaee30a44a340193b1ac6814fd9b7b4e88e9d4519a3e4abe1cfd" [[package]] name = "smawk" @@ -11307,7 +11419,7 @@ dependencies = [ "bs58", "chacha20", "crossbeam-queue", - "derive_more 0.99.18", + "derive_more 0.99.19", "ed25519-zebra 4.0.3", "either", "event-listener 4.0.3", @@ -11362,10 +11474,10 @@ dependencies = [ "bs58", "chacha20", "crossbeam-queue", - "derive_more 0.99.18", + "derive_more 0.99.19", "ed25519-zebra 4.0.3", "either", - "event-listener 5.3.1", + "event-listener 5.4.0", "fnv", "futures-lite", "futures-util", @@ -11411,7 +11523,7 @@ dependencies = [ "async-lock", "base64 0.21.7", "blake2-rfc", - "derive_more 0.99.18", + "derive_more 0.99.19", "either", "event-listener 4.0.3", "fnv", @@ -11448,9 +11560,9 @@ dependencies = [ "base64 0.22.1", "blake2-rfc", "bs58", - "derive_more 0.99.18", + "derive_more 0.99.19", "either", - "event-listener 5.3.1", + "event-listener 5.4.0", "fnv", "futures-channel", "futures-lite", @@ -11490,7 +11602,7 @@ dependencies = [ "chacha20poly1305", "curve25519-dalek 4.1.3", "rand_core 0.6.4", - "ring 0.17.8", + "ring 0.17.14", "rustc_version", "sha2 0.10.8", "subtle 2.6.1", @@ -11540,7 +11652,7 @@ dependencies = [ "base64 0.22.1", "bytes", "futures", - "http 1.2.0", + "http 1.3.1", "httparse", "log", "rand 0.8.5", @@ -11602,7 +11714,7 @@ dependencies = [ "Inflector", "blake2 0.10.6", "expander", - "proc-macro-crate 3.2.0", + "proc-macro-crate 3.3.0", "proc-macro2", "quote", "syn 2.0.100", @@ -11617,7 +11729,7 @@ dependencies = [ "Inflector", "blake2 0.10.6", "expander", - "proc-macro-crate 3.2.0", + "proc-macro-crate 3.3.0", "proc-macro2", "quote", "syn 2.0.100", @@ -12376,7 +12488,7 @@ checksum = "0195f32c628fee3ce1dfbbf2e7e52a30ea85f3589da9fe62a8b816d70fc06294" dependencies = [ "Inflector", "expander", - "proc-macro-crate 3.2.0", + "proc-macro-crate 3.3.0", "proc-macro2", "quote", "syn 2.0.100", @@ -12756,7 +12868,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "54cabc8279e835cd9c608d70cb00e693bddec94fe8478e9f3104dad1da5f93ca" dependencies = [ "parity-scale-codec", - "proc-macro-warning 1.0.2", + "proc-macro-warning 1.84.1", "proc-macro2", "quote", "syn 2.0.100", @@ -12829,7 +12941,7 @@ checksum = "9dbb79b4db5ac7e4628e6537551c905661d0525dfe34051d14137cd347f85e21" dependencies = [ "log", "serde_json", - "thiserror 2.0.11", + "thiserror 2.0.12", "ureq", ] @@ -13012,7 +13124,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7b6772e9c3621b8d067a706dfda6a20db6faa7cde39822c58ffc8588d16409c5" dependencies = [ "http-body-util", - "hyper 1.5.2", + "hyper 1.6.0", "hyper-util", "log", "prometheus", @@ -13070,9 +13182,9 @@ dependencies = [ [[package]] name = "subxt" -version = "0.38.0" +version = "0.38.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c53029d133e4e0cb7933f1fe06f2c68804b956de9bb8fa930ffca44e9e5e4230" +checksum = "1c17d7ec2359d33133b63c97e28c8b7cd3f0a5bc6ce567ae3aef9d9e85be3433" dependencies = [ "async-trait", "derive-where", @@ -13081,7 +13193,7 @@ dependencies = [ "futures", "hex", "impl-serde 0.5.0", - "jsonrpsee 0.24.7", + "jsonrpsee 0.24.9", "parity-scale-codec", "polkadot-sdk", "primitive-types 0.13.1", @@ -13092,10 +13204,10 @@ dependencies = [ "scale-value 0.17.0", "serde", "serde_json", - "subxt-core 0.38.0", - "subxt-lightclient 0.38.0", - "subxt-macro 0.38.0", - "subxt-metadata 0.38.0", + "subxt-core 0.38.1", + "subxt-lightclient 0.38.1", + "subxt-macro 0.38.1", + "subxt-metadata 0.38.1", "thiserror 1.0.69", "tokio", "tokio-util", @@ -13128,9 +13240,9 @@ dependencies = [ [[package]] name = "subxt-codegen" -version = "0.38.0" +version = "0.38.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3cfcfb7d9589f3df0ac87c4988661cf3fb370761fcb19f2fd33104cc59daf22a" +checksum = "6550ef451c77db6e3bc7c56fb6fe1dca9398a2c8fc774b127f6a396a769b9c5b" dependencies = [ "heck 0.5.0", "parity-scale-codec", @@ -13138,7 +13250,7 @@ dependencies = [ "quote", "scale-info", "scale-typegen 0.9.0", - "subxt-metadata 0.38.0", + "subxt-metadata 0.38.1", "syn 2.0.100", "thiserror 1.0.69", ] @@ -13172,9 +13284,9 @@ dependencies = [ [[package]] name = "subxt-core" -version = "0.38.0" +version = "0.38.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ea28114366780d23684bd55ab879cd04c9d4cbba3b727a3854a3eca6bf29a1a" +checksum = "cb7a1bc6c9c1724971636a66e3225a7253cdb35bb6efb81524a6c71c04f08c59" dependencies = [ "base58", "blake2 0.10.6", @@ -13195,7 +13307,7 @@ dependencies = [ "scale-value 0.17.0", "serde", "serde_json", - "subxt-metadata 0.38.0", + "subxt-metadata 0.38.1", "tracing", ] @@ -13218,9 +13330,9 @@ dependencies = [ [[package]] name = "subxt-lightclient" -version = "0.38.0" +version = "0.38.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "534d4b725183a9fa09ce0e0f135674473297fdd97dee4d683f41117f365ae997" +checksum = "89ebc9131da4d0ba1f7814495b8cc79698798ccd52cacd7bcefe451e415bd945" dependencies = [ "futures", "futures-util", @@ -13250,16 +13362,16 @@ dependencies = [ [[package]] name = "subxt-macro" -version = "0.38.0" +version = "0.38.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "228db9a5c95a6d8dc6152b4d6cdcbabc4f60821dd3f482a4f8791e022b7caadb" +checksum = "7819c5e09aae0319981ee853869f2fcd1fac4db8babd0d004c17161297aadc05" dependencies = [ "darling 0.20.10", "parity-scale-codec", "proc-macro-error2", "quote", "scale-typegen 0.9.0", - "subxt-codegen 0.38.0", + "subxt-codegen 0.38.1", "subxt-utils-fetchmetadata", "syn 2.0.100", ] @@ -13279,9 +13391,9 @@ dependencies = [ [[package]] name = "subxt-metadata" -version = "0.38.0" +version = "0.38.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee13e6862eda035557d9a2871955306aff540d2b89c06e0a62a1136a700aed28" +checksum = "aacd4e7484fef58deaa2dcb32d94753a864b208a668c0dd0c28be1d8abeeadb2" dependencies = [ "frame-decode", "frame-metadata 17.0.0", @@ -13317,9 +13429,9 @@ dependencies = [ [[package]] name = "subxt-signer" -version = "0.38.0" +version = "0.38.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e7a336d6a1f86f126100a4a717be58352de4c8214300c4f7807f974494efdb9" +checksum = "d680352d04665b1e4eb6f9d2a54b800c4d8e1b20478e69be1b7d975b08d9fc34" dependencies = [ "base64 0.22.1", "bip39", @@ -13338,15 +13450,15 @@ dependencies = [ "serde", "serde_json", "sha2 0.10.8", - "subxt-core 0.38.0", + "subxt-core 0.38.1", "zeroize", ] [[package]] name = "subxt-utils-fetchmetadata" -version = "0.38.0" +version = "0.38.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3082b17a86e3c3fe45d858d94d68f6b5247caace193dad6201688f24db8ba9bb" +checksum = "a3c53bc3eeaacc143a2f29ace4082edd2edaccab37b69ad20befba9fb00fdb3d" dependencies = [ "hex", "parity-scale-codec", @@ -13419,7 +13531,7 @@ version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3c879d448e9d986b661742763247d3693ed13609438cf3d006f51f5368a5ba6b" dependencies = [ - "bitflags 2.6.0", + "bitflags 2.9.0", "core-foundation 0.9.4", "system-configuration-sys", ] @@ -13442,9 +13554,9 @@ checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" [[package]] name = "tar" -version = "0.4.43" +version = "0.4.44" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c65998313f8e17d0d553d28f91a0df93e4dbbbf770279c7bc21ca0f09ea1a1f6" +checksum = "1d863878d212c87a19c1a610eb53bb01fe12951c0501cf5a0d65f724914a667a" dependencies = [ "filetime", "libc", @@ -13459,15 +13571,14 @@ checksum = "61c41af27dd6d1e27b1b16b489db798443478cef1f06a660c96db617ba5de3b1" [[package]] name = "tempfile" -version = "3.17.1" +version = "3.19.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22e5a0acb1f3f55f65cc4a866c361b2fb2a0ff6366785ae6fbb5f85df07ba230" +checksum = "7437ac7763b9b123ccf33c338a5cc1bac6f69b45a136c19bdd8a65e3916435bf" dependencies = [ - "cfg-if", "fastrand", - "getrandom 0.3.1", + "getrandom 0.3.2", "once_cell", - "rustix 0.38.42", + "rustix 1.0.3", "windows-sys 0.59.0", ] @@ -13502,19 +13613,19 @@ dependencies = [ [[package]] name = "termtree" -version = "0.4.1" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3369f5ac52d5eb6ab48c6b4ffdc8efbcad6b89c765749064ba298f2c68a16a76" +checksum = "8f50febec83f5ee1df3015341d8bd429f2d1cc62bcba7ea2076759d315084683" [[package]] name = "textwrap" -version = "0.16.1" +version = "0.16.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23d434d3f8967a09480fb04132ebe0a3e088c173e6d0ee7897abbdf4eab0f8b9" +checksum = "c13547615a44dc9c452a8a534638acdf07120d4b6847c8178705da06306a3057" dependencies = [ "smawk", "unicode-linebreak", - "unicode-width 0.1.14", + "unicode-width", ] [[package]] @@ -13528,11 +13639,11 @@ dependencies = [ [[package]] name = "thiserror" -version = "2.0.11" +version = "2.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d452f284b73e6d76dd36758a0c8684b1d5be31f92b89d07fd5822175732206fc" +checksum = "567b8a2dae586314f7be2a752ec7474332959c6460e02bde30d702a66d488708" dependencies = [ - "thiserror-impl 2.0.11", + "thiserror-impl 2.0.12", ] [[package]] @@ -13548,9 +13659,9 @@ dependencies = [ [[package]] name = "thiserror-impl" -version = "2.0.11" +version = "2.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26afc1baea8a989337eeb52b6e72a039780ce45c3edfcc9c5b9d112feeb173c2" +checksum = "7f7cf42b4507d8ea322120659672cf1b9dbb93f8f2d4ecfd6e51350ff5b17a1d" dependencies = [ "proc-macro2", "quote", @@ -13596,9 +13707,9 @@ dependencies = [ [[package]] name = "time" -version = "0.3.37" +version = "0.3.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35e7868883861bd0e56d9ac6efcaaca0d6d5d82a2a7ec8209ff492c07cf37b21" +checksum = "8a7619e19bc266e0f9c5e6686659d394bc57973859340060a69221e57dbc0c40" dependencies = [ "deranged", "itoa", @@ -13611,15 +13722,15 @@ dependencies = [ [[package]] name = "time-core" -version = "0.1.2" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" +checksum = "c9e9a38711f559d9e3ce1cdb06dd7c5b8ea546bc90052da6d06bb76da74bb07c" [[package]] name = "time-macros" -version = "0.2.19" +version = "0.2.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2834e6017e3e5e4b9834939793b282bc03b37a3336245fa820e35e233e2a85de" +checksum = "3526739392ec93fd8b359c8e98514cb3e8e021beb4e5f597b00a0221f8ed8a49" dependencies = [ "num-conv", "time-core", @@ -13646,9 +13757,9 @@ dependencies = [ [[package]] name = "tinyvec" -version = "1.8.0" +version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "445e881f4f6d382d5f27c034e25eb92edd7c784ceab92a0937db7f2e9471b938" +checksum = "09b3661f17e86524eccd4371ab0429194e0d7c008abb45f7a7495b1719463c71" dependencies = [ "tinyvec_macros", ] @@ -13661,9 +13772,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.42.0" +version = "1.44.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5cec9b21b0450273377fc97bd4c33a8acffc8c996c987a7c5b319a0083707551" +checksum = "f382da615b842244d4b8738c82ed1275e6c5dd90c459a30941cd07080b06c91a" dependencies = [ "backtrace", "bytes", @@ -13689,9 +13800,9 @@ dependencies = [ [[package]] name = "tokio-macros" -version = "2.4.0" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "693d596312e88961bc67d7f1f97af8a70227d9f90c31bba5806eec004978d752" +checksum = "6e06d43f1345a3bcd39f6a56dbb7dcab2ba47e68e8ac134855e7e2bdbaf8cab8" dependencies = [ "proc-macro2", "quote", @@ -13731,9 +13842,9 @@ dependencies = [ [[package]] name = "tokio-rustls" -version = "0.26.1" +version = "0.26.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f6d0975eaace0cf0fcadee4e4aaa5da15b5c079146f2cffb67c113be122bf37" +checksum = "8e727b36a1a0e8b74c376ac2211e40c2c8af09fb4013c60d910495810f008e9b" dependencies = [ "rustls 0.23.25", "tokio", @@ -13788,15 +13899,15 @@ dependencies = [ "rustls-native-certs 0.8.1", "rustls-pki-types", "tokio", - "tokio-rustls 0.26.1", + "tokio-rustls 0.26.2", "tungstenite 0.26.2", ] [[package]] name = "tokio-util" -version = "0.7.13" +version = "0.7.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7fcaa8d55a2bdd6b83ace262b016eca0d79ee02818c5c1bcdf0305114081078" +checksum = "6b9590b93e6fcc1739458317cccd391ad3955e2bde8913edf6f95f9e65a8f034" dependencies = [ "bytes", "futures-core", @@ -13818,9 +13929,9 @@ dependencies = [ [[package]] name = "toml" -version = "0.8.19" +version = "0.8.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1ed1f98e3fdc28d6d910e6737ae6ab1a93bf1985935a1193e68f93eeb68d24e" +checksum = "cd87a5cdd6ffab733b2f74bc4fd7ee5fff6634124999ac278c35fc78c6120148" dependencies = [ "serde", "serde_spanned", @@ -13890,7 +14001,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "61c5bb1d698276a2443e5ecfabc1008bf15a36c12e6a7176e7bf089ea9131140" dependencies = [ "base64 0.21.7", - "bitflags 2.6.0", + "bitflags 2.9.0", "bytes", "futures-core", "futures-util", @@ -13910,9 +14021,9 @@ version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e9cd434a998747dd2c4276bc96ee2e0c7a2eadf3cae88e52be55a05fa9053f5" dependencies = [ - "bitflags 2.6.0", + "bitflags 2.9.0", "bytes", - "http 1.2.0", + "http 1.3.1", "http-body 1.0.1", "http-body-util", "pin-project-lite", @@ -13926,10 +14037,10 @@ version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "403fa3b783d4b626a8ad51d766ab03cb6d2dbfc46b1c5d4448395e6628dc9697" dependencies = [ - "bitflags 2.6.0", + "bitflags 2.9.0", "bytes", "futures-util", - "http 1.2.0", + "http 1.3.1", "http-body 1.0.1", "http-body-util", "http-range-header 0.4.2", @@ -14019,7 +14130,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0f074568687ffdfd0adb6005aa8d1d96840197f2c159f80471285f08694cf0ce" dependencies = [ "expander", - "proc-macro-crate 3.2.0", + "proc-macro-crate 3.3.0", "proc-macro2", "quote", "syn 2.0.100", @@ -14201,14 +14312,14 @@ checksum = "4793cb5e56680ecbb1d843515b23b6de9a75eb04b66643e256a396d43be33c13" dependencies = [ "bytes", "data-encoding", - "http 1.2.0", + "http 1.3.1", "httparse", "log", "rand 0.9.0", "rustls 0.23.25", "rustls-pki-types", "sha1", - "thiserror 2.0.11", + "thiserror 2.0.12", "url", "utf-8", ] @@ -14233,9 +14344,9 @@ dependencies = [ [[package]] name = "typenum" -version = "1.17.0" +version = "1.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" +checksum = "1dccffe3ce07af9386bfd29e80c0ab1a8205a2fc34e4bcd40364df902cfa8f3f" [[package]] name = "ucd-trie" @@ -14269,9 +14380,9 @@ dependencies = [ [[package]] name = "unicase" -version = "2.8.0" +version = "2.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e51b68083f157f853b6379db119d1c1be0e6e4dec98101079dec41f6f5cf6df" +checksum = "75b844d17643ee918803943289730bec8aac480150456169e647ed0b576ba539" [[package]] name = "unicode-bidi" @@ -14281,9 +14392,9 @@ checksum = "5c1cb5db39152898a79168971543b1cb5020dff7fe43c8dc468b0885f5e29df5" [[package]] name = "unicode-ident" -version = "1.0.14" +version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "adb9e6ca4f869e1180728b7950e35922a7fc6397f7b641499e8f3ef06e50dc83" +checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" [[package]] name = "unicode-linebreak" @@ -14306,12 +14417,6 @@ version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493" -[[package]] -name = "unicode-width" -version = "0.1.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af" - [[package]] name = "unicode-width" version = "0.2.0" @@ -14399,7 +14504,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ae239d0a3341aebc94259414d1dc67cfce87d41cbebc816772c91b77902fafa4" dependencies = [ "base64 0.22.1", - "http 1.2.0", + "http 1.3.1", "httparse", "log", ] @@ -14442,11 +14547,11 @@ checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" [[package]] name = "uuid" -version = "1.11.0" +version = "1.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8c5f0a0af699448548ad1a2fbf920fb4bee257eae39953ba95cb84891a0446a" +checksum = "458f7a779bf54acc9f347480ac654f68407d3aab21269a6e3c9f922acd9e2da9" dependencies = [ - "getrandom 0.2.15", + "getrandom 0.3.2", ] [[package]] @@ -14461,9 +14566,9 @@ dependencies = [ [[package]] name = "valuable" -version = "0.1.0" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" +checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65" [[package]] name = "vcpkg" @@ -14509,9 +14614,9 @@ dependencies = [ [[package]] name = "wait-timeout" -version = "0.2.0" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f200f5b12eb75f8c1ed65abd4b2db8a6e1b138a20de009dacee265a2498f3f6" +checksum = "09ac3b126d3914f9849036f826e054cbabdc8519970b8998ddaf3b5bd3c65f11" dependencies = [ "libc", ] @@ -14543,9 +14648,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasi" -version = "0.13.3+wasi-0.2.2" +version = "0.14.2+wasi-0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26816d2e1a4a36a2940b96c5296ce403917633dff8f3440e9b236ed6f6bacad2" +checksum = "9683f9a5a998d873c0d21fcbe3c083009670149a8fab228644b8bd36b2c48cb3" dependencies = [ "wit-bindgen-rt", ] @@ -14561,20 +14666,21 @@ dependencies = [ [[package]] name = "wasm-bindgen" -version = "0.2.99" +version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a474f6281d1d70c17ae7aa6a613c87fce69a127e2624002df63dcb39d6cf6396" +checksum = "1edc8929d7499fc4e8f0be2262a241556cfc54a0bea223790e71446f2aab1ef5" dependencies = [ "cfg-if", "once_cell", + "rustversion", "wasm-bindgen-macro", ] [[package]] name = "wasm-bindgen-backend" -version = "0.2.99" +version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f89bb38646b4f81674e8f5c3fb81b562be1fd936d84320f3264486418519c79" +checksum = "2f0a0651a5c2bc21487bde11ee802ccaf4c51935d0d3d42a6101f98161700bc6" dependencies = [ "bumpalo", "log", @@ -14586,9 +14692,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-futures" -version = "0.4.49" +version = "0.4.50" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38176d9b44ea84e9184eff0bc34cc167ed044f816accfe5922e54d84cf48eca2" +checksum = "555d470ec0bc3bb57890405e5d4322cc9ea83cebb085523ced7be4144dac1e61" dependencies = [ "cfg-if", "js-sys", @@ -14599,9 +14705,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.99" +version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2cc6181fd9a7492eef6fef1f33961e3695e4579b9872a6f7c83aee556666d4fe" +checksum = "7fe63fc6d09ed3792bd0897b314f53de8e16568c2b3f7982f468c0bf9bd0b407" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -14609,9 +14715,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.99" +version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30d7a95b763d3c45903ed6c81f156801839e5ee968bb07e534c44df0fcd330c2" +checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de" dependencies = [ "proc-macro2", "quote", @@ -14622,18 +14728,21 @@ dependencies = [ [[package]] name = "wasm-bindgen-shared" -version = "0.2.99" +version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "943aab3fdaaa029a6e0271b35ea10b72b943135afe9bffca82384098ad0e06a6" +checksum = "1a05d73b933a847d6cccdda8f838a22ff101ad9bf93e33684f39c1f5f0eece3d" +dependencies = [ + "unicode-ident", +] [[package]] name = "wasm-encoder" -version = "0.220.0" +version = "0.220.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ebf48234b389415b226a4daef6562933d38c7b28a8b8f64c5c4130dad1561ab7" +checksum = "e913f9242315ca39eff82aee0e19ee7a372155717ff0eb082c741e435ce25ed1" dependencies = [ "leb128", - "wasmparser 0.220.0", + "wasmparser 0.220.1", ] [[package]] @@ -14783,12 +14892,12 @@ dependencies = [ [[package]] name = "wasmparser" -version = "0.220.0" +version = "0.220.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e246c2772ce3ebc83f89a2d4487ac5794cad6c309b2071818a88c7db7c36d87b" +checksum = "8d07b6a3b550fefa1a914b6d54fc175dd11c3392da11eee604e6ffc759805d25" dependencies = [ "ahash 0.8.11", - "bitflags 2.6.0", + "bitflags 2.9.0", "hashbrown 0.14.5", "indexmap 2.8.0", "semver", @@ -15001,9 +15110,9 @@ dependencies = [ [[package]] name = "web-sys" -version = "0.3.76" +version = "0.3.77" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04dd7223427d52553d3702c004d3b2fe07c148165faa56313cb00211e31c12bc" +checksum = "33b6dd2ef9186f1f2072e409e99cd22a975331a6b3591b12c764e0e55c60d5d2" dependencies = [ "js-sys", "wasm-bindgen", @@ -15025,10 +15134,19 @@ version = "0.22.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed63aea5ce73d0ff405984102c42de94fc55a6b75765d621c65262469b3c9b53" dependencies = [ - "ring 0.17.8", + "ring 0.17.14", "untrusted 0.9.0", ] +[[package]] +name = "webpki-root-certs" +version = "0.26.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09aed61f5e8d2c18344b3faa33a4c837855fe56642757754775548fee21386c4" +dependencies = [ + "rustls-pki-types", +] + [[package]] name = "webpki-roots" version = "0.25.4" @@ -15046,21 +15164,21 @@ dependencies = [ [[package]] name = "which" -version = "7.0.0" +version = "7.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c9cad3279ade7346b96e38731a641d7343dd6a53d55083dd54eadfa5a1b38c6b" +checksum = "2774c861e1f072b3aadc02f8ba886c26ad6321567ecc294c935434cad06f1283" dependencies = [ "either", - "home", - "rustix 0.38.42", + "env_home", + "rustix 0.38.44", "winsafe", ] [[package]] name = "wide" -version = "0.7.30" +version = "0.7.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "58e6db2670d2be78525979e9a5f9c69d296fd7d670549fe9ebf70f8708cb5019" +checksum = "41b5576b9a81633f3e8df296ce0063042a73507636cbe956c61133dd7034ab22" dependencies = [ "bytemuck", "safe_arch", @@ -15142,15 +15260,21 @@ dependencies = [ "windows-targets 0.52.6", ] +[[package]] +name = "windows-link" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76840935b766e1b0a05c0066835fb9ec80071d4c09a16f6bd5f7e655e3c14c38" + [[package]] name = "windows-registry" -version = "0.2.0" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e400001bb720a623c1c69032f8e3e4cf09984deec740f007dd2b03ec864804b0" +checksum = "4286ad90ddb45071efd1a66dfa43eb02dd0dfbae1545ad6cc3c51cf34d7e8ba3" dependencies = [ - "windows-result 0.2.0", + "windows-result 0.3.2", "windows-strings", - "windows-targets 0.52.6", + "windows-targets 0.53.0", ] [[package]] @@ -15164,21 +15288,20 @@ dependencies = [ [[package]] name = "windows-result" -version = "0.2.0" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d1043d8214f791817bab27572aaa8af63732e11bf84aa21a45a78d6c317ae0e" +checksum = "c64fd11a4fd95df68efcfee5f44a294fe71b8bc6a91993e2791938abcc712252" dependencies = [ - "windows-targets 0.52.6", + "windows-link", ] [[package]] name = "windows-strings" -version = "0.1.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4cd9b125c486025df0eabcb585e62173c6c9eddcec5d117d3b6e8c30e2ee4d10" +checksum = "87fa48cc5d406560701792be122a10132491cff9d0aeb23583cc2dcafc847319" dependencies = [ - "windows-result 0.2.0", - "windows-targets 0.52.6", + "windows-link", ] [[package]] @@ -15256,13 +15379,29 @@ dependencies = [ "windows_aarch64_gnullvm 0.52.6", "windows_aarch64_msvc 0.52.6", "windows_i686_gnu 0.52.6", - "windows_i686_gnullvm", + "windows_i686_gnullvm 0.52.6", "windows_i686_msvc 0.52.6", "windows_x86_64_gnu 0.52.6", "windows_x86_64_gnullvm 0.52.6", "windows_x86_64_msvc 0.52.6", ] +[[package]] +name = "windows-targets" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1e4c7e8ceaaf9cb7d7507c974735728ab453b67ef8f18febdd7c11fe59dca8b" +dependencies = [ + "windows_aarch64_gnullvm 0.53.0", + "windows_aarch64_msvc 0.53.0", + "windows_i686_gnu 0.53.0", + "windows_i686_gnullvm 0.53.0", + "windows_i686_msvc 0.53.0", + "windows_x86_64_gnu 0.53.0", + "windows_x86_64_gnullvm 0.53.0", + "windows_x86_64_msvc 0.53.0", +] + [[package]] name = "windows_aarch64_gnullvm" version = "0.42.2" @@ -15281,6 +15420,12 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86b8d5f90ddd19cb4a147a5fa63ca848db3df085e25fee3cc10b39b6eebae764" + [[package]] name = "windows_aarch64_msvc" version = "0.42.2" @@ -15299,6 +15444,12 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" +[[package]] +name = "windows_aarch64_msvc" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7651a1f62a11b8cbd5e0d42526e55f2c99886c77e007179efff86c2b137e66c" + [[package]] name = "windows_i686_gnu" version = "0.42.2" @@ -15317,12 +15468,24 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" +[[package]] +name = "windows_i686_gnu" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1dc67659d35f387f5f6c479dc4e28f1d4bb90ddd1a5d3da2e5d97b42d6272c3" + [[package]] name = "windows_i686_gnullvm" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" +[[package]] +name = "windows_i686_gnullvm" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ce6ccbdedbf6d6354471319e781c0dfef054c81fbc7cf83f338a4296c0cae11" + [[package]] name = "windows_i686_msvc" version = "0.42.2" @@ -15341,6 +15504,12 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" +[[package]] +name = "windows_i686_msvc" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "581fee95406bb13382d2f65cd4a908ca7b1e4c2f1917f143ba16efe98a589b5d" + [[package]] name = "windows_x86_64_gnu" version = "0.42.2" @@ -15359,6 +15528,12 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" +[[package]] +name = "windows_x86_64_gnu" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e55b5ac9ea33f2fc1716d1742db15574fd6fc8dadc51caab1c16a3d3b4190ba" + [[package]] name = "windows_x86_64_gnullvm" version = "0.42.2" @@ -15377,6 +15552,12 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0a6e035dd0599267ce1ee132e51c27dd29437f63325753051e71dd9e42406c57" + [[package]] name = "windows_x86_64_msvc" version = "0.42.2" @@ -15395,6 +15576,12 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" +[[package]] +name = "windows_x86_64_msvc" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "271414315aff87387382ec3d271b52d7ae78726f5d44ac98b4f4030c91880486" + [[package]] name = "winnow" version = "0.7.4" @@ -15422,11 +15609,11 @@ checksum = "d135d17ab770252ad95e9a872d365cf3090e3be864a34ab46f48555993efc904" [[package]] name = "wit-bindgen-rt" -version = "0.33.0" +version = "0.39.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3268f3d866458b787f390cf61f4bbb563b922d091359f9608842999eaee3943c" +checksum = "6f42320e61fe2cfd34354ecb597f86f413484a798ba44a8ca1165c58d42da6c1" dependencies = [ - "bitflags 2.6.0", + "bitflags 2.9.0", ] [[package]] @@ -15492,19 +15679,18 @@ dependencies = [ "nom", "oid-registry 0.8.1", "rusticata-macros", - "thiserror 2.0.11", + "thiserror 2.0.12", "time", ] [[package]] name = "xattr" -version = "1.3.1" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8da84f1a25939b27f6820d92aed108f83ff920fdf11a7b19366c27c4cda81d4f" +checksum = "0d65cbf2f12c15564212d48f4e3dfb87923d25d611f2aed18f4cb23f0413d89e" dependencies = [ "libc", - "linux-raw-sys 0.4.14", - "rustix 0.38.42", + "rustix 1.0.3", ] [[package]] @@ -15548,9 +15734,9 @@ dependencies = [ [[package]] name = "xxhash-rust" -version = "0.8.12" +version = "0.8.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a5cbf750400958819fb6178eaa83bee5cd9c29a26a40cc241df8c70fdd46984" +checksum = "fdd20c5420375476fbd4394763288da7eb0cc0b8c11deed431a91562af7335d3" [[package]] name = "yamux" @@ -15628,7 +15814,6 @@ version = "0.7.35" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" dependencies = [ - "byteorder", "zerocopy-derive 0.7.35", ] @@ -15665,18 +15850,18 @@ dependencies = [ [[package]] name = "zerofrom" -version = "0.1.5" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cff3ee08c995dee1859d998dea82f7374f2826091dd9cd47def953cae446cd2e" +checksum = "50cc42e0333e05660c3587f3bf9d0478688e15d870fab3346451ce7f8c9fbea5" dependencies = [ "zerofrom-derive", ] [[package]] name = "zerofrom-derive" -version = "0.1.5" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "595eed982f7d355beb85837f651fa22e90b3c044842dc7f2c2842c086f295808" +checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502" dependencies = [ "proc-macro2", "quote", @@ -15728,17 +15913,15 @@ dependencies = [ [[package]] name = "zip" -version = "2.2.2" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae9c1ea7b3a5e1f4b922ff856a129881167511563dc219869afe3787fc0c1a45" +checksum = "27c03817464f64e23f6f37574b4fdc8cf65925b5bfd2b0f2aedf959791941f88" dependencies = [ "arbitrary", "crc32fast", "crossbeam-utils", - "displaydoc", "indexmap 2.8.0", "memchr", - "thiserror 2.0.11", ] [[package]] @@ -15756,7 +15939,7 @@ dependencies = [ "serde_json", "thiserror 1.0.69", "tokio", - "toml 0.8.19", + "toml 0.8.20", "tracing", "url", "zombienet-support", @@ -15783,8 +15966,8 @@ dependencies = [ "serde_json", "sha2 0.10.8", "sp-core 35.0.0", - "subxt 0.38.0", - "subxt-signer 0.38.0", + "subxt 0.38.1", + "subxt-signer 0.38.1", "thiserror 1.0.69", "tokio", "tracing", @@ -15846,8 +16029,8 @@ dependencies = [ "async-trait", "futures", "lazy_static", - "subxt 0.38.0", - "subxt-signer 0.38.0", + "subxt 0.38.1", + "subxt-signer 0.38.1", "tokio", "zombienet-configuration", "zombienet-orchestrator", @@ -15914,9 +16097,9 @@ dependencies = [ [[package]] name = "zstd-sys" -version = "2.0.13+zstd.1.5.6" +version = "2.0.15+zstd.1.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38ff0f21cfee8f97d94cef41359e0c89aa6113028ab0291aa8ca0038995a95aa" +checksum = "eb81183ddd97d0c74cedf1d50d85c8d08c1b8b68ee863bdee9e706eedba1a237" dependencies = [ "cc", "pkg-config", diff --git a/Cargo.toml b/Cargo.toml index ffaa52208..70e4941bc 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -24,6 +24,12 @@ version = "0.6.0" anyhow = "1.0" assert_cmd = "2.0.14" cargo_toml = "0.20.3" +# deranged 0.4.1 implements PartialOrd for some types leading to conflicts with core primitive types. +# Some related discussion: 'https://github.com/jhpratt/deranged/issues/18' +# This creates conflicts on the dependency tree of Pop-cli as deranged is somewhere there and some downstream crates +# are affected in the way described in the discussion. Til that's fixed, a pin to the version 0.4.0 is necessary as +# a workaround. Pinned in all pop-cli crates for this reason. +deranged = { version = "=0.4.0", default-features = false } dirs = "5.0" duct = "0.13" env_logger = "0.11.7" @@ -36,7 +42,6 @@ mockito = "1.4.0" pathdiff = "0.2.1" proc-macro2 = "1.0.86" rustilities = "2.1.0" -rustls-webpki = "0.102" rust_writer = "1.0.4" syn = "2.0.100" tar = "0.4.40" diff --git a/crates/pop-cli/Cargo.toml b/crates/pop-cli/Cargo.toml index 56350fc0c..44d5f1f58 100644 --- a/crates/pop-cli/Cargo.toml +++ b/crates/pop-cli/Cargo.toml @@ -14,6 +14,8 @@ path = "src/main.rs" [dependencies] anyhow.workspace = true +# Pin to solve dependencies conflics. See Cargo.toml for further info. +deranged.workspace = true duct.workspace = true env_logger.workspace = true fs_rollback.workspace = true diff --git a/crates/pop-common/Cargo.toml b/crates/pop-common/Cargo.toml index a0a718cce..de93ec5d9 100644 --- a/crates/pop-common/Cargo.toml +++ b/crates/pop-common/Cargo.toml @@ -12,6 +12,8 @@ anyhow.workspace = true cargo_toml.workspace = true contract-build.workspace = true contract-extrinsics.workspace = true +# Pin to solve dependencies conflics. See Cargo.toml for further info. +deranged.workspace = true duct.workspace = true flate2.workspace = true fs_rollback.workspace = true diff --git a/crates/pop-contracts/Cargo.toml b/crates/pop-contracts/Cargo.toml index 581075f95..f217bcdb8 100644 --- a/crates/pop-contracts/Cargo.toml +++ b/crates/pop-contracts/Cargo.toml @@ -12,6 +12,8 @@ version.workspace = true [dependencies] anyhow.workspace = true +# Pin to solve dependencies conflics. See Cargo.toml for further info. +deranged.workspace = true duct.workspace = true reqwest.workspace = true tempfile.workspace = true @@ -38,4 +40,4 @@ pop-common = { path = "../pop-common", version = "0.6.0" } [dev-dependencies] # Used in doc tests. -tokio-test.workspace = true \ No newline at end of file +tokio-test.workspace = true diff --git a/crates/pop-parachains/Cargo.toml b/crates/pop-parachains/Cargo.toml index b73ae7541..8cff33407 100644 --- a/crates/pop-parachains/Cargo.toml +++ b/crates/pop-parachains/Cargo.toml @@ -11,6 +11,8 @@ version.workspace = true [dependencies] anyhow.workspace = true clap.workspace = true +# Pin to solve dependencies conflics. See Cargo.toml for further info. +deranged.workspace = true duct.workspace = true glob.workspace = true serde_json.workspace = true diff --git a/crates/pop-telemetry/Cargo.toml b/crates/pop-telemetry/Cargo.toml index 9db875169..03aa9357a 100644 --- a/crates/pop-telemetry/Cargo.toml +++ b/crates/pop-telemetry/Cargo.toml @@ -8,6 +8,8 @@ repository.workspace = true version.workspace = true [dependencies] +# Pin to solve dependencies conflics. See Cargo.toml for further info. +deranged.workspace = true dirs = { workspace = true } env_logger.workspace = true log.workspace = true @@ -19,4 +21,4 @@ tokio.workspace = true [dev-dependencies] mockito.workspace = true -tempfile.workspace = true \ No newline at end of file +tempfile.workspace = true From 33c9567749ec4fd5fcc7fde368b880c8d38d5d3d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1s=20Senovilla=20Polo?= Date: Thu, 27 Mar 2025 13:09:30 +0100 Subject: [PATCH 39/46] Update integration tests for add-to + add them to CI --- .github/workflows/ci.yml | 40 +++++++++++++++++++ Cargo.lock | 1 + .../new_pallet_added_to_existing_runtime.rs | 2 +- .../tests/pop_add_to_pallet_config_type.rs | 4 +- .../tests/pop_add_to_runtime_pallet.rs | 4 +- 5 files changed, 46 insertions(+), 5 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 3dbca9ea5..97b08edf4 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -199,3 +199,43 @@ jobs: - name: Run integration tests run: cargo test --no-default-features --features parachain --test parachain + + file-writer-integration-tests: + needs: lint + strategy: + matrix: + os: ["ubuntu-latest", "macos-latest"] + runs-on: ${{ matrix.os }} + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Install stable toolchain + uses: actions-rs/toolchain@v1 + with: + profile: minimal + toolchain: stable + default: true + target: wasm32-unknown-unknown + components: rust-src, clippy + + - name: Cache + uses: Swatinem/rust-cache@v2 + + - name: Install packages (Linux) + if: matrix.os == 'ubuntu-latest' + uses: "./.github/actions/init" + with: + git-user: ${{ env.GITHUB_ACTOR }} + + - name: Install packages (macOS) + if: matrix.os == 'macos-latest' + run: | + brew install protobuf + protoc --version + + - name: Run integration tests + run: | + cargo test --test pop_add_to_pallet_config_type && \ + cargo test --test pop_add_to_runtime_pallet && \ + cargo test --test new_pallet_added_to_existing_runtime diff --git a/Cargo.lock b/Cargo.lock index ae760fd6a..899f8b122 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -9070,6 +9070,7 @@ dependencies = [ "tokio", "tokio-native-tls", "tokio-util", + "tower 0.5.2", "tower-service", "url", "wasm-bindgen", diff --git a/crates/pop-cli/tests/new_pallet_added_to_existing_runtime.rs b/crates/pop-cli/tests/new_pallet_added_to_existing_runtime.rs index 6280e081b..a92e32a9e 100644 --- a/crates/pop-cli/tests/new_pallet_added_to_existing_runtime.rs +++ b/crates/pop-cli/tests/new_pallet_added_to_existing_runtime.rs @@ -11,7 +11,7 @@ fn pop_new_pallet_modifies_runtime() { Command::cargo_bin("pop") .unwrap() .current_dir(&tempdir) - .args(&["new", "parachain", "test_parachain", "-t", "standard"]) + .args(&["new", "parachain", "test_parachain", "-t", "r0gue-io/base-parachain"]) .assert() .success(); diff --git a/crates/pop-cli/tests/pop_add_to_pallet_config_type.rs b/crates/pop-cli/tests/pop_add_to_pallet_config_type.rs index 9841dc013..96e8151db 100644 --- a/crates/pop-cli/tests/pop_add_to_pallet_config_type.rs +++ b/crates/pop-cli/tests/pop_add_to_pallet_config_type.rs @@ -11,7 +11,7 @@ fn pop_add_to_pallet_config_type_works() { Command::cargo_bin("pop") .unwrap() .current_dir(&tempdir) - .args(&["new", "parachain", "test_parachain", "-t", "standard"]) + .args(&["new", "parachain", "test_parachain", "-t", "r0gue-io/base-parachain"]) .assert() .success(); @@ -179,7 +179,7 @@ fn pop_add_to_pallet_config_type_doesnt_modify_on_fail() { Command::cargo_bin("pop") .unwrap() .current_dir(&tempdir) - .args(&["new", "parachain", "test_parachain", "-t", "standard"]) + .args(&["new", "parachain", "test_parachain", "-t", "r0gue-io/base-parachain"]) .assert() .success(); diff --git a/crates/pop-cli/tests/pop_add_to_runtime_pallet.rs b/crates/pop-cli/tests/pop_add_to_runtime_pallet.rs index 29dffc6c6..7a48d1d80 100644 --- a/crates/pop-cli/tests/pop_add_to_runtime_pallet.rs +++ b/crates/pop-cli/tests/pop_add_to_runtime_pallet.rs @@ -11,7 +11,7 @@ fn pop_add_to_runtime_pallet_runtime_macro_v2_works() { Command::cargo_bin("pop") .unwrap() .current_dir(&tempdir) - .args(&["new", "parachain", "test_parachain", "-t", "standard"]) + .args(&["new", "parachain", "test_parachain", "-t", "r0gue-io/base-parachain"]) .assert() .success(); @@ -208,7 +208,7 @@ fn pop_add_to_runtime_pallet_doesnt_modify_on_failure() { Command::cargo_bin("pop") .unwrap() .current_dir(&tempdir) - .args(&["new", "parachain", "test_parachain3", "-t", "contracts"]) + .args(&["new", "parachain", "test_parachain3", "-t", "r0gue-io/contracts-parachain"]) .assert() .success(); From 90843f52fd836fa2ad8360e663e4d0ecacc46ee6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1s=20Senovilla=20Polo?= Date: Thu, 27 Mar 2025 13:20:03 +0100 Subject: [PATCH 40/46] Move add tests to their respective modules; It's testing the command so not integration at all --- .github/workflows/ci.yml | 40 ------------------- .../src/commands/add/pallet_config_type.rs | 3 ++ .../commands/add/pallet_config_type/tests.rs} | 0 .../src/commands/add/runtime_pallet.rs | 3 ++ .../commands/add/runtime_pallet/tests.rs} | 0 crates/pop-cli/src/commands/new/pallet.rs | 3 ++ .../commands/new/pallet/tests.rs} | 0 7 files changed, 9 insertions(+), 40 deletions(-) rename crates/pop-cli/{tests/pop_add_to_pallet_config_type.rs => src/commands/add/pallet_config_type/tests.rs} (100%) rename crates/pop-cli/{tests/pop_add_to_runtime_pallet.rs => src/commands/add/runtime_pallet/tests.rs} (100%) rename crates/pop-cli/{tests/new_pallet_added_to_existing_runtime.rs => src/commands/new/pallet/tests.rs} (100%) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 97b08edf4..3dbca9ea5 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -199,43 +199,3 @@ jobs: - name: Run integration tests run: cargo test --no-default-features --features parachain --test parachain - - file-writer-integration-tests: - needs: lint - strategy: - matrix: - os: ["ubuntu-latest", "macos-latest"] - runs-on: ${{ matrix.os }} - steps: - - name: Checkout - uses: actions/checkout@v4 - - - name: Install stable toolchain - uses: actions-rs/toolchain@v1 - with: - profile: minimal - toolchain: stable - default: true - target: wasm32-unknown-unknown - components: rust-src, clippy - - - name: Cache - uses: Swatinem/rust-cache@v2 - - - name: Install packages (Linux) - if: matrix.os == 'ubuntu-latest' - uses: "./.github/actions/init" - with: - git-user: ${{ env.GITHUB_ACTOR }} - - - name: Install packages (macOS) - if: matrix.os == 'macos-latest' - run: | - brew install protobuf - protoc --version - - - name: Run integration tests - run: | - cargo test --test pop_add_to_pallet_config_type && \ - cargo test --test pop_add_to_runtime_pallet && \ - cargo test --test new_pallet_added_to_existing_runtime diff --git a/crates/pop-cli/src/commands/add/pallet_config_type.rs b/crates/pop-cli/src/commands/add/pallet_config_type.rs index 6a79fe5ee..4cc5f8769 100644 --- a/crates/pop-cli/src/commands/add/pallet_config_type.rs +++ b/crates/pop-cli/src/commands/add/pallet_config_type.rs @@ -1,5 +1,8 @@ // SPDX-License-Identifier: GPL-3.0 +#[cfg(test)] +mod tests; + mod common_types; use crate::{ diff --git a/crates/pop-cli/tests/pop_add_to_pallet_config_type.rs b/crates/pop-cli/src/commands/add/pallet_config_type/tests.rs similarity index 100% rename from crates/pop-cli/tests/pop_add_to_pallet_config_type.rs rename to crates/pop-cli/src/commands/add/pallet_config_type/tests.rs diff --git a/crates/pop-cli/src/commands/add/runtime_pallet.rs b/crates/pop-cli/src/commands/add/runtime_pallet.rs index 5f4b38a73..7497bebce 100644 --- a/crates/pop-cli/src/commands/add/runtime_pallet.rs +++ b/crates/pop-cli/src/commands/add/runtime_pallet.rs @@ -1,5 +1,8 @@ // SPDX-License-Identifier: GPL-3.0 +#[cfg(test)] +mod tests; + use crate::{ cli::{traits::Cli as _, Cli}, multiselect_pick, diff --git a/crates/pop-cli/tests/pop_add_to_runtime_pallet.rs b/crates/pop-cli/src/commands/add/runtime_pallet/tests.rs similarity index 100% rename from crates/pop-cli/tests/pop_add_to_runtime_pallet.rs rename to crates/pop-cli/src/commands/add/runtime_pallet/tests.rs diff --git a/crates/pop-cli/src/commands/new/pallet.rs b/crates/pop-cli/src/commands/new/pallet.rs index db0fb8a30..94caa2efe 100644 --- a/crates/pop-cli/src/commands/new/pallet.rs +++ b/crates/pop-cli/src/commands/new/pallet.rs @@ -1,5 +1,8 @@ // SPDX-License-Identifier: GPL-3.0 +#[cfg(test)] +mod tests; + use crate::{ cli::{traits::Cli as _, Cli}, multiselect_pick, diff --git a/crates/pop-cli/tests/new_pallet_added_to_existing_runtime.rs b/crates/pop-cli/src/commands/new/pallet/tests.rs similarity index 100% rename from crates/pop-cli/tests/new_pallet_added_to_existing_runtime.rs rename to crates/pop-cli/src/commands/new/pallet/tests.rs From 7530ffcb34e4e4e2e0e1b57a013ef83de43febe3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1s=20Senovilla=20Polo?= Date: Thu, 27 Mar 2025 15:08:53 +0100 Subject: [PATCH 41/46] Assert_cmd has problems finding binary if not integration test; Revert last commit --- .github/workflows/ci.yml | 40 +++++++++++++++++++ .../src/commands/add/pallet_config_type.rs | 3 -- .../src/commands/add/runtime_pallet.rs | 3 -- crates/pop-cli/src/commands/new/pallet.rs | 3 -- .../new_pallet_added_to_existing_runtime.rs} | 0 .../pop_add_to_pallet_config_type.rs} | 0 .../pop_add_to_runtime_pallet.rs} | 0 7 files changed, 40 insertions(+), 9 deletions(-) rename crates/pop-cli/{src/commands/new/pallet/tests.rs => tests/new_pallet_added_to_existing_runtime.rs} (100%) rename crates/pop-cli/{src/commands/add/pallet_config_type/tests.rs => tests/pop_add_to_pallet_config_type.rs} (100%) rename crates/pop-cli/{src/commands/add/runtime_pallet/tests.rs => tests/pop_add_to_runtime_pallet.rs} (100%) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 3dbca9ea5..97b08edf4 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -199,3 +199,43 @@ jobs: - name: Run integration tests run: cargo test --no-default-features --features parachain --test parachain + + file-writer-integration-tests: + needs: lint + strategy: + matrix: + os: ["ubuntu-latest", "macos-latest"] + runs-on: ${{ matrix.os }} + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Install stable toolchain + uses: actions-rs/toolchain@v1 + with: + profile: minimal + toolchain: stable + default: true + target: wasm32-unknown-unknown + components: rust-src, clippy + + - name: Cache + uses: Swatinem/rust-cache@v2 + + - name: Install packages (Linux) + if: matrix.os == 'ubuntu-latest' + uses: "./.github/actions/init" + with: + git-user: ${{ env.GITHUB_ACTOR }} + + - name: Install packages (macOS) + if: matrix.os == 'macos-latest' + run: | + brew install protobuf + protoc --version + + - name: Run integration tests + run: | + cargo test --test pop_add_to_pallet_config_type && \ + cargo test --test pop_add_to_runtime_pallet && \ + cargo test --test new_pallet_added_to_existing_runtime diff --git a/crates/pop-cli/src/commands/add/pallet_config_type.rs b/crates/pop-cli/src/commands/add/pallet_config_type.rs index 4cc5f8769..6a79fe5ee 100644 --- a/crates/pop-cli/src/commands/add/pallet_config_type.rs +++ b/crates/pop-cli/src/commands/add/pallet_config_type.rs @@ -1,8 +1,5 @@ // SPDX-License-Identifier: GPL-3.0 -#[cfg(test)] -mod tests; - mod common_types; use crate::{ diff --git a/crates/pop-cli/src/commands/add/runtime_pallet.rs b/crates/pop-cli/src/commands/add/runtime_pallet.rs index 7497bebce..5f4b38a73 100644 --- a/crates/pop-cli/src/commands/add/runtime_pallet.rs +++ b/crates/pop-cli/src/commands/add/runtime_pallet.rs @@ -1,8 +1,5 @@ // SPDX-License-Identifier: GPL-3.0 -#[cfg(test)] -mod tests; - use crate::{ cli::{traits::Cli as _, Cli}, multiselect_pick, diff --git a/crates/pop-cli/src/commands/new/pallet.rs b/crates/pop-cli/src/commands/new/pallet.rs index 94caa2efe..db0fb8a30 100644 --- a/crates/pop-cli/src/commands/new/pallet.rs +++ b/crates/pop-cli/src/commands/new/pallet.rs @@ -1,8 +1,5 @@ // SPDX-License-Identifier: GPL-3.0 -#[cfg(test)] -mod tests; - use crate::{ cli::{traits::Cli as _, Cli}, multiselect_pick, diff --git a/crates/pop-cli/src/commands/new/pallet/tests.rs b/crates/pop-cli/tests/new_pallet_added_to_existing_runtime.rs similarity index 100% rename from crates/pop-cli/src/commands/new/pallet/tests.rs rename to crates/pop-cli/tests/new_pallet_added_to_existing_runtime.rs diff --git a/crates/pop-cli/src/commands/add/pallet_config_type/tests.rs b/crates/pop-cli/tests/pop_add_to_pallet_config_type.rs similarity index 100% rename from crates/pop-cli/src/commands/add/pallet_config_type/tests.rs rename to crates/pop-cli/tests/pop_add_to_pallet_config_type.rs diff --git a/crates/pop-cli/src/commands/add/runtime_pallet/tests.rs b/crates/pop-cli/tests/pop_add_to_runtime_pallet.rs similarity index 100% rename from crates/pop-cli/src/commands/add/runtime_pallet/tests.rs rename to crates/pop-cli/tests/pop_add_to_runtime_pallet.rs From 05313e1ff3cef535e4864c51ae1c33fbcca4c9e8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1s=20Senovilla=20Polo?= Date: Thu, 27 Mar 2025 15:44:16 +0100 Subject: [PATCH 42/46] Modify construct_runtme add pallet test; unparsing an AST sometimes returns an unexpected fmt --- .../tests/pop_add_to_runtime_pallet.rs | 31 ++++--------------- 1 file changed, 6 insertions(+), 25 deletions(-) diff --git a/crates/pop-cli/tests/pop_add_to_runtime_pallet.rs b/crates/pop-cli/tests/pop_add_to_runtime_pallet.rs index 7a48d1d80..7d820d697 100644 --- a/crates/pop-cli/tests/pop_add_to_runtime_pallet.rs +++ b/crates/pop-cli/tests/pop_add_to_runtime_pallet.rs @@ -157,37 +157,13 @@ fn pop_add_to_runtime_pallet_construct_runtime_specified_impl_path_works() { let runtime_lib_content_after = std::fs::read_to_string(&runtime_lib_path).unwrap(); let manifest_content_after = std::fs::read_to_string(&manifest_path).unwrap(); - let runtime_lib_diff = - TextDiff::from_lines(&runtime_lib_content_before, &runtime_lib_content_after); let manifest_diff = TextDiff::from_lines(&manifest_content_before, &manifest_content_after); - let expected_inserted_lines_runtime_lib = vec![ - "use crate::Balances;\n", - "parameter_types! {\n", - " pub Schedule : pallet_contracts::Schedule < Runtime > = Default::default();\n", - "}\n", - "\n", - "#[derive_impl(pallet_contracts::config_preludes::TestDefaultConfig)]\n", - "impl pallet_contracts::Config for Runtime {\n", - " type CallStack = Schedule;\n", - " type Currency = Balances;\n", - " type Schedule = [pallet_contracts::Frame; 5];\n", - "}\n", - ]; let expected_inserted_lines_manifest = vec!["pallet-contracts = { version = \"27.0.0\", default-features = false }\n"]; - let mut inserted_lines_runtime_lib = Vec::with_capacity(3); let mut inserted_lines_manifest = Vec::with_capacity(1); - for change in runtime_lib_diff.iter_all_changes() { - match change.tag() { - ChangeTag::Delete => panic!("no deletion expected"), - ChangeTag::Insert => inserted_lines_runtime_lib.push(change.value()), - _ => (), - } - } - for change in manifest_diff.iter_all_changes() { match change.tag() { ChangeTag::Delete => panic!("no deletion expected"), @@ -196,8 +172,13 @@ fn pop_add_to_runtime_pallet_construct_runtime_specified_impl_path_works() { } } - assert_eq!(expected_inserted_lines_runtime_lib, inserted_lines_runtime_lib); assert_eq!(expected_inserted_lines_manifest, inserted_lines_manifest); + + // Unparsing the AST with construct_runtime is a bit unpredictable due to the well-known issue + // of formatting a macro invocation AST, so the assertions we can do are limited. Let's just + // state that pallet_contracts have been added. + assert!(!runtime_lib_content_before.contains("pallet_contracts")); + assert!(runtime_lib_content_after.contains("pallet_contracts")); } #[test] From 5affe2cbb37fdbc45027b5669acb8e1915a89011 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1s=20Senovilla=20Polo?= Date: Thu, 27 Mar 2025 16:05:52 +0100 Subject: [PATCH 43/46] Modify construct_runtme add pallet test; unparsing an AST sometimes returns an unexpected fmt --- crates/pop-cli/tests/pop_add_to_runtime_pallet.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/crates/pop-cli/tests/pop_add_to_runtime_pallet.rs b/crates/pop-cli/tests/pop_add_to_runtime_pallet.rs index 7d820d697..3154bc3d8 100644 --- a/crates/pop-cli/tests/pop_add_to_runtime_pallet.rs +++ b/crates/pop-cli/tests/pop_add_to_runtime_pallet.rs @@ -110,7 +110,7 @@ impl pallet_contracts::Config for Runtime { } #[test] -fn pop_add_to_runtime_pallet_construct_runtime_specified_impl_path_works() { +fn pop_add_to_runtime_pallet_construct_runtime_works() { let temp = tempfile::tempdir().unwrap(); let tempdir = temp.path(); @@ -148,8 +148,6 @@ fn pop_add_to_runtime_pallet_construct_runtime_specified_impl_path_works() { "pallet", "-p", "contracts", - "--pallet-impl-path", - runtime_lib_path.to_str().unwrap(), ]) .assert() .success(); From 0fec7e0513c53545306b4bd31c4ba24ac4c60087 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1s=20Senovilla=20Polo?= Date: Thu, 27 Mar 2025 16:08:16 +0100 Subject: [PATCH 44/46] fmt --- crates/pop-cli/tests/pop_add_to_runtime_pallet.rs | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/crates/pop-cli/tests/pop_add_to_runtime_pallet.rs b/crates/pop-cli/tests/pop_add_to_runtime_pallet.rs index 3154bc3d8..34e35b7ab 100644 --- a/crates/pop-cli/tests/pop_add_to_runtime_pallet.rs +++ b/crates/pop-cli/tests/pop_add_to_runtime_pallet.rs @@ -142,13 +142,7 @@ fn pop_add_to_runtime_pallet_construct_runtime_works() { Command::cargo_bin("pop") .unwrap() .current_dir(&test_parachain) - .args(&[ - "add-to", - "runtime", - "pallet", - "-p", - "contracts", - ]) + .args(&["add-to", "runtime", "pallet", "-p", "contracts"]) .assert() .success(); From 19775e5988981a674cf20541b21b84bc1f168678 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1s=20Senovilla=20Polo?= Date: Tue, 1 Apr 2025 19:01:01 +0200 Subject: [PATCH 45/46] Bump fs_rollback to 3.0.0 and fix related issue in pop new pallet and pop add-to runtime pallet --- Cargo.lock | 24 +++++++------------ Cargo.toml | 2 +- .../src/commands/add/runtime_pallet.rs | 16 +++++++++---- crates/pop-cli/src/commands/new/pallet.rs | 20 ++++++++++------ .../tests/pop_add_to_runtime_pallet.rs | 14 ++++++++++- 5 files changed, 47 insertions(+), 29 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 899f8b122..cb7d9870e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3565,11 +3565,12 @@ dependencies = [ [[package]] name = "fs_rollback" -version = "2.0.0" +version = "3.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3de930156615ed4eb3165da0bd81c0e5079d4e14a8a965bc56cfd7400f94f718" +checksum = "110a7d453ac4dce499ec5a8da4267007fafef274c936cc60eb56f7ba162393f7" dependencies = [ - "rustilities 1.1.0", + "rustilities", + "same-file", "tempfile", "thiserror 2.0.12", ] @@ -8157,7 +8158,7 @@ dependencies = [ "proc-macro2", "reqwest", "rust_writer", - "rustilities 2.2.0", + "rustilities", "serde", "serde_json", "similar", @@ -8196,7 +8197,7 @@ dependencies = [ "regex", "reqwest", "rust_writer", - "rustilities 2.2.0", + "rustilities", "scale-info", "serde", "serde_json", @@ -9253,7 +9254,7 @@ dependencies = [ "proc-macro2", "regex", "rust_writer_proc", - "rustilities 2.2.0", + "rustilities", "syn 2.0.100", "thiserror 2.0.12", ] @@ -9266,7 +9267,7 @@ checksum = "54abd3b6b8f7e68143a45c862405827fc453433e46c5d892d59421607bea8074" dependencies = [ "proc-macro2", "quote", - "rustilities 2.2.0", + "rustilities", "syn 2.0.100", ] @@ -9312,15 +9313,6 @@ dependencies = [ "nom", ] -[[package]] -name = "rustilities" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bfbd7c1a4f912953f84295e1a6119d3800d87a3555454241fbdaa1f48cfe344" -dependencies = [ - "thiserror 2.0.12", -] - [[package]] name = "rustilities" version = "2.2.0" diff --git a/Cargo.toml b/Cargo.toml index ea6bf293f..bde62ae68 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -34,7 +34,7 @@ dirs = "5.0" duct = "0.13" env_logger = "0.11.7" flate2 = "1.0.30" -fs_rollback = "2.0.0" +fs_rollback = "3.0.0" git2 = { version = "0.18", features = ["vendored-openssl"] } glob = "0.3.1" log = "0.4.20" diff --git a/crates/pop-cli/src/commands/add/runtime_pallet.rs b/crates/pop-cli/src/commands/add/runtime_pallet.rs index 5f4b38a73..4dd345c39 100644 --- a/crates/pop-cli/src/commands/add/runtime_pallet.rs +++ b/crates/pop-cli/src/commands/add/runtime_pallet.rs @@ -107,7 +107,12 @@ impl AddPalletCommand { rollback.note_file(&runtime_lib_path)?; rollback.note_file(&runtime_manifest)?; if let Some(ref pallet_impl_path) = self.pallet_impl_path { - rollback.note_file(pallet_impl_path)?; + // The impl path may be the runtime lib, so the path may be already noted. + match rollback.note_file(pallet_impl_path) { + Ok(()) => (), + Err(fs_rollback::Error::AlreadyNoted(_)) => (), + Err(err) => return Err(err.into()), + } } for (index, pallet) in pallets.iter().enumerate() { @@ -117,9 +122,12 @@ impl AddPalletCommand { let pallet_config_path = &precomputed_pallet_config_paths[index]; let roll_pallet_impl_path = match self.pallet_impl_path { - Some(ref pallet_impl_path) => rollback - .get_noted_file(pallet_impl_path) - .expect("The file has been noted above;qed;"), + // specified impl path, so get it. + Some(ref pallet_impl_path) => rollback.get_noted_file(pallet_impl_path).unwrap_or( + rollback + .get_noted_file(&runtime_lib_path) + .expect("The file has been noted above;qed;"), + ), None => { rollback = rust_writer_helpers::compute_new_pallet_impl_path( rollback, diff --git a/crates/pop-cli/src/commands/new/pallet.rs b/crates/pop-cli/src/commands/new/pallet.rs index db0fb8a30..a37ce6a7a 100644 --- a/crates/pop-cli/src/commands/new/pallet.rs +++ b/crates/pop-cli/src/commands/new/pallet.rs @@ -239,17 +239,23 @@ impl NewPalletCommand { let mut rollback = Rollback::default(); - if let Some(ref pallet_impl_path) = self.pallet_impl_path { - rollback.note_file(pallet_impl_path)?; - } - rollback.note_file(&runtime_manifest)?; rollback.note_file(&runtime_lib_path)?; + if let Some(ref pallet_impl_path) = self.pallet_impl_path { + // The impl path may be the runtime lib, so the path may be already noted. + match rollback.note_file(pallet_impl_path) { + Ok(()) => (), + Err(fs_rollback::Error::AlreadyNoted(_)) => (), + Err(err) => return Err(err.into()), + } + } let roll_pallet_impl_path = match self.pallet_impl_path { - Some(ref pallet_impl_path) => rollback - .get_noted_file(&pallet_impl_path) - .expect("The file has been noted above;qed;"), + Some(ref pallet_impl_path) => rollback.get_noted_file(pallet_impl_path).unwrap_or( + rollback + .get_noted_file(&runtime_lib_path) + .expect("The file has been noted above;qed;"), + ), None => { rollback = rust_writer_helpers::compute_new_pallet_impl_path( rollback, diff --git a/crates/pop-cli/tests/pop_add_to_runtime_pallet.rs b/crates/pop-cli/tests/pop_add_to_runtime_pallet.rs index 34e35b7ab..0e0cf0921 100644 --- a/crates/pop-cli/tests/pop_add_to_runtime_pallet.rs +++ b/crates/pop-cli/tests/pop_add_to_runtime_pallet.rs @@ -142,7 +142,15 @@ fn pop_add_to_runtime_pallet_construct_runtime_works() { Command::cargo_bin("pop") .unwrap() .current_dir(&test_parachain) - .args(&["add-to", "runtime", "pallet", "-p", "contracts"]) + .args(&[ + "add-to", + "runtime", + "pallet", + "-p", + "contracts", + "--pallet-impl-path", + runtime_lib_path.to_str().unwrap(), + ]) .assert() .success(); @@ -169,8 +177,12 @@ fn pop_add_to_runtime_pallet_construct_runtime_works() { // Unparsing the AST with construct_runtime is a bit unpredictable due to the well-known issue // of formatting a macro invocation AST, so the assertions we can do are limited. Let's just // state that pallet_contracts have been added. + assert!(!runtime_lib_content_before.contains("Contracts")); + assert!(runtime_lib_content_after.contains("Contracts")); assert!(!runtime_lib_content_before.contains("pallet_contracts")); assert!(runtime_lib_content_after.contains("pallet_contracts")); + assert!(!runtime_lib_content_before.contains("type CallStack = Schedule;")); + assert!(runtime_lib_content_after.contains("type CallStack = Schedule;")); } #[test] From c2749017bd1eecc757b2bb4f1bf161b3ca0bf05c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1s=20Senovilla=20Polo?= <117524919+tsenovilla@users.noreply.github.com> Date: Thu, 3 Apr 2025 12:18:09 +0200 Subject: [PATCH 46/46] Suggested change Co-authored-by: Tin Chung <56880684+chungquantin@users.noreply.github.com> --- crates/pop-cli/src/commands/new/pallet.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/pop-cli/src/commands/new/pallet.rs b/crates/pop-cli/src/commands/new/pallet.rs index a37ce6a7a..1e7ee1a38 100644 --- a/crates/pop-cli/src/commands/new/pallet.rs +++ b/crates/pop-cli/src/commands/new/pallet.rs @@ -64,7 +64,7 @@ pub struct NewPalletCommand { pub(crate) description: Option, #[arg( long, - help = "If your pallet is created in a workspace containing a runtime, Pop-Cli will place the impl blocks for your pallets' Config traits inside a dedicated file under configs directory. Use this argument to point to other path." + help = "If your pallet is created within a workspace that includes a runtime, the `impl` blocks will be generated for your pallet's `Config` traits in a dedicated file under the configs directory. Use this argument to specify a different path." )] pub(crate) pallet_impl_path: Option, #[command(subcommand)]