-
Notifications
You must be signed in to change notification settings - Fork 45
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Part of #512. We're adding the Artifact trait that will provide a uniform interface for working with different artifact sources.
- Loading branch information
Tamika Nomara
authored
Jun 24, 2021
1 parent
540a9c2
commit bfdff6f
Showing
5 changed files
with
240 additions
and
5 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,101 @@ | ||
//! Tools for loading artifacts that contain compiled contracts. | ||
//! | ||
//! Artifacts come in various shapes and sizes, but usually they | ||
//! are JSON files containing one or multiple compiled contracts | ||
//! as well as their deployment information. | ||
//! | ||
//! This module provides trait [`Artifact`] that encapsulates different | ||
//! artifact models. It also provides tools to load artifacts from different | ||
//! sources, and parse them using different formats. | ||
use crate::Contract; | ||
use std::collections::HashMap; | ||
|
||
pub mod truffle; | ||
|
||
/// An entity that contains compiled contracts. | ||
pub struct Artifact { | ||
origin: String, | ||
contracts: HashMap<String, Contract>, | ||
} | ||
|
||
impl Artifact { | ||
/// Create a new empty artifact. | ||
pub fn new() -> Self { | ||
Artifact { | ||
origin: "<unknown>".to_string(), | ||
contracts: HashMap::new(), | ||
} | ||
} | ||
|
||
/// Create a new artifact with an origin information. | ||
pub fn with_origin(origin: String) -> Self { | ||
Artifact { | ||
origin, | ||
contracts: HashMap::new(), | ||
} | ||
} | ||
|
||
/// Describe where this artifact comes from. | ||
/// | ||
/// This function is used when a human-readable reference to the artifact | ||
/// is required. It could be anything: path to a json file, url, etc. | ||
pub fn origin(&self) -> &str { | ||
&self.origin | ||
} | ||
|
||
/// Set new origin for the artifact. | ||
/// | ||
/// Artifact loaders will set origin to something meaningful in most cases, | ||
/// so this function should not be used often. There are cases when | ||
/// it is required, though. | ||
pub fn set_origin(&mut self, origin: impl Into<String>) { | ||
self.origin = origin.into(); | ||
} | ||
|
||
/// Check whether this artifact has a contract with the given name. | ||
pub fn contains(&self, name: &str) -> bool { | ||
self.contracts.contains_key(name) | ||
} | ||
|
||
/// Get contract by name. | ||
/// | ||
/// Some artifact formats allow exporting a single unnamed contract. | ||
/// In this case, the contract will have an empty string as its name. | ||
pub fn get(&self, name: &str) -> Option<&Contract> { | ||
self.contracts.get(name) | ||
} | ||
|
||
/// Insert a new contract to the artifact. | ||
/// | ||
/// If contract with this name already exists, replace it | ||
/// and return an old contract. | ||
pub fn insert(&mut self, contract: Contract) -> Option<Contract> { | ||
self.contracts.insert(contract.name.clone(), contract) | ||
} | ||
|
||
/// Remove contract from the artifact. | ||
/// | ||
/// Returns removed contract or [`None`] if contract with the given name | ||
/// wasn't found. | ||
pub fn remove(&mut self, name: &str) -> Option<Contract> { | ||
self.contracts.remove(name) | ||
} | ||
|
||
/// Create an iterator that yields the artifact's contracts. | ||
pub fn iter(&self) -> impl Iterator<Item = &Contract> + '_ { | ||
self.contracts.values() | ||
} | ||
|
||
/// Take all contracts from the artifact, leaving it empty, | ||
/// and iterate over them. | ||
pub fn drain(&mut self) -> impl Iterator<Item = Contract> + '_ { | ||
self.contracts.drain().map(|(_, contract)| contract) | ||
} | ||
} | ||
|
||
impl Default for Artifact { | ||
fn default() -> Self { | ||
Artifact::new() | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,133 @@ | ||
//! Implements the most common artifact format used in Truffle, Waffle | ||
//! and some other libraries. | ||
//! | ||
//! This artifact is represented as a JSON file containing information about | ||
//! a single contract. We parse the following fields: | ||
//! | ||
//! - `contractName`: name of the contract (optional); | ||
//! - `abi`: information about contract's interface; | ||
//! - `bytecode`: contract's compiled bytecode (optional); | ||
//! - `networks`: info about known contract deployments (optional); | ||
//! - `devdoc`, `userdoc`: additional documentation for contract's methods. | ||
use crate::artifact::Artifact; | ||
use crate::errors::ArtifactError; | ||
use crate::Contract; | ||
use serde_json::Value; | ||
use std::fs::File; | ||
use std::path::Path; | ||
|
||
/// Loads truffle artifacts. | ||
pub struct TruffleLoader { | ||
/// Override for artifact's origin. | ||
/// | ||
/// If empty, origin will be derived automatically. | ||
pub origin: Option<String>, | ||
|
||
/// Override for contract's name. | ||
/// | ||
/// Truffle artifacts contain a single contract which may | ||
pub name: Option<String>, | ||
} | ||
|
||
impl TruffleLoader { | ||
/// Create a new truffle loader. | ||
pub fn new() -> Self { | ||
TruffleLoader { | ||
origin: None, | ||
name: None, | ||
} | ||
} | ||
|
||
/// Create a new truffle loader and set an override for artifact's origins. | ||
pub fn with_origin(origin: String) -> Self { | ||
TruffleLoader { | ||
origin: Some(origin), | ||
name: None, | ||
} | ||
} | ||
|
||
/// Set new override for artifact's origin. See [`origin`] for more info. | ||
/// | ||
/// [`origin`]: #structfield.origin | ||
#[inline] | ||
pub fn origin(mut self, origin: String) -> Self { | ||
self.origin = Some(origin); | ||
self | ||
} | ||
|
||
/// Set new override for artifact's name. See [`name`] for more info. | ||
/// | ||
/// [`name`]: #structfield.name | ||
#[inline] | ||
pub fn name(mut self, name: String) -> Self { | ||
self.name = Some(name); | ||
self | ||
} | ||
|
||
/// Parse a truffle artifact from JSON string. | ||
pub fn load_from_string(&self, json: &str) -> Result<Artifact, ArtifactError> { | ||
let origin = self | ||
.origin | ||
.clone() | ||
.unwrap_or_else(|| "<memory>".to_string()); | ||
let mut artifact = Artifact::with_origin(origin); | ||
artifact.insert(self.load_contract_from_string(json)?); | ||
Ok(artifact) | ||
} | ||
|
||
/// Parse a contract from JSON string. | ||
pub fn load_contract_from_string(&self, json: &str) -> Result<Contract, ArtifactError> { | ||
let mut contract: Contract = serde_json::from_str(json)?; | ||
if let Some(name) = &self.name { | ||
contract.name = name.clone(); | ||
} | ||
Ok(contract) | ||
} | ||
|
||
/// Loads a truffle artifact from JSON value. | ||
pub fn load_from_json(&self, value: Value) -> Result<Artifact, ArtifactError> { | ||
let origin = self | ||
.origin | ||
.clone() | ||
.unwrap_or_else(|| "<memory>".to_string()); | ||
let mut artifact = Artifact::with_origin(origin); | ||
artifact.insert(self.load_contract_from_json(value)?); | ||
Ok(artifact) | ||
} | ||
|
||
/// Loads a contract from JSON value. | ||
pub fn load_contract_from_json(&self, value: Value) -> Result<Contract, ArtifactError> { | ||
let mut contract: Contract = serde_json::from_value(value)?; | ||
if let Some(name) = &self.name { | ||
contract.name = name.clone(); | ||
} | ||
Ok(contract) | ||
} | ||
|
||
/// Loads a truffle artifact from disk. | ||
pub fn load_from_file(&self, path: &Path) -> Result<Artifact, ArtifactError> { | ||
let origin = self | ||
.origin | ||
.clone() | ||
.unwrap_or_else(|| path.display().to_string()); | ||
let mut artifact = Artifact::with_origin(origin); | ||
artifact.insert(self.load_contract_from_file(path)?); | ||
Ok(artifact) | ||
} | ||
|
||
/// Loads a contract from disk. | ||
pub fn load_contract_from_file(&self, path: &Path) -> Result<Contract, ArtifactError> { | ||
let mut contract: Contract = serde_json::from_reader(File::open(path)?)?; | ||
if let Some(name) = &self.name { | ||
contract.name = name.clone(); | ||
} | ||
Ok(contract) | ||
} | ||
} | ||
|
||
impl Default for TruffleLoader { | ||
fn default() -> Self { | ||
TruffleLoader::new() | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters