3 files changed
+101
-47
crates/cli/src/deploy/config.rs
+16
-23
@@ -4,14 +4,17 @@ use crate::{
4
};
5
use git2::{Cred, CredentialType, Error};
6
use serde::{Deserialize, Serialize};
7
-use smbcloud_model::{account::User, project::Project};
7
+use smbcloud_model::{
8
+ account::User,
9
+ error_codes::{ErrorCode, ErrorResponse},
10
+ project::Project,
11
+};
12
use smbcloud_networking::environment::Environment;
13
use smbcloud_networking_project::crud_project_read::get_project;
14
use spinners::Spinner;
15
use std::{fs, path::Path};
12
-use thiserror::Error;
16
14
-pub(crate) async fn check_config(env: Environment) -> Result<Config, ConfigError> {
17
+pub(crate) async fn check_config(env: Environment) -> Result<Config, ErrorResponse> {
18
let mut spinner: Spinner = Spinner::new(
19
spinners::Spinners::SimpleDotsScrolling,
20
succeed_message("Checking config"),
@@ -31,7 +34,10 @@ pub(crate) async fn check_config(env: Environment) -> Result<Config, ConfigError
34
}
35
36
// Parse toml file
34
- let config_content = fs::read_to_string(config_path).map_err(|_| ConfigError::MissingConfig)?;
37
+ let config_content = fs::read_to_string(config_path).map_err(|_| ErrorResponse::Error {
38
+ error_code: ErrorCode::MissingConfig,
39
+ message: ErrorCode::MissingConfig.message(None).to_string(),
40
+ })?;
41
42
let config: Config = match toml::from_str(&config_content) {
43
Ok(value) => value,
@@ -49,7 +55,7 @@ pub(crate) async fn check_config(env: Environment) -> Result<Config, ConfigError
55
Ok(config)
56
}
57
52
-fn handle_config_error() -> Result<Config, ConfigError> {
58
+fn handle_config_error() -> Result<Config, ErrorResponse> {
59
todo!()
60
}
61
@@ -57,7 +63,7 @@ pub(crate) async fn check_project(
63
env: Environment,
64
access_token: &str,
65
id: i32,
60
-) -> Result<(), ConfigError> {
66
+) -> Result<(), ErrorResponse> {
67
let mut spinner: Spinner = Spinner::new(
68
spinners::Spinners::Hamburger,
69
succeed_message("Validate project"),
@@ -69,7 +75,10 @@ pub(crate) async fn check_project(
75
}
76
Err(_) => {
77
spinner.stop_and_persist(&fail_symbol(), succeed_message("Project is unsynched"));
72
- Err(ConfigError::ProjectNotFound)
78
+ Err(ErrorResponse::Error {
79
+ error_code: ErrorCode::ProjectNotFound,
80
+ message: ErrorCode::ProjectNotFound.message(None).to_string(),
81
+ })
82
}
83
}
84
}
@@ -100,19 +109,3 @@ impl Config {
109
key_path_str
110
}
111
}
103
-
104
-#[derive(Error, Debug, PartialEq, Eq)]
105
-pub enum ConfigError {
106
- #[error("Missing token. Make sure you are logged in.")]
107
- MissingToken,
108
- #[error("Missing config file. Please regenerate with 'smb init'.")]
109
- MissingConfig,
110
- #[error("Missing id in repository. Please regenerate with 'smb init'.")]
111
- MissingId,
112
- #[error("Could not find project in your list. Make sure you have access to the project.")]
113
- ProjectNotFound,
114
- #[error("Cancel operation.")]
115
- Cancel,
116
- #[error("Input error.")]
117
- InputError,
118
-}
crates/cli/src/deploy/setup.rs
+68
-23
@@ -1,17 +1,17 @@
1
-use crate::{
2
- deploy::config::{Config, ConfigError},
3
- ui::highlight,
4
-};
1
+use crate::{deploy::config::Config, ui::highlight};
2
use dialoguer::{theme::ColorfulTheme, Confirm, Input, Select};
3
use regex::Regex;
7
-use smbcloud_model::project::{Project, ProjectCreate};
4
+use smbcloud_model::{
5
+ error_codes::{ErrorCode, ErrorResponse},
6
+ project::{Project, ProjectCreate},
7
+};
8
use smbcloud_networking::{environment::Environment, get_smb_token};
9
use smbcloud_networking_project::{
10
crud_project_create::create_project, crud_project_read::get_projects,
11
};
12
use std::{env, fs, path::Path};
13
14
-pub async fn setup_project(env: Environment) -> Result<Config, ConfigError> {
14
+pub async fn setup_project(env: Environment) -> Result<Config, ErrorResponse> {
15
let path = env::current_dir().ok();
16
let path_str = path
17
.as_ref()
@@ -21,20 +21,36 @@ pub async fn setup_project(env: Environment) -> Result<Config, ConfigError> {
21
let confirm = Confirm::with_theme(&ColorfulTheme::default())
22
.with_prompt(format!("Setup project in {}? y/n", highlight(&path_str)))
23
.interact()
24
- .map_err(|_| ConfigError::InputError)?;
24
+ .map_err(|_| ErrorResponse::Error {
25
+ error_code: ErrorCode::InputError,
26
+ message: ErrorCode::InputError.message(None).to_string(),
27
+ })?;
28
29
if !confirm {
27
- return Err(ConfigError::Cancel);
30
+ return Err(ErrorResponse::Error {
31
+ error_code: ErrorCode::Cancel,
32
+ message: ErrorCode::Cancel.message(None).to_string(),
33
+ });
34
}
35
36
let access_token = match get_smb_token(env).await {
37
Ok(token) => token,
32
- Err(_) => return Err(ConfigError::MissingToken),
38
+ Err(_) => {
39
+ return Err(ErrorResponse::Error {
40
+ error_code: ErrorCode::Unauthorized,
41
+ message: ErrorCode::Unauthorized.message(None).to_string(),
42
+ })
43
+ }
44
};
45
46
let projects = match get_projects(env, access_token).await {
47
Ok(x) => x,
37
- Err(_) => return Err(ConfigError::InputError),
48
+ Err(_) => {
49
+ return Err(ErrorResponse::Error {
50
+ error_code: ErrorCode::InputError,
51
+ message: ErrorCode::InputError.message(None).to_string(),
52
+ })
53
+ }
54
};
55
56
let project: Project = if !projects.is_empty() {
@@ -56,12 +72,21 @@ pub async fn setup_project(env: Environment) -> Result<Config, ConfigError> {
72
// Ensure .smb directory exists
73
let smb_dir = Path::new(".smb");
74
if !smb_dir.exists() {
59
- fs::create_dir(smb_dir).map_err(|_| ConfigError::MissingConfig)?;
75
+ fs::create_dir(smb_dir).map_err(|_| ErrorResponse::Error {
76
+ error_code: ErrorCode::MissingConfig,
77
+ message: ErrorCode::MissingConfig.message(None).to_string(),
78
+ })?;
79
}
80
81
// Write config to .smb/config.toml
63
- let config_toml = toml::to_string(&config).map_err(|_| ConfigError::MissingConfig)?;
64
- fs::write(".smb/config.toml", config_toml).map_err(|_| ConfigError::MissingConfig)?;
82
+ let config_toml = toml::to_string(&config).map_err(|_| ErrorResponse::Error {
83
+ error_code: ErrorCode::MissingConfig,
84
+ message: ErrorCode::MissingConfig.message(None).to_string(),
85
+ })?;
86
+ fs::write(".smb/config.toml", config_toml).map_err(|_| ErrorResponse::Error {
87
+ error_code: ErrorCode::MissingConfig,
88
+ message: ErrorCode::MissingConfig.message(None).to_string(),
89
+ })?;
90
91
Ok(config)
92
}
@@ -70,11 +95,14 @@ async fn select_project(
95
env: Environment,
96
projects: Vec<Project>,
97
path: &str,
73
-) -> Result<Project, ConfigError> {
98
+) -> Result<Project, ErrorResponse> {
99
let confirm = Confirm::with_theme(&ColorfulTheme::default())
100
.with_prompt("Use existing project? y/n")
101
.interact()
77
- .map_err(|_| ConfigError::InputError)?;
102
+ .map_err(|_| ErrorResponse::Error {
103
+ error_code: ErrorCode::InputError,
104
+ message: ErrorCode::InputError.message(None).to_string(),
105
+ })?;
106
107
if !confirm {
108
return create_new_project(env, path).await;
@@ -83,20 +111,23 @@ async fn select_project(
111
.items(&projects)
112
.default(0)
113
.interact()
86
- .map_err(|_| ConfigError::InputError)?;
114
+ .map_err(|_| ErrorResponse::Error {
115
+ error_code: ErrorCode::InputError,
116
+ message: ErrorCode::InputError.message(None).to_string(),
117
+ })?;
118
119
let project = projects[selection].clone();
120
121
Ok(project)
122
}
123
93
-async fn create_new_project(env: Environment, path: &str) -> Result<Project, ConfigError> {
124
+async fn create_new_project(env: Environment, path: &str) -> Result<Project, ErrorResponse> {
125
let default_name = Path::new(path)
126
.file_name()
127
.and_then(|os_str| os_str.to_str())
128
.unwrap_or("project")
129
.to_lowercase()
99
- .replace(' ', "")
130
+ .replace([' ', '-'], "")
131
.replace('-', "");
132
133
let name = match Input::<String>::with_theme(&ColorfulTheme::default())
@@ -106,7 +137,10 @@ async fn create_new_project(env: Environment, path: &str) -> Result<Project, Con
137
{
138
Ok(project_name) => project_name,
139
Err(_) => {
109
- return Err(ConfigError::InputError);
140
+ return Err(ErrorResponse::Error {
141
+ error_code: ErrorCode::InputError,
142
+ message: ErrorCode::InputError.message(None).to_string(),
143
+ });
144
}
145
};
146
@@ -126,7 +160,10 @@ async fn create_new_project(env: Environment, path: &str) -> Result<Project, Con
160
{
161
Ok(repo) => repo,
162
Err(_) => {
129
- return Err(ConfigError::InputError);
163
+ return Err(ErrorResponse::Error {
164
+ error_code: ErrorCode::InputError,
165
+ message: ErrorCode::InputError.message(None).to_string(),
166
+ });
167
}
168
};
169
@@ -136,13 +173,21 @@ async fn create_new_project(env: Environment, path: &str) -> Result<Project, Con
173
{
174
Ok(description) => description,
175
Err(_) => {
139
- return Err(ConfigError::InputError);
176
+ return Err(ErrorResponse::Error {
177
+ error_code: ErrorCode::InputError,
178
+ message: ErrorCode::InputError.message(None).to_string(),
179
+ });
180
}
181
};
182
183
let access_token = match get_smb_token(env).await {
184
Ok(token) => token,
145
- Err(_) => return Err(ConfigError::MissingToken),
185
+ Err(_) => {
186
+ return Err(ErrorResponse::Error {
187
+ error_code: ErrorCode::Unauthorized,
188
+ message: ErrorCode::Unauthorized.message(None).to_string(),
189
+ })
190
+ }
191
};
192
193
match create_project(
@@ -157,6 +202,6 @@ async fn create_new_project(env: Environment, path: &str) -> Result<Project, Con
202
.await
203
{
204
Ok(project) => Ok(project),
160
- Err(_) => Err(ConfigError::MissingConfig),
205
+ Err(e) => Err(e),
206
}
207
}
crates/smbcloud-model/src/error_codes.rs
+17
-1
@@ -24,12 +24,21 @@ impl Display for ErrorResponse {
24
#[derive(Error, Serialize_repr, Deserialize_repr, Debug, EnumIter, IntoStaticStr)]
25
#[repr(i32)]
26
pub enum ErrorCode {
27
+ // Generic errors
28
#[error("Unknown error.")]
29
Unknown = 0,
30
#[error("Parse error.")]
31
ParseError = 1,
32
#[error("Network error.")]
33
NetworkError = 2,
34
+ #[error("Input error")]
35
+ InputError = 3,
36
+ #[error("Missing config file. Please regenerate with 'smb init'.")]
37
+ MissingConfig = 4,
38
+ // #[error("Missing id in repository. Please regenerate with 'smb init'.")]
39
+ // MissingId,
40
+ #[error("Cancel operation.")]
41
+ Cancel = 5,
42
// Account
43
#[error("Unauthorized access.")]
44
Unauthorized = 100,
@@ -47,9 +56,13 @@ impl ErrorCode {
56
100 => ErrorCode::Unauthorized,
57
// Projects
58
1000 => ErrorCode::ProjectNotFound,
50
- // Fallback
59
+ // Generic errors
60
+ 5 => ErrorCode::Cancel,
61
+ 4 => ErrorCode::MissingConfig,
62
+ 3 => ErrorCode::InputError,
63
2 => ErrorCode::ParseError,
64
1 => ErrorCode::NetworkError,
65
+ // Fallback
66
_ => ErrorCode::Unknown,
67
}
68
}
@@ -63,6 +76,9 @@ impl ErrorCode {
76
ErrorCode::ParseError => "Parse error.",
77
ErrorCode::NetworkError => "Network error.",
78
ErrorCode::Unauthorized => "Unauthorized access.",
79
+ ErrorCode::InputError => "Input error.",
80
+ ErrorCode::MissingConfig => "Missing config.",
81
+ ErrorCode::Cancel => "Cancelled operation.",
82
}
83
}
84