use clap::{Parser, Subcommand};
use colored::Colorize;
use std::process::ExitCode;
use tracing_subscriber::EnvFilter;
mod commands;
mod error;
mod templates;
use commands::{check, codegen, init, new_project, profile};
#[derive(Parser)]
#[command(name = "ringkernel")]
#[command(author, version, about, long_about = None)]
#[command(propagate_version = true)]
struct Cli {
#[arg(short, long, global = true)]
verbose: bool,
#[arg(short, long, global = true)]
quiet: bool,
#[command(subcommand)]
command: Commands,
}
#[derive(Subcommand)]
enum Commands {
New {
name: String,
#[arg(short, long, default_value = "basic")]
template: String,
#[arg(short, long)]
path: Option<String>,
#[arg(short, long, default_value = "cuda")]
backends: String,
#[arg(long)]
no_git: bool,
},
Init {
#[arg(short, long, default_value = "cuda")]
backends: String,
#[arg(long)]
force: bool,
},
Codegen {
file: String,
#[arg(short, long, default_value = "cuda")]
backend: String,
#[arg(short, long)]
output: Option<String>,
#[arg(short, long)]
kernel: Option<String>,
#[arg(long)]
dry_run: bool,
},
Check {
#[arg(short, long, default_value = "src")]
path: String,
#[arg(short, long, default_value = "all")]
backends: String,
#[arg(long)]
detailed: bool,
},
Profile {
kernel: String,
#[arg(short, long, default_value = "1000")]
iterations: u32,
#[arg(short, long, default_value = "text")]
format: String,
#[arg(short, long, default_value = "10")]
warmup: u32,
#[arg(short, long)]
output: Option<String>,
#[arg(long)]
detailed: bool,
},
Completions {
#[arg(value_enum)]
shell: clap_complete::Shell,
},
}
fn setup_logging(verbose: bool, quiet: bool) {
let filter = if quiet {
EnvFilter::new("error")
} else if verbose {
EnvFilter::new("debug")
} else {
EnvFilter::new("info")
};
tracing_subscriber::fmt()
.with_env_filter(filter)
.with_target(false)
.without_time()
.init();
}
fn print_banner() {
println!(
"{}",
r#"
____ _ _ __ _
| _ \(_)_ __ __ _| |/ /___ _ __ _ __ ___| |
| |_) | | '_ \ / _` | ' // _ \ '__| '_ \ / _ \ |
| _ <| | | | | (_| | . \ __/ | | | | | __/ |
|_| \_\_|_| |_|\__, |_|\_\___|_| |_| |_|\___|_|
|___/
"#
.bright_cyan()
);
println!(
" {} {}\n",
"GPU-Native Persistent Actor Framework".bright_white(),
format!("v{}", env!("CARGO_PKG_VERSION")).dimmed()
);
}
#[tokio::main]
async fn main() -> ExitCode {
let cli = Cli::parse();
setup_logging(cli.verbose, cli.quiet);
if !cli.quiet {
print_banner();
}
let result = match cli.command {
Commands::New {
name,
template,
path,
backends,
no_git,
} => new_project::execute(&name, &template, path.as_deref(), &backends, no_git).await,
Commands::Init { backends, force } => init::execute(&backends, force).await,
Commands::Codegen {
file,
backend,
output,
kernel,
dry_run,
} => {
codegen::execute(
&file,
&backend,
output.as_deref(),
kernel.as_deref(),
dry_run,
)
.await
}
Commands::Check {
path,
backends,
detailed,
} => check::execute(&path, &backends, detailed).await,
Commands::Profile {
kernel,
iterations,
format,
warmup,
output,
detailed,
} => {
profile::execute(
&kernel,
iterations,
&format,
Some(warmup),
output.as_deref(),
detailed,
)
.await
}
Commands::Completions { shell } => {
use clap::CommandFactory;
clap_complete::generate(
shell,
&mut Cli::command(),
"ringkernel",
&mut std::io::stdout(),
);
Ok(())
}
};
match result {
Ok(()) => ExitCode::SUCCESS,
Err(e) => {
eprintln!("{} {}", "Error:".red().bold(), e);
ExitCode::FAILURE
}
}
}