1use std::env;
4
5use heck::ToSnakeCase;
6#[allow(unused_imports)]
7use rhai::{CustomType, Dynamic, EvalAltResult, Position, TypeBuilder};
8use serde::{Deserialize, Serialize};
9
10use crate::{
11 wizard::{self, AssetsOption, BackgroundOption, DBOption},
12 PIPI_VERSION, OS,
13};
14
15#[derive(Serialize, Deserialize, Clone, Debug, CustomType)]
17pub struct Settings {
18 pub package_name: String,
19 pub module_name: String,
20 pub db: Option<Db>,
21 pub background: Option<Background>,
22 pub asset: Option<Asset>,
23 pub auth: bool,
24 pub mailer: bool,
25 pub initializers: Option<Initializers>,
26 pub features: Features,
27 pub pipi_version_text: String,
28 pub os: OS,
29}
30
31impl From<DBOption> for Option<Db> {
32 fn from(db_option: DBOption) -> Self {
33 match db_option {
34 DBOption::None => None,
35 _ => Some(Db {
36 kind: db_option.clone(),
37 endpoint: db_option.endpoint_config().to_string(),
38 }),
39 }
40 }
41}
42
43impl From<BackgroundOption> for Option<Background> {
44 fn from(bg: BackgroundOption) -> Self {
45 Some(Background { kind: bg })
46 }
47}
48
49impl From<AssetsOption> for Option<Asset> {
50 fn from(asset: AssetsOption) -> Self {
51 match asset {
52 AssetsOption::None => None,
53 _ => Some(Asset { kind: asset }),
54 }
55 }
56}
57
58impl Settings {
59 #[must_use]
61 pub fn from_wizard(package_name: &str, prompt_selection: &wizard::Selections, os: OS) -> Self {
62 let features = if prompt_selection.db.enable() {
63 Features::default()
64 } else {
65 let mut features = Features::disable_features();
66 if matches!(prompt_selection.background, wizard::BackgroundOption::Queue) {
67 features.names.push("bg_redis".to_string());
68 }
69 features
70 };
71
72 Self {
73 package_name: package_name.to_string(),
74 module_name: package_name.to_snake_case(),
75 auth: prompt_selection.db.enable(),
76 mailer: prompt_selection.db.enable(),
77 db: prompt_selection.db.clone().into(),
78 background: prompt_selection.background.clone().into(),
79 asset: prompt_selection.asset.clone().into(),
80 initializers: if prompt_selection.asset == AssetsOption::Serverside {
81 Some(Initializers { view_engine: true })
82 } else {
83 None
84 },
85 features,
86 pipi_version_text: get_pipi_version_text(),
87 os,
88 }
89 }
90}
91impl Default for Settings {
92 fn default() -> Self {
93 #[allow(clippy::default_trait_access)]
94 Self {
95 package_name: Default::default(),
96 module_name: Default::default(),
97 db: Default::default(),
98 background: Default::default(),
99 asset: Default::default(),
100 auth: Default::default(),
101 mailer: Default::default(),
102 initializers: Default::default(),
103 features: Default::default(),
104 pipi_version_text: get_pipi_version_text(),
105 os: Default::default(),
106 }
107 }
108}
109
110fn get_pipi_version_text() -> String {
111 env::var("PIPI_DEV_MODE_PATH").map_or_else(
112 |_| format!(r#"version = "{PIPI_VERSION}""#),
113 |path| {
114 let path = path.replace('\\', "/");
115 format!(r#"version = "{PIPI_VERSION}", path = "{path}""#)
116 },
117 )
118}
119
120#[derive(Serialize, Deserialize, Clone, Debug, Default, CustomType)]
122pub struct Db {
123 pub kind: DBOption,
124 pub endpoint: String,
125}
126
127#[derive(Serialize, Deserialize, Clone, Debug, Default, CustomType)]
129pub struct Background {
130 pub kind: BackgroundOption,
131}
132
133#[derive(Serialize, Deserialize, Clone, Debug, Default, CustomType)]
135pub struct Asset {
136 pub kind: AssetsOption,
137}
138
139#[derive(Serialize, Deserialize, Clone, Debug, Default, CustomType)]
140pub struct Initializers {
141 pub view_engine: bool,
142}
143
144#[derive(Serialize, Deserialize, Clone, Debug)]
146pub struct Features {
147 pub default_features: bool,
148 pub names: Vec<String>,
149}
150
151impl Default for Features {
152 fn default() -> Self {
153 Self {
154 default_features: true,
155 names: vec![],
156 }
157 }
158}
159
160impl Features {
161 #[must_use]
163 pub fn disable_features() -> Self {
164 Self {
165 default_features: false,
166 names: vec!["cli".to_string()],
167 }
168 }
169}