Menu
Public repository / master
AkurAI-Framework / crates/cli/src/main.rs
Latest change f9fa0a48c9b9f40868041393d79336eeb32d8592 - Image generation API, app VERSION in health, base64 decode by Ólafur Búi Ólafsson
//! `akurai` — the AkurAI-Framework CLI.
//!
//! Single binary, two jobs for now: scaffold a project (`new`) and serve it
//! (`serve` / `dev`). Argument parsing is hand-rolled to keep the zero-dependency
//! promise; it stays small because the command surface is small.
mod asset_pipeline;
mod auth;
mod client_logs;
mod cmd_new;
mod cmd_serve;
mod cmd_update;
mod collections_api;
mod css_build;
mod dev_reload;
mod forms;
mod guestbook;
mod i18n;
mod images;
mod json_api;
mod mime;
mod routes;
mod seo;
mod ssg;
use std::path::PathBuf;
use std::process::ExitCode;
const VERSION: &str = env!("CARGO_PKG_VERSION");
fn main() -> ExitCode {
let args: Vec<String> = std::env::args().skip(1).collect();
match run(&args) {
Ok(()) => ExitCode::SUCCESS,
Err(msg) => {
eprintln!("error: {msg}");
ExitCode::FAILURE
}
}
}
fn run(args: &[String]) -> Result<(), String> {
match args.first().map(String::as_str) {
Some("new") => {
let path = args.get(1).ok_or("usage: akurai new <path>")?;
cmd_new::run(&PathBuf::from(path)).map_err(|e| e.to_string())
}
Some(cmd @ ("serve" | "dev")) => {
let mut cfg = parse_serve(&args[1..])?;
cfg.dev = cmd == "dev"; // `dev` enables live-reload; `serve` never does
cmd_serve::run(cfg).map_err(|e| e.to_string())
}
Some("update" | "upgrade" | "self-update") => cmd_update::run(&args[1..], VERSION),
Some("version") | Some("--version") | Some("-V") => {
println!("akurai {VERSION}");
Ok(())
}
Some("help") | Some("--help") | Some("-h") | None => {
print_help();
Ok(())
}
Some(other) => Err(format!("unknown command '{other}' (try: akurai help)")),
}
}
/// Parse flags for `serve`/`dev`: `--dir`, `--host`, `--port`.
fn parse_serve(args: &[String]) -> Result<cmd_serve::Config, String> {
let mut host = "127.0.0.1".to_string();
let mut port: u16 = 8090;
let mut dir = PathBuf::from("frontend");
let mut name = "akurai-framework".to_string();
let mut i = 0;
while i < args.len() {
match args[i].as_str() {
"--host" => {
host = next(args, &mut i, "--host")?;
}
"--port" => {
port = next(args, &mut i, "--port")?
.parse()
.map_err(|_| "invalid --port".to_string())?;
}
"--dir" => {
dir = PathBuf::from(next(args, &mut i, "--dir")?);
}
"--name" => {
name = next(args, &mut i, "--name")?;
}
other => return Err(format!("unknown flag '{other}'")),
}
i += 1;
}
Ok(cmd_serve::Config {
host,
port,
dir,
name,
dev: false,
})
}
fn next(args: &[String], i: &mut usize, flag: &str) -> Result<String, String> {
*i += 1;
args.get(*i)
.cloned()
.ok_or_else(|| format!("{flag} needs a value"))
}
fn print_help() {
println!(
"akurai {VERSION} — single-binary, zero-dependency web framework\n\n\
USAGE:\n\
\x20 akurai new <path> Bootstrap a new project\n\
\x20 akurai serve [opts] Serve the current project (alias: dev)\n\
\x20 akurai update Self-update to the latest release (aliases: upgrade, self-update)\n\
\x20 akurai version Print version\n\n\
UPDATE OPTIONS:\n\
\x20 --check Report whether an update is available; install nothing\n\n\
SERVE OPTIONS:\n\
\x20 --dir <path> Frontend directory (default: frontend)\n\
\x20 --host <addr> Bind host (default: 127.0.0.1)\n\
\x20 --port <n> Bind port (default: 8090)\n\
\x20 --name <name> App name for health endpoint (default: akurai-framework)"
);
}