@@ -2,13 +2,16 @@ mod config_file;
2
2
mod package;
3
3
4
4
use crate :: package:: Package ;
5
- use clap:: { Parser , Subcommand , ValueEnum } ;
5
+ use clap:: { ColorChoice , Parser , Subcommand , ValueEnum } ;
6
6
use config_file:: ConfigFile ;
7
+ use console:: { self , Term } ;
8
+ use indicatif:: { ProgressBar , ProgressStyle } ;
7
9
use std:: env:: current_dir;
8
10
use std:: fs:: { create_dir, read_dir, read_to_string, remove_dir, write} ;
9
11
use std:: io:: { stdin, Read , Result } ;
10
12
use std:: panic;
11
13
use std:: path:: { Path , PathBuf } ;
14
+ use std:: time:: Duration ;
12
15
13
16
#[ derive( Parser ) ]
14
17
#[ command( name = "gpm" ) ]
@@ -25,6 +28,7 @@ struct Args {
25
28
) ]
26
29
/// Specify the location of the package configuration file (https://github.com/godot-package-manager#godotpackage). If -, read from stdin.
27
30
config_file : PathBuf ,
31
+
28
32
#[ arg(
29
33
short = 'l' ,
30
34
long = "lock-file" ,
@@ -33,13 +37,21 @@ struct Args {
33
37
) ]
34
38
/// Specify the location of the lock file. If -, print to stdout.
35
39
lock_file : PathBuf ,
40
+
41
+ #[ arg( long = "colors" , default_value = "auto" , global = true ) ]
42
+ /// Control color output.
43
+ colors : ColorChoice ,
36
44
}
37
45
38
46
#[ derive( Subcommand ) ]
39
47
enum Actions {
40
48
#[ clap( short_flag = 'u' ) ]
41
49
/// Downloads the latest versions of your wanted packages.
42
- Update ,
50
+ Update {
51
+ #[ arg( short = 's' ) ]
52
+ /// To print the progress bar
53
+ silent : bool ,
54
+ } ,
43
55
#[ clap( short_flag = 'p' ) ]
44
56
/// Deletes all installed packages.
45
57
Purge ,
@@ -56,44 +68,56 @@ Produces output like
56
68
charset : CharSet ,
57
69
58
70
#[ arg( value_enum, default_value = "indent" , long = "prefix" ) ]
59
- /// The prefix (indentation) of how the tree entrys are displayed
71
+ /// The prefix (indentation) of how the tree entrys are displayed.
60
72
prefix : PrefixType ,
61
73
62
74
#[ arg( long = "tarballs" , default_value = "false" ) ]
63
- /// To print download urls next to the package name
75
+ /// To print download urls next to the package name.
64
76
print_tarballs : bool ,
65
77
} ,
66
78
}
67
79
68
80
#[ derive( Copy , Clone , PartialEq , Eq , PartialOrd , Ord , ValueEnum ) ]
69
- /// Charset for the tree subcommand
81
+ /// Charset for the tree subcommand.
70
82
enum CharSet {
83
+ /// Unicode characters (├── └──).
71
84
UTF8 ,
85
+ /// ASCII characters (|-- `--).
72
86
ASCII ,
73
87
}
74
88
75
89
#[ derive( Copy , Clone , PartialEq , Eq , PartialOrd , Ord , ValueEnum ) ]
76
- /// Prefix type for the tree subcommand
90
+ /// Prefix type for the tree subcommand.
77
91
enum PrefixType {
92
+ /// Indents the tree entries proportional to the depth.
78
93
Indent ,
94
+ /// Print the depth before the entries.
79
95
Depth ,
96
+ /// No indentation, just list.
80
97
None ,
81
98
}
82
99
83
100
fn main ( ) {
84
- #[ rustfmt:: skip]
85
101
panic:: set_hook ( Box :: new ( |panic_info| {
86
- const RED : & str = "\x1b [1;31m" ;
87
- const RESET : & str = "\x1b [0m" ;
88
102
match panic_info. location ( ) {
89
- Some ( s) => print ! ( "{RED}err{RESET} @{}:{}:{}: " , s . file ( ) , s. line ( ) , s. column ( ) ) ,
90
- None => print ! ( "{RED}err{RESET} : " ) ,
103
+ Some ( s) => eprint ! ( "{} @{}:{}: " , print_consts :: err ( ) , s. file ( ) , s. line ( ) ) ,
104
+ None => eprint ! ( "{} : " , print_consts :: err ( ) ) ,
91
105
}
92
- if let Some ( s) = panic_info. payload ( ) . downcast_ref :: < & str > ( ) { println ! ( "{s}" ) ; }
93
- else if let Some ( s) = panic_info. payload ( ) . downcast_ref :: < String > ( ) { println ! ( "{s}" ) ; }
94
- else { println ! ( "unknown" ) ; } ;
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" ) ; } ;
95
110
} ) ) ;
96
111
let args = Args :: parse ( ) ;
112
+ fn set_colors ( val : bool ) {
113
+ console:: set_colors_enabled ( val) ;
114
+ console:: set_colors_enabled_stderr ( val)
115
+ }
116
+ match args. colors {
117
+ ColorChoice :: Always => set_colors ( true ) ,
118
+ ColorChoice :: Never => set_colors ( false ) ,
119
+ ColorChoice :: Auto => set_colors ( Term :: stdout ( ) . is_term ( ) && Term :: stderr ( ) . is_term ( ) ) ,
120
+ }
97
121
let mut contents = String :: from ( "" ) ;
98
122
if args. config_file == Path :: new ( "-" ) {
99
123
let bytes = stdin ( )
@@ -107,7 +131,7 @@ fn main() {
107
131
} ;
108
132
let mut cfg_file = ConfigFile :: new ( & contents) ;
109
133
match args. action {
110
- Actions :: Update => update ( & mut cfg_file, true ) ,
134
+ Actions :: Update { silent } => update ( & mut cfg_file, true , silent ) ,
111
135
Actions :: Purge => purge ( & mut cfg_file) ,
112
136
Actions :: Tree {
113
137
charset,
@@ -123,23 +147,47 @@ fn main() {
123
147
}
124
148
}
125
149
126
- fn update ( cfg : & mut ConfigFile , modify : bool ) {
150
+ fn update ( cfg : & mut ConfigFile , modify : bool , silent : bool ) {
127
151
if !Path :: new ( "./addons/" ) . exists ( ) {
128
152
create_dir ( "./addons/" ) . expect ( "Should be able to create addons folder" ) ;
129
153
}
130
- if cfg. packages . is_empty ( ) {
154
+ let packages = cfg. collect ( ) ;
155
+ if packages. is_empty ( ) {
131
156
panic ! ( "No packages to update (modify the \" godot.package\" file to add packages)" ) ;
132
157
}
133
158
println ! (
134
- "Update {} package{}" ,
135
- cfg . packages. len( ) ,
136
- if cfg . packages. len( ) > 1 { "s" } else { "" }
159
+ "Updating {} package{}" ,
160
+ packages. len( ) ,
161
+ if packages. len( ) > 1 { "s" } else { "" }
137
162
) ;
138
- cfg. for_each ( |p| {
163
+ let bar = if silent {
164
+ ProgressBar :: hidden ( )
165
+ } 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
176
+ } ;
177
+ packages. into_iter ( ) . for_each ( |mut p| {
178
+ bar. set_message ( format ! ( "downloading {p}" ) ) ;
139
179
p. download ( ) ;
180
+ bar. inc ( 1 ) ;
181
+ bar. set_message ( format ! ( "modifying {p}" ) ) ;
140
182
if modify {
141
- p. modify ( )
183
+ if let Err ( e) = p. modify ( ) {
184
+ eprintln ! (
185
+ "{}: modification of {p} failed with err {e}" ,
186
+ print_consts:: warn( )
187
+ )
188
+ }
142
189
}
190
+ bar. inc ( 1 ) ;
143
191
} ) ;
144
192
}
145
193
@@ -180,7 +228,7 @@ fn purge(cfg: &mut ConfigFile) {
180
228
} ;
181
229
} ;
182
230
println ! (
183
- "Purge {} package{}" ,
231
+ "Purging {} package{}" ,
184
232
packages. len( ) ,
185
233
if packages. len( ) > 1 { "s" } else { "" }
186
234
) ;
@@ -318,7 +366,7 @@ mod test_utils {
318
366
fn gpm ( ) {
319
367
let _t = test_utils:: mktemp ( ) ;
320
368
let cfg_file = & mut config_file:: ConfigFile :: new ( & r#"packages: {"@bendn/test":2.0.10}"# . into ( ) ) ;
321
- update ( cfg_file, false ) ;
369
+ update ( cfg_file, false , false ) ;
322
370
assert_eq ! ( test_utils:: hashd( "addons" ) . join( "|" ) , "1c2fd93634817a9e5f3f22427bb6b487520d48cf3cbf33e93614b055bcbd1329|8e77e3adf577d32c8bc98981f05d40b2eb303271da08bfa7e205d3f27e188bd7|a625595a71b159e33b3d1ee6c13bea9fc4372be426dd067186fe2e614ce76e3c|c5566e4fbea9cc6dbebd9366b09e523b20870b1d69dc812249fccd766ebce48e|c5566e4fbea9cc6dbebd9366b09e523b20870b1d69dc812249fccd766ebce48e|c850a9300388d6da1566c12a389927c3353bf931c4d6ea59b02beb302aac03ea|d060936e5f1e8b1f705066ade6d8c6de90435a91c51f122905a322251a181a5c|d711b57105906669572a0e53b8b726619e3a21463638aeda54e586a320ed0fc5|d794f3cee783779f50f37a53e1d46d9ebbc5ee7b37c36d7b6ee717773b6955cd|e4f9df20b366a114759282209ff14560401e316b0059c1746c979f478e363e87" ) ;
323
371
purge ( cfg_file) ;
324
372
assert_eq ! ( test_utils:: hashd( "addons" ) , vec![ ] as Vec <String >) ;
@@ -336,3 +384,17 @@ fn gpm() {
336
384
337
385
) ;
338
386
}
387
+
388
+ pub mod print_consts {
389
+ use console:: { style, StyledObject } ;
390
+
391
+ #[ inline]
392
+ pub fn err ( ) -> StyledObject < & ' static str > {
393
+ style ( "err" ) . red ( ) . bold ( )
394
+ }
395
+
396
+ #[ inline]
397
+ pub fn warn ( ) -> StyledObject < & ' static str > {
398
+ style ( "err" ) . yellow ( ) . bold ( )
399
+ }
400
+ }
0 commit comments