11use crate :: commands:: util:: get_path;
2+ use anyhow:: Context ;
23use indicatif:: { ProgressBar , ProgressStyle } ;
34use reqwest:: { header, Url } ;
45use std:: cmp:: min;
@@ -22,19 +23,21 @@ pub const DELAY: u128 = 1440 * 60 * 1000;
2223/// Will run in privileged stage if needed on Windows!
2324///
2425
25- pub fn check_for_update ( ) {
26- if is_it_time_yet ( ) {
27- generate_time_stamp ( ) ;
28- checktemp ( ) ;
29- let new_ver = get_latest_version ( ) ;
26+ pub fn check_for_update ( ) -> anyhow :: Result < ( ) > {
27+ if is_it_time_yet ( ) ? {
28+ generate_time_stamp ( ) ? ;
29+ checktemp ( ) ? ;
30+ let new_ver = get_latest_version ( ) ? ;
3031 println ! ( "Checking for updates..." ) ;
3132 if compare_versions ( new_ver) {
32- process_update ( ) ;
33+ process_update ( ) ? ;
3334 }
3435 }
36+ Ok ( ( ) )
3537}
36- fn checktemp ( ) {
37- let mut tmp_filepath = env:: current_exe ( ) . unwrap ( ) ;
38+
39+ fn checktemp ( ) -> anyhow:: Result < ( ) > {
40+ let mut tmp_filepath = env:: current_exe ( ) ?;
3841 tmp_filepath. pop ( ) ;
3942 let tmp_filepath = Path :: new ( & tmp_filepath) . join ( "tmp" ) ;
4043 let tmp_filepath = tmp_filepath. join ( "tmc.exe" ) ;
@@ -51,33 +54,37 @@ fn checktemp() {
5154 }
5255 }
5356 }
57+ Ok ( ( ) )
5458}
59+
5560pub fn cleartemp ( ) -> Result < ( ) , std:: io:: Error > {
5661 println ! ( "Cleaning temp..." ) ;
57- let mut tmp_filepath = env:: current_exe ( ) . unwrap ( ) ;
62+ let mut tmp_filepath = env:: current_exe ( ) ? ;
5863 tmp_filepath. pop ( ) ;
5964 let tmp_filepath = Path :: new ( & tmp_filepath) . join ( "tmp" ) ;
6065 let tmp_filepath = tmp_filepath. join ( "tmc.exe" ) ;
6166 fs:: remove_file ( & tmp_filepath) ?;
6267 println ! ( "Temp cleared!" ) ;
6368 Ok ( ( ) )
6469}
65- pub fn process_update ( ) {
66- let new_ver = get_latest_version ( ) ;
70+
71+ pub fn process_update ( ) -> anyhow:: Result < ( ) > {
72+ let new_ver = get_latest_version ( ) ?;
6773 match stash_old_executable ( ) {
68- Err ( e) => match e. kind ( ) {
69- std:: io:: ErrorKind :: PermissionDenied => {
74+ Err ( e) => match e. downcast_ref :: < std :: io :: Error > ( ) . map ( |e| e . kind ( ) ) {
75+ Some ( std:: io:: ErrorKind :: PermissionDenied ) => {
7076 println ! ( "Permission Denied! Restarting with administrator privileges..." ) ;
7177 elevate ( "fetchupdate" . to_string ( ) ) ;
72- return ;
78+ return Ok ( ( ) ) ;
7379 }
7480 _ => {
7581 println ! ( "{:#?}" , e) ;
7682 }
7783 } ,
78- _ => update ( new_ver) . unwrap ( ) ,
84+ _ => update ( new_ver) ? ,
7985 }
80- println ! ( "Update completed succesfully!" )
86+ println ! ( "Update completed succesfully!" ) ;
87+ Ok ( ( ) )
8188}
8289fn elevate ( command : String ) {
8390 Command :: new ( "powershell" )
@@ -92,33 +99,32 @@ fn elevate(command: String) {
9299 . spawn ( )
93100 . expect ( "launch failure" ) ;
94101}
95- fn is_it_time_yet ( ) -> bool {
96- let config = TmcConfig :: load ( PLUGIN , get_path ( ) . as_path ( ) ) . unwrap ( ) ;
102+ fn is_it_time_yet ( ) -> anyhow :: Result < bool > {
103+ let config = TmcConfig :: load ( PLUGIN , get_path ( ) ? . as_path ( ) ) ? ;
97104
98- let last_check = match config. get ( "update-last-checked" ) {
99- ConfigValue :: Value ( Some ( s) ) => toml:: Value :: as_str ( & s) . unwrap ( ) . to_string ( ) ,
105+ let value = config. get ( "update-last-checked" ) ;
106+ let last_check = match & value {
107+ ConfigValue :: Value ( Some ( s) ) => s. as_str ( ) . context ( "invalid value" ) ?,
100108 _ => {
101- return true ;
109+ return Ok ( true ) ;
102110 }
103111 } ;
104112
105113 let last_check = match last_check. parse :: < u128 > ( ) {
106114 Ok ( time) => time,
107- _ => return true ,
115+ _ => return Ok ( true ) ,
108116 } ;
109117 let now = SystemTime :: now ( ) ;
110118 let now = now
111119 . duration_since ( UNIX_EPOCH )
112120 . expect ( "Time went backwards" )
113121 . as_millis ( ) ;
114- if now - last_check as u128 > DELAY {
115- return true ;
116- }
117- false
122+ let update = now - last_check as u128 > DELAY ;
123+ Ok ( update)
118124}
119125
120- fn generate_time_stamp ( ) {
121- let mut config = TmcConfig :: load ( PLUGIN , get_path ( ) . as_path ( ) ) . unwrap ( ) ;
126+ fn generate_time_stamp ( ) -> anyhow :: Result < ( ) > {
127+ let mut config = TmcConfig :: load ( PLUGIN , get_path ( ) ? . as_path ( ) ) ? ;
122128 let now = SystemTime :: now ( ) ;
123129 let since_the_epoch = now
124130 . duration_since ( UNIX_EPOCH )
@@ -131,12 +137,13 @@ fn generate_time_stamp() {
131137 ) {
132138 println ! ( "timestamp could not be changed" ) ;
133139 }
134- if let Err ( _err) = config. save ( get_path ( ) . as_path ( ) ) {
140+ if let Err ( _err) = config. save ( get_path ( ) ? . as_path ( ) ) {
135141 println ! ( "Problem saving timestamp" ) ;
136142 }
143+ Ok ( ( ) )
137144}
138145
139- fn get_latest_version ( ) -> String {
146+ fn get_latest_version ( ) -> anyhow :: Result < String > {
140147 let url = GITHUB_URL ;
141148 let mut headers = header:: HeaderMap :: new ( ) ;
142149 headers. insert (
@@ -146,21 +153,20 @@ fn get_latest_version() -> String {
146153 let resp = reqwest:: blocking:: Client :: new ( )
147154 . get ( url)
148155 . headers ( headers)
149- . send ( )
150- . unwrap ( ) ;
156+ . send ( ) ?;
151157 if !resp. status ( ) . is_success ( ) {
152- panic ! (
158+ anyhow :: bail !(
153159 "Version lookup failed with status: {:?} - for: {:?}" ,
154160 resp. status( ) ,
155161 & url
156162 ) ;
157163 }
158- let tags = resp. json :: < serde_json:: Value > ( ) . unwrap ( ) ;
159- let tags = tags. as_array ( ) . unwrap ( ) ;
164+ let tags = resp. json :: < serde_json:: Value > ( ) ? ;
165+ let tags = tags. as_array ( ) . context ( "tags were not an array" ) ? ;
160166
161167 let latest = tags[ 0 ] [ "name" ] . to_string ( ) ;
162-
163- latest [ 1 ..latest . len ( ) - 1 ] . to_string ( )
168+ let latest = latest [ 1 ..latest . len ( ) - 1 ] . to_string ( ) ;
169+ Ok ( latest )
164170}
165171
166172fn compare_versions ( version : String ) -> bool {
@@ -188,23 +194,18 @@ fn compare_versions(version: String) -> bool {
188194 false
189195}
190196
191- fn update ( version : String ) -> Result < ( ) , std :: io :: Error > {
197+ fn update ( version : String ) -> anyhow :: Result < ( ) > {
192198 use io:: BufRead ;
193199 let resp = reqwest:: blocking:: Client :: new ( )
194- . get ( generate_download_url ( version) )
195- . send ( )
196- . unwrap ( ) ;
200+ . get ( generate_download_url ( version) ?)
201+ . send ( ) ?;
197202 let size = resp
198203 . headers ( )
199204 . get ( reqwest:: header:: CONTENT_LENGTH )
200- . map ( |val| {
201- val. to_str ( )
202- . map ( |s| s. parse :: < u64 > ( ) . unwrap_or ( 0 ) )
203- . unwrap_or ( 0 )
204- } )
205+ . and_then ( |val| val. to_str ( ) . ok ( ) . and_then ( |s| s. parse :: < u64 > ( ) . ok ( ) ) )
205206 . unwrap_or ( 0 ) ;
206207 if !resp. status ( ) . is_success ( ) {
207- panic ! ( "Download request failed with status: {:?}" , resp. status( ) ) ;
208+ anyhow :: bail !( "Download request failed with status: {:?}" , resp. status( ) ) ;
208209 }
209210 let filepath = env:: current_exe ( ) ?;
210211 let mut dest = fs:: File :: create ( & filepath) ?;
@@ -232,64 +233,61 @@ fn update(version: String) -> Result<(), std::io::Error> {
232233 Ok ( ( ) )
233234}
234235
235- fn stash_old_executable ( ) -> Result < ( ) , std :: io :: Error > {
236- let filepath = env:: current_exe ( ) . unwrap ( ) ;
236+ fn stash_old_executable ( ) -> anyhow :: Result < ( ) > {
237+ let filepath = env:: current_exe ( ) ? ;
237238
238- let mut tmp_filepath = env :: current_exe ( ) . unwrap ( ) ;
239+ let mut tmp_filepath = filepath . clone ( ) ;
239240 tmp_filepath. pop ( ) ;
240- let tmp_filepath = Path :: new ( & tmp_filepath) . join ( "tmp" ) ;
241- fs:: create_dir_all ( & tmp_filepath) ?;
242- let tmp_filepath = tmp_filepath. join ( "tmc.exe" ) ;
243-
244- if tmp_filepath. exists ( ) {
245- fs:: remove_file ( & tmp_filepath) ?;
246- }
247-
248- fs:: rename ( & filepath, & tmp_filepath) ?;
241+ let tmp_dir = tmp_filepath. join ( "tmp" ) ;
242+ fs:: create_dir_all ( & tmp_dir) ?;
243+ let tmp_tmc = tmp_dir. join ( "tmc.exe" ) ;
244+ fs:: rename ( & filepath, & tmp_tmc) ?;
249245 Ok ( ( ) )
250246}
251247
252- fn generate_download_url ( version : String ) -> Url {
248+ fn generate_download_url ( version : String ) -> anyhow :: Result < Url > {
253249 let arch = env:: consts:: ARCH ;
254- let mut target = String :: new ( ) ;
255- match arch {
256- "x86_64" => target. push_str ( "x86_64-pc-windows-msvc-" ) ,
257- "i686" => target. push_str ( "i686-pc-windows-msvc-" ) ,
258- _ => println ! ( "Wow! {}" , arch) ,
259- }
260- let mut download_url = String :: from ( "https://download.mooc.fi/tmc-cli-rust/tmc-cli-rust-" ) ;
261- download_url. push_str ( & target) ;
262- download_url. push_str ( & version) ;
263- download_url. push_str ( ".exe" ) ;
264- Url :: parse ( & download_url) . unwrap ( )
250+ let target = match arch {
251+ "x86_64" => "x86_64-pc-windows-msvc" ,
252+ "i686" => "i686-pc-windows-msvc-" ,
253+ unexpected => anyhow:: bail!( "Unexpected arch {unexpected}" ) ,
254+ } ;
255+ let download_url =
256+ format ! ( "https://download.mooc.fi/tmc-cli-rust/tmc-cli-rust-{target}-{version}.exe" ) ;
257+ let url = Url :: parse ( & download_url) ?;
258+ Ok ( url)
265259}
266260
267- #[ test]
268- fn compare_versions_test ( ) {
269- let oldest = String :: from ( "v0.0.1" ) ;
270- let the_future = String :: from ( "v999.999.999" ) ;
271- assert_eq ! ( compare_versions( oldest) , false ) ;
272- assert_eq ! ( compare_versions( the_future) , true ) ;
273- assert_eq ! (
274- compare_versions( env!( "CARGO_PKG_VERSION" ) . to_string( ) ) ,
275- false
276- ) ;
277- }
261+ #[ cfg( test) ]
262+ mod test {
263+ use super :: * ;
278264
279- #[ test]
280- #[ cfg( windows) ]
281- fn generate_download_url_test ( ) {
282- let oldest = String :: from ( "v0.0.1" ) ;
283- let arch = env:: consts:: ARCH ;
284- match arch {
285- "x86_64" => assert_eq ! (
286- generate_download_url( oldest) . to_string( ) ,
265+ #[ test]
266+ fn compare_versions_test ( ) {
267+ let oldest = String :: from ( "v0.0.1" ) ;
268+ let the_future = String :: from ( "v999.999.999" ) ;
269+ assert_eq ! ( compare_versions( oldest) , false ) ;
270+ assert_eq ! ( compare_versions( the_future) , true ) ;
271+ assert_eq ! (
272+ compare_versions( env!( "CARGO_PKG_VERSION" ) . to_string( ) ) ,
273+ false
274+ ) ;
275+ }
276+
277+ #[ test]
278+ fn generate_download_url_test ( ) {
279+ let oldest = String :: from ( "v0.0.1" ) ;
280+ let arch = env:: consts:: ARCH ;
281+ match arch {
282+ "x86_64" => assert_eq ! (
283+ generate_download_url( oldest) . unwrap( ) . to_string( ) ,
287284 "https://download.mooc.fi/tmc-cli-rust/tmc-cli-rust-x86_64-pc-windows-msvc-v0.0.1.exe"
288285 ) ,
289- "i686" => assert_eq ! (
290- generate_download_url( oldest) . to_string( ) ,
286+ "i686" => assert_eq ! (
287+ generate_download_url( oldest) . unwrap ( ) . to_string( ) ,
291288 "https://download.mooc.fi/tmc-cli-rust/tmc-cli-rust-i686-pc-windows-msvc-v0.0.1.exe"
292289 ) ,
293- _ => println ! ( "Wow! {}" , arch) ,
290+ _ => println ! ( "Wow! {}" , arch) ,
291+ }
294292 }
295293}
0 commit comments