Skip to content

Commit

Permalink
Merge pull request #558 from rainlanguage/2024-04-05-scenario-compose…
Browse files Browse the repository at this point in the history
…-cli-command

adding order compose for scenario cli command
  • Loading branch information
thedavidmeister authored Apr 5, 2024
2 parents 6f542bf + 7f07f60 commit 16c197f
Show file tree
Hide file tree
Showing 6 changed files with 273 additions and 0 deletions.
54 changes: 54 additions & 0 deletions crates/cli/src/commands/order/compose.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
use crate::execute::Execute;
use crate::output::{output, SupportedOutputEncoding};
use anyhow::{anyhow, Result};
use clap::Args;
use rain_orderbook_common::dotrain_order::DotrainOrder;
use std::fs::read_to_string;
use std::path::PathBuf;

#[derive(Args, Clone)]
pub struct Compose {
#[arg(
short = 'f',
long,
help = "Path to the .rain file specifying the order"
)]
dotrain_file: PathBuf,

// path to the settings yaml
#[arg(
short = 'c',
long,
help = "Path to the settings yaml file",
default_value = "settings.yml"
)]
settings_file: Option<PathBuf>,

// the name of the scenrio to use
#[arg(short = 's', long, help = "The name of the scenario to use")]
scenario: String,

// supported encoding
#[arg(short = 'o', long, help = "Output encoding", default_value = "binary")]
encoding: SupportedOutputEncoding,
}

impl Execute for Compose {
async fn execute(&self) -> Result<()> {
let dotrain = read_to_string(self.dotrain_file.clone()).map_err(|e| anyhow!(e))?;
let settings = match &self.settings_file {
Some(settings_file) => {
Some(read_to_string(settings_file.clone()).map_err(|e| anyhow!(e))?)
}
None => None,
};
let rainlang = DotrainOrder::new(dotrain, settings)
.await?
.compose_scenario_to_rainlang(self.scenario.clone())
.await?;

output(&None, self.encoding.clone(), rainlang.as_bytes())?;

Ok(())
}
}
6 changes: 6 additions & 0 deletions crates/cli/src/commands/order/mod.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
mod add;
mod compose;
mod detail;
mod list;
mod remove;
Expand All @@ -7,6 +8,7 @@ use crate::execute::Execute;
use add::CliOrderAddArgs;
use anyhow::Result;
use clap::Parser;
use compose::Compose;
use detail::CliOrderDetailArgs;
use list::CliOrderListArgs;
use remove::CliOrderRemoveArgs;
Expand All @@ -24,6 +26,9 @@ pub enum Order {

#[command(about = "Remove an Order", alias = "rm")]
Remove(CliOrderRemoveArgs),

#[command(about = "Compose a .rain order file to Rainlang", alias = "comp")]
Compose(Compose),
}

impl Execute for Order {
Expand All @@ -33,6 +38,7 @@ impl Execute for Order {
Order::Detail(detail) => detail.execute().await,
Order::Create(create) => create.execute().await,
Order::Remove(remove) => remove.execute().await,
Order::Compose(compose) => compose.execute().await,
}
}
}
1 change: 1 addition & 0 deletions crates/cli/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ use clap::Subcommand;

mod commands;
mod execute;
mod output;
mod status;
mod subgraph;
mod transaction;
Expand Down
29 changes: 29 additions & 0 deletions crates/cli/src/output.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
use std::io::Write;
use std::path::PathBuf;

#[derive(clap::ValueEnum, Clone)]
pub enum SupportedOutputEncoding {
Binary,
Hex,
}

pub fn output(
output_path: &Option<PathBuf>,
output_encoding: SupportedOutputEncoding,
bytes: &[u8],
) -> anyhow::Result<()> {
let hex_encoded: String;
let encoded_bytes: &[u8] = match output_encoding {
SupportedOutputEncoding::Binary => bytes,
SupportedOutputEncoding::Hex => {
hex_encoded = alloy_primitives::hex::encode_prefixed(bytes);
hex_encoded.as_bytes()
}
};
if let Some(output_path) = output_path {
std::fs::write(output_path, encoded_bytes)?
} else {
std::io::stdout().write_all(encoded_bytes)?
}
Ok(())
}
182 changes: 182 additions & 0 deletions crates/common/src/dotrain_order.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,182 @@
use dotrain::{error::ComposeError, RainDocument};
use rain_orderbook_app_settings::{
config_source::{ConfigSource, ConfigSourceError},
merge::MergeError,
Config, ParseConfigSourceError,
};
use thiserror::Error;

use crate::rainlang::compose_to_rainlang;

pub struct DotrainOrder {
pub config: Config,
pub dotrain: String,
}

#[derive(Error, Debug)]
pub enum DotrainOrderError {
#[error(transparent)]
ConfigSourceError(#[from] ConfigSourceError),

#[error(transparent)]
ParseConfigSourceError(#[from] ParseConfigSourceError),

#[error("Scenario {0} not found")]
ScenarioNotFound(String),

#[error(transparent)]
ComposeError(#[from] ComposeError),

#[error(transparent)]
MergeConfigError(#[from] MergeError),
}

impl DotrainOrder {
pub async fn new(dotrain: String, config: Option<String>) -> Result<Self, DotrainOrderError> {
match config {
Some(config) => {
let config_string = ConfigSource::try_from_string(config).await?;
let frontmatter = RainDocument::get_front_matter(&dotrain).unwrap();
let mut frontmatter_config =
ConfigSource::try_from_string(frontmatter.to_string()).await?;
frontmatter_config.merge(config_string)?;
Ok(Self {
dotrain,
config: frontmatter_config.try_into()?,
})
}
None => {
let frontmatter = RainDocument::get_front_matter(&dotrain).unwrap();
let config_string = ConfigSource::try_from_string(frontmatter.to_string()).await?;
let config: Config = config_string.try_into()?;
Ok(Self { dotrain, config })
}
}
}

pub async fn compose_scenario_to_rainlang(
&self,
scenario: String,
) -> Result<String, DotrainOrderError> {
let scenario = self
.config
.scenarios
.get(&scenario)
.ok_or_else(|| DotrainOrderError::ScenarioNotFound(scenario))?;

Ok(compose_to_rainlang(
self.dotrain.clone(),
scenario.bindings.clone(),
)?)
}
}

#[cfg(test)]
mod tests {
use super::*;

#[tokio::test]
async fn test_config_parse() {
let dotrain = r#"
networks:
polygon:
rpc: https://rpc.ankr.com/polygon
chain-id: 137
network-id: 137
currency: MATIC
deployers:
polygon:
address: 0x1234567890123456789012345678901234567890
scenarios:
polygon:
---
#calculate-io
_ _: 0 0;
#handle-io
:;"#;

let dotrain_order = DotrainOrder::new(dotrain.to_string(), None).await.unwrap();

assert_eq!(
dotrain_order.config.networks.get("polygon").unwrap().rpc,
"https://rpc.ankr.com/polygon".parse().unwrap()
);
}

#[tokio::test]
async fn test_rainlang_from_scenario() {
let dotrain = r#"
networks:
polygon:
rpc: https://rpc.ankr.com/polygon
chain-id: 137
network-id: 137
currency: MATIC
deployers:
polygon:
address: 0x1234567890123456789012345678901234567890
scenarios:
polygon:
---
#calculate-io
_ _: 0 0;
#handle-io
:;"#;

let dotrain_order = DotrainOrder::new(dotrain.to_string(), None).await.unwrap();

let rainlang = dotrain_order
.compose_scenario_to_rainlang("polygon".to_string())
.await
.unwrap();

assert_eq!(
rainlang,
r#"/* 0. calculate-io */
_ _: 0 0;
/* 1. handle-io */
:;"#
);
}

#[tokio::test]
async fn test_config_merge() {
let dotrain = r#"
networks:
polygon:
rpc: https://rpc.ankr.com/polygon
chain-id: 137
network-id: 137
currency: MATIC
---
#calculate-io
_ _: 00;
#handle-io
:;"#;

let settings = r#"
networks:
mainnet:
rpc: https://1rpc.io/eth
chain-id: 1
network-id: 1
currency: ETH"#;

let merged_dotrain_order =
DotrainOrder::new(dotrain.to_string(), Some(settings.to_string()))
.await
.unwrap();

assert_eq!(
merged_dotrain_order
.config
.networks
.get("mainnet")
.unwrap()
.rpc,
"https://1rpc.io/eth".parse().unwrap()
);
}
}
1 change: 1 addition & 0 deletions crates/common/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ pub mod add_order;
pub mod csv;
pub mod deposit;
pub mod dotrain_add_order_lsp;
pub mod dotrain_order;
pub mod frontmatter;
pub mod fuzz;
pub mod meta;
Expand Down

0 comments on commit 16c197f

Please sign in to comment.