Skip to main content

cup_cli/cli/
mod.rs

1mod create_project;
2mod enums;
3
4use std::path::PathBuf;
5
6use anyhow::anyhow;
7use clap::Parser;
8pub use create_project::*;
9pub use enums::*;
10use path_clean::PathClean;
11
12use crate::{logo, plugin::create_instance};
13
14#[derive(Debug, Clone, clap::Parser)]
15#[clap(author, version, about, long_about = None)]
16pub enum Cli {
17    /// Create a new project
18    New {
19        /// The name of the project
20        name: String,
21        /// The type of the project
22        #[arg(short, long, default_value = "exe")]
23        template: TemplateType,
24        /// Location for creating the project
25        #[arg(short, long, default_value = ".")]
26        path: PathBuf,
27    },
28    /// Initialize an existing directory with a project template
29    Init {
30        /// The type of the project
31        #[arg(short, long, default_value = "exe")]
32        template: TemplateType,
33        /// Location for creating the project
34        #[arg(short, long, default_value = ".")]
35        path: PathBuf,
36    },
37    /// Build the project
38    Build,
39    /// Run the project with specified parameters
40    Run,
41    /// Clean the project's build directory
42    Clean,
43    /// Install dependencies
44    Install,
45    /// Uninstall dependencies
46    Uninstall,
47    /// Package the project
48    Pack,
49    /// Publish the project to the internet
50    Publish,
51    /// List information of the specified type
52    List,
53    /// Show the cup logo.
54    Logo,
55}
56
57impl Cli {
58    /// 构造一个 Cli 对象,并重整化路径
59    ///
60    /// # Note
61    /// 此函数内部已进行命令行参数解析,返回值必定是有效数据
62    pub fn new() -> Self {
63        let mut cli = Cli::parse();
64
65        // 重整化路径,使其成为绝对路径
66        let base_path = std::env::current_dir().unwrap();
67        // 路径重整化宏
68        macro_rules! to_abs_path {
69            ($($t: tt)*) => {
70                if let $($t)* { ref mut path, .. } = cli {
71                    if path.is_relative() {
72                        *path = base_path.join(&path).clean();
73                    }
74                }
75            };
76        }
77        // 重整化路径
78        to_abs_path!(Self::New);
79        to_abs_path!(Self::Init);
80
81        cli
82    }
83
84    /// 分派不同子命令的任务
85    pub fn dispatch(self) -> anyhow::Result<()> {
86        match self {
87            // 显示 LOGO
88            Cli::Logo => logo(),
89            // 创建项目
90            Cli::New {
91                name,
92                template,
93                path,
94            } => {
95                let plugin = create_instance(template);
96
97                let project_path = path.join(&name);
98                if project_path.exists() {
99                    return Err(anyhow!(
100                        "Directory or file {} already exists!",
101                        project_path.clean().display()
102                    ));
103                }
104
105                fs_err::create_dir_all(&project_path)?;
106                let result = plugin.create_project(&name, &project_path);
107                // 状态回退
108                if let Err(e) = result {
109                    fs_err::remove_dir_all(&project_path)?;
110                    return Err(e);
111                }
112            }
113            // 初始化项目
114            Cli::Init { template, path } => {
115                let plugin = create_instance(template);
116
117                if !path.exists() {
118                    return Err(anyhow!(
119                        "Directory {} does not exist!",
120                        path.clean().display()
121                    ));
122                }
123                if !path.is_dir() {
124                    return Err(anyhow!("{} is not a directory!", path.clean().display()));
125                }
126                if fs_err::read_dir(&path)?.next().is_some() {
127                    return Err(anyhow!(
128                        "Directory {} is not empty!",
129                        path.clean().display()
130                    ));
131                }
132
133                let name = path.file_name().unwrap().to_str().unwrap();
134                let result = plugin.create_project(name, &path);
135                // 状态回退
136                if let Err(e) = result {
137                    fs_err::remove_dir_all(&path)?;
138                    fs_err::create_dir(path)?;
139                    return Err(e);
140                }
141            }
142            _ => todo!(),
143        };
144        Ok(())
145    }
146}