Skip to content

Commit 6914f33

Browse files
committed
wip
1 parent 7e5999a commit 6914f33

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

69 files changed

+214
-304
lines changed

src/git.rs

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
use std::fs::File;
2+
use std::io::Write;
3+
use std::path::Path;
4+
5+
use anyhow::Result;
6+
7+
use crate::utils;
8+
9+
pub fn init_repository(dir: &Path) -> Result<()> {
10+
if !dir.join(".git").exists() {
11+
// Temporary fix to work around bug in libgit2 when creating a
12+
// directory in the root of a posix filesystem.
13+
// See: https://github.com/libgit2/libgit2/issues/5130
14+
utils::create_dir_all(dir)?;
15+
git2::Repository::init(dir)?;
16+
write_ignore_file(dir)?;
17+
}
18+
Ok(())
19+
}
20+
21+
pub fn write_ignore_file(project_path: &Path) -> Result<()> {
22+
let fp_ignore = project_path.join(".gitignore");
23+
let mut fp_ignore_file = File::create(fp_ignore)?;
24+
fp_ignore_file.write_all(b"/target\n/migration/target")?;
25+
Ok(())
26+
}

src/main.rs

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,13 @@ use clap::Parser;
55
mod test;
66
mod utils;
77
use i18n::set_locale;
8-
use utils::check_for_updates;
98
mod i18n;
9+
mod git;
10+
mod templates;
11+
mod project;
12+
mod updater;
13+
mod printer;
14+
mod namer;
1015

1116
rust_i18n::i18n!("locales", fallback = "en");
1217
#[derive(Parser, Debug)]
@@ -28,17 +33,19 @@ pub struct NewCmd {
2833
}
2934
#[tokio::main]
3035
async fn main() -> Result<()> {
31-
utils::print_logo();
36+
printer::print_logo();
3237
let opts: Opts = Opts::parse();
3338
match opts.subcmd {
3439
SubCommand::New(new_cmd) => {
3540
set_locale(&new_cmd.lang);
36-
check_for_updates().await;
37-
match utils::create_project(&new_cmd) {
41+
updater::check_for_updates().await;
42+
match project::create(&new_cmd) {
3843
Ok(_) => (),
39-
Err(e) => utils::error(e.to_string()),
44+
Err(e) => printer::error(e.to_string()),
4045
};
4146
}
4247
}
4348
Ok(())
4449
}
50+
51+

src/utils/restricted_names.rs renamed to src/namer.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
use anyhow::bail;
22
use anyhow::Result;
33

4+
45
/// Returns `true` if the name contains non-ASCII characters.
56
pub fn is_non_ascii_name(name: &str) -> bool {
67
name.chars().any(|ch| ch > '\x7f')
File renamed without changes.

src/project.rs

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
use std::ffi::{OsStr, OsString};
2+
use std::path::Path;
3+
use std::{env, slice};
4+
5+
use anyhow::{Context, Result};
6+
use rust_i18n::t;
7+
8+
use crate::printer::{self, success, warning};
9+
use crate::namer;
10+
use crate::NewCmd;
11+
12+
pub fn create(new_cmd: &NewCmd) -> Result<()> {
13+
check_name(&new_cmd.project_name)?;
14+
let project_name = &new_cmd.project_name;
15+
let project_path = Path::new(project_name);
16+
if project_path.exists() {
17+
anyhow::bail!(t!(
18+
"error_project_path_exist",
19+
path = project_path.to_string_lossy()
20+
))
21+
}
22+
23+
check_path(project_path)?;
24+
crate::templates::classic::generate(new_cmd)?;
25+
after_print_info(project_name);
26+
Ok(())
27+
}
28+
29+
fn after_print_info(project_name: &String) {
30+
println!(); // a new line
31+
success(t!("create_info", project_name = project_name).replace(r"\n", "\n"));
32+
success(t!("create_success").replace(r"\n", "\n"));
33+
success(t!("rust_version_tip"));
34+
println!(); // a new line
35+
}
36+
37+
fn check_name(name: &str) -> Result<()> {
38+
namer::validate_package_name(name, "package name")?;
39+
40+
if namer::is_keyword(name) {
41+
anyhow::bail!(t!("error_is_keyword", name = name));
42+
}
43+
if namer::is_conflicting_artifact_name(name) {
44+
warning(t!("error_is_conflicting_artifact_name", name = name).replace(r"\n", "\n"));
45+
}
46+
if name == "test" {
47+
anyhow::bail!(t!("error_equal_test").replace(r"\n", "\n"))
48+
}
49+
if ["core", "std", "alloc", "proc_macro", "proc-macro"].contains(&name) {
50+
warning(t!("error_part_of_standard_library", name = name,).replace(r"\n", "\n"));
51+
}
52+
if namer::is_windows_reserved(name) {
53+
if cfg!(windows) {
54+
anyhow::bail!(t!("error_is_windows_reserved", name = name),);
55+
} else {
56+
warning(t!("warning_is_windows_reserved", name = name).replace(r"\n", "\n"));
57+
}
58+
}
59+
if namer::is_non_ascii_name(name) {
60+
warning(t!("warning_is_non_ascii_name", name = name).replace(r"\n", "\n"));
61+
}
62+
Ok(())
63+
}
64+
fn check_path(path: &Path) -> Result<()> {
65+
// warn if the path contains characters that will break `env::join_paths`
66+
if join_paths(slice::from_ref(&OsStr::new(path)), "").is_err() {
67+
let path = path.to_string_lossy();
68+
printer::warning(t!("warning_invalid_path", path = path));
69+
}
70+
Ok(())
71+
}
72+
73+
fn join_paths<T: AsRef<OsStr>>(paths: &[T], env: &str) -> Result<OsString> {
74+
env::join_paths(paths.iter()).with_context(|| {
75+
let mut message = t!("erroe_join_paths", env = env).replace(r"\n", "\n");
76+
for path in paths {
77+
use std::fmt::Write;
78+
write!(&mut message, "\n {:?}", Path::new(path)).unwrap();
79+
}
80+
message
81+
})
82+
}
Lines changed: 13 additions & 113 deletions
Original file line numberDiff line numberDiff line change
@@ -1,69 +1,43 @@
1-
use std::ffi::{OsStr, OsString};
1+
use std::ffi::OsStr;
22
use std::fs::{self, File};
33
use std::io::Write;
44
use std::path::Path;
5-
use std::{env, slice};
65

7-
use anyhow::{Context, Result};
6+
use anyhow::Result;
87
use liquid::model::Object;
9-
use print_util::success;
108
use rust_i18n::t;
119

12-
use super::get_selection::{get_user_selected, UserSelected};
13-
use super::{print_util, restricted_names, warning};
14-
use crate::NewCmd;
10+
use crate::printer::warning;
11+
use crate::{git, NewCmd};
12+
13+
mod selection;
14+
use selection::Selected;
1515

1616
#[derive(rust_embed::RustEmbed)]
17-
#[folder = "./template"]
17+
#[folder = "./templates/classic"]
1818
struct Template;
1919

20-
pub fn create_project(new_cmd: &NewCmd) -> Result<()> {
21-
check_name(&new_cmd.project_name)?;
22-
let project_name = &new_cmd.project_name;
23-
let project_path = Path::new(project_name);
24-
if project_path.exists() {
25-
anyhow::bail!(t!(
26-
"error_project_path_exist",
27-
path = project_path.to_string_lossy()
28-
))
29-
}
30-
31-
check_path(project_path)?;
32-
let Some(config) = get_user_selected()? else {
20+
pub fn generate(new_cmd: &NewCmd) -> Result<()> {
21+
let Some(config) = selection::get_selected()? else {
3322
anyhow::bail!("cli quit!")
3423
};
35-
match init_git(project_path) {
24+
let project_path = Path::new(&new_cmd.project_name);
25+
match git::init_repository(project_path) {
3626
Ok(_) => {}
3727
Err(e) => {
3828
warning(t!("warning_init_git", error = e).replace(r"\n", "\n"));
3929
}
4030
}
4131

4232
create_files(project_path, config, new_cmd)?;
43-
44-
after_print_info(project_name);
4533
Ok(())
4634
}
4735

48-
fn after_print_info(project_name: &String) {
49-
println!(); // a new line
50-
success(t!("create_info", project_name = project_name).replace(r"\n", "\n"));
51-
success(t!("create_success").replace(r"\n", "\n"));
52-
success(t!("rust_version_tip"));
53-
println!(); // a new line
54-
}
55-
56-
pub fn create_files(
57-
project_path: &Path,
58-
user_selected: UserSelected,
59-
new_cmd: &NewCmd,
60-
) -> Result<()> {
61-
let code_gen = user_selected.code_gen.to_string();
36+
fn create_files(project_path: &Path, user_selected: Selected, new_cmd: &NewCmd) -> Result<()> {
6237
let db_lib = user_selected.db_lib.to_string();
6338
let db_type = user_selected.db_type.to_string();
6439
let data = liquid::object!({
6540
"project_name": new_cmd.project_name,
66-
"code_gen":code_gen,
6741
"db_type":db_type,
6842
"db_lib":db_lib,
6943
"main_log_message":t!("main_log_message"),
@@ -177,77 +151,3 @@ fn write_file(tmpl: &[u8], file_path: &Path, data: &Object) -> Result<()> {
177151
}
178152
Ok(())
179153
}
180-
181-
fn check_name(name: &str) -> Result<()> {
182-
restricted_names::validate_package_name(name, "package name")?;
183-
184-
if restricted_names::is_keyword(name) {
185-
anyhow::bail!(t!("error_is_keyword", name = name));
186-
}
187-
if restricted_names::is_conflicting_artifact_name(name) {
188-
warning(t!("error_is_conflicting_artifact_name", name = name).replace(r"\n", "\n"));
189-
}
190-
if name == "test" {
191-
anyhow::bail!(t!("error_equal_test").replace(r"\n", "\n"))
192-
}
193-
if ["core", "std", "alloc", "proc_macro", "proc-macro"].contains(&name) {
194-
warning(t!("error_part_of_standard_library", name = name,).replace(r"\n", "\n"));
195-
}
196-
if restricted_names::is_windows_reserved(name) {
197-
if cfg!(windows) {
198-
anyhow::bail!(t!("error_is_windows_reserved", name = name),);
199-
} else {
200-
warning(t!("warning_is_windows_reserved", name = name).replace(r"\n", "\n"));
201-
}
202-
}
203-
if restricted_names::is_non_ascii_name(name) {
204-
warning(t!("warning_is_non_ascii_name", name = name).replace(r"\n", "\n"));
205-
}
206-
Ok(())
207-
}
208-
fn check_path(path: &Path) -> Result<()> {
209-
// warn if the path contains characters that will break `env::join_paths`
210-
if join_paths(slice::from_ref(&OsStr::new(path)), "").is_err() {
211-
let path = path.to_string_lossy();
212-
print_util::warning(t!("warning_invalid_path", path = path));
213-
}
214-
Ok(())
215-
}
216-
217-
pub fn join_paths<T: AsRef<OsStr>>(paths: &[T], env: &str) -> Result<OsString> {
218-
env::join_paths(paths.iter()).with_context(|| {
219-
let mut message = t!("erroe_join_paths", env = env).replace(r"\n", "\n");
220-
for path in paths {
221-
use std::fmt::Write;
222-
write!(&mut message, "\n {:?}", Path::new(path)).unwrap();
223-
}
224-
message
225-
})
226-
}
227-
228-
pub fn init_git(project_path: &Path) -> Result<()> {
229-
if !project_path.join(".git").exists() {
230-
// Temporary fix to work around bug in libgit2 when creating a
231-
// directory in the root of a posix filesystem.
232-
// See: https://github.com/libgit2/libgit2/issues/5130
233-
create_dir_all(project_path)?;
234-
git2::Repository::init(project_path)?;
235-
write_ignore_file(project_path)?;
236-
}
237-
Ok(())
238-
}
239-
240-
fn write_ignore_file(project_path: &Path) -> Result<()> {
241-
let fp_ignore = project_path.join(".gitignore");
242-
let mut fp_ignore_file = File::create(fp_ignore)?;
243-
fp_ignore_file.write_all(b"/target\n/migration/target")?;
244-
Ok(())
245-
}
246-
247-
/// Equivalent to [`create_dir_all`] with better error messages.
248-
pub fn create_dir_all(p: impl AsRef<Path>) -> Result<()> {
249-
let p = p.as_ref();
250-
fs::create_dir_all(p)
251-
.with_context(|| format!("failed to create directory `{}`", p.display()))?;
252-
Ok(())
253-
}

0 commit comments

Comments
 (0)