use std::path::PathBuf;
use askama::Template;
use heck::ToTitleCase;
use inquire::Confirm;
use crate::cli::NewArgs;
use crate::frontend::write_frontend_tree;
use crate::generate::{
ScaffoldCargoToml, ScaffoldEnvExample, ScaffoldHealth, ScaffoldLibRs, ScaffoldMainRs,
ScaffoldPrintRoutes, ScaffoldPurwaToml, ScaffoldReadme, ScaffoldTestNoDb, ScaffoldTestPostgres,
ScaffoldWelcome, crate_package_name, features_csv, purwa_dep_toml, purwa_orm_dep_toml,
purwa_testing_dep_toml, rust_lib_name_from_package,
};
use crate::util::{GlobalOpts, write_output};
pub fn run_new(
args: NewArgs,
opts: GlobalOpts,
) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
let mut name = args.name;
if name.as_deref().map(str::trim).unwrap_or("").is_empty() && !args.yes {
name = Some(inquire::Text::new("Project name (kebab-case)?").prompt()?);
}
let name = name.ok_or("project name required (pass as arg or use prompt)")?;
let name = name.trim();
if name.is_empty() {
return Err("project name must not be empty".into());
}
let pkg = crate_package_name(name);
let lib = rust_lib_name_from_package(&pkg);
let root = args.output.clone().unwrap_or_else(|| PathBuf::from(&pkg));
let mut auth = args.auth;
let mut inertia = args.inertia;
let mut purwa_path = args.purwa_path.clone();
let port = args.port;
if !args.yes {
if !args.auth
&& Confirm::new("Enable auth feature (purwa/auth)?")
.with_default(false)
.prompt()?
{
auth = true;
}
if !args.inertia
&& Confirm::new("Enable inertia feature (purwa/inertia)?")
.with_default(false)
.prompt()?
{
inertia = true;
}
if purwa_path.is_none()
&& Confirm::new("Use local path for `purwa` dependency (instead of crates.io 0.1.0)?")
.with_default(false)
.prompt()?
{
let p: String =
inquire::Text::new("Path to purwa facade crate (directory containing Cargo.toml)?")
.with_default("../purwa/purwa")
.prompt()?;
purwa_path = Some(PathBuf::from(p.trim()));
}
}
let mut feats: Vec<&str> = Vec::new();
if auth {
feats.push("auth");
}
if inertia {
feats.push("inertia");
}
let features_csv = features_csv(&feats);
let dep_inner = purwa_dep_toml(purwa_path.as_deref());
let purwa_testing_dep = purwa_testing_dep_toml(purwa_path.as_deref());
let purwa_orm_dep = purwa_orm_dep_toml(purwa_path.as_deref());
let title = pkg.to_title_case();
let app_name = lib.clone();
let cargo = ScaffoldCargoToml {
crate_name: &pkg,
purwa_dep: &dep_inner,
purwa_testing_dep: &purwa_testing_dep,
purwa_orm_dep: &purwa_orm_dep,
features_csv: &features_csv,
inertia,
}
.render()?;
let lib_rs = ScaffoldLibRs {
title: &title,
inertia,
}
.render()?;
let main_rs = ScaffoldMainRs {
title: &title,
rust_lib_name: &lib,
port,
inertia,
}
.render()?;
let print_rs = ScaffoldPrintRoutes {
rust_lib_name: &lib,
inertia,
}
.render()?;
let health_rs = ScaffoldHealth.render()?;
let purwa_toml = ScaffoldPurwaToml {
title: &title,
app_name: &app_name,
port,
inertia,
}
.render()?;
let env_ex = ScaffoldEnvExample {
app_name: &app_name,
}
.render()?;
let readme = ScaffoldReadme {
title: &title,
port,
inertia,
}
.render()?;
let welcome_rs = if inertia {
Some(ScaffoldWelcome.render()?)
} else {
None
};
let test_no_db = ScaffoldTestNoDb {
rust_lib_name: &lib,
}
.render()?;
let test_postgres = ScaffoldTestPostgres {
rust_lib_name: &lib,
}
.render()?;
let mut paths: Vec<(PathBuf, String)> = vec![
(root.join("Cargo.toml"), cargo),
(root.join("src/lib.rs"), lib_rs),
(root.join("src/main.rs"), main_rs),
(root.join("src/bin/purwa-print-routes.rs"), print_rs),
(root.join("src/routes/health.rs"), health_rs),
(root.join("purwa.toml"), purwa_toml),
(root.join(".env.example"), env_ex),
(root.join("README.md"), readme),
(root.join("tests/no_db_smoke.rs"), test_no_db),
(root.join("tests/postgres_optional.rs"), test_postgres),
];
if let Some(w) = welcome_rs {
paths.push((root.join("src/routes/welcome.rs"), w));
paths.push((root.join("public/.gitkeep"), String::new()));
}
for (path, content) in paths {
write_output(&path, &content, opts)?;
}
let gitkeep = root.join("database/migrations/.gitkeep");
write_output(&gitkeep, "", opts)?;
if inertia {
write_frontend_tree(&root.join("frontend"), port, opts)?;
}
if !opts.dry_run {
eprintln!("Created Purwa app at {}", root.display());
eprintln!("Next: cd {} && cargo build", root.display());
}
Ok(())
}