summaryrefslogtreecommitdiff
path: root/src/input.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/input.rs')
-rw-r--r--src/input.rs435
1 files changed, 301 insertions, 134 deletions
diff --git a/src/input.rs b/src/input.rs
index 28a0b7b..144f22a 100644
--- a/src/input.rs
+++ b/src/input.rs
@@ -1,85 +1,24 @@
1use std::env; 1use crate::{error::{MLE, MLError, ErrorType}, Modloader, config::Cfg, db::lists_get, get_current_list, List, modrinth::{get_minecraft_version, MCVersionType}};
2use crate::{config::Cfg, list, modification, update, setup, download, io, error::{MLError, ErrorType, MLE}};
3 2
4#[derive(Debug, Clone, PartialEq, Eq)] 3#[derive(Debug, Clone, PartialEq, Eq)]
5pub struct Input { 4pub struct Input {
6 pub command: Cmd, 5 pub command: Option<Cmd>,
7 pub subcommand: Option<Subcmd>, 6 pub mod_options: Option<ModOptions>,
8 pub args: Option<Vec<String>>, 7 pub mod_id: Option<String>,
9 pub direct_download: bool, 8 pub mod_version: Option<String>,
9 pub set_version: bool,
10 pub all_lists: bool, 10 pub all_lists: bool,
11 pub delete_old: bool,
12 pub clean: bool, 11 pub clean: bool,
13 pub disable_download: bool, 12 pub direct_download: bool,
14 pub version: bool, 13 pub delete_old: bool,
15} 14 pub list: Option<List>,
16 15 pub list_options: Option<ListOptions>,
17impl Input { 16 pub list_id: Option<String>,
18 fn from(string: &str) -> MLE<Self> { 17 pub list_mcversion: Option<String>,
19 let mut split: Vec<&str> = string.split(' ').collect(); 18 pub modloader: Option<Modloader>,
20 19 pub directory: Option<String>,
21 let mut direct_download = false; 20 pub io_options: Option<IoOptions>,
22 let mut all_lists = false; 21 pub file: Option<String>,
23 let mut delete_old = false;
24 let mut clean = false;
25 let mut disable_download = false;
26 let mut version = false;
27
28 let mut toremove: Vec<usize> = vec![];
29 for (i, input) in split.clone().into_iter().enumerate() {
30 if input.starts_with("--") {
31 match input {
32 "--direct-download" => direct_download = true,
33 "--all-lists" => all_lists = true,
34 "--delete-old" => delete_old = true,
35 "--clean" => clean = true,
36 "--disable-download" => disable_download = true,
37 "--version" => version = true,
38 _ => continue,
39 }
40 toremove.push(i)
41 }
42 }
43
44 for rem in toremove.into_iter().rev() {
45 split.remove(rem);
46 }
47
48 if version {
49 match std::env::var("DEV") {
50 Ok(dev) => {
51 let devint = dev.parse::<i32>().unwrap();
52 if devint >= 1 {
53 println!("Modlist by FxQnLr v{} (DEV)", env!("CARGO_PKG_VERSION"));
54 } else {
55 println!("Modlist by FxQnLr v{}", env!("CARGO_PKG_VERSION"));
56 }
57 },
58 Err(..) => println!("Modlist by FxQnLr v{}", env!("CARGO_PKG_VERSION")),
59 }
60
61 std::process::exit(0);
62 }
63
64 let command = Cmd::from(split.remove(0))?;
65 let subcommand = match split.is_empty() {
66 false => Some(Subcmd::from(split.remove(0))?),
67 true => None
68 };
69
70 let args = match split.is_empty() {
71 true => None,
72 false => {
73 let mut strsplit: Vec<String> = Vec::new();
74 for s in split {
75 strsplit.push(String::from(s))
76 }
77 Some(strsplit)
78 }
79 };
80
81 Ok(Self { command, subcommand, args, direct_download, all_lists, delete_old, clean, disable_download, version })
82 }
83} 22}
84 23
85#[derive(Debug, Clone, PartialEq, Eq)] 24#[derive(Debug, Clone, PartialEq, Eq)]
@@ -88,90 +27,318 @@ pub enum Cmd {
88 List, 27 List,
89 Update, 28 Update,
90 Download, 29 Download,
91 Setup, 30 Io,
92 Io 31 Version,
93} 32}
94 33
95impl Cmd { 34#[derive(Debug, Clone, PartialEq, Eq)]
96 fn from(string: &str) -> MLE<Self> { 35pub enum ModOptions {
97 let cmd = match string { 36 Add,
98 "mod" => Self::Mod, 37 Remove
99 "list" => Self::List,
100 "update" => Self::Update,
101 "download" => Self::Download,
102 "setup" => Self::Setup,
103 "io" => Self::Io,
104 _ => return Err(MLError::new(ErrorType::ArgumentError, "Unknown command"))
105 };
106 Ok(cmd)
107 }
108} 38}
109 39
110#[derive(Debug, Clone, PartialEq, Eq)] 40#[derive(Debug, Clone, PartialEq, Eq)]
111pub enum Subcmd { 41pub enum ListOptions {
112 Add, 42 Add,
113 Remove, 43 Remove,
114 Change, 44 Change,
115 Version, 45 Version,
46}
47
48#[derive(Debug, Clone, PartialEq, Eq)]
49pub enum IoOptions {
116 Export, 50 Export,
117 Import, 51 Import
118} 52}
119 53
120impl Subcmd { 54impl Input {
121 fn from(string: &str) -> MLE<Self> { 55 fn from(config: Cfg, input: Vec<String>) -> MLE<Self> {
122 let cmd = match string { 56 let input_string = input.join(" ");
123 "add" => Self::Add, 57 let mut args: Vec<&str> = input_string.split(" -").collect();
124 "remove" => Self::Remove, 58 args[0] = args[0].split_at(1).1;
125 "change" => Self::Change, 59
126 "version" => Self::Version, 60 let mut command: Option<Cmd> = None;
127 "export" => Self::Export, 61
128 "import" => Self::Import, 62 let mut mod_options: Option<ModOptions> = None;
129 _ => return Err(MLError::new(ErrorType::ArgumentError, "SUBCMD_NOT_FOUND")) 63 let mut mod_id: Option<String> = None;
130 }; 64 let mut mod_version: Option<String> = None;
131 Ok(cmd) 65 let mut set_version = false;
66 let mut all_lists = false;
67 let mut clean = false;
68 let mut direct_download = true;
69 let mut delete_old = false;
70 let mut list: Option<List> = None;
71 let mut list_options: Option<ListOptions> = None;
72 let mut list_id: Option<String> = None;
73 let mut list_mcversion: Option<String> = None;
74 let mut modloader: Option<Modloader> = None;
75 let mut directory: Option<String> = None;
76 let mut io_options: Option<IoOptions> = None;
77 let mut file: Option<String> = None;
78
79 for arg in args {
80 let arg_split: Vec<&str> = arg.trim().split(" ").collect();
81 match arg_split[0] {
82 "v" | "version" => {
83 command = Some(Cmd::Version);
84 },
85 "d" | "download" => {
86 command = Some(Cmd::Download);
87 },
88 "u" | "update" => {
89 command = Some(Cmd::Update);
90 },
91 "ma" => {
92 command = Some(Cmd::Mod);
93 mod_options = Some(ModOptions::Add);
94 if arg_split.len() == 2 {
95 mod_id = Some(String::from(arg_split[1]));
96 } else {
97 return Err(MLError::new(ErrorType::ArgumentError, "Please specify a list mod slug or id"));
98 }
99 },
100 "mv" => {
101 command = Some(Cmd::Mod);
102 mod_options = Some(ModOptions::Add);
103 if arg_split.len() == 2 {
104 mod_version = Some(String::from(arg_split[1]));
105 } else {
106 return Err(MLError::new(ErrorType::ArgumentError, "Please specify a version id"));
107 };
108 },
109 "mr" => {
110 command = Some(Cmd::Mod);
111 mod_options = Some(ModOptions::Remove);
112 if arg_split.len() == 2 {
113 mod_id = Some(String::from(arg_split[1]));
114 } else {
115 return Err(MLError::new(ErrorType::ArgumentError, "Please specify a mod id"));
116 };
117 },
118 "set_version" => {
119 set_version = true;
120 },
121 "all_lists" => {
122 all_lists = true;
123 },
124 "clean" => {
125 clean = true;
126 },
127 "no_download" => {
128 direct_download = false;
129 },
130 "delete_old" => {
131 delete_old = true;
132 },
133 "l" => {
134 if arg_split.len() == 2 {
135 list = Some(lists_get(config.clone(), String::from(arg_split[1]))?);
136 } else {
137 return Err(MLError::new(ErrorType::ArgumentError, "Please specify a list via it's id"));
138 }
139 }
140 "la" => {
141 command = Some(Cmd::List);
142 list_options = Some(ListOptions::Add);
143 if arg_split.len() == 2 {
144 list_id = Some(String::from(arg_split[1]));
145 } else {
146 return Err(MLError::new(ErrorType::ArgumentError, "Please give the new list an id"));
147 }
148 },
149 "lr" => {
150 command = Some(Cmd::List);
151 list_options = Some(ListOptions::Remove);
152 },
153 "lc" => {
154 command = Some(Cmd::List);
155 list_options = Some(ListOptions::Change);
156 },
157 "lv" => {
158 command = Some(Cmd::List);
159 list_options = Some(ListOptions::Version);
160 if arg_split.len() == 2 {
161 list_mcversion = Some(String::from(arg_split[1]));
162 } else {
163 return Err(MLError::new(ErrorType::ArgumentError, "Please specify a minecraft version"));
164 }
165 },
166 "mcv" => {
167 if arg_split.len() == 2 {
168 list_mcversion = Some(String::from(arg_split[1]));
169 } else {
170 return Err(MLError::new(ErrorType::ArgumentError, "Please specify a minecraft version"));
171 }
172 },
173 "ml" => {
174 if arg_split.len() == 2 {
175 modloader = Some(Modloader::from(arg_split[1])?);
176 } else {
177 return Err(MLError::new(ErrorType::ArgumentError, "Please specify a modloader"));
178 }
179 },
180 "dir" => {
181 if arg_split.len() == 2 {
182 directory = Some(String::from(arg_split[1]));
183 } else {
184 return Err(MLError::new(ErrorType::ArgumentError, "Please specify a directory"));
185 }
186 },
187 "export" => {
188 command = Some(Cmd::Io);
189 io_options = Some(IoOptions::Export);
190 },
191 "import" => {
192 command = Some(Cmd::Io);
193 io_options = Some(IoOptions::Import);
194 },
195 "f" => {
196 file = Some(String::from(arg_split[1]));
197 },
198 _ => return Err(MLError::new(ErrorType::ArgumentError, format!("Unknown Argument ({})", arg_split[0]).as_str())),
199 }
200 }
201
202 Ok(Self {
203 command,
204 mod_options,
205 mod_id,
206 mod_version,
207 set_version,
208 all_lists,
209 clean,
210 direct_download,
211 delete_old,
212 list,
213 list_options,
214 list_id,
215 list_mcversion,
216 modloader,
217 directory,
218 io_options,
219 file
220 })
132 } 221 }
133} 222}
134 223
135pub async fn get_input(config: Cfg) -> Result<(), Box<dyn std::error::Error>> { 224pub async fn get_input(config: Cfg, args: Vec<String>) -> MLE<Input> {
136 let mut args: Vec<String> = env::args().collect(); 225 let input = Input::from(config.clone(), args)?;
137 args.reverse(); 226
138 args.pop(); 227 if input.command.is_none() { return Err(MLError::new(ErrorType::ArgumentError, "No command specified")); };
139 args.reverse();
140 228
141 let input = Input::from(&args.join(" "))?; 229 match input.clone().command.unwrap() {
230 Cmd::Mod => check_mod(input, config),
231 Cmd::List => check_list(input, config).await,
232 _ => Ok(input),
233 }
234}
142 235
143 match input.command { 236fn check_mod(mut input: Input, config: Cfg) -> MLE<Input> {
144 Cmd::Mod => { 237 if input.mod_options.is_none() {
145 modification(config, input).await 238 return Err(MLError::new(ErrorType::ArgumentError, "No mod option"));
239 };
240 match input.clone().mod_options.unwrap() {
241 ModOptions::Add => {
242 if input.mod_id.is_none() && input.mod_version.is_none() { return Err(MLError::new(ErrorType::ArgumentError, "No mod id/slug or version id")); };
243 if input.list_id.is_none() { input.list = Some(get_current_list(config.clone())?); };
244 Ok(input)
146 }, 245 },
147 Cmd::List => { 246 ModOptions::Remove => {
148 list(config, input).await 247 if input.mod_id.is_none() { return Err(MLError::new(ErrorType::ArgumentError, "MODS_NO_MODID")); };
248 Ok(input)
149 }, 249 },
150 Cmd::Update => { 250 }
151 match update(config, input).await { 251}
152 Ok(..) => Ok(()), 252
153 Err(..) => Err(Box::new(MLError::new(ErrorType::Other, "UPDATE_ERR"))) 253async fn check_list(mut input: Input, config: Cfg) -> MLE<Input> {
154 } 254 if input.list_options.is_none() {
255 return Err(MLError::new(ErrorType::ArgumentError, "NO_LIST_ARGUMENT"));
256 };
257 match input.clone().list_options.unwrap() {
258 ListOptions::Add => {
259 if input.list_id.is_none() { return Err(MLError::new(ErrorType::ArgumentError, "no list id specified")); };
260 if input.list_mcversion.is_none() {
261 println!("No Minecraft Version specified, defaulting to latest release");
262 input.list_mcversion = Some(get_minecraft_version(config.apis.modrinth, MCVersionType::Release).await);
263 };
264 if input.directory.is_none() {
265 let id = input.clone().list_id.unwrap();
266 println!("No download directory specified, defaulting to ./downloads/{}", id);
267 input.directory = Some(format!("./downloads/{}", id))
268 };
269 if input.modloader.is_none() { return Err(MLError::new(ErrorType::ArgumentError, "no modloader specified")); };
270 Ok(input)
155 }, 271 },
156 Cmd::Setup => { 272 ListOptions::Remove => {
157 setup(config).await 273 if input.list.is_none() { return Err(MLError::new(ErrorType::ArgumentError, "NO_LIST_SPECIFIED")); };
274 Ok(input)
158 }, 275 },
159 Cmd::Download => { 276 ListOptions::Change => {
160 download(config, input).await 277 //TODO check if no change
278 if input.list.is_none() { return Err(MLError::new(ErrorType::ArgumentError, "NO_LIST_SPECIFIED")); };
279 Ok(input)
161 }, 280 },
162 Cmd::Io => { 281 ListOptions::Version => {
163 io(config, input).await 282 if input.list.is_none() {
283 println!("No list specified, using default");
284 input.list = Some(get_current_list(config)?);
285 };
286 Ok(input)
164 } 287 }
165 } 288 }
166} 289}
167 290
168#[test] 291#[test]
169fn input_from() { 292fn input_from() {
170 let string = "list add test 1.19.2 fabric"; 293 let config = Cfg::init("modlist.toml").unwrap();
171 let input = Input{ command: Cmd::List, subcommand: Some(Subcmd::Add), args: Some(vec![String::from("test"), String::from("1.19.2"), String::from("fabric")]), direct_download: false, all_lists: false, clean: false, delete_old: false, disable_download: false, version: false }; 294 assert_eq!(
172 assert_eq!(Input::from(string).unwrap(), input); 295 Input::from(config.clone(), vec![String::from("-la test -lv 1.19.3")]).unwrap(),
296 Input {
297 command: Some(Cmd::List),
298 mod_options: None,
299 mod_id: None,
300 mod_version: None,
301 set_version: false,
302 all_lists: false,
303 clean: false,
304 direct_download: false,
305 delete_old: false,
306 list: None,
307 list_options: Some(ListOptions::Add),
308 list_id: Some(String::from("test")),
309 list_mcversion: Some(String::from("1.19.3")),
310 modloader: None,
311 directory: None,
312 io_options: None,
313 file: None
314 }
315 );
173 316
174 let string = "update --direct-download --delete-old"; 317}
175 let input = Input{ command: Cmd::Update, subcommand: None, args: None, direct_download: true, all_lists: false, clean: false, delete_old: true, disable_download: false, version: false }; 318
176 assert_eq!(Input::from(string).unwrap(), input); 319#[tokio::test]
320async fn get_input_test() {
321 let config = Cfg::init("modlist.toml").unwrap();
322 assert_eq!(
323 get_input(config.clone(), vec![String::from("-ma test")]).await.unwrap(),
324 Input {
325 command: Some(Cmd::Mod),
326 mod_options: Some(ModOptions::Add),
327 mod_id: Some(String::from("test")),
328 mod_version: None,
329 set_version: false,
330 all_lists: false,
331 clean: false,
332 direct_download: false,
333 delete_old: false,
334 list: Some(lists_get(config.clone(), String::from("one")).unwrap()),
335 list_options: None,
336 list_id: None,
337 list_mcversion: None,
338 modloader: None,
339 directory: None,
340 io_options: None,
341 file: None
342 }
343 )
177} 344}