Skip to content

Commit

Permalink
[Rust]: Add the new blockchain crate to 'rust/tw_coin_registry/Cargo.…
Browse files Browse the repository at this point in the history
…toml'
  • Loading branch information
satoshiotomakan committed Nov 21, 2023
1 parent 4ec1948 commit aadca2b
Show file tree
Hide file tree
Showing 7 changed files with 116 additions and 58 deletions.
7 changes: 7 additions & 0 deletions codegen-v2/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions codegen-v2/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ path = "src/main.rs"

[dependencies]
convert_case = "0.6.0"
pathdiff = "0.2.1"
serde = { version = "1.0.159", features = ["derive"] }
serde_json = "1.0.95"
serde_yaml = "0.9.21"
Expand Down
36 changes: 23 additions & 13 deletions codegen-v2/src/codegen/rust/blockchain_type.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,11 @@
// terms governing use, modification, and redistribution, is contained in the
// file LICENSE at the root of the source code distribution tree.

use crate::codegen::rust::toml_editor::Dependencies;
use crate::codegen::rust::{rust_source_directory, CoinItem};
use crate::utils::{read_lines, write_lines, FileContent};
use crate::{Error, Result};
use std::fs;
use std::path::PathBuf;
use crate::utils::FileContent;
use crate::Result;
use std::path::{Path, PathBuf};

const BLOCKCHAIN_TYPE_START: &str = "start_of_blockchain_type";
const BLOCKCHAIN_TYPE_END: &str = "end_of_blockchain_type";
Expand All @@ -31,22 +31,34 @@ pub fn dispatcher_path() -> PathBuf {
coin_registry_directory().join("src").join("dispatcher.rs")
}

pub struct BlockchainType {
pub struct CoinRegistry {
coin: CoinItem,
}

impl BlockchainType {
pub fn new(coin: CoinItem) -> BlockchainType {
BlockchainType { coin }
impl CoinRegistry {
pub fn new(coin: CoinItem) -> CoinRegistry {
CoinRegistry { coin }
}

pub fn add(self) -> Result<()> {
pub fn add(self, path_to_new_blockchain_crate: &Path) -> Result<()> {
self.add_blockchain_crate_to_manifest_file(path_to_new_blockchain_crate)?;
self.add_blockchain_variant()?;
self.add_use_of_blockchain_entry()?;
self.add_blockchain_entry()?;
self.add_blockchain_dispatcher()
}

fn add_blockchain_crate_to_manifest_file(
&self,
path_to_new_blockchain_crate: &Path,
) -> Result<()> {
let path_to_cargo_manifest = coin_registry_directory().join("Cargo.toml");
Dependencies::new(path_to_cargo_manifest).insert_dependency(
&self.coin.id.to_tw_crate_name(),
path_to_new_blockchain_crate,
)
}

fn add_blockchain_variant(&self) -> Result<()> {
let blockchain_type_rs_path = blockchain_type_path();
let blockchain_type = self.coin.blockchain_type();
Expand All @@ -72,10 +84,8 @@ impl BlockchainType {

{
let import_pattern = "use ";
let mut entries_region =
dispatcher_rs.rfind_line(|line| line.contains(import_pattern))?;
entries_region
.push_line_after(format!("use {tw_crate_name}::entry::{blockchain_entry};"));
let mut last_entry = dispatcher_rs.rfind_line(|line| line.contains(import_pattern))?;
last_entry.push_line_after(format!("use {tw_crate_name}::entry::{blockchain_entry};"));
}

dispatcher_rs.write()
Expand Down
32 changes: 8 additions & 24 deletions codegen-v2/src/codegen/rust/coin_integration_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

use crate::codegen::rust::coin_id::CoinId;
use crate::codegen::rust::{rs_header, tw_any_coin_directory, CoinItem};
use crate::utils::read_lines;
use crate::utils::FileContent;
use crate::{Error, Result};
use std::fs;
use std::path::PathBuf;
Expand Down Expand Up @@ -120,30 +120,14 @@ mod {chain_id}_sign;
let chains_mod_path = chains_integration_tests_directory().join("mod.rs");
let chain_id = self.coin.id.as_str();

let mut chains_mod_rs: Vec<_> = read_lines(&chains_mod_path)?;
let last_line = chains_mod_rs.len() - 1;
let mut chains_mod_rs = FileContent::read(chains_mod_path)?;

// Find the first line that declares a coin module.
let first_mod_idx = chains_mod_rs
.iter()
.position(|line| line.starts_with("mod "))
// Otherwise consider the last line.
.unwrap_or(last_line);

// Insert the new module before the first `mod` line.
chains_mod_rs.insert(first_mod_idx, format!("mod {chain_id};"));

// Find the last line that declares a coin module.
let last_mod_idx = chains_mod_rs
.iter()
.rposition(|line| line.starts_with("mod "))
// Otherwise consider the last line.
.unwrap_or(last_line);

// Sort only the modules alphabetically.
chains_mod_rs[first_mod_idx..=last_mod_idx].sort();
{
let mod_pattern = "mod ";
let mut last_mod = chains_mod_rs.rfind_line(|line| line.starts_with(mod_pattern))?;
last_mod.push_line_after(format!("mod {chain_id};"));
}

let result_chains_mod_rs = chains_mod_rs.join("\n");
fs::write(chains_mod_path, result_chains_mod_rs).map_err(Error::from)
chains_mod_rs.write()
}
}
8 changes: 4 additions & 4 deletions codegen-v2/src/codegen/rust/new_blockchain.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
// terms governing use, modification, and redistribution, is contained in the
// file LICENSE at the root of the source code distribution tree.

use crate::codegen::rust::blockchain_type::BlockchainType;
use crate::codegen::rust::blockchain_type::CoinRegistry;
use crate::codegen::rust::coin_crate::CoinCrate;
use crate::codegen::rust::coin_id::CoinId;
use crate::codegen::rust::coin_integration_tests::CoinIntegrationTests;
Expand All @@ -20,11 +20,11 @@ pub fn new_blockchain(coin: &str) -> Result<()> {
let blockchain_crate_path = CoinCrate::new(coin_item.clone()).create()?;

// Insert the created crate to the workspace.
Workspace::new(workspace_toml_path()).insert_crate(blockchain_crate_path)?;
Workspace::new(workspace_toml_path()).insert_crate(&blockchain_crate_path)?;
// Create integration tests.
CoinIntegrationTests::new(coin_item.clone()).create()?;
// Add the new `BlockchainType` enum variant.
BlockchainType::new(coin_item).add()?;
// Add the new blockchain to the `tw_coin_registry`.
CoinRegistry::new(coin_item).add(&blockchain_crate_path)?;

Ok(())
}
88 changes: 72 additions & 16 deletions codegen-v2/src/codegen/rust/toml_editor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,9 @@

use crate::{Error, Result};
use std::fs;
use std::path::PathBuf;
use std::path::{Path, PathBuf};
use std::str::FromStr;
use toml_edit::{Document, InlineTable, Item, Value};

const NEW_LINE_TAB_DECORATOR: &str = "\n ";
const NO_DECORATOR: &str = "";
Expand All @@ -21,31 +22,23 @@ impl Workspace {
Workspace { path_to_toml }
}

pub fn insert_crate(self, path_to_crate: PathBuf) -> Result<()> {
pub fn insert_crate(self, path_to_crate: &Path) -> Result<()> {
let manifest = fs::read_to_string(&self.path_to_toml)?;
let mut manifest = toml_edit::Document::from_str(&manifest)?;
let mut manifest = Document::from_str(&manifest)?;

let members = manifest["workspace"]["members"]
.as_array_mut()
.ok_or(Error::TomlFormat(
"Invalid 'workspace' TOML format".to_string(),
))?;

// Try to get a `path_to_crate` relative to the `path_to_toml`
let absolute_path_to_manifest = self.path_to_toml.parent().unwrap().canonicalize()?;
let relative_path_to_crate = path_to_crate
.canonicalize()?
.strip_prefix(absolute_path_to_manifest)
.map_err(|e| Error::io_error_other(e.to_string()))?
.to_str()
.ok_or_else(|| Error::io_error_other("Invalid path to the crate".to_string()))?
.to_string();
// Try to get a path to the crate relative to the `Cargo.toml`.
let relative_path_to_crate = relative_path_to_crate(&self.path_to_toml, path_to_crate)?;

// Push the new member and saves sort the manifest.
// Push the new member, sort and save the manifest.

let relative_path_to_crate_decorated =
toml_edit::Value::from(relative_path_to_crate.to_string())
.decorated(NEW_LINE_TAB_DECORATOR, NO_DECORATOR);
let relative_path_to_crate_decorated = Value::from(relative_path_to_crate.to_string())
.decorated(NEW_LINE_TAB_DECORATOR, NO_DECORATOR);

members.push_formatted(relative_path_to_crate_decorated);
members.sort_by(|x, y| x.as_str().cmp(&y.as_str()));
Expand All @@ -54,3 +47,66 @@ impl Workspace {
Ok(())
}
}

pub struct Dependencies {
path_to_toml: PathBuf,
}

impl Dependencies {
pub fn new(path_to_toml: PathBuf) -> Dependencies {
Dependencies { path_to_toml }
}

pub fn insert_dependency(self, dep_name: &str, path_to_dep_crate: &Path) -> Result<()> {
let manifest = fs::read_to_string(&self.path_to_toml)?;
let mut manifest = Document::from_str(&manifest)?;

let dependencies = manifest["dependencies"]
.as_table_like_mut()
.ok_or(Error::TomlFormat("Invalid 'Cargo.toml' format".to_string()))?;

// Try to get a path to the crate relative to the `Cargo.toml`.
let relative_path_to_crate = relative_path_to_crate(&self.path_to_toml, path_to_dep_crate)?;

// Create the new dependency member (aka a TOML inline table with `path` key-value).
let mut new_member = InlineTable::new();
new_member.insert("path", relative_path_to_crate.into());

// Push the new member, sort and save the manifest.
dependencies.insert(dep_name, Item::Value(Value::InlineTable(new_member).into()));
dependencies.sort_values();

fs::write(self.path_to_toml, manifest.to_string())?;

Ok(())
}
}

/// Returns a path to the dependency accordingly to the Cargo manifest file.
/// The result string can be put to `Cargo.toml` as:
/// ```toml
/// tw_foo = { path = "<RESULT_PATH>" }
/// ```
fn relative_path_to_crate(
path_to_cargo_manifest: &Path,
path_to_dependency: &Path,
) -> Result<String> {
let absolute_path_to_crate_directory = path_to_cargo_manifest
.parent()
.ok_or_else(|| Error::io_error_other("Cannot get a parent directory".to_string()))?
.canonicalize()?;
let absolute_path_to_dependency = path_to_dependency.canonicalize()?;

let relative_path_to_dependency = pathdiff::diff_paths(
absolute_path_to_dependency,
absolute_path_to_crate_directory,
)
.ok_or_else(|| {
Error::io_error_other("Cannot get a relative path to the dependency".to_string())
})?
.to_str()
.ok_or_else(|| Error::io_error_other("Invalid path to the crate".to_string()))?
.to_string();

Ok(relative_path_to_dependency)
}
2 changes: 1 addition & 1 deletion codegen-v2/src/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@
// file LICENSE at the root of the source code distribution tree.

use crate::{Error, Result};
use std::fs;
use std::path::{Path, PathBuf};
use std::{fs, io};

pub fn read_lines<P: AsRef<Path>>(path: P) -> Result<Vec<String>> {
let lines = fs::read_to_string(path)?
Expand Down

0 comments on commit aadca2b

Please sign in to comment.