1use std::path::PathBuf;
2
3use anyhow::Context;
4use clap::CommandFactory;
5
6use crate::args::{
7 Cli, CompletionsArgs, ManpagesArgs, MigrationListArgs, MigrationMakeArgs, MigrationNewArgs,
8 ProjectNewArgs,
9};
10use crate::migration_generator::{
11 MigrationGeneratorOptions, create_new_migration, list_migrations, make_migrations,
12};
13use crate::new_project::{CotSource, new_project};
14
15pub fn handle_new_project(
16 ProjectNewArgs { path, name, source }: ProjectNewArgs,
17) -> anyhow::Result<()> {
18 let project_name = match name {
19 None => {
20 let dir_name = path
21 .file_name()
22 .with_context(|| format!("file name not present: {}", path.display()))?;
23 dir_name.to_string_lossy().into_owned()
24 }
25 Some(name) => name,
26 };
27
28 let cot_source = if source.use_git {
29 CotSource::Git
30 } else if let Some(path) = &source.cot_path {
31 CotSource::Path(path)
32 } else {
33 CotSource::PublishedCrate
34 };
35 new_project(&path, &project_name, &cot_source).with_context(|| "unable to create project")
36}
37
38pub fn handle_migration_list(MigrationListArgs { path }: MigrationListArgs) -> anyhow::Result<()> {
39 let path = path.unwrap_or(PathBuf::from("."));
40 let migrations = list_migrations(&path).with_context(|| "unable to list migrations")?;
41 for (app_name, migs) in migrations {
42 for mig in migs {
43 println!("{app_name}\t{mig}");
44 }
45 }
46
47 Ok(())
48}
49
50pub fn handle_migration_make(
51 MigrationMakeArgs {
52 path,
53 app_name,
54 output_dir,
55 }: MigrationMakeArgs,
56) -> anyhow::Result<()> {
57 let path = path.unwrap_or(PathBuf::from("."));
58 let options = MigrationGeneratorOptions {
59 app_name,
60 output_dir,
61 };
62 make_migrations(&path, options).with_context(|| "unable to create migrations")
63}
64
65pub fn handle_migration_new(
66 MigrationNewArgs {
67 name,
68 path,
69 app_name,
70 }: MigrationNewArgs,
71) -> anyhow::Result<()> {
72 let path = path.unwrap_or(PathBuf::from("."));
73 let options = MigrationGeneratorOptions {
74 app_name,
75 output_dir: None,
76 };
77 create_new_migration(&path, &name, options).with_context(|| "unable to create migration")
78}
79
80pub fn handle_cli_manpages(
81 ManpagesArgs { output_dir, create }: ManpagesArgs,
82) -> anyhow::Result<()> {
83 let output_dir = output_dir.unwrap_or(PathBuf::from("."));
84 if create {
85 std::fs::create_dir_all(&output_dir).context("unable to create output directory")?;
86 }
87 clap_mangen::generate_to(Cli::command(), output_dir)
88 .context("unable to generate manpages in output directory")
89}
90
91#[expect(clippy::unnecessary_wraps)] pub fn handle_cli_completions(CompletionsArgs { shell }: CompletionsArgs) -> anyhow::Result<()> {
93 generate_completions(shell, &mut std::io::stdout());
94
95 Ok(())
96}
97
98fn generate_completions(shell: clap_complete::Shell, writer: &mut impl std::io::Write) {
99 clap_complete::generate(shell, &mut Cli::command(), "cot", writer);
100}
101
102#[cfg(test)]
103mod tests {
104 use super::*;
105 use crate::args::CotSourceArgs;
106
107 #[test]
108 fn new_project_wrong_directory() {
109 let temp_dir = tempfile::tempdir().unwrap();
110 let args = ProjectNewArgs {
111 path: temp_dir.path().to_path_buf(),
112 name: None,
113 source: CotSourceArgs {
114 use_git: false,
115 cot_path: None,
116 },
117 };
118
119 let result = handle_new_project(args);
120
121 assert!(result.is_err());
122 }
123
124 #[test]
125 fn migration_list_wrong_directory() {
126 let args = MigrationListArgs {
127 path: Some(PathBuf::from("nonexistent")),
128 };
129
130 let result = handle_migration_list(args);
131
132 assert!(result.is_err());
133 }
134
135 #[test]
136 fn migration_make_wrong_directory() {
137 let args = MigrationMakeArgs {
138 path: Some(PathBuf::from("nonexistent")),
139 app_name: None,
140 output_dir: None,
141 };
142
143 let result = handle_migration_make(args);
144
145 assert!(result.is_err());
146 }
147
148 #[test]
149 fn migration_new_wrong_directory() {
150 let args = MigrationNewArgs {
151 name: "test_migration".to_string(),
152 path: Some(PathBuf::from("nonexistent")),
153 app_name: None,
154 };
155
156 let result = handle_migration_new(args);
157
158 assert!(result.is_err());
159 }
160
161 #[test]
162 fn generate_manpages() {
163 let temp_dir = tempfile::tempdir().unwrap();
164 let args = ManpagesArgs {
165 output_dir: Some(temp_dir.path().to_path_buf()),
166 create: true,
167 };
168
169 let result = handle_cli_manpages(args);
170
171 assert!(result.is_ok());
172 assert!(temp_dir.path().join("cot.1").exists());
173 }
174
175 #[test]
176 fn generate_completions_shell() {
177 let mut output = Vec::new();
178
179 generate_completions(clap_complete::Shell::Bash, &mut output);
180
181 assert!(!output.is_empty());
182 }
183}