23
23
import zipfile
24
24
import re
25
25
import time
26
- from datetime import timedelta
27
- import functools
26
+ import argparse
28
27
29
28
# Initialize start_time globally
30
29
start_time = - 1
@@ -67,10 +66,12 @@ def mkdir_p(path):
67
66
if exc .errno != errno .EEXIST or not os .path .isdir (path ):
68
67
raise
69
68
69
+
70
70
def format_time (seconds ):
71
71
minutes , seconds = divmod (seconds , 60 )
72
72
return "{:02}:{:05.2f}" .format (int (minutes ), seconds )
73
73
74
+
74
75
def report_progress (block_count , block_size , total_size , start_time ):
75
76
downloaded_size = block_count * block_size
76
77
time_elapsed = time .time () - start_time
@@ -79,137 +80,148 @@ def report_progress(block_count, block_size, total_size, start_time):
79
80
if sys .stdout .isatty ():
80
81
if total_size > 0 :
81
82
percent_complete = min ((downloaded_size / total_size ) * 100 , 100 )
82
- sys .stdout .write (f"\r Downloading... { percent_complete :.2f} % - { downloaded_size / 1024 / 1024 :.2f} MB downloaded - Elapsed Time: { format_time (time_elapsed )} - Speed: { current_speed / 1024 / 1024 :.2f} MB/s" )
83
+ sys .stdout .write (
84
+ f"\r Downloading... { percent_complete :.2f} % - { downloaded_size / 1024 / 1024 :.2f} MB downloaded - Elapsed Time: { format_time (time_elapsed )} - Speed: { current_speed / 1024 / 1024 :.2f} MB/s" # noqa: E501
85
+ )
83
86
else :
84
- sys .stdout .write (f"\r Downloading... { downloaded_size / 1024 / 1024 :.2f} MB downloaded - Elapsed Time: { format_time (time_elapsed )} - Speed: { current_speed / 1024 / 1024 :.2f} MB/s" )
87
+ sys .stdout .write (
88
+ f"\r Downloading... { downloaded_size / 1024 / 1024 :.2f} MB downloaded - Elapsed Time: { format_time (time_elapsed )} - Speed: { current_speed / 1024 / 1024 :.2f} MB/s" # noqa: E501
89
+ )
85
90
sys .stdout .flush ()
86
91
92
+
87
93
def print_verification_progress (total_files , i , t1 ):
88
94
if sys .stdout .isatty ():
89
- sys .stdout .write (f' \r Elapsed time { format_time (time .time () - t1 )} ' )
95
+ sys .stdout .write (f" \r Elapsed time { format_time (time .time () - t1 )} " )
90
96
sys .stdout .flush ()
91
97
98
+
92
99
def verify_files (filename , destination , rename_to ):
93
100
# Set the path of the extracted directory
94
101
extracted_dir_path = destination
95
102
t1 = time .time ()
96
103
if filename .endswith (".zip" ):
97
104
try :
98
- with zipfile .ZipFile (filename , 'r' ) as archive :
99
- first_dir = archive .namelist ()[0 ].split ('/' )[0 ]
105
+ with zipfile .ZipFile (filename , "r" ) as archive :
106
+ first_dir = archive .namelist ()[0 ].split ("/" )[0 ]
100
107
total_files = len (archive .namelist ())
101
108
for i , zipped_file in enumerate (archive .namelist (), 1 ):
102
109
local_path = os .path .join (extracted_dir_path , zipped_file .replace (first_dir , rename_to , 1 ))
103
110
if not os .path .exists (local_path ):
104
- #print(f'\nMissing {zipped_file} on location: {extracted_dir_path}')
111
+ # print(f'\nMissing {zipped_file} on location: {extracted_dir_path}')
105
112
print (f"Verification failed; aborted in { format_time (time .time () - t1 )} " )
106
113
return False
107
- print_verification_progress (total_files , i , t1 )
114
+ print_verification_progress (total_files , i , t1 )
108
115
except zipfile .BadZipFile :
109
116
print (f"Verification failed; aborted in { format_time (time .time () - t1 )} " )
110
117
return False
111
118
elif filename .endswith (".tar.gz" ):
112
119
try :
113
- with tarfile .open (filename , ' r:gz' ) as archive :
114
- first_dir = archive .getnames ()[0 ].split ('/' )[0 ]
120
+ with tarfile .open (filename , " r:gz" ) as archive :
121
+ first_dir = archive .getnames ()[0 ].split ("/" )[0 ]
115
122
total_files = len (archive .getnames ())
116
123
for i , zipped_file in enumerate (archive .getnames (), 1 ):
117
124
local_path = os .path .join (extracted_dir_path , zipped_file .replace (first_dir , rename_to , 1 ))
118
125
if not os .path .exists (local_path ):
119
- #print(f'\nMissing {zipped_file} on location: {extracted_dir_path}')
126
+ # print(f'\nMissing {zipped_file} on location: {extracted_dir_path}')
120
127
print (f"Verification failed; aborted in { format_time (time .time () - t1 )} " )
121
128
return False
122
- print_verification_progress (total_files , i , t1 )
129
+ print_verification_progress (total_files , i , t1 )
123
130
except tarfile .ReadError :
124
131
print (f"Verification failed; aborted in { format_time (time .time () - t1 )} " )
125
132
return False
126
133
elif filename .endswith (".tar.xz" ):
127
134
try :
128
- with tarfile .open (filename , ' r:xz' ) as archive :
129
- first_dir = archive .getnames ()[0 ].split ('/' )[0 ]
135
+ with tarfile .open (filename , " r:xz" ) as archive :
136
+ first_dir = archive .getnames ()[0 ].split ("/" )[0 ]
130
137
total_files = len (archive .getnames ())
131
138
for i , zipped_file in enumerate (archive .getnames (), 1 ):
132
139
local_path = os .path .join (extracted_dir_path , zipped_file .replace (first_dir , rename_to , 1 ))
133
140
if not os .path .exists (local_path ):
134
- # print(f'\nMissing {zipped_file} on location: {extracted_dir_path}')
141
+ print (f'\n Missing { zipped_file } on location: { extracted_dir_path } ' )
135
142
print (f"Verification failed; aborted in { format_time (time .time () - t1 )} " )
136
143
return False
137
- print_verification_progress (total_files , i , t1 )
144
+ print_verification_progress (total_files , i , t1 )
138
145
except tarfile .ReadError :
139
146
print (f"Verification failed; aborted in { format_time (time .time () - t1 )} " )
140
147
return False
141
148
else :
142
- raise NotImplementedError (' Unsupported archive type' )
149
+ raise NotImplementedError (" Unsupported archive type" )
143
150
144
- #if(verbose):
145
- # print(f"\nVerification passed; completed in {format_time(time.time() - t1)}")
151
+ # if(verbose):
152
+ # print(f"\nVerification passed; completed in {format_time(time.time() - t1)}")
146
153
return True
147
154
148
155
149
156
def unpack (filename , destination , force_extract ):
150
- dirname = ''
151
- file_is_corrupted = False
152
- if (not force_extract ):
153
- print (f' > Verify archive... ' , end = "" , flush = True )
157
+ dirname = ""
158
+ cfile = None # Compressed file
159
+ file_is_corrupted = False
160
+ if not force_extract :
161
+ print (" > Verify archive... " , end = "" , flush = True )
154
162
155
163
try :
156
- if filename .endswith (' tar.gz' ):
164
+ if filename .endswith (" tar.gz" ):
157
165
if tarfile .is_tarfile (filename ):
158
- tfile = tarfile .open (filename , ' r:gz' )
159
- dirname = tfile .getnames ()[0 ]
166
+ cfile = tarfile .open (filename , " r:gz" )
167
+ dirname = cfile .getnames ()[0 ]
160
168
else :
161
- print (' File corrupted!' )
162
- file_is_corrupted = True
163
- elif filename .endswith (' tar.xz' ):
169
+ print (" File corrupted!" )
170
+ file_is_corrupted = True
171
+ elif filename .endswith (" tar.xz" ):
164
172
if tarfile .is_tarfile (filename ):
165
- tfile = tarfile .open (filename , ' r:xz' )
166
- dirname = tfile .getnames ()[0 ]
173
+ cfile = tarfile .open (filename , " r:xz" )
174
+ dirname = cfile .getnames ()[0 ]
167
175
else :
168
- print (' File corrupted!' )
169
- file_is_corrupted = True
170
- elif filename .endswith (' zip' ):
176
+ print (" File corrupted!" )
177
+ file_is_corrupted = True
178
+ elif filename .endswith (" zip" ):
171
179
if zipfile .is_zipfile (filename ):
172
- zfile = zipfile .ZipFile (filename )
173
- dirname = zfile .namelist ()[0 ]
180
+ cfile = zipfile .ZipFile (filename )
181
+ dirname = cfile .namelist ()[0 ]
174
182
else :
175
- print (' File corrupted!' )
176
- file_is_corrupted = True
183
+ print (" File corrupted!" )
184
+ file_is_corrupted = True
177
185
else :
178
- raise NotImplementedError (' Unsupported archive type' )
186
+ raise NotImplementedError (" Unsupported archive type" )
179
187
except EOFError :
180
- print (f'File corrupted or incomplete!' )
181
- file_is_corrupted = True
188
+ print ("File corrupted or incomplete!" )
189
+ cfile = None
190
+ file_is_corrupted = True
182
191
183
- if ( file_is_corrupted ) :
192
+ if file_is_corrupted :
184
193
corrupted_filename = filename + ".corrupted"
185
194
os .rename (filename , corrupted_filename )
186
- if ( verbose ) :
187
- print (f' Renaming corrupted archive to { corrupted_filename } ' )
195
+ if verbose :
196
+ print (f" Renaming corrupted archive to { corrupted_filename } " )
188
197
return False
189
198
190
199
# A little trick to rename tool directories so they don't contain version number
191
- rename_to = re .match (r' ^([a-z][^\-]*\-*)+' , dirname ).group (0 ).strip ('-' )
192
- if rename_to == dirname and dirname .startswith (' esp32-arduino-libs-' ):
193
- rename_to = ' esp32-arduino-libs'
200
+ rename_to = re .match (r" ^([a-z][^\-]*\-*)+" , dirname ).group (0 ).strip ("-" )
201
+ if rename_to == dirname and dirname .startswith (" esp32-arduino-libs-" ):
202
+ rename_to = " esp32-arduino-libs"
194
203
195
204
if not force_extract :
196
- if ( verify_files (filename , destination , rename_to ) ):
205
+ if verify_files (filename , destination , rename_to ):
197
206
print (" Files ok. Skipping Extraction" )
198
207
return True
199
208
else :
200
209
print (" Extracting archive..." )
201
210
else :
202
211
print (" Forcing extraction" )
203
212
204
- if filename .endswith ('tar.gz' ):
205
- tfile = tarfile .open (filename , 'r:gz' )
206
- tfile .extractall (destination )
207
- elif filename .endswith ('tar.xz' ):
208
- tfile = tarfile .open (filename , 'r:xz' )
209
- tfile .extractall (destination )
210
- elif filename .endswith ('zip' ):
211
- zfile = zipfile .ZipFile (filename )
212
- zfile .extractall (destination )
213
+ if filename .endswith ("tar.gz" ):
214
+ if not cfile :
215
+ cfile = tarfile .open (filename , "r:gz" )
216
+ cfile .extractall (destination )
217
+ elif filename .endswith ("tar.xz" ):
218
+ if not cfile :
219
+ cfile = tarfile .open (filename , "r:xz" )
220
+ cfile .extractall (destination )
221
+ elif filename .endswith ("zip" ):
222
+ if not cfile :
223
+ cfile = zipfile .ZipFile (filename )
224
+ cfile .extractall (destination )
213
225
else :
214
226
raise NotImplementedError ("Unsupported archive type" )
215
227
@@ -221,7 +233,8 @@ def unpack(filename, destination, force_extract):
221
233
222
234
return True
223
235
224
- def download_file_with_progress (url ,filename , start_time ):
236
+
237
+ def download_file_with_progress (url , filename , start_time ):
225
238
import ssl
226
239
import contextlib
227
240
@@ -246,7 +259,7 @@ def download_file_with_progress(url,filename, start_time):
246
259
block_count += 1
247
260
report_progress (block_count , block_size , total_size , start_time )
248
261
else :
249
- raise Exception (' Non-existing file or connection error' )
262
+ raise Exception (" Non-existing file or connection error" )
250
263
251
264
252
265
def download_file (url , filename ):
@@ -268,19 +281,21 @@ def download_file(url, filename):
268
281
break
269
282
out_file .write (block )
270
283
else :
271
- raise Exception ('Non-existing file or connection error' )
284
+ raise Exception ("Non-existing file or connection error" )
285
+
272
286
273
287
def get_tool (tool , force_download , force_extract ):
274
288
sys_name = platform .system ()
275
289
archive_name = tool ["archiveFileName" ]
290
+ checksum = tool ["checksum" ][8 :]
276
291
local_path = dist_dir + archive_name
277
- url = tool [' url' ]
292
+ url = tool [" url" ]
278
293
start_time = time .time ()
279
294
if not os .path .isfile (local_path ) or force_download :
280
295
if verbose :
281
- print (' Downloading \' ' + archive_name + ' \' to \' ' + local_path + ' \' ' )
296
+ print (" Downloading '" + archive_name + "' to '" + local_path + "'" )
282
297
else :
283
- print (' Downloading \' ' + archive_name + ' \' ...' )
298
+ print (" Downloading '" + archive_name + "' ..." )
284
299
sys .stdout .flush ()
285
300
if "CYGWIN_NT" in sys_name :
286
301
import ssl
@@ -301,14 +316,19 @@ def get_tool(tool, force_download, force_extract):
301
316
else :
302
317
try :
303
318
urlretrieve (url , local_path , report_progress )
304
- except :
319
+ except : # noqa: E722
305
320
download_file_with_progress (url , local_path , start_time )
306
321
sys .stdout .write (" - Done\n " )
307
322
sys .stdout .flush ()
308
323
else :
309
324
print ("Tool {0} already downloaded" .format (archive_name ))
310
325
sys .stdout .flush ()
311
- return unpack (local_path , '.' , force_extract )
326
+
327
+ if sha256sum (local_path ) != checksum :
328
+ print ("Checksum mismatch for {0}" .format (archive_name ))
329
+ return False
330
+
331
+ return unpack (local_path , "." , force_extract )
312
332
313
333
314
334
def load_tools_list (filename , platform ):
@@ -355,29 +375,55 @@ def identify_platform():
355
375
print ("System: %s, Bits: %d, Info: %s" % (sys_name , bits , sys_platform ))
356
376
return arduino_platform_names [sys_name ][bits ]
357
377
358
- def print_help ():
359
- print ("TODO help" )
360
378
361
- if __name__ == '__main__' :
362
- option_print_help = "-h" in sys .argv
363
- verbose = "-v" in sys .argv
364
- force_download = "-d" in sys .argv
365
- force_extract = "-e" in sys .argv
366
- force_all = "-f" in sys .argv
367
- is_test = "-t" in sys .argv
379
+ if __name__ == "__main__" :
380
+ parser = argparse .ArgumentParser (description = "Download and extract tools" )
381
+
382
+ parser .add_argument ("-v" , "--verbose" ,
383
+ type = bool ,
384
+ default = False ,
385
+ required = False ,
386
+ help = "Print verbose output" )
387
+
388
+ parser .add_argument ("-d" , "--force_download" ,
389
+ type = bool ,
390
+ default = False ,
391
+ required = False ,
392
+ help = "Force download of tools" )
393
+
394
+ parser .add_argument ("-e" , "--force_extract" ,
395
+ type = bool ,
396
+ default = False ,
397
+ required = False ,
398
+ help = "Force extraction of tools" )
399
+
400
+ parser .add_argument ("-f" , "--force_all" ,
401
+ type = bool ,
402
+ default = False ,
403
+ required = False ,
404
+ help = "Force download and extraction of tools" )
405
+
406
+ parser .add_argument ("-t" , "--test" ,
407
+ type = bool ,
408
+ default = False ,
409
+ required = False ,
410
+ help = argparse .SUPPRESS )
411
+
412
+ args = parser .parse_args ()
368
413
369
- print (f'Debug: options values: option_print_help={ option_print_help } ; verbose={ verbose } ; force_download={ force_download } ; force_extract={ force_extract } ; force_all={ force_all } ; is_test={ is_test } ;' )
370
- if option_print_help :
371
- print_help ()
372
- sys .exit ()
414
+ verbose = args .verbose
415
+ force_download = args .force_download
416
+ force_extract = args .force_extract
417
+ force_all = args .force_all
418
+ is_test = args .test
373
419
374
420
if is_test and (force_download or force_extract or force_all ):
375
- print (' Cannot combine test (-t) and forced execution (-d | -e | -f)' )
376
- print_help ()
377
- sys .exit ()
421
+ print (" Cannot combine test (-t) and forced execution (-d | -e | -f)" )
422
+ parser . print_help (sys . stderr )
423
+ sys .exit (1 )
378
424
379
425
if is_test :
380
- print (' Test run!' )
426
+ print (" Test run!" )
381
427
382
428
if force_all :
383
429
force_download = True
@@ -393,9 +439,11 @@ def print_help():
393
439
if is_test :
394
440
print ("Would install: {0}" .format (tool ["archiveFileName" ]))
395
441
else :
396
- if ( not get_tool (tool , force_download , force_extract ) ):
397
- if ( verbose ) :
442
+ if not get_tool (tool , force_download , force_extract ):
443
+ if verbose :
398
444
print (f"Tool { tool ['archiveFileName' ]} was corrupted. Re-downloading...\n " )
399
- if (not get_tool (tool , True , force_extract )): # Corrupted file was renamed, will not be found and will be re-downloaded
445
+ if not get_tool (
446
+ tool , True , force_extract
447
+ ): # Corrupted file was renamed, will not be found and will be re-downloaded
400
448
print (f"Tool { tool ['archiveFileName' ]} was corrupted, but re-downloading did not help!\n " )
401
- print (' Platform Tools Installed' )
449
+ print (" Platform Tools Installed" )
0 commit comments