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