feat: add util to build SPKG with a modified start block

This commit is contained in:
Thales Lima
2025-03-10 19:21:04 -03:00
committed by Tamara
parent 0bc39aee55
commit 4425fe1680
4 changed files with 139 additions and 4 deletions

View File

@@ -2720,6 +2720,7 @@ dependencies = [
"postgres",
"serde",
"serde_json",
"serde_yaml",
"tokio",
"tracing",
"tracing-subscriber",

View File

@@ -19,3 +19,4 @@ serde = { version = "1.0.218", features = ["derive"] }
hex = "0.4.3"
tracing-subscriber = "0.3.19"
postgres = "0.19.10"
serde_yaml = "0.9.34"

View File

@@ -1,6 +1,5 @@
use std::collections::HashMap;
use figment::providers::Format;
use hex::FromHex;
use serde::{Deserialize, Serialize};
@@ -18,9 +17,9 @@ impl From<String> for HexBytes {
}
}
impl Into<String> for HexBytes {
fn into(self) -> String {
format!("0x{}", hex::encode(self.0))
impl From<HexBytes> for String {
fn from(val: HexBytes) -> Self {
format!("0x{}", hex::encode(val.0))
}
}

View File

@@ -0,0 +1,134 @@
use std::{error::Error, fs, path::Path, process::Command};
use figment::{
providers::{Format, Yaml},
value::Value,
Figment,
};
/// Build a Substreams package with modifications to the YAML file.
pub fn build_spkg<F>(yaml_file_path: &str, modify_func: F) -> Result<String, Box<dyn Error>>
where
F: FnOnce(&mut Value) -> Result<(), Box<dyn Error>>,
{
// Create a backup file of the unmodified Substreams protocol YAML config file.
let backup_file_path = format!("{}.backup", yaml_file_path);
fs::copy(yaml_file_path, &backup_file_path)?;
let figment = Figment::new().merge(Yaml::file(yaml_file_path));
let mut data: Value = figment.extract()?;
// Apply the modification function to update the YAML files
modify_func(&mut data).expect("Failed to modify the YAML config file.");
let parent_dir = Path::new(yaml_file_path)
.parent()
.unwrap_or_else(|| Path::new(""))
.to_str()
.unwrap_or("");
let package_name = data
.clone()
.find("package")
.expect("Package not found on YAML")
.find("name")
.expect("Name not found on YAML")
.as_str()
.expect("Failed to convert name to string.")
.replace("_", "-");
let binding = data
.clone()
.find("package")
.expect("Package not found on YAML")
.find("version")
.expect("Version not found on YAML");
let package_version = binding.as_str().unwrap_or("");
let spkg_name = format!("{}/{}-{}.spkg", parent_dir, package_name, package_version);
// Write the modified YAML back to the file
let yaml_string = serde_yaml::to_string(&data)?;
fs::write(yaml_file_path, yaml_string)?;
// Run the substreams pack command to create the spkg
match Command::new("substreams")
.arg("pack")
.arg(yaml_file_path)
.output()
{
Ok(output) => {
if !output.status.success() {
println!(
"Substreams pack command failed: {}",
String::from_utf8_lossy(&output.stderr)
);
}
}
Err(e) => {
println!("Error running substreams pack command: {}", e);
}
}
// Restore the original YAML from backup
fs::copy(&backup_file_path, yaml_file_path)?;
fs::remove_file(&backup_file_path)?;
Ok(spkg_name)
}
/// Update the initial block for all modules in the configuration data.
pub fn modify_initial_block(data: &mut Value, start_block: usize) {
if let Value::Dict(_, ref mut dict) = data {
if let Some(Value::Array(_, modules)) = dict.get_mut("modules") {
for module in modules.iter_mut() {
if let Value::Dict(_, ref mut module_dict) = module {
module_dict.insert("initialBlock".to_string(), Value::from(start_block));
}
}
}
}
}
#[cfg(test)]
mod tests {
use figment::value::Value;
use super::*;
fn create_test_data() -> Value {
let file_path = Path::new("src/assets/substreams_example.yaml");
let figment = Figment::new().merge(Yaml::file(file_path));
figment
.extract()
.expect("Failed to parse YAML file")
}
#[test]
fn test_modify_initial_block_normal_case() {
let mut data = create_test_data();
// Apply modification
let new_block = 12345;
modify_initial_block(&mut data, new_block);
// Verify all modules now have the correct initialBlock
if let Value::Dict(_, dict) = &data {
if let Some(Value::Array(_, modules)) = dict.get("modules") {
for module in modules {
if let Value::Dict(_, module_dict) = module {
if let Some(Value::Num(_, block)) = module_dict.get("initialBlock") {
assert_eq!(block.to_u128().unwrap(), new_block as u128);
} else {
panic!("initialBlock not found or has wrong type");
}
}
}
} else {
panic!("modules not found or has wrong type");
}
}
}
}