main.rs
1 mod commands; 2 3 use clap::{Args, Parser, Subcommand}; 4 use colored::*; 5 use gramr::Result; 6 7 #[derive(Parser)] 8 #[command( 9 name = "gramr", 10 version, 11 about = "⚔️ A blazing-fast CLI for scaffolding smart contracts", 12 long_about = "Gramr is a Rust-based CLI tool that rapidly generates boilerplate for Solidity contracts, tests, and deployment scripts in Foundry projects." 13 )] 14 struct Cli { 15 #[command(subcommand)] 16 command: Commands, 17 } 18 19 #[derive(Subcommand)] 20 enum Commands { 21 /// Create a new contract, test, or script 22 New(NewArgs), 23 /// Launch interactive wizard (calls wotan) 24 Wizard, 25 /// Show version information 26 Version, 27 } 28 29 #[derive(Args)] 30 struct NewArgs { 31 /// Type of resource to create (contract, library, script, or test) 32 resource_type: String, 33 34 /// Name of the resource 35 name: String, 36 37 /// Generate a Solidity contract 38 #[arg(long)] 39 solidity: bool, 40 41 /// Generate a Rust/Stylus contract for Arbitrum Stylus 42 #[arg(long = "rust-stylus")] 43 rust_stylus: bool, 44 45 /// Inherit from OpenZeppelin ERC20 46 #[arg(long = "oz-erc20")] 47 oz_erc20: bool, 48 49 /// Inherit from OpenZeppelin ERC721 50 #[arg(long = "oz-erc721")] 51 oz_erc721: bool, 52 53 /// Inherit from OpenZeppelin ERC1155 54 #[arg(long = "oz-erc1155")] 55 oz_erc1155: bool, 56 57 /// Use upgradeable version of the contract 58 #[arg(long = "upgradeable")] 59 upgradeable: bool, 60 61 /// Add token extensions (comma-separated: burnable,pausable,votes) 62 #[arg(long = "extensions", value_delimiter = ',')] 63 extensions: Vec<String>, 64 65 /// Generate corresponding test file 66 #[arg(long = "with-test")] 67 with_test: bool, 68 69 /// Generate deployment script 70 #[arg(long = "with-script")] 71 with_script: bool, 72 73 /// Solidity pragma version 74 #[arg(long = "pragma", default_value = "0.8.30")] 75 pragma: String, 76 77 /// SPDX License Identifier 78 #[arg(long = "license", default_value = "UNLICENSED")] 79 license: String, 80 81 /// Include section markers (comment blocks for organizing contract code) 82 #[arg(long = "with-section-markers")] 83 with_section_markers: bool, 84 } 85 86 fn main() { 87 if let Err(e) = run() { 88 eprintln!("{} {}", "Error:".red().bold(), e); 89 std::process::exit(1); 90 } 91 } 92 93 fn run() -> Result<()> { 94 let cli = Cli::parse(); 95 96 match cli.command { 97 Commands::New(args) => commands::execute_new( 98 &args.resource_type, 99 args.name, 100 args.solidity, 101 args.rust_stylus, 102 args.oz_erc20, 103 args.oz_erc721, 104 args.oz_erc1155, 105 args.upgradeable, 106 args.extensions, 107 args.with_test, 108 args.with_script, 109 args.pragma, 110 args.license, 111 args.with_section_markers, 112 ), 113 Commands::Wizard => launch_wizard(), 114 Commands::Version => { 115 println!("⚔️ Gramr v{}", env!("CARGO_PKG_VERSION")); 116 println!(" The legendary sword that forges smart contracts"); 117 Ok(()) 118 } 119 } 120 } 121 122 fn launch_wizard() -> gramr::Result<()> { 123 use std::process::Command; 124 125 // Try to run wotan 126 match Command::new("wotan").status() { 127 Ok(status) => { 128 if status.success() { 129 Ok(()) 130 } else { 131 Err(gramr::GramrError::Other( 132 "Wotan wizard exited with error".to_string(), 133 )) 134 } 135 } 136 Err(_) => { 137 eprintln!( 138 "{} Wotan wizard not found. Please install it with:", 139 "Error:".red().bold() 140 ); 141 eprintln!(" {}", "gramrup install".cyan()); 142 eprintln!(" or"); 143 eprintln!( 144 " {}", 145 "cargo install --git https://github.com/pxlvre/gramr wotan".cyan() 146 ); 147 Err(gramr::GramrError::Other( 148 "Wotan wizard not installed".to_string(), 149 )) 150 } 151 } 152 }