1
- use clap:: Subcommand ;
2
- use semver:: VersionReq ;
3
- use zip:: ZipArchive ;
4
1
use crate :: config:: Config ;
5
2
use crate :: file:: copy_dir_recursive;
6
3
use crate :: util:: logging:: ask_value;
7
4
use crate :: util:: mod_file:: { parse_mod_info, try_parse_mod_info} ;
8
- use crate :: { done, info, warn, fatal, NiceUnwrap } ;
9
- use sha3:: { Digest , Sha3_256 } ;
10
- use serde:: { Serialize , Deserialize } ;
5
+ use crate :: { done, fatal, info, warn, NiceUnwrap } ;
6
+ use clap:: Subcommand ;
7
+ use colored:: Colorize ;
8
+ use reqwest:: header:: { AUTHORIZATION , USER_AGENT } ;
9
+ use semver:: VersionReq ;
10
+ use serde:: { Deserialize , Serialize } ;
11
11
use serde_json:: json;
12
- use reqwest :: header :: { USER_AGENT , AUTHORIZATION } ;
12
+ use sha3 :: { Digest , Sha3_256 } ;
13
13
use std:: collections:: HashSet ;
14
14
use std:: fs;
15
- use std:: path:: { Path , PathBuf } ;
16
15
use std:: io;
17
- use colored:: Colorize ;
16
+ use std:: path:: { Path , PathBuf } ;
17
+ use zip:: ZipArchive ;
18
18
19
19
#[ derive( Subcommand , Debug ) ]
20
20
#[ clap( rename_all = "kebab-case" ) ]
21
21
pub enum Index {
22
22
/// Create a new entry to be used in the index
23
23
New {
24
24
/// Output folder of entry
25
- output : PathBuf
25
+ output : PathBuf ,
26
26
} ,
27
27
28
28
/// Install a mod from the index to the current profile
@@ -58,38 +58,50 @@ pub struct Entry {
58
58
59
59
pub fn update_index ( config : & Config ) {
60
60
let index_dir = config. get_current_profile ( ) . index_dir ( ) ;
61
-
61
+
62
62
let target_index_dir = index_dir. join ( "geode-sdk_mods" ) ;
63
63
// note to loader devs: never change the format pretty please
64
64
let checksum = index_dir. join ( "geode-sdk_mods.checksum" ) ;
65
65
let current_sha = fs:: read_to_string ( & checksum) . unwrap_or_default ( ) ;
66
66
67
67
let client = reqwest:: blocking:: Client :: new ( ) ;
68
68
69
- let response = client. get ( "https://api.github.com/repos/geode-sdk/mods/commits/main" )
69
+ let response = client
70
+ . get ( "https://api.github.com/repos/geode-sdk/mods/commits/main" )
70
71
. header ( "Accept" , "application/vnd.github.sha" )
71
72
. header ( "If-None-Match" , format ! ( "\" {}\" " , current_sha) )
72
73
. header ( USER_AGENT , "GeodeCli" )
73
- . header ( AUTHORIZATION , std:: env:: var ( "GITHUB_TOKEN" ) . map_or ( "" . into ( ) , |token| format ! ( "Bearer {token}" ) ) )
74
+ . header (
75
+ AUTHORIZATION ,
76
+ std:: env:: var ( "GITHUB_TOKEN" ) . map_or ( "" . into ( ) , |token| format ! ( "Bearer {token}" ) ) ,
77
+ )
74
78
. send ( )
75
79
. nice_unwrap ( "Unable to fetch index version" ) ;
76
80
77
81
if response. status ( ) == 304 {
78
82
done ! ( "Index is up-to-date" ) ;
79
83
return ;
80
84
}
81
- assert ! ( response. status( ) == 200 , "Version check received status code {}" , response. status( ) ) ;
82
- let latest_sha = response. text ( ) . nice_unwrap ( "Unable to decode index version" ) ;
85
+ assert ! (
86
+ response. status( ) == 200 ,
87
+ "Version check received status code {}" ,
88
+ response. status( )
89
+ ) ;
90
+ let latest_sha = response
91
+ . text ( )
92
+ . nice_unwrap ( "Unable to decode index version" ) ;
83
93
84
94
let mut zip_data = io:: Cursor :: new ( Vec :: new ( ) ) ;
85
95
86
- client. get ( "https://github.com/geode-sdk/mods/zipball/main" )
87
- . send ( ) . nice_unwrap ( "Unable to download index" )
88
- . copy_to ( & mut zip_data) . nice_unwrap ( "Unable to write to index" ) ;
96
+ client
97
+ . get ( "https://github.com/geode-sdk/mods/zipball/main" )
98
+ . send ( )
99
+ . nice_unwrap ( "Unable to download index" )
100
+ . copy_to ( & mut zip_data)
101
+ . nice_unwrap ( "Unable to write to index" ) ;
89
102
90
103
let mut zip_archive = ZipArchive :: new ( zip_data) . nice_unwrap ( "Unable to decode index zip" ) ;
91
104
92
-
93
105
let before_items = if target_index_dir. join ( "mods-v2" ) . exists ( ) {
94
106
let mut items = fs:: read_dir ( target_index_dir. join ( "mods-v2" ) )
95
107
. unwrap ( )
@@ -108,16 +120,21 @@ pub fn update_index(config: &Config) {
108
120
fs:: remove_dir_all ( & extract_dir) . nice_unwrap ( "Unable to prepare new index" ) ;
109
121
}
110
122
fs:: create_dir ( & extract_dir) . unwrap ( ) ;
111
- zip_archive. extract ( & extract_dir) . nice_unwrap ( "Unable to extract new index" ) ;
123
+ zip_archive
124
+ . extract ( & extract_dir)
125
+ . nice_unwrap ( "Unable to extract new index" ) ;
112
126
113
-
114
- let new_root_dir = fs:: read_dir ( & extract_dir) . unwrap ( ) . next ( ) . unwrap ( ) . unwrap ( ) . path ( ) ;
115
- copy_dir_recursive ( & new_root_dir, & target_index_dir)
116
- . nice_unwrap ( "Unable to copy new index" ) ;
127
+ let new_root_dir = fs:: read_dir ( & extract_dir)
128
+ . unwrap ( )
129
+ . next ( )
130
+ . unwrap ( )
131
+ . unwrap ( )
132
+ . path ( ) ;
133
+ copy_dir_recursive ( & new_root_dir, & target_index_dir) . nice_unwrap ( "Unable to copy new index" ) ;
117
134
118
135
// we don't care if temp dir removal fails
119
136
drop ( fs:: remove_dir_all ( extract_dir) ) ;
120
-
137
+
121
138
let mut after_items = fs:: read_dir ( target_index_dir. join ( "mods-v2" ) )
122
139
. unwrap ( )
123
140
. map ( |x| x. unwrap ( ) . path ( ) )
@@ -130,13 +147,21 @@ pub fn update_index(config: &Config) {
130
147
131
148
for i in & before_items {
132
149
if !after_items. contains ( i) {
133
- println ! ( " {} {}" , "-" . red( ) , i. file_name( ) . unwrap( ) . to_str( ) . unwrap( ) ) ;
150
+ println ! (
151
+ " {} {}" ,
152
+ "-" . red( ) ,
153
+ i. file_name( ) . unwrap( ) . to_str( ) . unwrap( )
154
+ ) ;
134
155
}
135
156
}
136
157
137
158
for i in & after_items {
138
159
if !before_items. contains ( i) {
139
- println ! ( " {} {}" , "+" . green( ) , i. file_name( ) . unwrap( ) . to_str( ) . unwrap( ) ) ;
160
+ println ! (
161
+ " {} {}" ,
162
+ "+" . green( ) ,
163
+ i. file_name( ) . unwrap( ) . to_str( ) . unwrap( )
164
+ ) ;
140
165
}
141
166
}
142
167
}
@@ -147,18 +172,30 @@ pub fn update_index(config: &Config) {
147
172
}
148
173
149
174
pub fn index_mods_dir ( config : & Config ) -> PathBuf {
150
- config. get_current_profile ( ) . index_dir ( ) . join ( "geode-sdk_mods" ) . join ( "mods-v2" )
175
+ config
176
+ . get_current_profile ( )
177
+ . index_dir ( )
178
+ . join ( "geode-sdk_mods" )
179
+ . join ( "mods-v2" )
151
180
}
152
181
153
182
pub fn get_entry ( config : & Config , id : & String , version : & VersionReq ) -> Option < Entry > {
154
- for dir in index_mods_dir ( config) . read_dir ( ) . nice_unwrap ( "Unable to read index" ) {
183
+ for dir in index_mods_dir ( config)
184
+ . read_dir ( )
185
+ . nice_unwrap ( "Unable to read index" )
186
+ {
155
187
let path = dir. unwrap ( ) . path ( ) ;
156
- let Ok ( mod_info) = try_parse_mod_info ( & path) else { continue ; } ;
188
+ let Ok ( mod_info) = try_parse_mod_info ( & path) else {
189
+ continue ;
190
+ } ;
157
191
if & mod_info. id == id && version. matches ( & mod_info. version ) {
158
- return Some ( serde_json:: from_str (
159
- & fs:: read_to_string ( path. join ( "entry.json" ) )
160
- . nice_unwrap ( "Unable to read index entry" )
161
- ) . nice_unwrap ( "Unable to parse index entry" ) ) ;
192
+ return Some (
193
+ serde_json:: from_str (
194
+ & fs:: read_to_string ( path. join ( "entry.json" ) )
195
+ . nice_unwrap ( "Unable to read index entry" ) ,
196
+ )
197
+ . nice_unwrap ( "Unable to parse index entry" ) ,
198
+ ) ;
162
199
}
163
200
}
164
201
None
@@ -167,7 +204,7 @@ pub fn get_entry(config: &Config, id: &String, version: &VersionReq) -> Option<E
167
204
pub fn install_mod ( config : & Config , id : & String , version : & VersionReq ) -> PathBuf {
168
205
let entry = get_entry ( config, id, version)
169
206
. nice_unwrap ( format ! ( "Unable to find '{id}' version '{version}'" ) ) ;
170
-
207
+
171
208
let plat = if cfg ! ( windows) {
172
209
"windows"
173
210
} else if cfg ! ( target_os = "macos" ) {
@@ -179,15 +216,18 @@ pub fn install_mod(config: &Config, id: &String, version: &VersionReq) -> PathBu
179
216
if !entry. platforms . contains ( plat) {
180
217
fatal ! ( "Mod '{}' is not available on '{}'" , id, plat) ;
181
218
}
182
-
219
+
183
220
info ! ( "Installing mod '{}' version '{}'" , id, version) ;
184
221
185
222
let bytes = reqwest:: blocking:: get ( entry. r#mod . download )
186
223
. nice_unwrap ( "Unable to download mod" )
187
224
. bytes ( )
188
225
. nice_unwrap ( "Unable to download mod" ) ;
189
-
190
- let dest = config. get_current_profile ( ) . mods_dir ( ) . join ( format ! ( "{id}.geode" ) ) ;
226
+
227
+ let dest = config
228
+ . get_current_profile ( )
229
+ . mods_dir ( )
230
+ . join ( format ! ( "{id}.geode" ) ) ;
191
231
192
232
let mut hasher = Sha3_256 :: new ( ) ;
193
233
hasher. update ( & bytes) ;
@@ -214,10 +254,17 @@ fn create_index_json(path: &Path) {
214
254
215
255
let response = reqwest:: blocking:: get ( & url) . nice_unwrap ( "Unable to access .geode file at URL" ) ;
216
256
217
- let file_name = reqwest:: Url :: parse ( & url) . unwrap ( )
257
+ let file_name = reqwest:: Url :: parse ( & url)
258
+ . unwrap ( )
218
259
. path_segments ( )
219
260
. and_then ( |segments| segments. last ( ) )
220
- . and_then ( |name| if name. is_empty ( ) { None } else { Some ( name. to_string ( ) ) } )
261
+ . and_then ( |name| {
262
+ if name. is_empty ( ) {
263
+ None
264
+ } else {
265
+ Some ( name. to_string ( ) )
266
+ }
267
+ } )
221
268
. unwrap_or_else ( || ask_value ( "Filename" , None , true ) ) ;
222
269
223
270
let file_contents = response
@@ -254,7 +301,8 @@ fn create_index_json(path: &Path) {
254
301
std:: fs:: write (
255
302
path. join ( "index.json" ) ,
256
303
String :: from_utf8 ( ser. into_inner ( ) ) . unwrap ( ) ,
257
- ) . nice_unwrap ( "Unable to write to project" ) ;
304
+ )
305
+ . nice_unwrap ( "Unable to write to project" ) ;
258
306
}
259
307
260
308
fn create_entry ( out_path : & Path ) {
@@ -303,6 +351,6 @@ pub fn subcommand(config: &mut Config, cmd: Index) {
303
351
update_index ( config) ;
304
352
install_mod ( config, & id, & version. unwrap_or ( VersionReq :: STAR ) ) ;
305
353
done ! ( "Mod installed" ) ;
306
- } ,
354
+ }
307
355
}
308
356
}
0 commit comments