From 417f325ee7e5fbf9e1b669474df2ee285a647b4b Mon Sep 17 00:00:00 2001 From: Artur Michalek Date: Tue, 22 Oct 2024 14:35:53 +0200 Subject: [PATCH 1/6] Move contracts code to contract.rs --- crates/scarb-api/src/contracts.rs | 134 ++++++++++++++++++++++++++++++ crates/scarb-api/src/lib.rs | 131 ++--------------------------- 2 files changed, 141 insertions(+), 124 deletions(-) create mode 100644 crates/scarb-api/src/contracts.rs diff --git a/crates/scarb-api/src/contracts.rs b/crates/scarb-api/src/contracts.rs new file mode 100644 index 000000000..886f027a8 --- /dev/null +++ b/crates/scarb-api/src/contracts.rs @@ -0,0 +1,134 @@ +use anyhow::{anyhow, Context, Result}; +use camino::{Utf8Path, Utf8PathBuf}; +use serde::Deserialize; +use std::collections::HashMap; +use std::fs; +use universal_sierra_compiler_api::{compile_sierra_at_path, SierraType}; + +#[derive(Deserialize, Debug, PartialEq, Clone)] +struct StarknetArtifacts { + version: u32, + contracts: Vec, +} + +#[allow(dead_code)] +#[derive(Deserialize, Debug, PartialEq, Clone)] +pub(crate) struct StarknetContract { + pub id: String, + pub package_name: String, + pub contract_name: String, + pub artifacts: StarknetContractArtifactPaths, +} + +#[allow(dead_code)] +#[derive(Deserialize, Debug, PartialEq, Clone)] +pub(crate) struct StarknetContractArtifactPaths { + pub sierra: Utf8PathBuf, +} + +/// Get deserialized contents of `starknet_artifacts.json` file generated by Scarb +/// +/// # Arguments +/// +/// * `path` - A path to `starknet_artifacts.json` file. +fn artifacts_for_package(path: &Utf8Path) -> Result { + let starknet_artifacts = + fs::read_to_string(path).with_context(|| format!("Failed to read {path:?} contents"))?; + let starknet_artifacts: StarknetArtifacts = + serde_json::from_str(starknet_artifacts.as_str()) + .with_context(|| format!("Failed to parse {path:?} contents. Make sure you have enabled sierra code generation in Scarb.toml"))?; + Ok(starknet_artifacts) +} + +/// Contains compiled Starknet artifacts +#[derive(Debug, PartialEq, Clone)] +pub struct StarknetContractArtifacts { + /// Compiled sierra code + pub sierra: String, + /// Compiled casm code + pub casm: String, +} + +impl StarknetContractArtifacts { + fn from_scarb_contract_artifact( + starknet_contract: &StarknetContract, + base_path: &Utf8Path, + ) -> Result { + let sierra_path = base_path.join(starknet_contract.artifacts.sierra.clone()); + let sierra = fs::read_to_string(sierra_path)?; + + let casm = compile_sierra_at_path( + starknet_contract.artifacts.sierra.as_str(), + Some(base_path.as_std_path()), + &SierraType::Contract, + )?; + + Ok(Self { sierra, casm }) + } +} + +pub(crate) fn load_contracts_artifacts_and_source_sierra_paths( + contracts_path: &Utf8PathBuf, +) -> Result> { + let base_path = contracts_path + .parent() + .ok_or_else(|| anyhow!("Failed to get parent for path = {}", &contracts_path))?; + let artifacts = artifacts_for_package(contracts_path)?; + let mut map = HashMap::new(); + + for ref contract in artifacts.contracts { + let name = contract.contract_name.clone(); + let contract_artifacts = + StarknetContractArtifacts::from_scarb_contract_artifact(contract, base_path)?; + + let sierra_path = base_path.join(contract.artifacts.sierra.clone()); + + map.insert(name.clone(), (contract_artifacts, sierra_path)); + } + Ok(map) +} + +#[cfg(test)] +mod tests { + use crate::ScarbCommand; + use assert_fs::fixture::{FileTouch, FileWriteStr, PathChild, PathCopy}; + use assert_fs::TempDir; + use camino::Utf8PathBuf; + + use super::*; + + #[test] + fn parsing_starknet_artifacts() { + let temp = crate::tests::setup_package("basic_package"); + + ScarbCommand::new_with_stdio() + .current_dir(temp.path()) + .arg("build") + .run() + .unwrap(); + + let artifacts_path = temp + .path() + .join("target/dev/basic_package.starknet_artifacts.json"); + let artifacts_path = Utf8PathBuf::from_path_buf(artifacts_path).unwrap(); + + let artifacts = artifacts_for_package(&artifacts_path).unwrap(); + + assert!(!artifacts.contracts.is_empty()); + } + + #[test] + fn parsing_starknet_artifacts_on_invalid_file() { + let temp = TempDir::new().unwrap(); + temp.copy_from("../../", &[".tool-versions"]).unwrap(); + let path = temp.child("wrong.json"); + path.touch().unwrap(); + path.write_str("\"aa\": {}").unwrap(); + let artifacts_path = Utf8PathBuf::from_path_buf(path.to_path_buf()).unwrap(); + + let result = artifacts_for_package(&artifacts_path); + let err = result.unwrap_err(); + + assert!(err.to_string().contains(&format!("Failed to parse {artifacts_path:?} contents. Make sure you have enabled sierra code generation in Scarb.toml"))); + } +} diff --git a/crates/scarb-api/src/lib.rs b/crates/scarb-api/src/lib.rs index 3cf5d339a..16edb8c1c 100644 --- a/crates/scarb-api/src/lib.rs +++ b/crates/scarb-api/src/lib.rs @@ -1,85 +1,24 @@ -use anyhow::{anyhow, Context, Result}; +use anyhow::{anyhow, Result}; use camino::{Utf8Path, Utf8PathBuf}; use rayon::iter::{IntoParallelRefIterator, ParallelIterator}; use scarb_metadata::{Metadata, PackageId, PackageMetadata, TargetMetadata}; use semver::VersionReq; -use serde::Deserialize; use std::collections::HashMap; -use std::fs; use std::str::FromStr; -use universal_sierra_compiler_api::{compile_sierra_at_path, SierraType}; +use crate::contracts::{ + load_contracts_artifacts_and_source_sierra_paths, StarknetContractArtifacts, +}; pub use command::*; use shared::print::print_as_warning; mod command; +mod contracts; pub mod metadata; pub mod version; const INTEGRATION_TEST_TYPE: &str = "integration"; -#[derive(Deserialize, Debug, PartialEq, Clone)] -struct StarknetArtifacts { - version: u32, - contracts: Vec, -} - -#[allow(dead_code)] -#[derive(Deserialize, Debug, PartialEq, Clone)] -struct StarknetContract { - id: String, - package_name: String, - contract_name: String, - artifacts: StarknetContractArtifactPaths, -} - -#[allow(dead_code)] -#[derive(Deserialize, Debug, PartialEq, Clone)] -struct StarknetContractArtifactPaths { - sierra: Utf8PathBuf, -} - -/// Contains compiled Starknet artifacts -#[derive(Debug, PartialEq, Clone)] -pub struct StarknetContractArtifacts { - /// Compiled sierra code - pub sierra: String, - /// Compiled casm code - pub casm: String, -} - -impl StarknetContractArtifacts { - fn from_scarb_contract_artifact( - starknet_contract: &StarknetContract, - base_path: &Utf8Path, - ) -> Result { - let sierra_path = base_path.join(starknet_contract.artifacts.sierra.clone()); - let sierra = fs::read_to_string(sierra_path)?; - - let casm = compile_sierra_at_path( - starknet_contract.artifacts.sierra.as_str(), - Some(base_path.as_std_path()), - &SierraType::Contract, - )?; - - Ok(Self { sierra, casm }) - } -} - -/// Get deserialized contents of `starknet_artifacts.json` file generated by Scarb -/// -/// # Arguments -/// -/// * `path` - A path to `starknet_artifacts.json` file. -fn artifacts_for_package(path: &Utf8Path) -> Result { - let starknet_artifacts = - fs::read_to_string(path).with_context(|| format!("Failed to read {path:?} contents"))?; - let starknet_artifacts: StarknetArtifacts = - serde_json::from_str(starknet_artifacts.as_str()) - .with_context(|| format!("Failed to parse {path:?} contents. Make sure you have enabled sierra code generation in Scarb.toml"))?; - Ok(starknet_artifacts) -} - #[derive(PartialEq, Debug)] struct StarknetArtifactsFiles { base_file: Utf8PathBuf, @@ -219,27 +158,6 @@ pub fn get_contracts_artifacts_and_source_sierra_paths( } } -fn load_contracts_artifacts_and_source_sierra_paths( - contracts_path: &Utf8PathBuf, -) -> Result> { - let base_path = contracts_path - .parent() - .ok_or_else(|| anyhow!("Failed to get parent for path = {}", &contracts_path))?; - let artifacts = artifacts_for_package(contracts_path)?; - let mut map = HashMap::new(); - - for ref contract in artifacts.contracts { - let name = contract.contract_name.clone(); - let contract_artifacts = - StarknetContractArtifacts::from_scarb_contract_artifact(contract, base_path)?; - - let sierra_path = base_path.join(contract.artifacts.sierra.clone()); - - map.insert(name.clone(), (contract_artifacts, sierra_path)); - } - Ok(map) -} - #[must_use] pub fn target_dir_for_workspace(metadata: &Metadata) -> Utf8PathBuf { metadata @@ -302,13 +220,13 @@ mod tests { use super::*; use crate::metadata::MetadataCommandExt; use assert_fs::fixture::{FileWriteStr, PathChild, PathCopy}; - use assert_fs::prelude::FileTouch; use assert_fs::TempDir; use camino::Utf8PathBuf; use indoc::{formatdoc, indoc}; + use std::fs; use std::str::FromStr; - fn setup_package(package_name: &str) -> TempDir { + pub(crate) fn setup_package(package_name: &str) -> TempDir { let temp = TempDir::new().unwrap(); temp.copy_from( format!("tests/data/{package_name}"), @@ -635,41 +553,6 @@ mod tests { assert!(path.is_none()); } - #[test] - fn parsing_starknet_artifacts() { - let temp = setup_package("basic_package"); - - ScarbCommand::new_with_stdio() - .current_dir(temp.path()) - .arg("build") - .run() - .unwrap(); - - let artifacts_path = temp - .path() - .join("target/dev/basic_package.starknet_artifacts.json"); - let artifacts_path = Utf8PathBuf::from_path_buf(artifacts_path).unwrap(); - - let artifacts = artifacts_for_package(&artifacts_path).unwrap(); - - assert!(!artifacts.contracts.is_empty()); - } - - #[test] - fn parsing_starknet_artifacts_on_invalid_file() { - let temp = TempDir::new().unwrap(); - temp.copy_from("../../", &[".tool-versions"]).unwrap(); - let path = temp.child("wrong.json"); - path.touch().unwrap(); - path.write_str("\"aa\": {}").unwrap(); - let artifacts_path = Utf8PathBuf::from_path_buf(path.to_path_buf()).unwrap(); - - let result = artifacts_for_package(&artifacts_path); - let err = result.unwrap_err(); - - assert!(err.to_string().contains(&format!("Failed to parse {artifacts_path:?} contents. Make sure you have enabled sierra code generation in Scarb.toml"))); - } - #[test] fn get_contracts() { let temp = setup_package("basic_package"); From 28778295f05b7f12364458a93a9b873022856b66 Mon Sep 17 00:00:00 2001 From: Artur Michalek Date: Tue, 22 Oct 2024 17:12:53 +0200 Subject: [PATCH 2/6] Refactor contract compilation structure --- Cargo.lock | 1 + crates/scarb-api/Cargo.toml | 1 + crates/scarb-api/src/contracts.rs | 97 ++++++------------- .../scarb-api/src/contracts/deserialized.rs | 39 ++++++++ crates/scarb-api/src/lib.rs | 56 +++++++---- 5 files changed, 111 insertions(+), 83 deletions(-) create mode 100644 crates/scarb-api/src/contracts/deserialized.rs diff --git a/Cargo.lock b/Cargo.lock index 106102c04..115ea7361 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4295,6 +4295,7 @@ dependencies = [ "assert_fs", "camino", "indoc", + "itertools 0.12.1", "rayon", "regex", "scarb-metadata", diff --git a/crates/scarb-api/Cargo.toml b/crates/scarb-api/Cargo.toml index d0a1cdc89..e2d811603 100644 --- a/crates/scarb-api/Cargo.toml +++ b/crates/scarb-api/Cargo.toml @@ -19,6 +19,7 @@ which.workspace = true semver.workspace = true regex.workspace = true rayon.workspace = true +itertools.workspace = true universal-sierra-compiler-api = { path = "../universal-sierra-compiler-api" } [dev-dependencies] diff --git a/crates/scarb-api/src/contracts.rs b/crates/scarb-api/src/contracts.rs index 886f027a8..a009bbb3a 100644 --- a/crates/scarb-api/src/contracts.rs +++ b/crates/scarb-api/src/contracts.rs @@ -1,43 +1,39 @@ -use anyhow::{anyhow, Context, Result}; +use crate::contracts::deserialized::{artifacts_for_package, StarknetArtifacts}; +use anyhow::{anyhow, Result}; use camino::{Utf8Path, Utf8PathBuf}; -use serde::Deserialize; -use std::collections::HashMap; use std::fs; use universal_sierra_compiler_api::{compile_sierra_at_path, SierraType}; -#[derive(Deserialize, Debug, PartialEq, Clone)] -struct StarknetArtifacts { - version: u32, - contracts: Vec, -} +pub mod deserialized; -#[allow(dead_code)] -#[derive(Deserialize, Debug, PartialEq, Clone)] -pub(crate) struct StarknetContract { - pub id: String, - pub package_name: String, - pub contract_name: String, - pub artifacts: StarknetContractArtifactPaths, +pub struct StarknetArtifactsRepresentation { + path: Utf8PathBuf, + artifacts: StarknetArtifacts, } -#[allow(dead_code)] -#[derive(Deserialize, Debug, PartialEq, Clone)] -pub(crate) struct StarknetContractArtifactPaths { - pub sierra: Utf8PathBuf, -} +impl StarknetArtifactsRepresentation { + pub fn try_from_path(path: &Utf8Path) -> Result { + let artifacts = artifacts_for_package(path)?; + let path = path + .parent() + .ok_or_else(|| anyhow!("Failed to get parent for path = {}", &path))? + .to_path_buf(); + + Ok(Self { path, artifacts }) + } -/// Get deserialized contents of `starknet_artifacts.json` file generated by Scarb -/// -/// # Arguments -/// -/// * `path` - A path to `starknet_artifacts.json` file. -fn artifacts_for_package(path: &Utf8Path) -> Result { - let starknet_artifacts = - fs::read_to_string(path).with_context(|| format!("Failed to read {path:?} contents"))?; - let starknet_artifacts: StarknetArtifacts = - serde_json::from_str(starknet_artifacts.as_str()) - .with_context(|| format!("Failed to parse {path:?} contents. Make sure you have enabled sierra code generation in Scarb.toml"))?; - Ok(starknet_artifacts) + pub fn artifacts(self) -> Vec<(String, Utf8PathBuf)> { + self.artifacts + .contracts + .into_iter() + .map(|contract| { + ( + contract.contract_name, + self.path.join(contract.artifacts.sierra.as_path()), + ) + }) + .collect() + } } /// Contains compiled Starknet artifacts @@ -50,42 +46,13 @@ pub struct StarknetContractArtifacts { } impl StarknetContractArtifacts { - fn from_scarb_contract_artifact( - starknet_contract: &StarknetContract, - base_path: &Utf8Path, - ) -> Result { - let sierra_path = base_path.join(starknet_contract.artifacts.sierra.clone()); - let sierra = fs::read_to_string(sierra_path)?; - - let casm = compile_sierra_at_path( - starknet_contract.artifacts.sierra.as_str(), - Some(base_path.as_std_path()), - &SierraType::Contract, - )?; - - Ok(Self { sierra, casm }) - } -} + pub fn try_compile_at_path(path: &Utf8Path) -> Result { + let sierra = fs::read_to_string(path)?; -pub(crate) fn load_contracts_artifacts_and_source_sierra_paths( - contracts_path: &Utf8PathBuf, -) -> Result> { - let base_path = contracts_path - .parent() - .ok_or_else(|| anyhow!("Failed to get parent for path = {}", &contracts_path))?; - let artifacts = artifacts_for_package(contracts_path)?; - let mut map = HashMap::new(); + let casm = compile_sierra_at_path(path.as_str(), None, &SierraType::Contract)?; - for ref contract in artifacts.contracts { - let name = contract.contract_name.clone(); - let contract_artifacts = - StarknetContractArtifacts::from_scarb_contract_artifact(contract, base_path)?; - - let sierra_path = base_path.join(contract.artifacts.sierra.clone()); - - map.insert(name.clone(), (contract_artifacts, sierra_path)); + Ok(Self { sierra, casm }) } - Ok(map) } #[cfg(test)] diff --git a/crates/scarb-api/src/contracts/deserialized.rs b/crates/scarb-api/src/contracts/deserialized.rs new file mode 100644 index 000000000..47faf298f --- /dev/null +++ b/crates/scarb-api/src/contracts/deserialized.rs @@ -0,0 +1,39 @@ +use anyhow::{Context, Result}; +use camino::{Utf8Path, Utf8PathBuf}; +use serde::Deserialize; +use std::fs; + +#[derive(Deserialize, Debug, PartialEq, Clone)] +pub(crate) struct StarknetArtifacts { + pub version: u32, + pub contracts: Vec, +} + +#[allow(dead_code)] +#[derive(Deserialize, Debug, PartialEq, Clone)] +pub(crate) struct StarknetContract { + pub id: String, + pub package_name: String, + pub contract_name: String, + pub artifacts: StarknetContractArtifactPaths, +} + +#[allow(dead_code)] +#[derive(Deserialize, Debug, PartialEq, Clone)] +pub(crate) struct StarknetContractArtifactPaths { + pub sierra: Utf8PathBuf, +} + +/// Get deserialized contents of `starknet_artifacts.json` file generated by Scarb +/// +/// # Arguments +/// +/// * `path` - A path to `starknet_artifacts.json` file. +pub(crate) fn artifacts_for_package(path: &Utf8Path) -> Result { + let starknet_artifacts = + fs::read_to_string(path).with_context(|| format!("Failed to read {path:?} contents"))?; + let starknet_artifacts: StarknetArtifacts = + serde_json::from_str(starknet_artifacts.as_str()) + .with_context(|| format!("Failed to parse {path:?} contents. Make sure you have enabled sierra code generation in Scarb.toml"))?; + Ok(starknet_artifacts) +} diff --git a/crates/scarb-api/src/lib.rs b/crates/scarb-api/src/lib.rs index 16edb8c1c..c6f4ab62a 100644 --- a/crates/scarb-api/src/lib.rs +++ b/crates/scarb-api/src/lib.rs @@ -1,22 +1,22 @@ +use crate::contracts::StarknetArtifactsRepresentation; use anyhow::{anyhow, Result}; use camino::{Utf8Path, Utf8PathBuf}; -use rayon::iter::{IntoParallelRefIterator, ParallelIterator}; +pub use command::*; +use itertools::Itertools; +use rayon::iter::{IntoParallelIterator, ParallelIterator}; use scarb_metadata::{Metadata, PackageId, PackageMetadata, TargetMetadata}; use semver::VersionReq; +use shared::print::print_as_warning; use std::collections::HashMap; use std::str::FromStr; -use crate::contracts::{ - load_contracts_artifacts_and_source_sierra_paths, StarknetContractArtifacts, -}; -pub use command::*; -use shared::print::print_as_warning; - mod command; mod contracts; pub mod metadata; pub mod version; +pub use crate::contracts::StarknetContractArtifacts; + const INTEGRATION_TEST_TYPE: &str = "integration"; #[derive(PartialEq, Debug)] @@ -29,19 +29,39 @@ impl StarknetArtifactsFiles { fn load_contracts_artifacts( self, ) -> Result> { - let mut base_artifacts = load_contracts_artifacts_and_source_sierra_paths(&self.base_file)?; - - let compiled_artifacts = self + let mut base_artifacts: HashMap = + StarknetArtifactsRepresentation::try_from_path(self.base_file.as_path())? + .artifacts() + .into_par_iter() + .map(|(name, path)| { + StarknetContractArtifacts::try_compile_at_path(path.as_path()) + .map(|artifact| (name.to_string(), (artifact, path))) + }) + .collect::>()?; + + let other_artifact_representations: Vec = self .other_files - .par_iter() - .map(load_contracts_artifacts_and_source_sierra_paths) - .collect::>>()?; + .iter() + .map(|path| StarknetArtifactsRepresentation::try_from_path(path.as_path())) + .collect::>()?; - for artifact in compiled_artifacts { - for (key, value) in artifact { - base_artifacts.entry(key).or_insert(value); - } - } + let other_artifacts: Vec<(String, Utf8PathBuf)> = other_artifact_representations + .into_iter() + .flat_map(StarknetArtifactsRepresentation::artifacts) + .unique() + .filter(|(name, _)| !base_artifacts.contains_key(name)) + .collect(); + + let compiled_artifacts: HashMap = + other_artifacts + .into_par_iter() + .map(|(name, path)| { + StarknetContractArtifacts::try_compile_at_path(path.as_path()) + .map(|artifact| (name.to_string(), (artifact, path))) + }) + .collect::>()?; + + base_artifacts.extend(compiled_artifacts); Ok(base_artifacts) } From 273a158cdb13bb6d2520725d2db5ef7159c0be18 Mon Sep 17 00:00:00 2001 From: Artur Michalek Date: Wed, 23 Oct 2024 12:39:59 +0200 Subject: [PATCH 3/6] Refactor function --- crates/scarb-api/src/lib.rs | 55 +++++++++++++++++++++---------------- 1 file changed, 32 insertions(+), 23 deletions(-) diff --git a/crates/scarb-api/src/lib.rs b/crates/scarb-api/src/lib.rs index c6f4ab62a..3862f6e71 100644 --- a/crates/scarb-api/src/lib.rs +++ b/crates/scarb-api/src/lib.rs @@ -2,7 +2,7 @@ use crate::contracts::StarknetArtifactsRepresentation; use anyhow::{anyhow, Result}; use camino::{Utf8Path, Utf8PathBuf}; pub use command::*; -use itertools::Itertools; +use itertools::{Itertools, Unique}; use rayon::iter::{IntoParallelIterator, ParallelIterator}; use scarb_metadata::{Metadata, PackageId, PackageMetadata, TargetMetadata}; use semver::VersionReq; @@ -30,14 +30,10 @@ impl StarknetArtifactsFiles { self, ) -> Result> { let mut base_artifacts: HashMap = - StarknetArtifactsRepresentation::try_from_path(self.base_file.as_path())? - .artifacts() - .into_par_iter() - .map(|(name, path)| { - StarknetContractArtifacts::try_compile_at_path(path.as_path()) - .map(|artifact| (name.to_string(), (artifact, path))) - }) - .collect::>()?; + compile_artifacts( + StarknetArtifactsRepresentation::try_from_path(self.base_file.as_path())? + .artifacts(), + )?; let other_artifact_representations: Vec = self .other_files @@ -45,21 +41,10 @@ impl StarknetArtifactsFiles { .map(|path| StarknetArtifactsRepresentation::try_from_path(path.as_path())) .collect::>()?; - let other_artifacts: Vec<(String, Utf8PathBuf)> = other_artifact_representations - .into_iter() - .flat_map(StarknetArtifactsRepresentation::artifacts) - .unique() - .filter(|(name, _)| !base_artifacts.contains_key(name)) - .collect(); + let other_artifacts: Vec<(String, Utf8PathBuf)> = + unique_artifacts(other_artifact_representations, &base_artifacts); - let compiled_artifacts: HashMap = - other_artifacts - .into_par_iter() - .map(|(name, path)| { - StarknetContractArtifacts::try_compile_at_path(path.as_path()) - .map(|artifact| (name.to_string(), (artifact, path))) - }) - .collect::>()?; + let compiled_artifacts = compile_artifacts(other_artifacts)?; base_artifacts.extend(compiled_artifacts); @@ -67,6 +52,30 @@ impl StarknetArtifactsFiles { } } +fn unique_artifacts( + artifact_representations: Vec, + current_artifacts: &HashMap, +) -> Vec<(String, Utf8PathBuf)> { + artifact_representations + .into_iter() + .flat_map(StarknetArtifactsRepresentation::artifacts) + .unique() + .filter(|(name, _)| !current_artifacts.contains_key(name)) + .collect() +} + +fn compile_artifacts( + artifacts: Vec<(String, Utf8PathBuf)>, +) -> Result> { + artifacts + .into_par_iter() + .map(|(name, path)| { + StarknetContractArtifacts::try_compile_at_path(path.as_path()) + .map(|artifact| (name.to_string(), (artifact, path))) + }) + .collect::>() +} + /// Constructs `StarknetArtifactsFiles` from contracts built using test target. /// /// If artifacts with `test_type` of `INTEGRATION_TEST_TYPE` are present, we use them base path From cb3f8b98ff23ff4349799517f4fa46613a2f4887 Mon Sep 17 00:00:00 2001 From: Artur Michalek Date: Wed, 23 Oct 2024 12:46:26 +0200 Subject: [PATCH 4/6] Move code to artifacts.rs --- crates/scarb-api/src/artifacts.rs | 70 +++++++++++++++++++ crates/scarb-api/src/lib.rs | 107 +++++++----------------------- 2 files changed, 93 insertions(+), 84 deletions(-) create mode 100644 crates/scarb-api/src/artifacts.rs diff --git a/crates/scarb-api/src/artifacts.rs b/crates/scarb-api/src/artifacts.rs new file mode 100644 index 000000000..2aa2b730a --- /dev/null +++ b/crates/scarb-api/src/artifacts.rs @@ -0,0 +1,70 @@ +use crate::contracts::StarknetArtifactsRepresentation; +use crate::StarknetContractArtifacts; +use camino::Utf8PathBuf; +use itertools::Itertools; +use rayon::iter::{IntoParallelIterator, ParallelIterator}; +use std::collections::HashMap; + +#[derive(PartialEq, Debug)] +pub(crate) struct StarknetArtifactsFiles { + base_file: Utf8PathBuf, + other_files: Vec, +} + +impl StarknetArtifactsFiles { + pub(crate) fn new(base_file: Utf8PathBuf, other_files: Vec) -> Self { + Self { + base_file, + other_files, + } + } + + pub(crate) fn load_contracts_artifacts( + self, + ) -> anyhow::Result> { + let mut base_artifacts: HashMap = + compile_artifacts( + StarknetArtifactsRepresentation::try_from_path(self.base_file.as_path())? + .artifacts(), + )?; + + let other_artifact_representations: Vec = self + .other_files + .iter() + .map(|path| StarknetArtifactsRepresentation::try_from_path(path.as_path())) + .collect::>()?; + + let other_artifacts: Vec<(String, Utf8PathBuf)> = + unique_artifacts(other_artifact_representations, &base_artifacts); + + let compiled_artifacts = compile_artifacts(other_artifacts)?; + + base_artifacts.extend(compiled_artifacts); + + Ok(base_artifacts) + } +} + +fn unique_artifacts( + artifact_representations: Vec, + current_artifacts: &HashMap, +) -> Vec<(String, Utf8PathBuf)> { + artifact_representations + .into_iter() + .flat_map(StarknetArtifactsRepresentation::artifacts) + .unique() + .filter(|(name, _)| !current_artifacts.contains_key(name)) + .collect() +} + +fn compile_artifacts( + artifacts: Vec<(String, Utf8PathBuf)>, +) -> anyhow::Result> { + artifacts + .into_par_iter() + .map(|(name, path)| { + StarknetContractArtifacts::try_compile_at_path(path.as_path()) + .map(|artifact| (name.to_string(), (artifact, path))) + }) + .collect::>() +} diff --git a/crates/scarb-api/src/lib.rs b/crates/scarb-api/src/lib.rs index 3862f6e71..3d206ddaa 100644 --- a/crates/scarb-api/src/lib.rs +++ b/crates/scarb-api/src/lib.rs @@ -1,15 +1,14 @@ -use crate::contracts::StarknetArtifactsRepresentation; +use crate::artifacts::StarknetArtifactsFiles; use anyhow::{anyhow, Result}; use camino::{Utf8Path, Utf8PathBuf}; pub use command::*; -use itertools::{Itertools, Unique}; -use rayon::iter::{IntoParallelIterator, ParallelIterator}; use scarb_metadata::{Metadata, PackageId, PackageMetadata, TargetMetadata}; use semver::VersionReq; use shared::print::print_as_warning; use std::collections::HashMap; use std::str::FromStr; +mod artifacts; mod command; mod contracts; pub mod metadata; @@ -19,63 +18,6 @@ pub use crate::contracts::StarknetContractArtifacts; const INTEGRATION_TEST_TYPE: &str = "integration"; -#[derive(PartialEq, Debug)] -struct StarknetArtifactsFiles { - base_file: Utf8PathBuf, - other_files: Vec, -} - -impl StarknetArtifactsFiles { - fn load_contracts_artifacts( - self, - ) -> Result> { - let mut base_artifacts: HashMap = - compile_artifacts( - StarknetArtifactsRepresentation::try_from_path(self.base_file.as_path())? - .artifacts(), - )?; - - let other_artifact_representations: Vec = self - .other_files - .iter() - .map(|path| StarknetArtifactsRepresentation::try_from_path(path.as_path())) - .collect::>()?; - - let other_artifacts: Vec<(String, Utf8PathBuf)> = - unique_artifacts(other_artifact_representations, &base_artifacts); - - let compiled_artifacts = compile_artifacts(other_artifacts)?; - - base_artifacts.extend(compiled_artifacts); - - Ok(base_artifacts) - } -} - -fn unique_artifacts( - artifact_representations: Vec, - current_artifacts: &HashMap, -) -> Vec<(String, Utf8PathBuf)> { - artifact_representations - .into_iter() - .flat_map(StarknetArtifactsRepresentation::artifacts) - .unique() - .filter(|(name, _)| !current_artifacts.contains_key(name)) - .collect() -} - -fn compile_artifacts( - artifacts: Vec<(String, Utf8PathBuf)>, -) -> Result> { - artifacts - .into_par_iter() - .map(|(name, path)| { - StarknetContractArtifacts::try_compile_at_path(path.as_path()) - .map(|artifact| (name.to_string(), (artifact, path))) - }) - .collect::>() -} - /// Constructs `StarknetArtifactsFiles` from contracts built using test target. /// /// If artifacts with `test_type` of `INTEGRATION_TEST_TYPE` are present, we use them base path @@ -126,10 +68,10 @@ fn get_starknet_artifacts_paths_from_test_targets( .collect(); let (base_artifact_path, _) = base_artifact; - Some(StarknetArtifactsFiles { - base_file: base_artifact_path, - other_files: other_artifacts_paths, - }) + Some(StarknetArtifactsFiles::new( + base_artifact_path, + other_artifacts_paths, + )) } else { None } @@ -154,10 +96,7 @@ fn get_starknet_artifacts_path( None }; - path.map(|path| StarknetArtifactsFiles { - base_file: path, - other_files: vec![], - }) + path.map(|path| StarknetArtifactsFiles::new(path, vec![])) } /// Get the map with `StarknetContractArtifacts` for the given package @@ -326,14 +265,14 @@ mod tests { assert_eq!( path, - StarknetArtifactsFiles { - base_file: Utf8PathBuf::from_path_buf( + StarknetArtifactsFiles::new( + Utf8PathBuf::from_path_buf( temp.path() .join("target/dev/basic_package.starknet_artifacts.json") ) .unwrap(), - other_files: vec![] - } + vec![] + ) ); } @@ -368,14 +307,14 @@ mod tests { assert_eq!( path, - StarknetArtifactsFiles { - base_file: Utf8PathBuf::from_path_buf( + StarknetArtifactsFiles::new( + Utf8PathBuf::from_path_buf( temp.path() .join("target/dev/basic_package_unittest.test.starknet_artifacts.json") ) .unwrap(), - other_files: vec![], - } + vec![], + ) ); } @@ -423,19 +362,19 @@ mod tests { assert_eq!( path, - StarknetArtifactsFiles { - base_file: Utf8PathBuf::from_path_buf( + StarknetArtifactsFiles::new( + Utf8PathBuf::from_path_buf( temp.path().join( "target/dev/basic_package_integrationtest.test.starknet_artifacts.json" ) ) .unwrap(), - other_files: vec![Utf8PathBuf::from_path_buf( + vec![Utf8PathBuf::from_path_buf( temp.path() .join("target/dev/basic_package_unittest.test.starknet_artifacts.json") ) .unwrap(),] - }, + ), ); } @@ -533,13 +472,13 @@ mod tests { assert_eq!( path, - StarknetArtifactsFiles { - base_file: Utf8PathBuf::from_path_buf( + StarknetArtifactsFiles::new( + Utf8PathBuf::from_path_buf( temp.path().join("target/dev/essa.starknet_artifacts.json") ) .unwrap(), - other_files: vec![] - } + vec![] + ) ); } From 04921f9a03ff7f7260b3ddb1ada112ba1789ca5d Mon Sep 17 00:00:00 2001 From: Artur Michalek Date: Wed, 23 Oct 2024 13:02:23 +0200 Subject: [PATCH 5/6] Restructure files --- crates/scarb-api/src/artifacts.rs | 74 +-------------- crates/scarb-api/src/artifacts/artifacts.rs | 89 +++++++++++++++++++ .../{contracts => artifacts}/deserialized.rs | 0 .../representation.rs} | 29 +----- crates/scarb-api/src/lib.rs | 5 +- 5 files changed, 98 insertions(+), 99 deletions(-) create mode 100644 crates/scarb-api/src/artifacts/artifacts.rs rename crates/scarb-api/src/{contracts => artifacts}/deserialized.rs (100%) rename crates/scarb-api/src/{contracts.rs => artifacts/representation.rs} (74%) diff --git a/crates/scarb-api/src/artifacts.rs b/crates/scarb-api/src/artifacts.rs index 2aa2b730a..7ae5b4b40 100644 --- a/crates/scarb-api/src/artifacts.rs +++ b/crates/scarb-api/src/artifacts.rs @@ -1,70 +1,4 @@ -use crate::contracts::StarknetArtifactsRepresentation; -use crate::StarknetContractArtifacts; -use camino::Utf8PathBuf; -use itertools::Itertools; -use rayon::iter::{IntoParallelIterator, ParallelIterator}; -use std::collections::HashMap; - -#[derive(PartialEq, Debug)] -pub(crate) struct StarknetArtifactsFiles { - base_file: Utf8PathBuf, - other_files: Vec, -} - -impl StarknetArtifactsFiles { - pub(crate) fn new(base_file: Utf8PathBuf, other_files: Vec) -> Self { - Self { - base_file, - other_files, - } - } - - pub(crate) fn load_contracts_artifacts( - self, - ) -> anyhow::Result> { - let mut base_artifacts: HashMap = - compile_artifacts( - StarknetArtifactsRepresentation::try_from_path(self.base_file.as_path())? - .artifacts(), - )?; - - let other_artifact_representations: Vec = self - .other_files - .iter() - .map(|path| StarknetArtifactsRepresentation::try_from_path(path.as_path())) - .collect::>()?; - - let other_artifacts: Vec<(String, Utf8PathBuf)> = - unique_artifacts(other_artifact_representations, &base_artifacts); - - let compiled_artifacts = compile_artifacts(other_artifacts)?; - - base_artifacts.extend(compiled_artifacts); - - Ok(base_artifacts) - } -} - -fn unique_artifacts( - artifact_representations: Vec, - current_artifacts: &HashMap, -) -> Vec<(String, Utf8PathBuf)> { - artifact_representations - .into_iter() - .flat_map(StarknetArtifactsRepresentation::artifacts) - .unique() - .filter(|(name, _)| !current_artifacts.contains_key(name)) - .collect() -} - -fn compile_artifacts( - artifacts: Vec<(String, Utf8PathBuf)>, -) -> anyhow::Result> { - artifacts - .into_par_iter() - .map(|(name, path)| { - StarknetContractArtifacts::try_compile_at_path(path.as_path()) - .map(|artifact| (name.to_string(), (artifact, path))) - }) - .collect::>() -} +#[allow(clippy::module_inception)] +pub mod artifacts; +pub mod deserialized; +pub mod representation; diff --git a/crates/scarb-api/src/artifacts/artifacts.rs b/crates/scarb-api/src/artifacts/artifacts.rs new file mode 100644 index 000000000..6aead10fc --- /dev/null +++ b/crates/scarb-api/src/artifacts/artifacts.rs @@ -0,0 +1,89 @@ +use anyhow::Result; + +use crate::artifacts::representation::StarknetArtifactsRepresentation; +use camino::{Utf8Path, Utf8PathBuf}; +use itertools::Itertools; +use rayon::iter::{IntoParallelIterator, ParallelIterator}; +use std::collections::HashMap; +use std::fs; +use universal_sierra_compiler_api::{compile_sierra_at_path, SierraType}; + +/// Contains compiled Starknet artifacts +#[derive(Debug, PartialEq, Clone)] +pub struct StarknetContractArtifacts { + /// Compiled sierra code + pub sierra: String, + /// Compiled casm code + pub casm: String, +} + +#[derive(PartialEq, Debug)] +pub(crate) struct StarknetArtifactsFiles { + base_file: Utf8PathBuf, + other_files: Vec, +} + +impl StarknetArtifactsFiles { + pub(crate) fn new(base_file: Utf8PathBuf, other_files: Vec) -> Self { + Self { + base_file, + other_files, + } + } + + pub(crate) fn load_contracts_artifacts( + self, + ) -> Result> { + let mut base_artifacts: HashMap = + compile_artifacts( + StarknetArtifactsRepresentation::try_from_path(self.base_file.as_path())? + .artifacts(), + )?; + + let other_artifact_representations: Vec = self + .other_files + .iter() + .map(|path| StarknetArtifactsRepresentation::try_from_path(path.as_path())) + .collect::>()?; + + let other_artifacts: Vec<(String, Utf8PathBuf)> = + unique_artifacts(other_artifact_representations, &base_artifacts); + + let compiled_artifacts = compile_artifacts(other_artifacts)?; + + base_artifacts.extend(compiled_artifacts); + + Ok(base_artifacts) + } +} + +fn unique_artifacts( + artifact_representations: Vec, + current_artifacts: &HashMap, +) -> Vec<(String, Utf8PathBuf)> { + artifact_representations + .into_iter() + .flat_map(StarknetArtifactsRepresentation::artifacts) + .unique() + .filter(|(name, _)| !current_artifacts.contains_key(name)) + .collect() +} + +fn compile_artifacts( + artifacts: Vec<(String, Utf8PathBuf)>, +) -> Result> { + artifacts + .into_par_iter() + .map(|(name, path)| { + compile_artifact_at_path(&path).map(|artifact| (name.to_string(), (artifact, path))) + }) + .collect::>() +} + +fn compile_artifact_at_path(path: &Utf8Path) -> Result { + let sierra = fs::read_to_string(path)?; + + let casm = compile_sierra_at_path(path.as_str(), None, &SierraType::Contract)?; + + Ok(StarknetContractArtifacts { sierra, casm }) +} diff --git a/crates/scarb-api/src/contracts/deserialized.rs b/crates/scarb-api/src/artifacts/deserialized.rs similarity index 100% rename from crates/scarb-api/src/contracts/deserialized.rs rename to crates/scarb-api/src/artifacts/deserialized.rs diff --git a/crates/scarb-api/src/contracts.rs b/crates/scarb-api/src/artifacts/representation.rs similarity index 74% rename from crates/scarb-api/src/contracts.rs rename to crates/scarb-api/src/artifacts/representation.rs index a009bbb3a..2b09567ce 100644 --- a/crates/scarb-api/src/contracts.rs +++ b/crates/scarb-api/src/artifacts/representation.rs @@ -1,10 +1,6 @@ -use crate::contracts::deserialized::{artifacts_for_package, StarknetArtifacts}; -use anyhow::{anyhow, Result}; +use crate::artifacts::deserialized::{artifacts_for_package, StarknetArtifacts}; +use anyhow::anyhow; use camino::{Utf8Path, Utf8PathBuf}; -use std::fs; -use universal_sierra_compiler_api::{compile_sierra_at_path, SierraType}; - -pub mod deserialized; pub struct StarknetArtifactsRepresentation { path: Utf8PathBuf, @@ -12,7 +8,7 @@ pub struct StarknetArtifactsRepresentation { } impl StarknetArtifactsRepresentation { - pub fn try_from_path(path: &Utf8Path) -> Result { + pub fn try_from_path(path: &Utf8Path) -> anyhow::Result { let artifacts = artifacts_for_package(path)?; let path = path .parent() @@ -36,25 +32,6 @@ impl StarknetArtifactsRepresentation { } } -/// Contains compiled Starknet artifacts -#[derive(Debug, PartialEq, Clone)] -pub struct StarknetContractArtifacts { - /// Compiled sierra code - pub sierra: String, - /// Compiled casm code - pub casm: String, -} - -impl StarknetContractArtifacts { - pub fn try_compile_at_path(path: &Utf8Path) -> Result { - let sierra = fs::read_to_string(path)?; - - let casm = compile_sierra_at_path(path.as_str(), None, &SierraType::Contract)?; - - Ok(Self { sierra, casm }) - } -} - #[cfg(test)] mod tests { use crate::ScarbCommand; diff --git a/crates/scarb-api/src/lib.rs b/crates/scarb-api/src/lib.rs index 3d206ddaa..aef7df540 100644 --- a/crates/scarb-api/src/lib.rs +++ b/crates/scarb-api/src/lib.rs @@ -1,5 +1,5 @@ -use crate::artifacts::StarknetArtifactsFiles; use anyhow::{anyhow, Result}; +use artifacts::artifacts::StarknetArtifactsFiles; use camino::{Utf8Path, Utf8PathBuf}; pub use command::*; use scarb_metadata::{Metadata, PackageId, PackageMetadata, TargetMetadata}; @@ -10,11 +10,10 @@ use std::str::FromStr; mod artifacts; mod command; -mod contracts; pub mod metadata; pub mod version; -pub use crate::contracts::StarknetContractArtifacts; +pub use crate::artifacts::artifacts::StarknetContractArtifacts; const INTEGRATION_TEST_TYPE: &str = "integration"; From e022e076cbdb123c0ba6d9c04365ae13766a1968 Mon Sep 17 00:00:00 2001 From: Artur Michalek Date: Wed, 23 Oct 2024 13:40:40 +0200 Subject: [PATCH 6/6] Reduce visibility of some methods/structs --- crates/scarb-api/src/artifacts/deserialized.rs | 8 ++++---- crates/scarb-api/src/artifacts/representation.rs | 6 +++--- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/crates/scarb-api/src/artifacts/deserialized.rs b/crates/scarb-api/src/artifacts/deserialized.rs index 47faf298f..8dd292d6e 100644 --- a/crates/scarb-api/src/artifacts/deserialized.rs +++ b/crates/scarb-api/src/artifacts/deserialized.rs @@ -4,14 +4,14 @@ use serde::Deserialize; use std::fs; #[derive(Deserialize, Debug, PartialEq, Clone)] -pub(crate) struct StarknetArtifacts { +pub(super) struct StarknetArtifacts { pub version: u32, pub contracts: Vec, } #[allow(dead_code)] #[derive(Deserialize, Debug, PartialEq, Clone)] -pub(crate) struct StarknetContract { +pub(super) struct StarknetContract { pub id: String, pub package_name: String, pub contract_name: String, @@ -20,7 +20,7 @@ pub(crate) struct StarknetContract { #[allow(dead_code)] #[derive(Deserialize, Debug, PartialEq, Clone)] -pub(crate) struct StarknetContractArtifactPaths { +pub(super) struct StarknetContractArtifactPaths { pub sierra: Utf8PathBuf, } @@ -29,7 +29,7 @@ pub(crate) struct StarknetContractArtifactPaths { /// # Arguments /// /// * `path` - A path to `starknet_artifacts.json` file. -pub(crate) fn artifacts_for_package(path: &Utf8Path) -> Result { +pub(super) fn artifacts_for_package(path: &Utf8Path) -> Result { let starknet_artifacts = fs::read_to_string(path).with_context(|| format!("Failed to read {path:?} contents"))?; let starknet_artifacts: StarknetArtifacts = diff --git a/crates/scarb-api/src/artifacts/representation.rs b/crates/scarb-api/src/artifacts/representation.rs index 2b09567ce..4017d91b8 100644 --- a/crates/scarb-api/src/artifacts/representation.rs +++ b/crates/scarb-api/src/artifacts/representation.rs @@ -2,13 +2,13 @@ use crate::artifacts::deserialized::{artifacts_for_package, StarknetArtifacts}; use anyhow::anyhow; use camino::{Utf8Path, Utf8PathBuf}; -pub struct StarknetArtifactsRepresentation { +pub(super) struct StarknetArtifactsRepresentation { path: Utf8PathBuf, artifacts: StarknetArtifacts, } impl StarknetArtifactsRepresentation { - pub fn try_from_path(path: &Utf8Path) -> anyhow::Result { + pub(super) fn try_from_path(path: &Utf8Path) -> anyhow::Result { let artifacts = artifacts_for_package(path)?; let path = path .parent() @@ -18,7 +18,7 @@ impl StarknetArtifactsRepresentation { Ok(Self { path, artifacts }) } - pub fn artifacts(self) -> Vec<(String, Utf8PathBuf)> { + pub(super) fn artifacts(self) -> Vec<(String, Utf8PathBuf)> { self.artifacts .contracts .into_iter()