From a2ccbde9815ce7888a00b1a70b44942daa81ebb7 Mon Sep 17 00:00:00 2001 From: lambda-0x <0xlambda@protonmail.com> Date: Sat, 5 Aug 2023 14:48:44 +0530 Subject: [PATCH] refactor: make `DojoMetadata` to handle metadata specific to dojo easier (#707) --- crates/sozo/src/commands/auth.rs | 8 +- crates/sozo/src/commands/component.rs | 8 +- crates/sozo/src/commands/events.rs | 8 +- crates/sozo/src/commands/execute.rs | 8 +- crates/sozo/src/commands/migrate.rs | 11 +- crates/sozo/src/commands/options/account.rs | 29 ++--- crates/sozo/src/commands/options/mod.rs | 109 ++++++++++++++++++- crates/sozo/src/commands/options/starknet.rs | 17 ++- crates/sozo/src/commands/options/world.rs | 16 +-- crates/sozo/src/commands/register.rs | 8 +- crates/sozo/src/commands/system.rs | 8 +- crates/sozo/src/ops/auth.rs | 5 +- crates/sozo/src/ops/component.rs | 5 +- crates/sozo/src/ops/events.rs | 4 +- crates/sozo/src/ops/execute.rs | 5 +- crates/sozo/src/ops/migration/mod.rs | 14 +-- crates/sozo/src/ops/register.rs | 5 +- crates/sozo/src/ops/system.rs | 5 +- 18 files changed, 169 insertions(+), 104 deletions(-) diff --git a/crates/sozo/src/commands/auth.rs b/crates/sozo/src/commands/auth.rs index 703ddc8608..808c75d3a2 100644 --- a/crates/sozo/src/commands/auth.rs +++ b/crates/sozo/src/commands/auth.rs @@ -39,13 +39,9 @@ impl AuthArgs { pub fn run(self, config: &Config) -> Result<()> { let env_metadata = if config.manifest_path().exists() { let ws = scarb::ops::read_workspace(config.manifest_path(), config)?; - let env_metadata = dojo_metadata_from_workspace(&ws) - .and_then(|dojo_metadata| dojo_metadata.get("env").cloned()); - env_metadata - .as_ref() - .and_then(|env_metadata| env_metadata.get(ws.config().profile().as_str()).cloned()) - .or(env_metadata) + // TODO: Check the updated scarb way to read profile specific values + dojo_metadata_from_workspace(&ws).and_then(|inner| inner.env().cloned()) } else { None }; diff --git a/crates/sozo/src/commands/component.rs b/crates/sozo/src/commands/component.rs index 1d9a6ed6df..d792cfd4db 100644 --- a/crates/sozo/src/commands/component.rs +++ b/crates/sozo/src/commands/component.rs @@ -66,13 +66,9 @@ impl ComponentArgs { pub fn run(self, config: &Config) -> Result<()> { let env_metadata = if config.manifest_path().exists() { let ws = scarb::ops::read_workspace(config.manifest_path(), config)?; - let env_metadata = dojo_metadata_from_workspace(&ws) - .and_then(|dojo_metadata| dojo_metadata.get("env").cloned()); - env_metadata - .as_ref() - .and_then(|env_metadata| env_metadata.get(ws.config().profile().as_str()).cloned()) - .or(env_metadata) + // TODO: Check the updated scarb way to read profile specific values + dojo_metadata_from_workspace(&ws).and_then(|inner| inner.env().cloned()) } else { None }; diff --git a/crates/sozo/src/commands/events.rs b/crates/sozo/src/commands/events.rs index 63dae94ee7..6541c93750 100644 --- a/crates/sozo/src/commands/events.rs +++ b/crates/sozo/src/commands/events.rs @@ -40,13 +40,9 @@ impl EventsArgs { pub fn run(self, config: &Config) -> Result<()> { let env_metadata = if config.manifest_path().exists() { let ws = scarb::ops::read_workspace(config.manifest_path(), config)?; - let env_metadata = dojo_metadata_from_workspace(&ws) - .and_then(|dojo_metadata| dojo_metadata.get("env").cloned()); - env_metadata - .as_ref() - .and_then(|env_metadata| env_metadata.get(ws.config().profile().as_str()).cloned()) - .or(env_metadata) + // TODO: Check the updated scarb way to read profile specific values + dojo_metadata_from_workspace(&ws).and_then(|inner| inner.env().cloned()) } else { None }; diff --git a/crates/sozo/src/commands/execute.rs b/crates/sozo/src/commands/execute.rs index 29e1112341..c595bf537a 100644 --- a/crates/sozo/src/commands/execute.rs +++ b/crates/sozo/src/commands/execute.rs @@ -35,13 +35,9 @@ impl ExecuteArgs { pub fn run(self, config: &Config) -> Result<()> { let env_metadata = if config.manifest_path().exists() { let ws = scarb::ops::read_workspace(config.manifest_path(), config)?; - let env_metadata = dojo_metadata_from_workspace(&ws) - .and_then(|dojo_metadata| dojo_metadata.get("env").cloned()); - env_metadata - .as_ref() - .and_then(|env_metadata| env_metadata.get(ws.config().profile().as_str()).cloned()) - .or(env_metadata) + // TODO: Check the updated scarb way to read profile specific values + dojo_metadata_from_workspace(&ws).and_then(|inner| inner.env().cloned()) } else { None }; diff --git a/crates/sozo/src/commands/migrate.rs b/crates/sozo/src/commands/migrate.rs index b8bd97fca8..56ae59c122 100644 --- a/crates/sozo/src/commands/migrate.rs +++ b/crates/sozo/src/commands/migrate.rs @@ -42,15 +42,8 @@ impl MigrateArgs { scarb::ops::compile(packages, &ws)?; } - let mut env_metadata = dojo_metadata_from_workspace(&ws) - .and_then(|dojo_metadata| dojo_metadata.get("env").cloned()); - - // If there is an environment-specific metadata, use that, otherwise use the - // workspace's default environment metadata. - env_metadata = env_metadata - .as_ref() - .and_then(|env_metadata| env_metadata.get(ws.config().profile().as_str()).cloned()) - .or(env_metadata); + let env_metadata = dojo_metadata_from_workspace(&ws).and_then(|inner| inner.env().cloned()); + // TODO: Check the updated scarb way to read profile specific values ws.config().tokio_handle().block_on(migration::execute( self, diff --git a/crates/sozo/src/commands/options/account.rs b/crates/sozo/src/commands/options/account.rs index 9a8b9f942c..2743991fd4 100644 --- a/crates/sozo/src/commands/options/account.rs +++ b/crates/sozo/src/commands/options/account.rs @@ -6,7 +6,8 @@ use starknet::accounts::SingleOwnerAccount; use starknet::core::types::FieldElement; use starknet::providers::Provider; use starknet::signers::{LocalWallet, SigningKey}; -use toml::Value; + +use super::Environment; #[derive(Debug, Args)] #[command(next_help_heading = "Account options")] @@ -39,7 +40,7 @@ impl AccountOptions { pub async fn account

( &self, provider: P, - env_metadata: Option<&Value>, + env_metadata: Option<&Environment>, ) -> Result> where P: Provider + Send + Sync + 'static, @@ -53,13 +54,11 @@ impl AccountOptions { Ok(SingleOwnerAccount::new(provider, signer, account_address, chain_id)) } - fn signer(&self, env_metadata: Option<&Value>) -> Result { + fn signer(&self, env_metadata: Option<&Environment>) -> Result { if let Some(private_key) = self .private_key .as_deref() - .or_else(|| { - env_metadata.and_then(|env| env.get("private_key").and_then(|v| v.as_str())) - }) + .or_else(|| env_metadata.and_then(|env| env.private_key())) .or(std::env::var("DOJO_PRIVATE_KEY").ok().as_deref()) { return Ok(LocalWallet::from_signing_key(SigningKey::from_secret_scalar( @@ -71,10 +70,7 @@ impl AccountOptions { if let Some(password) = self .keystore_password .as_deref() - .or_else(|| { - env_metadata - .and_then(|env| env.get("keystore_password").and_then(|v| v.as_str())) - }) + .or_else(|| env_metadata.and_then(|env| env.keystore_password())) .or(std::env::var("DOJO_KEYSTORE_PASSWORD").ok().as_deref()) { return Ok(LocalWallet::from_signing_key(SigningKey::from_keystore( @@ -91,15 +87,14 @@ impl AccountOptions { )) } - fn account_address(&self, env_metadata: Option<&Value>) -> Result { + fn account_address(&self, env_metadata: Option<&Environment>) -> Result { if let Some(address) = self.account_address { Ok(address) - } else if let Some(address) = env_metadata.and_then(|env| { - env.get("account_address") - .and_then(|v| v.as_str().map(|s| s.to_string())) - .or(std::env::var("DOJO_ACCOUNT_ADDRESS").ok()) - }) { - Ok(FieldElement::from_str(&address)?) + } else if let Some(address) = env_metadata + .and_then(|env| env.account_address()) + .or(std::env::var("DOJO_ACCOUNT_ADDRESS").ok().as_deref()) + { + Ok(FieldElement::from_str(address)?) } else { Err(anyhow!( "Could not find account address. Please specify it with --account-address or in \ diff --git a/crates/sozo/src/commands/options/mod.rs b/crates/sozo/src/commands/options/mod.rs index e4d81eaa7a..79237c1111 100644 --- a/crates/sozo/src/commands/options/mod.rs +++ b/crates/sozo/src/commands/options/mod.rs @@ -1,10 +1,111 @@ -use scarb::core::Workspace; -use toml::Value; +use scarb::core::{ManifestMetadata, Workspace}; +use serde::Deserialize; pub mod account; pub mod starknet; pub mod world; -pub(super) fn dojo_metadata_from_workspace(ws: &Workspace<'_>) -> Option { - ws.current_package().ok()?.manifest.metadata.tool_metadata.as_ref()?.get("dojo").cloned() +pub(crate) fn dojo_metadata_from_workspace(ws: &Workspace<'_>) -> Option { + Some(ws.current_package().ok()?.manifest.metadata.dojo()) +} + +#[derive(Default, Deserialize, Debug, Clone)] +pub(crate) struct DojoMetadata { + env: Option, +} + +#[derive(Default, Deserialize, Clone, Debug)] +pub struct Environment { + rpc_url: Option, + account_address: Option, + private_key: Option, + keystore_path: Option, + keystore_password: Option, + world_address: Option, +} + +impl Environment { + pub fn world_address(&self) -> Option<&str> { + self.world_address.as_deref() + } + + pub fn rpc_url(&self) -> Option<&str> { + self.rpc_url.as_deref() + } + + pub fn account_address(&self) -> Option<&str> { + self.account_address.as_deref() + } + + pub fn private_key(&self) -> Option<&str> { + self.private_key.as_deref() + } + + #[allow(dead_code)] + pub fn keystore_path(&self) -> Option<&str> { + self.keystore_path.as_deref() + } + + pub fn keystore_password(&self) -> Option<&str> { + self.keystore_password.as_deref() + } +} + +impl DojoMetadata { + pub fn env(&self) -> Option<&Environment> { + self.env.as_ref() + } +} +trait MetadataExt { + fn dojo(&self) -> DojoMetadata; +} + +impl MetadataExt for ManifestMetadata { + fn dojo(&self) -> DojoMetadata { + self.tool_metadata + .as_ref() + .and_then(|e| e.get("dojo")) + .cloned() + .map(|v| v.try_into::().unwrap_or_default()) + .unwrap_or_default() + } +} + +#[cfg(test)] +mod test { + use super::*; + #[test] + fn check_deserialization() { + let metadata: DojoMetadata = toml::from_str( + r#" +[env] +rpc_url = "http://localhost:5050/" +account_address = "0x03ee9e18edc71a6df30ac3aca2e0b02a198fbce19b7480a63a0d71cbd76652e0" +private_key = "0x0300001800000000300000180000000000030000000000003006001800006600" +keystore_path = "test/" +keystore_password = "dojo" +world_address = "0x0248cacaeac64c45be0c19ee8727e0bb86623ca7fa3f0d431a6c55e200697e5a" + "#, + ) + .unwrap(); + + assert!(metadata.env.is_some()); + let env = metadata.env.unwrap(); + + assert_eq!(env.rpc_url(), Some("http://localhost:5050/")); + assert_eq!( + env.account_address(), + Some("0x03ee9e18edc71a6df30ac3aca2e0b02a198fbce19b7480a63a0d71cbd76652e0") + ); + assert_eq!( + env.private_key(), + Some("0x0300001800000000300000180000000000030000000000003006001800006600") + ); + assert_eq!(env.keystore_path(), Some("test/")); + assert_eq!(env.keystore_password(), Some("dojo")); + assert_eq!( + env.world_address(), + Some("0x0248cacaeac64c45be0c19ee8727e0bb86623ca7fa3f0d431a6c55e200697e5a") + ); + } } diff --git a/crates/sozo/src/commands/options/starknet.rs b/crates/sozo/src/commands/options/starknet.rs index 9935343434..9c65d18788 100644 --- a/crates/sozo/src/commands/options/starknet.rs +++ b/crates/sozo/src/commands/options/starknet.rs @@ -2,9 +2,10 @@ use anyhow::{anyhow, Result}; use clap::Args; use starknet::providers::jsonrpc::HttpTransport; use starknet::providers::JsonRpcClient; -use toml::Value; use url::Url; +use super::Environment; + #[derive(Debug, Args)] #[command(next_help_heading = "Starknet options")] pub struct StarknetOptions { @@ -15,14 +16,18 @@ pub struct StarknetOptions { } impl StarknetOptions { - pub fn provider(&self, env_metadata: Option<&Value>) -> Result> { + pub fn provider( + &self, + env_metadata: Option<&Environment>, + ) -> Result> { let url = if let Some(url) = self.rpc_url.clone() { Some(url) - } else if let Some(url) = env_metadata - .and_then(|env| env.get("rpc_url").and_then(|v| v.as_str().map(|s| s.to_string()))) - .or(std::env::var("STARKNET_RPC_URL").ok()) + } else if let Some(url) = + env_metadata + .and_then(|env| env.rpc_url()) + .or(std::env::var("STARKNET_RPC_URL").ok().as_deref()) { - Some(Url::parse(&url)?) + Some(Url::parse(url)?) } else { None }; diff --git a/crates/sozo/src/commands/options/world.rs b/crates/sozo/src/commands/options/world.rs index 73c3233506..85744185ef 100644 --- a/crates/sozo/src/commands/options/world.rs +++ b/crates/sozo/src/commands/options/world.rs @@ -3,7 +3,8 @@ use std::str::FromStr; use anyhow::{anyhow, Result}; use clap::Args; use starknet::core::types::FieldElement; -use toml::Value; + +use super::Environment; #[derive(Debug, Args)] #[command(next_help_heading = "World options")] @@ -14,15 +15,14 @@ pub struct WorldOptions { } impl WorldOptions { - pub fn address(&self, env_metadata: Option<&Value>) -> Result { + pub fn address(&self, env_metadata: Option<&Environment>) -> Result { if let Some(world_address) = self.world_address { Ok(world_address) - } else if let Some(world_address) = env_metadata.and_then(|env| { - env.get("world_address") - .and_then(|v| v.as_str().map(|s| s.to_string())) - .or(std::env::var("DOJO_WORLD_ADDRESS").ok()) - }) { - Ok(FieldElement::from_str(&world_address)?) + } else if let Some(world_address) = env_metadata + .and_then(|env| env.world_address()) + .or(std::env::var("DOJO_WORLD_ADDRESS").ok().as_deref()) + { + Ok(FieldElement::from_str(world_address)?) } else { Err(anyhow!( "Could not find World address. Please specify it with --world or in the world \ diff --git a/crates/sozo/src/commands/register.rs b/crates/sozo/src/commands/register.rs index 102192704d..2b0e9c305d 100644 --- a/crates/sozo/src/commands/register.rs +++ b/crates/sozo/src/commands/register.rs @@ -58,13 +58,9 @@ impl RegisterArgs { pub fn run(self, config: &Config) -> Result<()> { let env_metadata = if config.manifest_path().exists() { let ws = scarb::ops::read_workspace(config.manifest_path(), config)?; - let env_metadata = dojo_metadata_from_workspace(&ws) - .and_then(|dojo_metadata| dojo_metadata.get("env").cloned()); - env_metadata - .as_ref() - .and_then(|env_metadata| env_metadata.get(ws.config().profile().as_str()).cloned()) - .or(env_metadata) + // TODO: Check the updated scarb way to read profile specific values + dojo_metadata_from_workspace(&ws).and_then(|inner| inner.env().cloned()) } else { None }; diff --git a/crates/sozo/src/commands/system.rs b/crates/sozo/src/commands/system.rs index dd698b590c..ee05d874ff 100644 --- a/crates/sozo/src/commands/system.rs +++ b/crates/sozo/src/commands/system.rs @@ -49,13 +49,9 @@ impl SystemArgs { pub fn run(self, config: &Config) -> Result<()> { let env_metadata = if config.manifest_path().exists() { let ws = scarb::ops::read_workspace(config.manifest_path(), config)?; - let env_metadata = dojo_metadata_from_workspace(&ws) - .and_then(|dojo_metadata| dojo_metadata.get("env").cloned()); - env_metadata - .as_ref() - .and_then(|env_metadata| env_metadata.get(ws.config().profile().as_str()).cloned()) - .or(env_metadata) + // TODO: Check the updated scarb way to read profile specific values + dojo_metadata_from_workspace(&ws).and_then(|inner| inner.env().cloned()) } else { None }; diff --git a/crates/sozo/src/ops/auth.rs b/crates/sozo/src/ops/auth.rs index aa46fc83b0..979ca4f14a 100644 --- a/crates/sozo/src/ops/auth.rs +++ b/crates/sozo/src/ops/auth.rs @@ -1,10 +1,9 @@ use anyhow::{Context, Result}; use dojo_client::contract::world::WorldContract; -use toml::Value; -use crate::commands::auth::AuthCommand; +use crate::commands::{auth::AuthCommand, options::Environment}; -pub async fn execute(command: AuthCommand, env_metadata: Option) -> Result<()> { +pub async fn execute(command: AuthCommand, env_metadata: Option) -> Result<()> { match command { AuthCommand::Writer { component, system, world, starknet, account } => { let world_address = world.address(env_metadata.as_ref())?; diff --git a/crates/sozo/src/ops/component.rs b/crates/sozo/src/ops/component.rs index d2aa75a109..9383b02e34 100644 --- a/crates/sozo/src/ops/component.rs +++ b/crates/sozo/src/ops/component.rs @@ -1,11 +1,10 @@ use anyhow::Result; use dojo_client::contract::world::WorldContractReader; use starknet::core::types::{BlockId, BlockTag}; -use toml::Value; -use crate::commands::component::ComponentCommands; +use crate::commands::{component::ComponentCommands, options::Environment}; -pub async fn execute(command: ComponentCommands, env_metadata: Option) -> Result<()> { +pub async fn execute(command: ComponentCommands, env_metadata: Option) -> Result<()> { match command { ComponentCommands::Get { name, world, starknet } => { let world_address = world.address(env_metadata.as_ref())?; diff --git a/crates/sozo/src/ops/events.rs b/crates/sozo/src/ops/events.rs index 838211d6d1..2155b93a09 100644 --- a/crates/sozo/src/ops/events.rs +++ b/crates/sozo/src/ops/events.rs @@ -2,11 +2,11 @@ use anyhow::Result; use starknet::core::types::{BlockId, EventFilter}; use starknet::core::utils::starknet_keccak; use starknet::providers::Provider; -use toml::Value; use crate::commands::events::EventsArgs; +use crate::commands::options::Environment; -pub async fn execute(args: EventsArgs, env_metadata: Option) -> Result<()> { +pub async fn execute(args: EventsArgs, env_metadata: Option) -> Result<()> { let EventsArgs { chunk_size, starknet, diff --git a/crates/sozo/src/ops/execute.rs b/crates/sozo/src/ops/execute.rs index 017c34cc95..5c2bb89667 100644 --- a/crates/sozo/src/ops/execute.rs +++ b/crates/sozo/src/ops/execute.rs @@ -1,10 +1,9 @@ use anyhow::{Context, Result}; use dojo_client::contract::world::WorldContract; -use toml::Value; -use crate::commands::execute::ExecuteArgs; +use crate::commands::{execute::ExecuteArgs, options::Environment}; -pub async fn execute(args: ExecuteArgs, env_metadata: Option) -> Result<()> { +pub async fn execute(args: ExecuteArgs, env_metadata: Option) -> Result<()> { let ExecuteArgs { system, calldata, world, starknet, account } = args; let world_address = world.address(env_metadata.as_ref())?; diff --git a/crates/sozo/src/ops/migration/mod.rs b/crates/sozo/src/ops/migration/mod.rs index 203074d3ab..ba4522fa41 100644 --- a/crates/sozo/src/ops/migration/mod.rs +++ b/crates/sozo/src/ops/migration/mod.rs @@ -14,7 +14,6 @@ use starknet::core::types::{ }; use starknet::core::utils::cairo_short_string_to_felt; use starknet::providers::jsonrpc::HttpTransport; -use toml::Value; #[cfg(test)] #[path = "migration_test.rs"] @@ -30,10 +29,11 @@ use crate::commands::migrate::MigrateArgs; use crate::commands::options::account::AccountOptions; use crate::commands::options::starknet::StarknetOptions; use crate::commands::options::world::WorldOptions; +use crate::commands::options::Environment; pub async fn execute( args: MigrateArgs, - env_metadata: Option, + env_metadata: Option, target_dir: U, config: &Config, ) -> Result<()> @@ -45,7 +45,7 @@ where // Setup account for migration and fetch world address if it exists. let (world_address, account) = - setup_env(account, starknet, world, env_metadata, config).await?; + setup_env(account, starknet, world, env_metadata.as_ref(), config).await?; // Load local and remote World manifests. @@ -89,14 +89,14 @@ async fn setup_env( account: AccountOptions, starknet: StarknetOptions, world: WorldOptions, - env_metadata: Option, + env_metadata: Option<&Environment>, config: &Config, ) -> Result<(Option, SingleOwnerAccount, LocalWallet>)> { - let world_address = world.address(env_metadata.as_ref()).ok(); + let world_address = world.address(env_metadata).ok(); let account = { - let provider = starknet.provider(env_metadata.as_ref())?; - let mut account = account.account(provider, env_metadata.as_ref()).await?; + let provider = starknet.provider(env_metadata)?; + let mut account = account.account(provider, env_metadata).await?; account.set_block_id(BlockId::Tag(BlockTag::Pending)); let address = account.address(); diff --git a/crates/sozo/src/ops/register.rs b/crates/sozo/src/ops/register.rs index 8be4aad354..d33a3b4c9a 100644 --- a/crates/sozo/src/ops/register.rs +++ b/crates/sozo/src/ops/register.rs @@ -1,10 +1,9 @@ use anyhow::{Context, Result}; use dojo_client::contract::world::WorldContract; -use toml::Value; -use crate::commands::register::RegisterCommand; +use crate::commands::{options::Environment, register::RegisterCommand}; -pub async fn execute(command: RegisterCommand, env_metadata: Option) -> Result<()> { +pub async fn execute(command: RegisterCommand, env_metadata: Option) -> Result<()> { match command { RegisterCommand::Component { components, world, starknet, account } => { let world_address = world.address(env_metadata.as_ref())?; diff --git a/crates/sozo/src/ops/system.rs b/crates/sozo/src/ops/system.rs index 81559b55b6..30a4e81ed8 100644 --- a/crates/sozo/src/ops/system.rs +++ b/crates/sozo/src/ops/system.rs @@ -1,12 +1,11 @@ use anyhow::Result; use dojo_client::contract::world::WorldContractReader; use starknet::core::types::{BlockId, BlockTag}; -use toml::Value; use yansi::Paint; -use crate::commands::system::SystemCommands; +use crate::commands::{options::Environment, system::SystemCommands}; -pub async fn execute(command: SystemCommands, env_metadata: Option) -> Result<()> { +pub async fn execute(command: SystemCommands, env_metadata: Option) -> Result<()> { match command { SystemCommands::Get { name, world, starknet } => { let world_address = world.address(env_metadata.as_ref())?;