1use clap::Args;
2use include_dir::{include_dir, Dir};
3use std::{fs, path::Path};
4
5use crate::commons::ErrorCode;
6
7static TEMPLATE: Dir = include_dir!("$CARGO_MANIFEST_DIR/src/new/template");
8
9#[derive(Args)]
10pub struct NewOpts {
11 pub package_name: String,
12 #[arg(long, default_value_t = {"./".to_string()})]
13 pub dest_dir: String,
14}
15
16pub fn run(opts: NewOpts) -> Result<(), ErrorCode> {
17 log::info!("Creating {}", opts.package_name);
18
19 let target_path = Path::new(&opts.dest_dir).join(&opts.package_name);
20
21 if let Ok(mut dir) = target_path.read_dir() {
23 if dir.next().is_some() {
24 log::error!(
25 "Destination dir ({}) is not empty",
26 target_path.to_string_lossy()
27 );
28 return Err(ErrorCode::NewProjectDirNotEmpty);
29 }
30 }
31
32 if let Err(err) = fs::create_dir_all(&target_path) {
34 log::error!(
35 "Can't create directory {}: {}",
36 target_path.to_string_lossy(),
37 err
38 );
39 return Err(ErrorCode::NewProjectCantCreateDir);
40 };
41
42 if let Err(err) = TEMPLATE.extract(Path::new(&opts.dest_dir).join(&opts.package_name)) {
44 log::error!(
45 "Can't unpack vertigo stub to {}: {}",
46 target_path.to_string_lossy(),
47 err
48 );
49 return Err(ErrorCode::NewProjectCantUnpackStub);
50 };
51
52 if let Err(err) = fs::remove_file(target_path.join("Cargo.toml_")) {
55 log::error!("Can't rename to Cargo.toml_ to Cargo.toml: {err}");
56 return Err(ErrorCode::NewProjectCantCreateCargoToml);
57 };
58
59 let Some(cargo_toml) = TEMPLATE.get_file("Cargo.toml_") else {
61 log::error!("Can't generate Cargo.toml");
62 return Err(ErrorCode::NewProjectCantCreateCargoToml);
63 };
64
65 let Some(cargo_toml_content) = cargo_toml.contents_utf8() else {
66 log::error!("Can't generate Cargo.toml (encoding error)");
67 return Err(ErrorCode::NewProjectCantCreateCargoToml);
68 };
69
70 if let Err(err) = fs::write(
71 target_path.join("Cargo.toml"),
72 cargo_toml_content.replace("my_app", &opts.package_name),
73 ) {
74 log::error!("Can't write to Cargo.toml: {err}");
75 return Err(ErrorCode::NewProjectCanWriteToCargoToml);
76 };
77
78 Ok(())
79}