Skip to content

Commit 3f4504b

Browse files
committed
change(get): Change get.py to match idf_tools.py more closely
1 parent 1a8400f commit 3f4504b

File tree

1 file changed

+153
-91
lines changed

1 file changed

+153
-91
lines changed

Diff for: tools/get.py

+153-91
Original file line numberDiff line numberDiff line change
@@ -24,22 +24,74 @@
2424
import re
2525
import time
2626
import argparse
27+
import ssl
28+
import contextlib
29+
30+
from urllib.request import urlretrieve
31+
from urllib.request import urlopen
32+
from urllib.response import addinfourl
33+
from typing import IO, Any, Callable, Dict, Iterator, List, Optional, Set, Tuple, Union
34+
from ssl import SSLContext
35+
36+
unicode = lambda s: str(s) # noqa: E731
37+
38+
# the older "DigiCert Global Root CA" certificate used with github.com
39+
DIGICERT_ROOT_CA_CERT = """
40+
-----BEGIN CERTIFICATE-----
41+
MIIDrzCCApegAwIBAgIQCDvgVpBCRrGhdWrJWZHHSjANBgkqhkiG9w0BAQUFADBh
42+
MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
43+
d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD
44+
QTAeFw0wNjExMTAwMDAwMDBaFw0zMTExMTAwMDAwMDBaMGExCzAJBgNVBAYTAlVT
45+
MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j
46+
b20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IENBMIIBIjANBgkqhkiG
47+
9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4jvhEXLeqKTTo1eqUKKPC3eQyaKl7hLOllsB
48+
CSDMAZOnTjC3U/dDxGkAV53ijSLdhwZAAIEJzs4bg7/fzTtxRuLWZscFs3YnFo97
49+
nh6Vfe63SKMI2tavegw5BmV/Sl0fvBf4q77uKNd0f3p4mVmFaG5cIzJLv07A6Fpt
50+
43C/dxC//AH2hdmoRBBYMql1GNXRor5H4idq9Joz+EkIYIvUX7Q6hL+hqkpMfT7P
51+
T19sdl6gSzeRntwi5m3OFBqOasv+zbMUZBfHWymeMr/y7vrTC0LUq7dBMtoM1O/4
52+
gdW7jVg/tRvoSSiicNoxBN33shbyTApOB6jtSj1etX+jkMOvJwIDAQABo2MwYTAO
53+
BgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUA95QNVbR
54+
TLtm8KPiGxvDl7I90VUwHwYDVR0jBBgwFoAUA95QNVbRTLtm8KPiGxvDl7I90VUw
55+
DQYJKoZIhvcNAQEFBQADggEBAMucN6pIExIK+t1EnE9SsPTfrgT1eXkIoyQY/Esr
56+
hMAtudXH/vTBH1jLuG2cenTnmCmrEbXjcKChzUyImZOMkXDiqw8cvpOp/2PV5Adg
57+
06O/nVsJ8dWO41P0jmP6P6fbtGbfYmbW0W5BjfIttep3Sp+dWOIrWcBAI+0tKIJF
58+
PnlUkiaY4IBIqDfv8NZ5YBberOgOzW6sRBc4L0na4UU+Krk2U886UAb3LujEV0ls
59+
YSEY1QSteDwsOoBrp+uvFRTp2InBuThs4pFsiv9kuXclVzDAGySj4dzp30d8tbQk
60+
CAUw7C29C79Fv1C5qfPrmAESrciIxpg0X40KPMbp1ZWVbd4=
61+
-----END CERTIFICATE-----
62+
"""
2763

28-
# Initialize start_time globally
29-
start_time = -1
30-
31-
if sys.version_info[0] == 3:
32-
from urllib.request import urlretrieve
33-
from urllib.request import urlopen
64+
# the newer "DigiCert Global Root G2" certificate used with dl.espressif.com
65+
DIGICERT_ROOT_G2_CERT = """
66+
-----BEGIN CERTIFICATE-----
67+
MIIDjjCCAnagAwIBAgIQAzrx5qcRqaC7KGSxHQn65TANBgkqhkiG9w0BAQsFADBh
68+
MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
69+
d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBH
70+
MjAeFw0xMzA4MDExMjAwMDBaFw0zODAxMTUxMjAwMDBaMGExCzAJBgNVBAYTAlVT
71+
MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j
72+
b20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IEcyMIIBIjANBgkqhkiG
73+
9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuzfNNNx7a8myaJCtSnX/RrohCgiN9RlUyfuI
74+
2/Ou8jqJkTx65qsGGmvPrC3oXgkkRLpimn7Wo6h+4FR1IAWsULecYxpsMNzaHxmx
75+
1x7e/dfgy5SDN67sH0NO3Xss0r0upS/kqbitOtSZpLYl6ZtrAGCSYP9PIUkY92eQ
76+
q2EGnI/yuum06ZIya7XzV+hdG82MHauVBJVJ8zUtluNJbd134/tJS7SsVQepj5Wz
77+
tCO7TG1F8PapspUwtP1MVYwnSlcUfIKdzXOS0xZKBgyMUNGPHgm+F6HmIcr9g+UQ
78+
vIOlCsRnKPZzFBQ9RnbDhxSJITRNrw9FDKZJobq7nMWxM4MphQIDAQABo0IwQDAP
79+
BgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBhjAdBgNVHQ4EFgQUTiJUIBiV
80+
5uNu5g/6+rkS7QYXjzkwDQYJKoZIhvcNAQELBQADggEBAGBnKJRvDkhj6zHd6mcY
81+
1Yl9PMWLSn/pvtsrF9+wX3N3KjITOYFnQoQj8kVnNeyIv/iPsGEMNKSuIEyExtv4
82+
NeF22d+mQrvHRAiGfzZ0JFrabA0UWTW98kndth/Jsw1HKj2ZL7tcu7XUIOGZX1NG
83+
Fdtom/DzMNU+MeKNhJ7jitralj41E6Vf8PlwUHBHQRFXGU7Aj64GxJUTFy8bJZ91
84+
8rGOmaFvE7FBcf6IKshPECBV1/MUReXgRPTqh5Uykw7+U0b6LJ3/iyK5S9kJRaTe
85+
pLiaWN0bfVKfjllDiIGknibVb63dDcY3fe0Dkhvld1927jyNxF1WW6LZZm6zNTfl
86+
MrY=
87+
-----END CERTIFICATE-----
88+
"""
3489

35-
unicode = lambda s: str(s) # noqa: E731
36-
else:
37-
# Not Python 3 - today, it is most likely to be Python 2
38-
from urllib import urlretrieve
39-
from urllib import urlopen
90+
DL_CERT_DICT = {'dl.espressif.com': DIGICERT_ROOT_G2_CERT,
91+
'github.com': DIGICERT_ROOT_CA_CERT}
4092

41-
if "Windows" in platform.system():
42-
import requests
93+
# Initialize start_time globally
94+
start_time = -1
4395

4496
# determine if application is a script file or frozen exe
4597
if getattr(sys, "frozen", False):
@@ -71,20 +123,18 @@ def format_time(seconds):
71123
return "{:02}:{:05.2f}".format(int(minutes), seconds)
72124

73125

74-
def report_progress(block_count, block_size, total_size, start_time):
126+
def report_progress(block_count, block_size, total_size):
75127
downloaded_size = block_count * block_size
76-
time_elapsed = time.time() - start_time
77-
current_speed = downloaded_size / (time_elapsed)
78128

79129
if sys.stdout.isatty():
80130
if total_size > 0:
81131
percent_complete = min((downloaded_size / total_size) * 100, 100)
82132
sys.stdout.write(
83-
f"\rDownloading... {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
133+
f"\rDownloading... {percent_complete:.2f}% - {downloaded_size / 1024 / 1024:.2f} MB downloaded" # noqa: E501
84134
)
85135
else:
86136
sys.stdout.write(
87-
f"\rDownloading... {downloaded_size / 1024 / 1024:.2f} MB downloaded - Elapsed Time: {format_time(time_elapsed)} - Speed: {current_speed / 1024 / 1024:.2f} MB/s" # noqa: E501
137+
f"\rDownloading... {downloaded_size / 1024 / 1024:.2f} MB downloaded" # noqa: E501
88138
)
89139
sys.stdout.flush()
90140

@@ -243,18 +293,25 @@ def unpack(filename, destination, force_extract, checksum): # noqa: C901
243293
if filename.endswith("tar.gz"):
244294
if not cfile:
245295
cfile = tarfile.open(filename, "r:gz")
246-
cfile.extractall(destination, filter="tar")
296+
cfile.extractall(destination, filter="fully_trusted")
247297
elif filename.endswith("tar.xz"):
248298
if not cfile:
249299
cfile = tarfile.open(filename, "r:xz")
250-
cfile.extractall(destination, filter="tar")
300+
cfile.extractall(destination, filter="fully_trusted")
251301
elif filename.endswith("zip"):
252302
if not cfile:
253303
cfile = zipfile.ZipFile(filename)
254304
cfile.extractall(destination)
255305
else:
256306
raise NotImplementedError("Unsupported archive type")
257307

308+
if sys.platform != 'win32' and filename.endswith('zip') and isinstance(cfile, ZipFile):
309+
for file_info in cfile.infolist():
310+
extracted_file = os.path.join(destination, file_info.filename)
311+
extracted_permissions = file_info.external_attr >> 16 & 0o777 # Extract Unix permissions
312+
if os.path.exists(extracted_file):
313+
os.chmod(extracted_file, extracted_permissions)
314+
258315
if rename_to != dirname:
259316
print("Renaming {0} to {1} ...".format(dirname, rename_to))
260317
shutil.move(dirname, rename_to)
@@ -275,55 +332,67 @@ def unpack(filename, destination, force_extract, checksum): # noqa: C901
275332
return False
276333

277334

278-
def download_file_with_progress(url, filename, start_time):
279-
import ssl
280-
import contextlib
281-
282-
ctx = ssl.create_default_context()
283-
ctx.check_hostname = False
284-
ctx.verify_mode = ssl.CERT_NONE
285-
with contextlib.closing(urlopen(url, context=ctx)) as fp:
286-
total_size = int(fp.getheader("Content-Length", fp.getheader("Content-length", "0")))
287-
block_count = 0
288-
block_size = 1024 * 8
289-
block = fp.read(block_size)
290-
if block:
291-
with open(filename, "wb") as out_file:
292-
out_file.write(block)
293-
block_count += 1
294-
report_progress(block_count, block_size, total_size, start_time)
295-
while True:
296-
block = fp.read(block_size)
297-
if not block:
298-
break
299-
out_file.write(block)
300-
block_count += 1
301-
report_progress(block_count, block_size, total_size, start_time)
302-
else:
303-
raise Exception("Non-existing file or connection error")
304-
305-
306-
def download_file(url, filename):
307-
import ssl
308-
import contextlib
309-
310-
ctx = ssl.create_default_context()
311-
ctx.check_hostname = False
312-
ctx.verify_mode = ssl.CERT_NONE
313-
with contextlib.closing(urlopen(url, context=ctx)) as fp:
314-
block_size = 1024 * 8
315-
block = fp.read(block_size)
316-
if block:
317-
with open(filename, "wb") as out_file:
318-
out_file.write(block)
319-
while True:
320-
block = fp.read(block_size)
321-
if not block:
322-
break
323-
out_file.write(block)
324-
else:
325-
raise Exception("Non-existing file or connection error")
326-
335+
def splittype(url: str) -> Tuple[Optional[str], str]:
336+
"""
337+
Splits given url into its type (e.g. https, file) and the rest.
338+
"""
339+
match = re.match('([^/:]+):(.*)', url, re.DOTALL)
340+
if match:
341+
scheme, data = match.groups()
342+
return scheme.lower(), data
343+
return None, url
344+
345+
def urlretrieve_ctx(url: str,
346+
filename: str,
347+
reporthook: Optional[Callable[[int, int, int], None]]=None,
348+
data: Optional[bytes]=None,
349+
context: Optional[SSLContext]=None) -> Tuple[str, addinfourl]:
350+
"""
351+
Retrieve data from given URL. An alternative version of urlretrieve which takes SSL context as an argument.
352+
"""
353+
url_type, path = splittype(url)
354+
355+
# urlopen doesn't have context argument in Python <=2.7.9
356+
extra_urlopen_args = {}
357+
if context:
358+
extra_urlopen_args['context'] = context
359+
with contextlib.closing(urlopen(url, data, **extra_urlopen_args)) as fp: # type: ignore
360+
headers = fp.info()
361+
362+
# Just return the local path and the "headers" for file://
363+
# URLs. No sense in performing a copy unless requested.
364+
if url_type == 'file' and not filename:
365+
return os.path.normpath(path), headers
366+
367+
# Handle temporary file setup.
368+
tfp = open(filename, 'wb')
369+
370+
with tfp:
371+
result = filename, headers
372+
bs = 1024 * 8
373+
size = int(headers.get('content-length', -1))
374+
read = 0
375+
blocknum = 0
376+
377+
if reporthook:
378+
reporthook(blocknum, bs, size)
379+
380+
while True:
381+
block = fp.read(bs)
382+
if not block:
383+
break
384+
read += len(block)
385+
tfp.write(block)
386+
blocknum += 1
387+
if reporthook:
388+
reporthook(blocknum, bs, size)
389+
390+
if size >= 0 and read < size:
391+
raise ContentTooShortError(
392+
'retrieval incomplete: got only %i out of %i bytes'
393+
% (read, size), result)
394+
395+
return result
327396

328397
def get_tool(tool, force_download, force_extract):
329398
sys_name = platform.system()
@@ -339,29 +408,22 @@ def get_tool(tool, force_download, force_extract):
339408
else:
340409
print("Downloading '" + archive_name + "' ...")
341410
sys.stdout.flush()
342-
if "CYGWIN_NT" in sys_name:
343-
import ssl
344-
345-
ctx = ssl.create_default_context()
346-
ctx.check_hostname = False
347-
ctx.verify_mode = ssl.CERT_NONE
348-
urlretrieve(url, local_path, report_progress, context=ctx)
349-
elif "Windows" in sys_name:
350-
r = requests.get(url)
351-
f = open(local_path, "wb")
352-
f.write(r.content)
353-
f.close()
354-
else:
355-
is_ci = os.environ.get("GITHUB_WORKSPACE")
356-
if is_ci:
357-
download_file(url, local_path)
411+
412+
try:
413+
for site, cert in DL_CERT_DICT.items():
414+
if site in url:
415+
ctx = ssl.create_default_context()
416+
ctx.load_verify_locations(cadata=cert)
417+
break
358418
else:
359-
try:
360-
urlretrieve(url, local_path, report_progress)
361-
except: # noqa: E722
362-
download_file_with_progress(url, local_path, start_time)
363-
sys.stdout.write(" - Done\n")
364-
sys.stdout.flush()
419+
ctx = None
420+
421+
urlretrieve_ctx(url, local_path, report_progress, context=ctx)
422+
except Exception as e:
423+
print(f"Failed to download {archive_name}: {e}")
424+
return False
425+
finally:
426+
sys.stdout.flush()
365427
else:
366428
print("Tool {0} already downloaded".format(archive_name))
367429
sys.stdout.flush()

0 commit comments

Comments
 (0)