use crate::utils::{
self,
dependencies::{Dependence, DEFAULT_DEPENDENCE, DEPENDENCE},
};
use crate::Commands;
use console::{style, Emoji};
use dialogue_macro::dialoguer;
use dialogue_macro::{dialogue_define, Dialogue};
use handlebars::Handlebars;
use serde_json::json;
use std::{
fs::{self, OpenOptions},
io::Write,
path::PathBuf,
process::Command,
};
use tracing::{debug, trace};
dialogue_define!({
project_name=>{
prompt:"请输入项目名称",
default:"wasm-project"
},
dependencies<Dependence>=>{
ty:"multiselect",
options:DEPENDENCE,
prompt:"请选择需要安装的依赖",
default:DEFAULT_DEPENDENCE
},
});
impl Commands {
pub fn new(vite: u8, name: &Option<String>) {
let mut d = Dialogue::new();
d.project_name();
d.dependencies();
let project_name = d.project_name.expect("project_name is None");
trace!("{:?}", project_name);
let selected_dependencies = d.dependencies.expect("dependencies is None");
trace!("{:?}", selected_dependencies);
let spinner = utils::Spinner::new(format!("创建项目中{}...", Emoji("🚚 ", "")));
spinner.start();
let project_dir = create_project(project_name.as_str());
append_create_type(&project_dir);
let mut dependencies_args = vec![];
let mut features_args = vec![];
for item in selected_dependencies.iter() {
dependencies_args.push(item.name);
features_args.push(item.features);
}
debug!("{:?}", dependencies_args);
debug!("{:?}", features_args);
Command::new("cargo")
.arg("add")
.args(dependencies_args)
.arg("--features")
.arg(format!(" {}", features_args.join(","),))
.current_dir(&project_dir)
.output()
.expect("failed to execute process");
let main_rs = render_template(&selected_dependencies);
fs::write(project_dir.join("src/lib.rs"), main_rs).unwrap();
spinner.stop(None);
if vite == 1 {
create_vite(&project_dir, name, &project_name);
}
println!("{} {}", Emoji("✨", ""), style("创建成功").green());
println!("cd {}", project_name);
}
}
fn create_project(project_name: &str) -> PathBuf {
let mut dir = std::env::current_dir().unwrap();
dir.push(project_name);
std::process::Command::new("cargo")
.arg("new")
.arg("--lib")
.arg(&dir)
.output()
.expect("failed to execute process");
dir.clone()
}
fn append_create_type(path: &PathBuf) {
let path = path.join("Cargo.toml");
let append = r#"
[lib]
crate-type = ["cdylib", "rlib"]
"#;
let mut file = OpenOptions::new().append(true).open(&path).unwrap();
file.write(append.to_string().as_bytes()).unwrap();
}
fn render_template(dev_list: &Vec<Dependence>) -> String {
let handlebars = Handlebars::new();
let mut dev_json = json!({});
for item in dev_list {
dev_json[item.name] = serde_json::Value::Bool(true);
}
handlebars
.render_template(include_str!("../templates/basic.hbs"), &dev_json)
.unwrap()
}
fn create_vite(dir: &PathBuf, name: &Option<String>, project_name: &str) {
let vite_name = name.as_deref().unwrap_or("vite-test");
let spinner = utils::Spinner::new(format!("创建vite环境中{}...", Emoji("🚚 ", "")));
spinner.start();
Command::new("npm")
.args([
"create",
"vite",
vite_name,
"--",
"--template",
"vanilla-ts",
])
.current_dir(dir)
.output()
.expect("failed to execute process");
let pkg_json = include_str!("../templates/vite.hbs");
let value = json!({
"name":vite_name,
"project_name":project_name
});
let handlebars = Handlebars::new();
let vite_pkg_json = handlebars.render_template(pkg_json, &value).unwrap();
fs::write(dir.join(vite_name).join("package.json"), vite_pkg_json).unwrap();
spinner.stop(None);
let spinner = utils::Spinner::new(format!("安装npm依赖中{}...", Emoji("🚚 ", "")));
spinner.start();
Command::new("wasm-pack")
.arg("build")
.arg("-t")
.arg("web")
.current_dir(dir)
.output()
.expect("failed to run wasm-pack");
Command::new("npm")
.args(["install"])
.current_dir(dir.join(vite_name))
.output()
.expect("failed to execute process");
spinner.stop(None);
}