Skip to content

Commit a464095

Browse files
authored
Update main.py
1 parent 7bbd98d commit a464095

File tree

1 file changed

+180
-21
lines changed

1 file changed

+180
-21
lines changed

builder/main.py

Lines changed: 180 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,29 @@
3636
from platformio.util import get_serial_ports
3737

3838

39+
def add_to_pythonpath(path):
40+
"""
41+
Add a path to the PYTHONPATH environment variable (cross-platform).
42+
43+
Args:
44+
path (str): The path to add to PYTHONPATH
45+
"""
46+
# Normalize the path for the current OS
47+
normalized_path = os.path.normpath(path)
48+
49+
# Add to PYTHONPATH environment variable
50+
if "PYTHONPATH" in os.environ:
51+
current_paths = os.environ["PYTHONPATH"].split(os.pathsep)
52+
if normalized_path not in current_paths:
53+
os.environ["PYTHONPATH"] += os.pathsep + normalized_path
54+
else:
55+
os.environ["PYTHONPATH"] = normalized_path
56+
57+
# Also add to sys.path for immediate availability
58+
if normalized_path not in sys.path:
59+
sys.path.insert(0, normalized_path)
60+
61+
3962
# Initialize environment and configuration
4063
env = DefaultEnvironment()
4164
platform = env.PioPlatform()
@@ -45,6 +68,13 @@
4568
# Framework directory path
4669
FRAMEWORK_DIR = platform.get_package_dir("framework-arduinoespressif32")
4770

71+
# Add framework Python tools to path if available
72+
if FRAMEWORK_DIR:
73+
framework_python_path = os.path.join(FRAMEWORK_DIR, "tools", "python")
74+
if os.path.isdir(framework_python_path):
75+
add_to_pythonpath(framework_python_path)
76+
77+
# Python dependencies required for the build process
4878
python_deps = {
4979
"uv": ">=0.1.0",
5080
"pyyaml": ">=6.0.2",
@@ -57,7 +87,16 @@
5787

5888

5989
def get_packages_to_install(deps, installed_packages):
60-
"""Generator for Python packages to install"""
90+
"""
91+
Generator for Python packages that need to be installed.
92+
93+
Args:
94+
deps (dict): Dictionary of package names and version specifications
95+
installed_packages (dict): Dictionary of currently installed packages
96+
97+
Yields:
98+
str: Package name that needs to be installed
99+
"""
61100
for package, spec in deps.items():
62101
if package not in installed_packages:
63102
yield package
@@ -68,7 +107,12 @@ def get_packages_to_install(deps, installed_packages):
68107

69108

70109
def install_python_deps():
71-
"""Ensure uv package manager is available, install with pip if not"""
110+
"""
111+
Ensure uv package manager is available and install required Python dependencies.
112+
113+
Returns:
114+
bool: True if successful, False otherwise
115+
"""
72116
try:
73117
result = subprocess.run(
74118
["uv", "--version"],
@@ -86,7 +130,8 @@ def install_python_deps():
86130
[env.subst("$PYTHONEXE"), "-m", "pip", "install", "uv>=0.1.0", "-q", "-q", "-q"],
87131
capture_output=True,
88132
text=True,
89-
timeout=30 # 30 second timeout
133+
timeout=30, # 30 second timeout
134+
env=os.environ # Use modified environment with custom PYTHONPATH
90135
)
91136
if result.returncode != 0:
92137
if result.stderr:
@@ -104,6 +149,12 @@ def install_python_deps():
104149

105150

106151
def _get_installed_uv_packages():
152+
"""
153+
Get list of installed packages using uv.
154+
155+
Returns:
156+
dict: Dictionary of installed packages with versions
157+
"""
107158
result = {}
108159
try:
109160
cmd = ["uv", "pip", "list", "--format=json"]
@@ -112,7 +163,8 @@ def _get_installed_uv_packages():
112163
capture_output=True,
113164
text=True,
114165
encoding='utf-8',
115-
timeout=30 # 30 second timeout
166+
timeout=30, # 30 second timeout
167+
env=os.environ # Use modified environment with custom PYTHONPATH
116168
)
117169

118170
if result_obj.returncode == 0:
@@ -154,7 +206,8 @@ def _get_installed_uv_packages():
154206
cmd,
155207
capture_output=True,
156208
text=True,
157-
timeout=30 # 30 second timeout for package installation
209+
timeout=30, # 30 second timeout for package installation
210+
env=os.environ # Use modified environment with custom PYTHONPATH
158211
)
159212

160213
if result.returncode != 0:
@@ -177,10 +230,22 @@ def _get_installed_uv_packages():
177230

178231

179232
def install_esptool(env):
180-
"""Install esptool from package folder "tool-esptoolpy" using uv package manager"""
233+
"""
234+
Install esptool from package folder "tool-esptoolpy" using uv package manager.
235+
236+
Args:
237+
env: SCons environment object
238+
239+
Returns:
240+
bool: True if successful, False otherwise
241+
"""
181242
try:
182-
subprocess.check_call([env.subst("$PYTHONEXE"), "-c", "import esptool"],
183-
stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
243+
subprocess.check_call(
244+
[env.subst("$PYTHONEXE"), "-c", "import esptool"],
245+
stdout=subprocess.DEVNULL,
246+
stderr=subprocess.DEVNULL,
247+
env=os.environ # Use modified environment with custom PYTHONPATH
248+
)
184249
return True
185250
except (subprocess.CalledProcessError, FileNotFoundError):
186251
pass
@@ -192,7 +257,7 @@ def install_esptool(env):
192257
"uv", "pip", "install", "--quiet",
193258
f"--python={env.subst('$PYTHONEXE')}",
194259
"-e", esptool_repo_path
195-
])
260+
], env=os.environ) # Use modified environment with custom PYTHONPATH
196261
return True
197262
except subprocess.CalledProcessError as e:
198263
print(f"Warning: Failed to install esptool: {e}")
@@ -201,6 +266,7 @@ def install_esptool(env):
201266
return False
202267

203268

269+
# Install Python dependencies and esptool
204270
install_python_deps()
205271
install_esptool(env)
206272

@@ -209,6 +275,11 @@ def BeforeUpload(target, source, env):
209275
"""
210276
Prepare the environment before uploading firmware.
211277
Handles port detection and special upload configurations.
278+
279+
Args:
280+
target: SCons target
281+
source: SCons source
282+
env: SCons environment object
212283
"""
213284
upload_options = {}
214285
if "BOARD" in env:
@@ -228,7 +299,12 @@ def BeforeUpload(target, source, env):
228299
def _get_board_memory_type(env):
229300
"""
230301
Determine the memory type configuration for the board.
231-
Returns the appropriate memory type string based on board configuration.
302+
303+
Args:
304+
env: SCons environment object
305+
306+
Returns:
307+
str: The appropriate memory type string based on board configuration
232308
"""
233309
board_config = env.BoardConfig()
234310
default_type = "%s_%s" % (
@@ -249,20 +325,41 @@ def _get_board_memory_type(env):
249325
def _normalize_frequency(frequency):
250326
"""
251327
Convert frequency value to normalized string format (e.g., "40m").
252-
Removes 'L' suffix and converts to MHz format.
328+
329+
Args:
330+
frequency: Frequency value to normalize
331+
332+
Returns:
333+
str: Normalized frequency string with 'm' suffix
253334
"""
254335
frequency = str(frequency).replace("L", "")
255336
return str(int(int(frequency) / 1000000)) + "m"
256337

257338

258339
def _get_board_f_flash(env):
259-
"""Get the flash frequency for the board."""
340+
"""
341+
Get the flash frequency for the board.
342+
343+
Args:
344+
env: SCons environment object
345+
346+
Returns:
347+
str: Flash frequency string
348+
"""
260349
frequency = env.subst("$BOARD_F_FLASH")
261350
return _normalize_frequency(frequency)
262351

263352

264353
def _get_board_f_image(env):
265-
"""Get the image frequency for the board, fallback to flash frequency."""
354+
"""
355+
Get the image frequency for the board, fallback to flash frequency.
356+
357+
Args:
358+
env: SCons environment object
359+
360+
Returns:
361+
str: Image frequency string
362+
"""
266363
board_config = env.BoardConfig()
267364
if "build.f_image" in board_config:
268365
return _normalize_frequency(board_config.get("build.f_image"))
@@ -271,7 +368,15 @@ def _get_board_f_image(env):
271368

272369

273370
def _get_board_f_boot(env):
274-
"""Get the boot frequency for the board, fallback to flash frequency."""
371+
"""
372+
Get the boot frequency for the board, fallback to flash frequency.
373+
374+
Args:
375+
env: SCons environment object
376+
377+
Returns:
378+
str: Boot frequency string
379+
"""
275380
board_config = env.BoardConfig()
276381
if "build.f_boot" in board_config:
277382
return _normalize_frequency(board_config.get("build.f_boot"))
@@ -283,6 +388,12 @@ def _get_board_flash_mode(env):
283388
"""
284389
Determine the appropriate flash mode for the board.
285390
Handles special cases for OPI memory types.
391+
392+
Args:
393+
env: SCons environment object
394+
395+
Returns:
396+
str: Flash mode string
286397
"""
287398
if _get_board_memory_type(env) in ("opi_opi", "opi_qspi"):
288399
return "dout"
@@ -297,6 +408,12 @@ def _get_board_boot_mode(env):
297408
"""
298409
Determine the boot mode for the board.
299410
Handles special cases for OPI memory types.
411+
412+
Args:
413+
env: SCons environment object
414+
415+
Returns:
416+
str: Boot mode string
300417
"""
301418
memory_type = env.BoardConfig().get("build.arduino.memory_type", "")
302419
build_boot = env.BoardConfig().get("build.boot", "$BOARD_FLASH_MODE")
@@ -308,7 +425,12 @@ def _get_board_boot_mode(env):
308425
def _parse_size(value):
309426
"""
310427
Parse size values from various formats (int, hex, K/M suffixes).
311-
Returns the size in bytes as an integer.
428+
429+
Args:
430+
value: Size value to parse
431+
432+
Returns:
433+
int: Size in bytes as an integer
312434
"""
313435
if isinstance(value, int):
314436
return value
@@ -326,6 +448,12 @@ def _parse_partitions(env):
326448
"""
327449
Parse the partition table CSV file and return partition information.
328450
Also sets the application offset for the environment.
451+
452+
Args:
453+
env: SCons environment object
454+
455+
Returns:
456+
list: List of partition dictionaries
329457
"""
330458
partitions_csv = env.subst("$PARTITIONS_TABLE_CSV")
331459
if not isfile(partitions_csv):
@@ -377,6 +505,9 @@ def _update_max_upload_size(env):
377505
"""
378506
Update the maximum upload size based on partition table configuration.
379507
Prioritizes user-specified partition names.
508+
509+
Args:
510+
env: SCons environment object
380511
"""
381512
if not env.get("PARTITIONS_TABLE_CSV"):
382513
return
@@ -412,14 +543,25 @@ def _update_max_upload_size(env):
412543

413544

414545
def _to_unix_slashes(path):
415-
"""Convert Windows-style backslashes to Unix-style forward slashes."""
546+
"""
547+
Convert Windows-style backslashes to Unix-style forward slashes.
548+
549+
Args:
550+
path (str): Path to convert
551+
552+
Returns:
553+
str: Path with Unix-style slashes
554+
"""
416555
return path.replace("\\", "/")
417556

418557

419558
def fetch_fs_size(env):
420559
"""
421560
Extract filesystem size and offset information from partition table.
422561
Sets FS_START, FS_SIZE, FS_PAGE, and FS_BLOCK environment variables.
562+
563+
Args:
564+
env: SCons environment object
423565
"""
424566
fs = None
425567
for p in _parse_partitions(env):
@@ -450,15 +592,27 @@ def fetch_fs_size(env):
450592

451593

452594
def __fetch_fs_size(target, source, env):
453-
"""Wrapper function for fetch_fs_size to be used as SCons emitter."""
595+
"""
596+
Wrapper function for fetch_fs_size to be used as SCons emitter.
597+
598+
Args:
599+
target: SCons target
600+
source: SCons source
601+
env: SCons environment object
602+
603+
Returns:
604+
tuple: (target, source) tuple
605+
"""
454606
fetch_fs_size(env)
455607
return (target, source)
456608

457609

458610
def check_lib_archive_exists():
459611
"""
460612
Check if lib_archive is set in platformio.ini configuration.
461-
Returns True if found, False otherwise.
613+
614+
Returns:
615+
bool: True if found, False otherwise
462616
"""
463617
for section in projectconfig.sections():
464618
if "lib_archive" in projectconfig.options(section):
@@ -611,8 +765,13 @@ def check_lib_archive_exists():
611765

612766
def firmware_metrics(target, source, env):
613767
"""
614-
Custom target to run esp-idf-size with support for command line parameters
768+
Custom target to run esp-idf-size with support for command line parameters.
615769
Usage: pio run -t metrics -- [esp-idf-size arguments]
770+
771+
Args:
772+
target: SCons target
773+
source: SCons source
774+
env: SCons environment object
616775
"""
617776
if terminal_cp != "utf-8":
618777
print("Firmware metrics can not be shown. Set the terminal codepage to \"utf-8\"")
@@ -655,8 +814,8 @@ def firmware_metrics(target, source, env):
655814
if env.GetProjectOption("custom_esp_idf_size_verbose", False):
656815
print(f"Running command: {' '.join(cmd)}")
657816

658-
# Call esp-idf-size
659-
result = subprocess.run(cmd, check=False, capture_output=False)
817+
# Call esp-idf-size with modified environment
818+
result = subprocess.run(cmd, check=False, capture_output=False, env=os.environ)
660819

661820
if result.returncode != 0:
662821
print(f"Warning: esp-idf-size exited with code {result.returncode}")

0 commit comments

Comments
 (0)