Skip to content

Commit

Permalink
Merge pull request #28 from SpiralOutDotEu/tmp
Browse files Browse the repository at this point in the history
Migrate CLI Argument Parsing to Clap
  • Loading branch information
SpiralOutDotEu committed Oct 29, 2023
2 parents e2303f6 + 09d03e0 commit e23d623
Show file tree
Hide file tree
Showing 7 changed files with 263 additions and 75 deletions.
173 changes: 173 additions & 0 deletions Cargo.lock

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

3 changes: 2 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@ edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
clap = { version= "4.4.7", features = ["derive"] }

[dev-dependencies]
assert_cmd = "2.0.12"
predicates = "3.0.4"
predicates = "3.0.4"
84 changes: 40 additions & 44 deletions src/main.rs
Original file line number Diff line number Diff line change
@@ -1,77 +1,73 @@
use clap::{Parser, Subcommand};
use std::env;
use std::fs::File;
use std::io::{self, Write};
use std::path::Path;
use std::process::Command;

/// Entry point of the application.
///
/// This function processes command line arguments to determine which action to perform.
/// Represents the command line interface for the Zero Knowledge Whitelist Tool.
/// Deriving `Parser` from clap allows for automatic parsing of command line arguments.
#[derive(Parser)]
#[clap(
name = "Zero Knowledge Whitelist Tool",
version = env!("CARGO_PKG_VERSION"),
author = "Nikos Koumbakis <n.koumbakis@gmail.com>",
about = "This tool orchestrates the management of an address whitelist using Zero-Knowledge (ZK) proofs.\nSimply input the addresses, and it will generate the corresponding Solidity code.\nIt streamlines the process of maintaining a secure and efficient whitelist for your decentralized application."
)]
struct Cli {
/// The subcommand to be executed, parsed from the command line arguments.
#[clap(subcommand)]
subcmd: SubCommand,
}

/// Enumerates the available subcommands.
/// Deriving `Subcommand` from clap provides automatic subcommand handling.
#[derive(Subcommand)]
enum SubCommand {
/// The `circuit` subcommand copies a circuit file template to the current directory.
Circuit,
/// The `compile` subcommand compiles the circuit file.
Compile,
}
/// The entry point of the application.
/// Parses command line arguments and executes the corresponding subcommand.
fn main() -> io::Result<()> {
// Collect command line arguments
let args: Vec<String> = env::args().collect();
// Check for version flag and display version if present
if args.contains(&"--version".to_string()) || args.contains(&"--v".to_string()) {
display_version();
}
// Check for circuit command and copy circuit file if present
else if args.contains(&"circuit".to_string()) {
copy_circuit_file()?;
}
// Check for compile command and compile circuit if present
else if args.contains(&"compile".to_string()) {
compile_circuit()?;
let args = Cli::parse();

match args.subcmd {
SubCommand::Circuit => copy_circuit_file()?,
SubCommand::Compile => compile_circuit()?,
}

Ok(())
}

/// Displays the version of the tool to the console.
fn display_version() {
println!(
"Zero Knowledge Whitelist Tool, version {}",
env!("CARGO_PKG_VERSION")
);
}

/// Copies the circuit file template to the current directory.
///
/// # Errors
///
/// Returns an error if there is a problem accessing the current directory or writing the file.
/// Copies a circuit file template to the current directory.
/// This function is called when the `circuit` subcommand is used.
fn copy_circuit_file() -> io::Result<()> {
// Getting the current directory
let current_dir = env::current_dir()?;
// Defining the path for the circuit file
let circuit_path = Path::new(&current_dir).join("circuit.circom");
// Creating and writing to the circuit file
let mut file = File::create(circuit_path)?;
file.write_all(include_bytes!("../templates/circuit.circom"))?;
Ok(())
}

/// Compiles the circuit file using the circom compiler.
///
/// # Errors
///
/// Returns an error if the compilation fails.
/// This function is called when the `compile` subcommand is used.
fn compile_circuit() -> io::Result<()> {
// Getting the current directory
let current_dir = env::current_dir()?;
// Executing the circom compiler with required arguments
eprintln!("Working directory: {:?}", current_dir);
let output = Command::new("circom")
.current_dir(&current_dir)
.arg("circuit.circom")
.args(&["--r1cs", "--sym", "--wasm"])
.output()?;

// Checking for compilation success
eprintln!("circom stdout: {}", String::from_utf8_lossy(&output.stdout));
eprintln!("circom stderr: {}", String::from_utf8_lossy(&output.stderr));

if !output.status.success() {
let error_message = format!(
"Compilation failed with error: {}",
String::from_utf8_lossy(&output.stderr)
);
return Err(io::Error::new(io::ErrorKind::Other, error_message));
return Err(io::Error::new(io::ErrorKind::Other, "Compilation failed"));
}

Ok(())
Expand Down
8 changes: 2 additions & 6 deletions tests/circuit_command_tests.rs
Original file line number Diff line number Diff line change
@@ -1,36 +1,32 @@
#[cfg(test)]
/// Module for testing the circuit command functionality.
mod tests {
use assert_cmd::Command;
use std::fs;
use std::path::Path;

/// Test to ensure the circuit command creates the circuit file with correct content
#[test]
fn test_circuit_command() {
// Arrange
let current_dir = std::env::current_dir().unwrap();
let circuit_path = current_dir.join("circuit.circom");
let expected_content = include_bytes!("../templates/circuit.circom");

// Act: Execute the circuit command
// Act
execute_circuit_command();

// Assert: Verify the content of the created file
// Assert
let actual_content = fs::read(&circuit_path).unwrap();
assert_files_match(expected_content, &actual_content, &circuit_path);

// Clean up: Remove the created circuit.circom file
fs::remove_file(circuit_path).unwrap();
}

// Function to execute the circuit command
fn execute_circuit_command() {
let mut cmd = Command::cargo_bin(env!("CARGO_PKG_NAME")).unwrap();
cmd.arg("circuit").assert().success();
}

// Function to compare the content of the files
fn assert_files_match(expected_content: &[u8], actual_content: &[u8], file_path: &Path) {
assert!(file_path.exists());
assert_eq!(expected_content, actual_content);
Expand Down
Loading

0 comments on commit e23d623

Please sign in to comment.