Skip to content

Commit 3cc0416

Browse files
committed
Test
Test Fix
1 parent 84167f6 commit 3cc0416

File tree

3 files changed

+239
-47
lines changed

3 files changed

+239
-47
lines changed

.github/scripts/upload_py_tools.sh

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
#!/bin/bash
22
CHANGED_FILES=$1
3-
echo "Pushing '$CHANGED_FILES' as github-actions"
4-
git config --global github.user "github-actions"
5-
git config --global user.name "github-actions"
6-
git config --global user.email "github-actions@github.com"
3+
echo "Pushing '$CHANGED_FILES' as github-actions[bot]"
4+
git config --global github.user "github-actions[bot]"
5+
git config --global user.name "github-actions[bot]"
6+
git config --global user.email "41898282+github-actions[bot]@users.noreply.github.com"
77
for tool in $CHANGED_FILES; do
88
git add tools/$tool.exe
99
done

.github/workflows/build_py_tools.yml

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -94,21 +94,22 @@ jobs:
9494
- name: Set up Python 3.8
9595
# Skip setting python on ARM because of missing compatibility: https://github.com/actions/setup-python/issues/108
9696
if: matrix.os != 'ARM' && matrix.os != 'ARM64'
97-
uses: actions/setup-python@master
97+
uses: actions/setup-python@v5
9898
with:
9999
python-version: 3.8
100+
cache: 'pip'
100101
- name: Install dependencies
101102
run: |
102103
python -m pip install --upgrade pip
103-
pip install pyinstaller requests
104+
pip install "pyinstaller==6.7.0" "requests==2.32.2"
104105
- name: Build with PyInstaller
105106
shell: bash
106107
run: |
107108
for tool in ${{ env.CHANGED_TOOLS }}; do
108109
pyinstaller --distpath ./${{ env.DISTPATH }} -F --icon=.github/pytools/espressif.ico tools/$tool.py
109110
done
110111
- name: Sign binaries
111-
if: matrix.os == 'windows-latest'
112+
if: matrix.os == 'windows-latest' && github.repository == 'espressif/arduino-esp32'
112113
env:
113114
CERTIFICATE: ${{ secrets.CERTIFICATE }}
114115
CERTIFICATE_PASSWORD: ${{ secrets.CERTIFICATE_PASSWORD }}

tools/get.py

Lines changed: 231 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,11 @@
2222
import tarfile
2323
import zipfile
2424
import re
25+
import time
26+
import argparse
27+
28+
# Initialize start_time globally
29+
start_time = -1
2530

2631
if sys.version_info[0] == 3:
2732
from urllib.request import urlretrieve
@@ -62,53 +67,174 @@ def mkdir_p(path):
6267
raise
6368

6469

65-
def report_progress(count, blockSize, totalSize):
70+
def format_time(seconds):
71+
minutes, seconds = divmod(seconds, 60)
72+
return "{:02}:{:05.2f}".format(int(minutes), seconds)
73+
74+
75+
def report_progress(block_count, block_size, total_size, start_time):
76+
downloaded_size = block_count * block_size
77+
time_elapsed = time.time() - start_time
78+
current_speed = downloaded_size / (time_elapsed)
79+
6680
if sys.stdout.isatty():
67-
if totalSize > 0:
68-
percent = int(count * blockSize * 100 / totalSize)
69-
percent = min(100, percent)
70-
sys.stdout.write("\r%d%%" % percent)
81+
if total_size > 0:
82+
percent_complete = min((downloaded_size / total_size) * 100, 100)
83+
sys.stdout.write(
84+
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
85+
)
7186
else:
72-
sofar = (count * blockSize) / 1024
73-
if sofar >= 1000:
74-
sofar /= 1024
75-
sys.stdout.write("\r%dMB " % (sofar))
76-
else:
77-
sys.stdout.write("\r%dKB" % (sofar))
87+
sys.stdout.write(
88+
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
89+
)
7890
sys.stdout.flush()
7991

8092

81-
def unpack(filename, destination):
93+
def print_verification_progress(total_files, i, t1):
94+
if sys.stdout.isatty():
95+
sys.stdout.write(f"\rElapsed time {format_time(time.time() - t1)}")
96+
sys.stdout.flush()
97+
98+
99+
def verify_files(filename, destination, rename_to):
100+
# Set the path of the extracted directory
101+
extracted_dir_path = destination
102+
t1 = time.time()
103+
if filename.endswith(".zip"):
104+
try:
105+
with zipfile.ZipFile(filename, "r") as archive:
106+
first_dir = archive.namelist()[0].split("/")[0]
107+
total_files = len(archive.namelist())
108+
for i, zipped_file in enumerate(archive.namelist(), 1):
109+
local_path = os.path.join(extracted_dir_path, zipped_file.replace(first_dir, rename_to, 1))
110+
if not os.path.exists(local_path):
111+
# print(f'\nMissing {zipped_file} on location: {extracted_dir_path}')
112+
print(f"Verification failed; aborted in {format_time(time.time() - t1)}")
113+
return False
114+
print_verification_progress(total_files, i, t1)
115+
except zipfile.BadZipFile:
116+
print(f"Verification failed; aborted in {format_time(time.time() - t1)}")
117+
return False
118+
elif filename.endswith(".tar.gz"):
119+
try:
120+
with tarfile.open(filename, "r:gz") as archive:
121+
first_dir = archive.getnames()[0].split("/")[0]
122+
total_files = len(archive.getnames())
123+
for i, zipped_file in enumerate(archive.getnames(), 1):
124+
local_path = os.path.join(extracted_dir_path, zipped_file.replace(first_dir, rename_to, 1))
125+
if not os.path.exists(local_path):
126+
# print(f'\nMissing {zipped_file} on location: {extracted_dir_path}')
127+
print(f"Verification failed; aborted in {format_time(time.time() - t1)}")
128+
return False
129+
print_verification_progress(total_files, i, t1)
130+
except tarfile.ReadError:
131+
print(f"Verification failed; aborted in {format_time(time.time() - t1)}")
132+
return False
133+
elif filename.endswith(".tar.xz"):
134+
try:
135+
with tarfile.open(filename, "r:xz") as archive:
136+
first_dir = archive.getnames()[0].split("/")[0]
137+
total_files = len(archive.getnames())
138+
for i, zipped_file in enumerate(archive.getnames(), 1):
139+
local_path = os.path.join(extracted_dir_path, zipped_file.replace(first_dir, rename_to, 1))
140+
if not os.path.exists(local_path):
141+
print(f'\nMissing {zipped_file} on location: {extracted_dir_path}')
142+
print(f"Verification failed; aborted in {format_time(time.time() - t1)}")
143+
return False
144+
print_verification_progress(total_files, i, t1)
145+
except tarfile.ReadError:
146+
print(f"Verification failed; aborted in {format_time(time.time() - t1)}")
147+
return False
148+
else:
149+
raise NotImplementedError("Unsupported archive type")
150+
151+
# if(verbose):
152+
# print(f"\nVerification passed; completed in {format_time(time.time() - t1)}")
153+
return True
154+
155+
156+
def unpack(filename, destination, force_extract):
82157
dirname = ""
83-
print("Extracting {0} ...".format(os.path.basename(filename)))
84-
sys.stdout.flush()
158+
cfile = None # Compressed file
159+
file_is_corrupted = False
160+
if not force_extract:
161+
print(" > Verify archive... ", end="", flush=True)
162+
163+
try:
164+
if filename.endswith("tar.gz"):
165+
if tarfile.is_tarfile(filename):
166+
cfile = tarfile.open(filename, "r:gz")
167+
dirname = cfile.getnames()[0]
168+
else:
169+
print("File corrupted!")
170+
file_is_corrupted = True
171+
elif filename.endswith("tar.xz"):
172+
if tarfile.is_tarfile(filename):
173+
cfile = tarfile.open(filename, "r:xz")
174+
dirname = cfile.getnames()[0]
175+
else:
176+
print("File corrupted!")
177+
file_is_corrupted = True
178+
elif filename.endswith("zip"):
179+
if zipfile.is_zipfile(filename):
180+
cfile = zipfile.ZipFile(filename)
181+
dirname = cfile.namelist()[0]
182+
else:
183+
print("File corrupted!")
184+
file_is_corrupted = True
185+
else:
186+
raise NotImplementedError("Unsupported archive type")
187+
except EOFError:
188+
print("File corrupted or incomplete!")
189+
cfile = None
190+
file_is_corrupted = True
191+
192+
if file_is_corrupted:
193+
corrupted_filename = filename + ".corrupted"
194+
os.rename(filename, corrupted_filename)
195+
if verbose:
196+
print(f"Renaming corrupted archive to {corrupted_filename}")
197+
return False
198+
199+
# A little trick to rename tool directories so they don't contain version number
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"
203+
204+
if not force_extract:
205+
if verify_files(filename, destination, rename_to):
206+
print(" Files ok. Skipping Extraction")
207+
return True
208+
else:
209+
print(" Extracting archive...")
210+
else:
211+
print(" Forcing extraction")
212+
85213
if filename.endswith("tar.gz"):
86-
tfile = tarfile.open(filename, "r:gz")
87-
tfile.extractall(destination)
88-
dirname = tfile.getnames()[0]
214+
if not cfile:
215+
cfile = tarfile.open(filename, "r:gz")
216+
cfile.extractall(destination)
89217
elif filename.endswith("tar.xz"):
90-
tfile = tarfile.open(filename, "r:xz")
91-
tfile.extractall(destination)
92-
dirname = tfile.getnames()[0]
218+
if not cfile:
219+
cfile = tarfile.open(filename, "r:xz")
220+
cfile.extractall(destination)
93221
elif filename.endswith("zip"):
94-
zfile = zipfile.ZipFile(filename)
95-
zfile.extractall(destination)
96-
dirname = zfile.namelist()[0]
222+
if not cfile:
223+
cfile = zipfile.ZipFile(filename)
224+
cfile.extractall(destination)
97225
else:
98226
raise NotImplementedError("Unsupported archive type")
99227

100-
# a little trick to rename tool directories so they don't contain version number
101-
rename_to = re.match(r"^([a-z][^\-]*\-*)+", dirname).group(0).strip("-")
102-
if rename_to == dirname and dirname.startswith("esp32-arduino-libs-"):
103-
rename_to = "esp32-arduino-libs"
104228
if rename_to != dirname:
105229
print("Renaming {0} to {1} ...".format(dirname, rename_to))
106230
if os.path.isdir(rename_to):
107231
shutil.rmtree(rename_to)
108232
shutil.move(dirname, rename_to)
109233

234+
return True
235+
110236

111-
def download_file_with_progress(url, filename):
237+
def download_file_with_progress(url, filename, start_time):
112238
import ssl
113239
import contextlib
114240

@@ -124,16 +250,16 @@ def download_file_with_progress(url, filename):
124250
with open(filename, "wb") as out_file:
125251
out_file.write(block)
126252
block_count += 1
127-
report_progress(block_count, block_size, total_size)
253+
report_progress(block_count, block_size, total_size, start_time)
128254
while True:
129255
block = fp.read(block_size)
130256
if not block:
131257
break
132258
out_file.write(block)
133259
block_count += 1
134-
report_progress(block_count, block_size, total_size)
260+
report_progress(block_count, block_size, total_size, start_time)
135261
else:
136-
raise Exception("nonexisting file or connection error")
262+
raise Exception("Non-existing file or connection error")
137263

138264

139265
def download_file(url, filename):
@@ -155,16 +281,21 @@ def download_file(url, filename):
155281
break
156282
out_file.write(block)
157283
else:
158-
raise Exception("nonexisting file or connection error")
284+
raise Exception("Non-existing file or connection error")
159285

160286

161-
def get_tool(tool):
287+
def get_tool(tool, force_download, force_extract):
162288
sys_name = platform.system()
163289
archive_name = tool["archiveFileName"]
290+
checksum = tool["checksum"][8:]
164291
local_path = dist_dir + archive_name
165292
url = tool["url"]
166-
if not os.path.isfile(local_path):
167-
print("Downloading " + archive_name + " ...")
293+
start_time = time.time()
294+
if not os.path.isfile(local_path) or force_download:
295+
if verbose:
296+
print("Downloading '" + archive_name + "' to '" + local_path + "'")
297+
else:
298+
print("Downloading '" + archive_name + "' ...")
168299
sys.stdout.flush()
169300
if "CYGWIN_NT" in sys_name:
170301
import ssl
@@ -186,13 +317,18 @@ def get_tool(tool):
186317
try:
187318
urlretrieve(url, local_path, report_progress)
188319
except: # noqa: E722
189-
download_file_with_progress(url, local_path)
190-
sys.stdout.write("\rDone \n")
320+
download_file_with_progress(url, local_path, start_time)
321+
sys.stdout.write(" - Done\n")
191322
sys.stdout.flush()
192323
else:
193324
print("Tool {0} already downloaded".format(archive_name))
194325
sys.stdout.flush()
195-
unpack(local_path, ".")
326+
327+
if "esp32-arduino-libs" not in archive_name and sha256sum(local_path) != checksum:
328+
print("Checksum mismatch for {0}".format(archive_name))
329+
return False
330+
331+
return unpack(local_path, ".", force_extract)
196332

197333

198334
def load_tools_list(filename, platform):
@@ -241,9 +377,58 @@ def identify_platform():
241377

242378

243379
if __name__ == "__main__":
244-
is_test = len(sys.argv) > 1 and sys.argv[1] == "-h"
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()
413+
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
419+
420+
if is_test and (force_download or force_extract or force_all):
421+
print("Cannot combine test (-t) and forced execution (-d | -e | -f)")
422+
parser.print_help(sys.stderr)
423+
sys.exit(1)
424+
245425
if is_test:
246426
print("Test run!")
427+
428+
if force_all:
429+
force_download = True
430+
force_extract = True
431+
247432
identified_platform = identify_platform()
248433
print("Platform: {0}".format(identified_platform))
249434
tools_to_download = load_tools_list(
@@ -254,5 +439,11 @@ def identify_platform():
254439
if is_test:
255440
print("Would install: {0}".format(tool["archiveFileName"]))
256441
else:
257-
get_tool(tool)
442+
if not get_tool(tool, force_download, force_extract):
443+
if verbose:
444+
print(f"Tool {tool['archiveFileName']} was corrupted. Re-downloading...\n")
445+
if not get_tool(
446+
tool, True, force_extract
447+
): # Corrupted file was renamed, will not be found and will be re-downloaded
448+
print(f"Tool {tool['archiveFileName']} was corrupted, but re-downloading did not help!\n")
258449
print("Platform Tools Installed")

0 commit comments

Comments
 (0)