30
30
import shutil
31
31
import hashlib
32
32
import logging
33
+ import threading
33
34
from contextlib import suppress
34
35
from os .path import join , exists , isabs , splitdrive , commonpath , relpath
35
36
from pathlib import Path
@@ -81,7 +82,8 @@ def setup_logging():
81
82
"CONFIG_FREERTOS_UNICORE=y"
82
83
}
83
84
84
- # Global flags to prevent message spam
85
+ # Thread-safe global flags to prevent message spam
86
+ _PATH_SHORTENING_LOCK = threading .Lock ()
85
87
_PATH_SHORTENING_MESSAGES = {
86
88
'shortening_applied' : False ,
87
89
'no_framework_paths_warning' : False ,
@@ -95,6 +97,7 @@ def __init__(self, platform, mcu):
95
97
self .platform = platform
96
98
self .mcu = mcu
97
99
self ._framework_dir = None
100
+ self ._framework_lib_dir = None
98
101
self ._sdk_dir = None
99
102
100
103
@property
@@ -104,7 +107,7 @@ def framework_dir(self):
104
107
return self ._framework_dir
105
108
106
109
@property
107
- def framework_dir (self ):
110
+ def framework_lib_dir (self ):
108
111
if self ._framework_lib_dir is None :
109
112
self ._framework_lib_dir = self .platform .get_package_dir ("framework-arduinoespressif32-libs" )
110
113
return self ._framework_lib_dir
@@ -119,32 +122,33 @@ def sdk_dir(self):
119
122
120
123
def check_and_warn_long_path_support ():
121
124
"""Checks Windows long path support and issues warning if disabled"""
122
- if not IS_WINDOWS or _PATH_SHORTENING_MESSAGES ['long_path_warning_shown' ]:
123
- return
124
-
125
- try :
126
- import winreg
127
- key = winreg .OpenKey (
128
- winreg .HKEY_LOCAL_MACHINE ,
129
- r"SYSTEM\CurrentControlSet\Control\FileSystem"
130
- )
131
- value , _ = winreg .QueryValueEx (key , "LongPathsEnabled" )
132
- winreg .CloseKey (key )
125
+ with _PATH_SHORTENING_LOCK : # Thread-safe access
126
+ if not IS_WINDOWS or _PATH_SHORTENING_MESSAGES ['long_path_warning_shown' ]:
127
+ return
128
+
129
+ try :
130
+ import winreg
131
+ key = winreg .OpenKey (
132
+ winreg .HKEY_LOCAL_MACHINE ,
133
+ r"SYSTEM\CurrentControlSet\Control\FileSystem"
134
+ )
135
+ value , _ = winreg .QueryValueEx (key , "LongPathsEnabled" )
136
+ winreg .CloseKey (key )
137
+
138
+ if value != 1 :
139
+ print ("*** WARNING: Windows Long Path Support is disabled ***" )
140
+ print ("*** Enable it for better performance: ***" )
141
+ print ("*** 1. Run as Administrator: gpedit.msc ***" )
142
+ print ("*** 2. Navigate to: Computer Configuration > Administrative Templates > System > Filesystem ***" )
143
+ print ("*** 3. Enable 'Enable Win32 long paths' ***" )
144
+ print ("*** OR run PowerShell as Admin: ***" )
145
+ print ("*** New-ItemProperty -Path 'HKLM:\\ SYSTEM\\ CurrentControlSet\\ Control\\ FileSystem' -Name 'LongPathsEnabled' -Value 1 -PropertyType DWORD -Force ***" )
146
+ print ("*** Restart required after enabling ***" )
147
+ except Exception :
148
+ print ("*** WARNING: Could not check Long Path Support status ***" )
149
+ print ("*** Consider enabling Windows Long Path Support for better performance ***" )
133
150
134
- if value != 1 :
135
- print ("*** WARNING: Windows Long Path Support is disabled ***" )
136
- print ("*** Enable it for better performance: ***" )
137
- print ("*** 1. Run as Administrator: gpedit.msc ***" )
138
- print ("*** 2. Navigate to: Computer Configuration > Administrative Templates > System > Filesystem ***" )
139
- print ("*** 3. Enable 'Enable Win32 long paths' ***" )
140
- print ("*** OR run PowerShell as Admin: ***" )
141
- print ("*** New-ItemProperty -Path 'HKLM:\\ SYSTEM\\ CurrentControlSet\\ Control\\ FileSystem' -Name 'LongPathsEnabled' -Value 1 -PropertyType DWORD -Force ***" )
142
- print ("*** Restart required after enabling ***" )
143
- except Exception :
144
- print ("*** WARNING: Could not check Long Path Support status ***" )
145
- print ("*** Consider enabling Windows Long Path Support for better performance ***" )
146
-
147
- _PATH_SHORTENING_MESSAGES ['long_path_warning_shown' ] = True
151
+ _PATH_SHORTENING_MESSAGES ['long_path_warning_shown' ] = True
148
152
149
153
# Secure deletion functions
150
154
def safe_delete_file (file_path : Union [str , Path ],
@@ -204,34 +208,37 @@ def safe_delete_directory(dir_path: Union[str, Path]) -> bool:
204
208
205
209
def validate_platformio_path (path : Union [str , Path ]) -> bool :
206
210
"""
207
- Special validation for PlatformIO package paths
211
+ Enhanced validation for PlatformIO package paths
208
212
"""
209
- path = Path (path ).resolve ()
210
- path_str = str (path )
211
-
212
- # Must be within .platformio directory structure
213
- if ".platformio" not in path_str :
214
- return False
215
-
216
- # Must be a packages directory
217
- if "packages" not in path_str :
218
- return False
213
+ try :
214
+ path = Path (path ).resolve ()
215
+ path_str = str (path )
219
216
220
- # Must be framework-related
221
- framework_indicators = [
222
- "framework-arduinoespressif32" ,
223
- ".platformio/packages" ,
224
- "packages/framework-arduinoespressif32" ,
225
- "packages/framework-arduinoespressif32-libs" ,
226
- "packages/framework-arduino-c2-skeleton-lib"
227
- ]
228
-
229
- if not any (indicator in path_str for indicator in framework_indicators ):
217
+ # Must be within .platformio directory structure
218
+ if ".platformio" not in path_str :
219
+ return False
220
+
221
+ # Must be a packages directory
222
+ if "packages" not in path_str :
223
+ return False
224
+
225
+ # Must be framework-related
226
+ framework_indicators = [
227
+ "framework-arduinoespressif32" ,
228
+ "framework-arduinoespressif32-libs" ,
229
+ "framework-arduino-c2-skeleton-lib"
230
+ ]
231
+
232
+ if not any (indicator in path_str for indicator in framework_indicators ):
233
+ return False
234
+
235
+ # Must not be a critical system path
236
+ critical_paths = ["/usr" , "/bin" , "/sbin" , "/etc" , "/boot" , "C:\\ Windows" , "C:\\ Program Files" ]
237
+ return not any (critical in path_str for critical in critical_paths )
238
+
239
+ except Exception as e :
240
+ logging .error (f"Path validation error: { e } " )
230
241
return False
231
-
232
- # Must not be a critical system path
233
- critical_paths = ["/usr" , "/bin" , "/sbin" , "/etc" , "/boot" ]
234
- return not any (critical in path_str for critical in critical_paths )
235
242
236
243
def validate_deletion_path (path : Union [str , Path ],
237
244
allowed_patterns : List [str ]) -> bool :
@@ -281,43 +288,42 @@ def validate_deletion_path(path: Union[str, Path],
281
288
return is_allowed
282
289
283
290
def safe_framework_cleanup ():
284
- """Secure cleanup of Arduino Framework"""
291
+ """Secure cleanup of Arduino Framework with enhanced error handling"""
292
+ success = True
285
293
286
- # Secure deletion of framework directories
294
+ # Framework directory cleanup
287
295
if exists (FRAMEWORK_DIR ):
288
296
logging .info (f"Attempting to validate framework path: { FRAMEWORK_DIR } " )
289
297
290
- # Use specialized PlatformIO path validation
291
298
if validate_platformio_path (FRAMEWORK_DIR ):
292
- #print("*** Secure framework cleanup ***")
293
299
logging .info (f"Framework path validated successfully: { FRAMEWORK_DIR } " )
294
300
295
301
if safe_delete_directory (FRAMEWORK_DIR ):
296
302
print ("Framework successfully removed" )
297
303
else :
298
304
print ("Error removing framework" )
299
- return False
305
+ success = False
300
306
else :
301
307
logging .error (f"PlatformIO path validation failed: { FRAMEWORK_DIR } " )
302
- return False
303
-
308
+ success = False
309
+
310
+ # Framework libs directory cleanup
311
+ if exists (FRAMEWORK_LIB_DIR ):
304
312
logging .info (f"Attempting to validate framework lib path: { FRAMEWORK_LIB_DIR } " )
305
313
306
- # Use specialized PlatformIO path validation
307
314
if validate_platformio_path (FRAMEWORK_LIB_DIR ):
308
- #print("*** Secure framework cleanup ***")
309
315
logging .info (f"Framework lib path validated successfully: { FRAMEWORK_LIB_DIR } " )
310
316
311
317
if safe_delete_directory (FRAMEWORK_LIB_DIR ):
312
318
print ("Framework libs successfully removed" )
313
- return True
314
319
else :
315
- print ("Error removing framework" )
316
- return False
320
+ print ("Error removing framework libs " )
321
+ success = False
317
322
else :
318
323
logging .error (f"PlatformIO path validation failed: { FRAMEWORK_LIB_DIR } " )
319
- return False
320
- return True
324
+ success = False
325
+
326
+ return success
321
327
322
328
def safe_remove_sdkconfig_files ():
323
329
"""Secure removal of SDKConfig files"""
@@ -499,9 +505,17 @@ def is_framework_subfolder(potential_subfolder):
499
505
return False
500
506
return commonpath ([FRAMEWORK_SDK_DIR ]) == commonpath ([FRAMEWORK_SDK_DIR , potential_subfolder ])
501
507
508
+ # Performance optimization with caching
502
509
def calculate_include_path_length (includes ):
503
- """Calculate total character count of all include paths"""
504
- return sum (len (str (inc )) for inc in includes )
510
+ """Calculate total character count of all include paths with caching"""
511
+ if not hasattr (calculate_include_path_length , '_cache' ):
512
+ calculate_include_path_length ._cache = {}
513
+
514
+ cache_key = tuple (includes )
515
+ if cache_key not in calculate_include_path_length ._cache :
516
+ calculate_include_path_length ._cache [cache_key ] = sum (len (str (inc )) for inc in includes )
517
+
518
+ return calculate_include_path_length ._cache [cache_key ]
505
519
506
520
def analyze_path_distribution (includes ):
507
521
"""Analyze the distribution of include path lengths for optimization insights"""
@@ -581,20 +595,21 @@ def apply_include_shortening(env, node, includes, total_length):
581
595
else :
582
596
generic_includes .append (inc )
583
597
584
- # Show result message only once
585
- if not _PATH_SHORTENING_MESSAGES ['shortening_applied' ]:
586
- if shortened_includes :
587
- new_total_length = original_length - saved_chars + len (f"-iprefix{ FRAMEWORK_SDK_DIR } " )
588
- print (f"*** Applied include path shortening for { len (shortened_includes )} framework paths ***" )
589
- print (f"*** Path length reduced from { original_length } to ~{ new_total_length } characters ***" )
590
- print (f"*** Estimated savings: { saved_chars } characters ***" )
591
- else :
592
- if not _PATH_SHORTENING_MESSAGES ['no_framework_paths_warning' ]:
593
- print ("*** Warning: Path length high but no framework paths found for shortening ***" )
594
- print ("*** This may indicate an architecture-specific issue ***" )
595
- print ("*** Run with -v (verbose) for detailed path analysis ***" )
596
- _PATH_SHORTENING_MESSAGES ['no_framework_paths_warning' ] = True
597
- _PATH_SHORTENING_MESSAGES ['shortening_applied' ] = True
598
+ # Show result message only once with thread safety
599
+ with _PATH_SHORTENING_LOCK :
600
+ if not _PATH_SHORTENING_MESSAGES ['shortening_applied' ]:
601
+ if shortened_includes :
602
+ new_total_length = original_length - saved_chars + len (f"-iprefix{ FRAMEWORK_SDK_DIR } " )
603
+ print (f"*** Applied include path shortening for { len (shortened_includes )} framework paths ***" )
604
+ print (f"*** Path length reduced from { original_length } to ~{ new_total_length } characters ***" )
605
+ print (f"*** Estimated savings: { saved_chars } characters ***" )
606
+ else :
607
+ if not _PATH_SHORTENING_MESSAGES ['no_framework_paths_warning' ]:
608
+ print ("*** Warning: Path length high but no framework paths found for shortening ***" )
609
+ print ("*** This may indicate an architecture-specific issue ***" )
610
+ print ("*** Run with -v (verbose) for detailed path analysis ***" )
611
+ _PATH_SHORTENING_MESSAGES ['no_framework_paths_warning' ] = True
612
+ _PATH_SHORTENING_MESSAGES ['shortening_applied' ] = True
598
613
599
614
common_flags = ["-iprefix" , FRAMEWORK_SDK_DIR ] + shortened_includes
600
615
@@ -645,14 +660,14 @@ def get_frameworks_in_current_env():
645
660
# Arduino as component is set, switch off Hybrid compile
646
661
flag_custom_sdkconfig = False
647
662
648
- # Framework reinstallation if required - IMPROVED WITH SECURE DELETION
663
+ # Framework reinstallation if required - Enhanced with secure deletion and error handling
649
664
if check_reinstall_frwrk ():
650
665
# Secure removal of SDKConfig files
651
666
safe_remove_sdkconfig_files ()
652
667
653
668
print ("*** Reinstall Arduino framework ***" )
654
669
655
- # Secure framework cleanup
670
+ # Secure framework cleanup with enhanced error handling
656
671
if safe_framework_cleanup ():
657
672
arduino_frmwrk_url = str (platform .get_package_spec ("framework-arduinoespressif32" )).split ("uri=" , 1 )[1 ][:- 1 ]
658
673
arduino_frmwrk_lib_url = str (platform .get_package_spec ("framework-arduinoespressif32-libs" )).split ("uri=" ,1 )[1 ][:- 1 ]
0 commit comments