@@ -5,13 +5,13 @@ use crate::package::Package;
5
5
use clap:: { ColorChoice , Parser , Subcommand , ValueEnum } ;
6
6
use config_file:: ConfigFile ;
7
7
use console:: { self , Term } ;
8
- use indicatif:: { ProgressBar , ProgressStyle } ;
8
+ use indicatif:: { HumanCount , HumanDuration , ProgressBar , ProgressIterator } ;
9
9
use std:: env:: current_dir;
10
10
use std:: fs:: { create_dir, read_dir, read_to_string, remove_dir, write} ;
11
11
use std:: io:: { stdin, Read , Result } ;
12
12
use std:: panic;
13
13
use std:: path:: { Path , PathBuf } ;
14
- use std:: time:: Duration ;
14
+ use std:: time:: Instant ;
15
15
16
16
#[ derive( Parser ) ]
17
17
#[ command( name = "gpm" ) ]
@@ -41,17 +41,17 @@ struct Args {
41
41
#[ arg( long = "colors" , default_value = "auto" , global = true ) ]
42
42
/// Control color output.
43
43
colors : ColorChoice ,
44
+
45
+ #[ arg( long = "nv" , global = true ) ]
46
+ /// Disable progress bars
47
+ not_verbose : bool ,
44
48
}
45
49
46
50
#[ derive( Subcommand ) ]
47
51
enum Actions {
48
52
#[ clap( short_flag = 'u' ) ]
49
53
/// Downloads the latest versions of your wanted packages.
50
- Update {
51
- #[ arg( short = 's' ) ]
52
- /// To print the progress bar
53
- silent : bool ,
54
- } ,
54
+ Update ,
55
55
#[ clap( short_flag = 'p' ) ]
56
56
/// Deletes all installed packages.
57
57
Purge ,
@@ -99,14 +99,18 @@ enum PrefixType {
99
99
100
100
fn main ( ) {
101
101
panic:: set_hook ( Box :: new ( |panic_info| {
102
- match panic_info. location ( ) {
103
- Some ( s) => eprint ! ( "{}@{}:{}: " , print_consts:: err( ) , s. file( ) , s. line( ) ) ,
104
- None => eprint ! ( "{}: " , print_consts:: err( ) ) ,
102
+ eprint ! ( "{:>12} " , print_consts:: err( ) ) ;
103
+ if let Some ( s) = panic_info. payload ( ) . downcast_ref :: < & str > ( ) {
104
+ eprint ! ( "{s}" ) ;
105
+ } else if let Some ( s) = panic_info. payload ( ) . downcast_ref :: < String > ( ) {
106
+ eprint ! ( "{s}" ) ;
107
+ } else {
108
+ eprint ! ( "unknown" ) ;
109
+ } ;
110
+ if let Some ( s) = panic_info. location ( ) {
111
+ eprint ! ( " (@{}:{})" , s. file( ) , s. line( ) )
105
112
}
106
- #[ rustfmt:: skip]
107
- if let Some ( s) = panic_info. payload ( ) . downcast_ref :: < & str > ( ) { eprintln ! ( "{s}" ) ; }
108
- else if let Some ( s) = panic_info. payload ( ) . downcast_ref :: < String > ( ) { eprintln ! ( "{s}" ) ; }
109
- else { eprintln ! ( "unknown" ) ; } ;
113
+ eprintln ! ( "" ) ;
110
114
} ) ) ;
111
115
let args = Args :: parse ( ) ;
112
116
fn set_colors ( val : bool ) {
@@ -131,8 +135,8 @@ fn main() {
131
135
} ;
132
136
let mut cfg_file = ConfigFile :: new ( & contents) ;
133
137
match args. action {
134
- Actions :: Update { silent } => update ( & mut cfg_file, true , silent ) ,
135
- Actions :: Purge => purge ( & mut cfg_file) ,
138
+ Actions :: Update => update ( & mut cfg_file, true , args . not_verbose ) ,
139
+ Actions :: Purge => purge ( & mut cfg_file, args . not_verbose ) ,
136
140
Actions :: Tree {
137
141
charset,
138
142
prefix,
@@ -147,48 +151,48 @@ fn main() {
147
151
}
148
152
}
149
153
150
- fn update ( cfg : & mut ConfigFile , modify : bool , silent : bool ) {
154
+ fn update ( cfg : & mut ConfigFile , modify : bool , not_verbose : bool ) {
151
155
if !Path :: new ( "./addons/" ) . exists ( ) {
152
156
create_dir ( "./addons/" ) . expect ( "Should be able to create addons folder" ) ;
153
157
}
154
158
let packages = cfg. collect ( ) ;
155
159
if packages. is_empty ( ) {
156
160
panic ! ( "No packages to update (modify the \" godot.package\" file to add packages)" ) ;
157
161
}
158
- println ! (
159
- "Updating {} package{}" ,
160
- packages. len( ) ,
161
- if packages. len( ) > 1 { "s" } else { "" }
162
- ) ;
163
- let bar = if silent {
164
- ProgressBar :: hidden ( )
162
+ let bar;
163
+ let p_count = packages. len ( ) as u64 ;
164
+ if not_verbose {
165
+ bar = ProgressBar :: hidden ( ) ;
165
166
} else {
166
- let bar = ProgressBar :: new ( packages. len ( ) as u64 * 3 ) ;
167
- bar. set_style (
168
- ProgressStyle :: with_template (
169
- "[{elapsed}] {bar:20.green/red} {human_pos:>3}/{human_len:3} {msg}" ,
170
- )
171
- . unwrap ( )
172
- . progress_chars ( "-|-" ) ,
173
- ) ;
174
- bar. enable_steady_tick ( Duration :: new ( 0 , 500 ) ) ;
175
- bar
167
+ bar = print_consts:: bar ( p_count) ;
168
+ bar. set_prefix ( "Updating" ) ;
176
169
} ;
177
- packages. into_iter ( ) . for_each ( |mut p| {
178
- bar. set_message ( format ! ( "downloading {p}" ) ) ;
179
- p. download ( ) ;
180
- bar. inc ( 1 ) ;
181
- bar. set_message ( format ! ( "modifying {p}" ) ) ;
182
- if modify {
183
- if let Err ( e) = p. modify ( ) {
184
- eprintln ! (
185
- "{}: modification of {p} failed with err {e}" ,
186
- print_consts:: warn( )
187
- )
170
+ let now = Instant :: now ( ) ;
171
+ packages
172
+ . into_iter ( )
173
+ . progress_with ( bar. clone ( ) )
174
+ . for_each ( |mut p| {
175
+ bar. set_message ( format ! ( "{p}" ) ) ;
176
+ p. download ( ) ;
177
+ if modify {
178
+ if let Err ( e) = p. modify ( ) {
179
+ bar. suspend ( || {
180
+ eprintln ! (
181
+ "{:>12} modification of {p} failed with err {e}" ,
182
+ print_consts:: warn( )
183
+ )
184
+ } ) ;
185
+ }
188
186
}
189
- }
190
- bar. inc ( 1 ) ;
191
- } ) ;
187
+ bar. suspend ( || println ! ( "{:>12} {p}" , print_consts:: green( "Downloaded" ) ) ) ;
188
+ } ) ;
189
+ println ! (
190
+ "{:>12} updated {} package{} in {}" ,
191
+ print_consts:: green( "Finished" ) ,
192
+ HumanCount ( p_count) ,
193
+ if p_count > 0 { "s" } else { "" } ,
194
+ HumanDuration ( now. elapsed( ) )
195
+ )
192
196
}
193
197
194
198
/// Recursively deletes empty directories.
@@ -214,32 +218,54 @@ fn recursive_delete_empty(dir: String) -> Result<()> {
214
218
Ok ( ( ) )
215
219
}
216
220
217
- fn purge ( cfg : & mut ConfigFile ) {
221
+ fn purge ( cfg : & mut ConfigFile , not_verbose : bool ) {
218
222
let packages = cfg
219
223
. collect ( )
220
224
. into_iter ( )
221
225
. filter ( |p| p. is_installed ( ) )
222
226
. collect :: < Vec < Package > > ( ) ;
223
227
if packages. is_empty ( ) {
224
228
if cfg. packages . is_empty ( ) {
225
- panic ! ( "No packages to update (modify the \" godot.package\" file to add packages)" )
229
+ panic ! ( "No packages configured (modify the \" godot.package\" file to add packages)" )
226
230
} else {
227
- panic ! ( "No packages installed(use \" gpm --update\" to install packages)" )
231
+ panic ! ( "No packages installed (use \" gpm --update\" to install packages)" )
228
232
} ;
229
233
} ;
230
- println ! (
231
- "Purging {} package{}" ,
232
- packages. len( ) ,
233
- if packages. len( ) > 1 { "s" } else { "" }
234
- ) ;
235
- packages. into_iter ( ) . for_each ( |p| p. purge ( ) ) ;
234
+ let p_count = packages. len ( ) as u64 ;
235
+ let bar;
236
+ if not_verbose {
237
+ bar = ProgressBar :: hidden ( ) ;
238
+ } else {
239
+ bar = print_consts:: bar ( p_count) ;
240
+ bar. set_prefix ( "Purging" ) ;
241
+ }
242
+ let now = Instant :: now ( ) ;
243
+ packages
244
+ . into_iter ( )
245
+ . progress_with ( bar. clone ( ) ) // the last steps
246
+ . for_each ( |p| {
247
+ bar. set_message ( format ! ( "{p}" ) ) ;
248
+ bar. println ( format ! (
249
+ "{:>12} {p} ({})" ,
250
+ print_consts:: green( "Deleting" ) ,
251
+ p. download_dir( ) ,
252
+ ) ) ;
253
+ p. purge ( )
254
+ } ) ;
236
255
237
256
// run multiple times because the algorithm goes from top to bottom, stupidly.
238
257
for _ in 0 ..3 {
239
258
if let Err ( e) = recursive_delete_empty ( "./addons" . to_string ( ) ) {
240
259
eprintln ! ( "Unable to remove empty directorys: {e}" )
241
260
}
242
261
}
262
+ println ! (
263
+ "{:>12} purge {} package{} in {}" ,
264
+ print_consts:: green( "Finished" ) ,
265
+ HumanCount ( p_count) ,
266
+ if p_count > 0 { "s" } else { "" } ,
267
+ HumanDuration ( now. elapsed( ) )
268
+ )
243
269
}
244
270
245
271
fn tree (
@@ -253,15 +279,14 @@ fn tree(
253
279
} else {
254
280
".\n " . to_string ( )
255
281
} ;
282
+ let mut count: u64 = 0 ;
256
283
iter (
257
284
& mut cfg. packages ,
258
285
"" ,
259
286
& mut tree,
260
287
match charset {
261
- CharSet :: UTF8 => "├──" , // believe it or not, these are unlike
262
- CharSet :: ASCII => "|--" , // its hard to tell, with ligatures enabled
263
- // and rustfmt wants to indent like
264
- // it must not be very stabled
288
+ CharSet :: UTF8 => "├──" , // believe it or not, these are quite unlike
289
+ CharSet :: ASCII => "|--" , // its hard to tell, with ligatures enable
265
290
} ,
266
291
match charset {
267
292
CharSet :: UTF8 => "└──" ,
@@ -270,7 +295,9 @@ fn tree(
270
295
prefix,
271
296
print_tarballs,
272
297
0 ,
298
+ & mut count,
273
299
) ;
300
+ tree. push_str ( format ! ( "{} dependencies" , HumanCount ( count) ) . as_str ( ) ) ;
274
301
275
302
fn iter (
276
303
packages : & mut Vec < Package > ,
@@ -281,11 +308,13 @@ fn tree(
281
308
prefix_type : PrefixType ,
282
309
print_tarballs : bool ,
283
310
depth : u32 ,
311
+ count : & mut u64 ,
284
312
) {
285
313
// the index is used to decide if the package is the last package,
286
314
// so we can use a L instead of a T.
287
315
let mut tmp: String ;
288
316
let mut index = packages. len ( ) ;
317
+ * count += index as u64 ;
289
318
for p in packages {
290
319
let name = p. to_string ( ) ;
291
320
index -= 1 ;
@@ -323,6 +352,7 @@ fn tree(
323
352
prefix_type,
324
353
print_tarballs,
325
354
depth + 1 ,
355
+ count,
326
356
) ;
327
357
}
328
358
}
@@ -368,7 +398,7 @@ fn gpm() {
368
398
let cfg_file = & mut config_file:: ConfigFile :: new ( & r#"packages: {"@bendn/test":2.0.10}"# . into ( ) ) ;
369
399
update ( cfg_file, false , false ) ;
370
400
assert_eq ! ( test_utils:: hashd( "addons" ) . join( "|" ) , "1c2fd93634817a9e5f3f22427bb6b487520d48cf3cbf33e93614b055bcbd1329|8e77e3adf577d32c8bc98981f05d40b2eb303271da08bfa7e205d3f27e188bd7|a625595a71b159e33b3d1ee6c13bea9fc4372be426dd067186fe2e614ce76e3c|c5566e4fbea9cc6dbebd9366b09e523b20870b1d69dc812249fccd766ebce48e|c5566e4fbea9cc6dbebd9366b09e523b20870b1d69dc812249fccd766ebce48e|c850a9300388d6da1566c12a389927c3353bf931c4d6ea59b02beb302aac03ea|d060936e5f1e8b1f705066ade6d8c6de90435a91c51f122905a322251a181a5c|d711b57105906669572a0e53b8b726619e3a21463638aeda54e586a320ed0fc5|d794f3cee783779f50f37a53e1d46d9ebbc5ee7b37c36d7b6ee717773b6955cd|e4f9df20b366a114759282209ff14560401e316b0059c1746c979f478e363e87" ) ;
371
- purge ( cfg_file) ;
401
+ purge ( cfg_file, false ) ;
372
402
assert_eq ! ( test_utils:: hashd( "addons" ) , vec![ ] as Vec <String >) ;
373
403
assert_eq ! (
374
404
tree(
@@ -381,20 +411,40 @@ fn gpm() {
381
411
. skip( 1 )
382
412
. collect:: <Vec <& str >>( )
383
413
. join( "\n " ) ,
384
-
414
+ "└── @bendn/[email protected] \n └── @bendn/[email protected] \n 2 dependencies "
385
415
) ;
386
416
}
387
417
418
+ /// Remember to use {:>12}
388
419
pub mod print_consts {
389
420
use console:: { style, StyledObject } ;
421
+ use indicatif:: { ProgressBar , ProgressStyle } ;
390
422
391
423
#[ inline]
392
- pub fn err ( ) -> StyledObject < & ' static str > {
393
- style ( "err" ) . red ( ) . bold ( )
424
+ pub fn err ( ) -> StyledObject < String > {
425
+ style ( format ! ( "Error" ) ) . red ( ) . bold ( )
394
426
}
395
427
396
428
#[ inline]
397
- pub fn warn ( ) -> StyledObject < & ' static str > {
398
- style ( "err" ) . yellow ( ) . bold ( )
429
+ pub fn warn ( ) -> StyledObject < String > {
430
+ style ( format ! ( "Warn" ) ) . yellow ( ) . bold ( )
431
+ }
432
+
433
+ #[ inline]
434
+ pub fn green ( t : & str ) -> StyledObject < & str > {
435
+ style ( t) . green ( ) . bold ( )
436
+ }
437
+
438
+ #[ inline]
439
+ pub fn bar ( len : u64 ) -> ProgressBar {
440
+ let bar = ProgressBar :: new ( len) ;
441
+ bar. set_style (
442
+ ProgressStyle :: with_template (
443
+ "{prefix:>12.cyan.bold} [{bar:20.green}] {human_pos}/{human_len}: {wide_msg}" ,
444
+ )
445
+ . unwrap ( )
446
+ . progress_chars ( "-> " ) ,
447
+ ) ;
448
+ bar
399
449
}
400
450
}
0 commit comments