vertigo_cli/new/
mod.rs

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    // Check if dir is empty or non-existent
22    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    // Create directory
33    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    // Paste files into it
43    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    // Remove Cargo.toml_
53    // (cargo packaging does not permit adding second Cargo.toml file)
54    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::NewProjectCanCreateCargoToml);
57    };
58
59    // Save Cargo.toml with replaced package name
60    let cargo_toml = TEMPLATE.get_file("Cargo.toml_").unwrap();
61    let cargo_toml_content = cargo_toml.contents_utf8().unwrap();
62
63    if let Err(err) = fs::write(
64        target_path.join("Cargo.toml"),
65        cargo_toml_content.replace("my_app", &opts.package_name),
66    ) {
67        log::error!("Can't write to Cargo.toml: {err}");
68        return Err(ErrorCode::NewProjectCanWriteToCargoToml);
69    };
70
71    Ok(())
72}