diff --git a/crates/dojo-cli/src/migrate.rs b/crates/dojo-cli/src/migrate.rs index 7e82627098..05a74b145b 100644 --- a/crates/dojo-cli/src/migrate.rs +++ b/crates/dojo-cli/src/migrate.rs @@ -1,23 +1,82 @@ -use std::env::current_dir; +use std::env::{self, current_dir}; +use std::fmt::Display; use std::fs; -use std::path::PathBuf; use anyhow::Context; use cairo_lang_starknet::casm_contract_class::CasmContractClass; +use camino::Utf8PathBuf; use clap::Args; use comfy_table::Table; +use dojo_project::WorldConfig; +use scarb::core::Config; +use scarb::ops; +use scarb::ui::Verbosity; use starknet::core::types::contract::CompiledClass; use starknet::core::types::FieldElement; #[derive(Args)] pub struct MigrateArgs { #[clap(help = "Source directory")] - path: Option, + path: Option, #[clap(short, long, help = "Perform a dry run and outputs the plan to be executed")] plan: bool, } +pub async fn run(args: MigrateArgs) -> anyhow::Result<()> { + let source_dir = match args.path { + Some(path) => { + if path.is_absolute() { + path + } else { + let mut current_path = current_dir().unwrap(); + current_path.push(path); + Utf8PathBuf::from_path_buf(current_path).unwrap() + } + } + None => Utf8PathBuf::from_path_buf(current_dir().unwrap()).unwrap(), + }; + + let world = World::from_path(source_dir.clone())?; + + println!("{world}"); + + Ok(()) +} + +struct World { + address: Option, + modules: Modules, +} + +impl World { + fn from_path(source_dir: Utf8PathBuf) -> anyhow::Result { + let manifest_path = source_dir.join("Scarb.toml"); + let config = Config::builder(manifest_path) + .ui_verbosity(Verbosity::Verbose) + .log_filter_directive(env::var_os("SCARB_LOG")) + .build() + .unwrap(); + let ws = ops::read_workspace(config.manifest_path(), &config).unwrap_or_else(|err| { + eprintln!("error: {}", err); + std::process::exit(1); + }); + let world_config = + WorldConfig::from_workspace(&ws).unwrap_or_else(|_| WorldConfig::default()); + + let modules = Modules::from_path(source_dir.clone())?; + + Ok(World { address: world_config.address, modules }) + } +} + +impl Display for World { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + writeln!(f, "World Address: 0x{:x}", self.address.unwrap())?; + writeln!(f, "{}", self.modules) + } +} + struct Module { name: String, hash: FieldElement, @@ -29,74 +88,79 @@ struct Modules { systems: Vec, } -pub async fn run(args: MigrateArgs) -> anyhow::Result<()> { - let source_dir = match args.path { - Some(path) => path, - None => current_dir().unwrap(), - }; - - let mut modules = Modules { contracts: vec![], components: vec![], systems: vec![] }; - - // Read the directory - let entries = fs::read_dir(source_dir.join("target/release")).unwrap_or_else(|error| { - panic!("Problem reading source directory: {:?}", error); - }); - - for entry in entries.flatten() { - let file_name = entry.file_name(); - let file_name_str = file_name.to_string_lossy(); - if !file_name_str.ends_with(".json") { - continue; +impl Modules { + fn from_path(source_dir: Utf8PathBuf) -> anyhow::Result { + let mut modules = Modules { contracts: vec![], components: vec![], systems: vec![] }; + + // Read the directory + let entries = fs::read_dir(source_dir.join("target/release")).unwrap_or_else(|error| { + panic!("Problem reading source directory: {:?}", error); + }); + + for entry in entries.flatten() { + let file_name = entry.file_name(); + let file_name_str = file_name.to_string_lossy(); + if !file_name_str.ends_with(".json") { + continue; + } + + let name = file_name_str.split('_').last().unwrap().to_string(); + let contract_class = serde_json::from_reader(fs::File::open(entry.path()).unwrap()) + .unwrap_or_else(|error| { + panic!("Problem parsing {} artifact: {:?}", file_name_str, error); + }); + + let casm_contract = CasmContractClass::from_contract_class(contract_class, true) + .with_context(|| "Compilation failed.")?; + let res = serde_json::to_string_pretty(&casm_contract) + .with_context(|| "Casm contract Serialization failed.")?; + + let compiled_class: CompiledClass = + serde_json::from_str(res.as_str()).unwrap_or_else(|error| { + panic!("Problem parsing {} artifact: {:?}", file_name_str, error); + }); + + let hash = compiled_class + .class_hash() + .with_context(|| "Casm contract Serialization failed.")?; + + if name.ends_with("Component.json") { + modules.components.push(Module { + name: name.strip_suffix("Component.json").unwrap().to_string(), + hash, + }); + } else if name.ends_with("System.json") { + modules.systems.push(Module { + name: name.strip_suffix("System.json").unwrap().to_string(), + hash, + }); + } else { + modules + .contracts + .push(Module { name: name.strip_suffix(".json").unwrap().to_string(), hash }); + }; } - - let name = file_name_str.split('_').last().unwrap().to_string(); - let contract_class = serde_json::from_reader(fs::File::open(entry.path()).unwrap()) - .unwrap_or_else(|error| { - panic!("Problem parsing {} artifact: {:?}", file_name_str, error); - }); - - let casm_contract = CasmContractClass::from_contract_class(contract_class, true) - .with_context(|| "Compilation failed.")?; - let res = serde_json::to_string_pretty(&casm_contract) - .with_context(|| "Casm contract Serialization failed.")?; - - let compiled_class: CompiledClass = - serde_json::from_str(res.as_str()).unwrap_or_else(|error| { - panic!("Problem parsing {} artifact: {:?}", file_name_str, error); - }); - - let hash = - compiled_class.class_hash().with_context(|| "Casm contract Serialization failed.")?; - - if name.ends_with("Component.json") { - modules.components.push(Module { - name: name.strip_suffix("Component.json").unwrap().to_string(), - hash, - }); - } else if name.ends_with("System.json") { - modules - .systems - .push(Module { name: name.strip_suffix("System.json").unwrap().to_string(), hash }); - } else { - modules - .contracts - .push(Module { name: name.strip_suffix(".json").unwrap().to_string(), hash }); - }; + Ok(modules) } +} - let mut components_table = Table::new(); - components_table.set_header(vec!["Component", "Class Hash"]); - for component in modules.components { - components_table.add_row(vec![component.name, format!("0x{:x} ", component.hash)]); - } - println!("{components_table}\n"); +impl Display for Modules { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + let mut components_table = Table::new(); + components_table.set_header(vec!["Component", "Class Hash"]); + for component in &self.components { + components_table + .add_row(vec![component.name.clone(), format!("0x{:x} ", component.hash)]); + } + writeln!(f, "{}", components_table)?; - let mut systems_table = Table::new(); - systems_table.set_header(vec!["System", "Class Hash"]); - for system in modules.systems { - systems_table.add_row(vec![system.name, format!("0x{:x} ", system.hash)]); - } - println!("{systems_table}"); + let mut systems_table = Table::new(); + systems_table.set_header(vec!["System", "Class Hash"]); + for system in &self.systems { + systems_table.add_row(vec![system.name.clone(), format!("0x{:x} ", system.hash)]); + } + writeln!(f, "{}", systems_table)?; - Ok(()) + Ok(()) + } } diff --git a/crates/dojo-lang/src/component.rs b/crates/dojo-lang/src/component.rs index ec063c86d8..99956ead08 100644 --- a/crates/dojo-lang/src/component.rs +++ b/crates/dojo-lang/src/component.rs @@ -8,10 +8,9 @@ use cairo_lang_semantic::patcher::{PatchBuilder, RewriteNode}; use cairo_lang_semantic::plugin::DynPluginAuxData; use cairo_lang_syntax::node::db::SyntaxGroup; use cairo_lang_syntax::node::{ast, Terminal, TypedSyntaxNode}; -use dojo_project::WorldConfig; use smol_str::SmolStr; -use crate::plugin::{get_contract_address, DojoAuxData}; +use crate::plugin::DojoAuxData; #[cfg(test)] #[path = "component_test.rs"] @@ -205,23 +204,3 @@ pub fn find_components(db: &dyn SemanticGroup, crate_ids: &[CrateId]) -> Vec String { - // Component name to felt - let component_name_raw = path.as_syntax_node().get_text(db); - let mut component_name_parts: Vec<&str> = component_name_raw.split("::").collect(); - let component_name = component_name_parts.pop().unwrap(); - - format!( - "{:#x}", - get_contract_address( - component_name, - world_config.initializer_class_hash.unwrap_or_default(), - world_config.address.unwrap_or_default(), - ) - ) -} diff --git a/crates/dojo-project/src/lib.rs b/crates/dojo-project/src/lib.rs index 4c5251ec0d..fcaf9affca 100644 --- a/crates/dojo-project/src/lib.rs +++ b/crates/dojo-project/src/lib.rs @@ -13,7 +13,6 @@ pub enum DeserializationError { #[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Serialize, Deserialize)] pub struct WorldConfig { pub address: Option, - pub initializer_class_hash: Option, } pub struct DeploymentConfig { @@ -47,14 +46,6 @@ impl WorldConfig { world_config.address = Some(world_address); } } - - if let Some(initializer_class_hash) = dojo_metadata.get("initializer_class_hash") { - if let Some(initializer_class_hash) = initializer_class_hash.as_str() { - let initializer_class_hash = FieldElement::from_hex_be(initializer_class_hash) - .map_err(|_| DeserializationError::ParsingFieldElement)?; - world_config.initializer_class_hash = Some(initializer_class_hash); - } - } } Ok(world_config)