|
12 | 12 | # See the License for the specific language governing permissions and
|
13 | 13 | # limitations under the License.
|
14 | 14 |
|
| 15 | +import fnmatch |
15 | 16 | import os
|
16 | 17 | import contextlib
|
17 | 18 | import json
|
@@ -117,6 +118,20 @@ def safe_remove_directory(path: str) -> bool:
|
117 | 118 | return True
|
118 | 119 |
|
119 | 120 |
|
| 121 | +@safe_file_operation |
| 122 | +def safe_remove_directory_pattern(base_path: str, pattern: str) -> bool: |
| 123 | + """Safely remove directories matching a pattern with error handling.""" |
| 124 | + if not os.path.exists(base_path): |
| 125 | + return True |
| 126 | + # Find all directories matching the pattern in the base directory |
| 127 | + for item in os.listdir(base_path): |
| 128 | + item_path = os.path.join(base_path, item) |
| 129 | + if os.path.isdir(item_path) and fnmatch.fnmatch(item, pattern): |
| 130 | + shutil.rmtree(item_path) |
| 131 | + logger.debug(f"Directory removed: {item_path}") |
| 132 | + return True |
| 133 | + |
| 134 | + |
120 | 135 | @safe_file_operation
|
121 | 136 | def safe_copy_file(src: str, dst: str) -> bool:
|
122 | 137 | """Safely copy files with error handling."""
|
@@ -148,6 +163,17 @@ def _get_tool_paths(self, tool_name: str) -> Dict[str, str]:
|
148 | 163 | """Get centralized path calculation for tools with caching."""
|
149 | 164 | if tool_name not in self._tools_cache:
|
150 | 165 | tool_path = os.path.join(self.packages_dir, tool_name)
|
| 166 | + # Remove all directories containing '@' in their name |
| 167 | + try: |
| 168 | + for item in os.listdir(self.packages_dir): |
| 169 | + if '@' in item and item.startswith(tool_name): |
| 170 | + item_path = os.path.join(self.packages_dir, item) |
| 171 | + if os.path.isdir(item_path): |
| 172 | + safe_remove_directory(item_path) |
| 173 | + logger.debug(f"Removed directory with '@' in name: {item_path}") |
| 174 | + except OSError as e: |
| 175 | + logger.error(f"Error scanning packages directory for '@' directories: {e}") |
| 176 | + |
151 | 177 | self._tools_cache[tool_name] = {
|
152 | 178 | 'tool_path': tool_path,
|
153 | 179 | 'package_path': os.path.join(tool_path, "package.json"),
|
@@ -297,9 +323,19 @@ def _handle_existing_tool(
|
297 | 323 | logger.debug(f"Tool {tool_name} found with correct version")
|
298 | 324 | return True
|
299 | 325 |
|
300 |
| - # Wrong version, reinstall |
| 326 | + # Wrong version, reinstall - remove similar paths too |
301 | 327 | logger.info(f"Reinstalling {tool_name} due to version mismatch")
|
| 328 | + |
| 329 | + tool_base_name = os.path.basename(paths['tool_path']) |
| 330 | + packages_dir = os.path.dirname(paths['tool_path']) |
| 331 | + |
| 332 | + # Remove similar directories with version suffixes FIRST (e.g., xtensa@src, xtensa.12232) |
| 333 | + safe_remove_directory_pattern(packages_dir, f"{tool_base_name}@*") |
| 334 | + safe_remove_directory_pattern(packages_dir, f"{tool_base_name}.*") |
| 335 | + |
| 336 | + # Then remove the main tool directory (if it still exists) |
302 | 337 | safe_remove_directory(paths['tool_path'])
|
| 338 | + |
303 | 339 | return self.install_tool(tool_name, retry_count + 1)
|
304 | 340 |
|
305 | 341 | def _configure_arduino_framework(self, frameworks: List[str]) -> None:
|
|
0 commit comments