/ cli / src / main.rs
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  }