fbuild 1.2.8__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (121) hide show
  1. fbuild/__init__.py +390 -0
  2. fbuild/assets/example.txt +1 -0
  3. fbuild/build/__init__.py +117 -0
  4. fbuild/build/archive_creator.py +186 -0
  5. fbuild/build/binary_generator.py +444 -0
  6. fbuild/build/build_component_factory.py +131 -0
  7. fbuild/build/build_info_generator.py +624 -0
  8. fbuild/build/build_state.py +325 -0
  9. fbuild/build/build_utils.py +93 -0
  10. fbuild/build/compilation_executor.py +422 -0
  11. fbuild/build/compiler.py +165 -0
  12. fbuild/build/compiler_avr.py +574 -0
  13. fbuild/build/configurable_compiler.py +664 -0
  14. fbuild/build/configurable_linker.py +637 -0
  15. fbuild/build/flag_builder.py +214 -0
  16. fbuild/build/library_dependency_processor.py +185 -0
  17. fbuild/build/linker.py +708 -0
  18. fbuild/build/orchestrator.py +67 -0
  19. fbuild/build/orchestrator_avr.py +651 -0
  20. fbuild/build/orchestrator_esp32.py +878 -0
  21. fbuild/build/orchestrator_rp2040.py +719 -0
  22. fbuild/build/orchestrator_stm32.py +696 -0
  23. fbuild/build/orchestrator_teensy.py +580 -0
  24. fbuild/build/source_compilation_orchestrator.py +218 -0
  25. fbuild/build/source_scanner.py +516 -0
  26. fbuild/cli.py +717 -0
  27. fbuild/cli_utils.py +314 -0
  28. fbuild/config/__init__.py +16 -0
  29. fbuild/config/board_config.py +542 -0
  30. fbuild/config/board_loader.py +92 -0
  31. fbuild/config/ini_parser.py +369 -0
  32. fbuild/config/mcu_specs.py +88 -0
  33. fbuild/daemon/__init__.py +42 -0
  34. fbuild/daemon/async_client.py +531 -0
  35. fbuild/daemon/client.py +1505 -0
  36. fbuild/daemon/compilation_queue.py +293 -0
  37. fbuild/daemon/configuration_lock.py +865 -0
  38. fbuild/daemon/daemon.py +585 -0
  39. fbuild/daemon/daemon_context.py +293 -0
  40. fbuild/daemon/error_collector.py +263 -0
  41. fbuild/daemon/file_cache.py +332 -0
  42. fbuild/daemon/firmware_ledger.py +546 -0
  43. fbuild/daemon/lock_manager.py +508 -0
  44. fbuild/daemon/logging_utils.py +149 -0
  45. fbuild/daemon/messages.py +957 -0
  46. fbuild/daemon/operation_registry.py +288 -0
  47. fbuild/daemon/port_state_manager.py +249 -0
  48. fbuild/daemon/process_tracker.py +366 -0
  49. fbuild/daemon/processors/__init__.py +18 -0
  50. fbuild/daemon/processors/build_processor.py +248 -0
  51. fbuild/daemon/processors/deploy_processor.py +664 -0
  52. fbuild/daemon/processors/install_deps_processor.py +431 -0
  53. fbuild/daemon/processors/locking_processor.py +777 -0
  54. fbuild/daemon/processors/monitor_processor.py +285 -0
  55. fbuild/daemon/request_processor.py +457 -0
  56. fbuild/daemon/shared_serial.py +819 -0
  57. fbuild/daemon/status_manager.py +238 -0
  58. fbuild/daemon/subprocess_manager.py +316 -0
  59. fbuild/deploy/__init__.py +21 -0
  60. fbuild/deploy/deployer.py +67 -0
  61. fbuild/deploy/deployer_esp32.py +310 -0
  62. fbuild/deploy/docker_utils.py +315 -0
  63. fbuild/deploy/monitor.py +519 -0
  64. fbuild/deploy/qemu_runner.py +603 -0
  65. fbuild/interrupt_utils.py +34 -0
  66. fbuild/ledger/__init__.py +52 -0
  67. fbuild/ledger/board_ledger.py +560 -0
  68. fbuild/output.py +352 -0
  69. fbuild/packages/__init__.py +66 -0
  70. fbuild/packages/archive_utils.py +1098 -0
  71. fbuild/packages/arduino_core.py +412 -0
  72. fbuild/packages/cache.py +256 -0
  73. fbuild/packages/concurrent_manager.py +510 -0
  74. fbuild/packages/downloader.py +518 -0
  75. fbuild/packages/fingerprint.py +423 -0
  76. fbuild/packages/framework_esp32.py +538 -0
  77. fbuild/packages/framework_rp2040.py +349 -0
  78. fbuild/packages/framework_stm32.py +459 -0
  79. fbuild/packages/framework_teensy.py +346 -0
  80. fbuild/packages/github_utils.py +96 -0
  81. fbuild/packages/header_trampoline_cache.py +394 -0
  82. fbuild/packages/library_compiler.py +203 -0
  83. fbuild/packages/library_manager.py +549 -0
  84. fbuild/packages/library_manager_esp32.py +725 -0
  85. fbuild/packages/package.py +163 -0
  86. fbuild/packages/platform_esp32.py +383 -0
  87. fbuild/packages/platform_rp2040.py +400 -0
  88. fbuild/packages/platform_stm32.py +581 -0
  89. fbuild/packages/platform_teensy.py +312 -0
  90. fbuild/packages/platform_utils.py +131 -0
  91. fbuild/packages/platformio_registry.py +369 -0
  92. fbuild/packages/sdk_utils.py +231 -0
  93. fbuild/packages/toolchain.py +436 -0
  94. fbuild/packages/toolchain_binaries.py +196 -0
  95. fbuild/packages/toolchain_esp32.py +489 -0
  96. fbuild/packages/toolchain_metadata.py +185 -0
  97. fbuild/packages/toolchain_rp2040.py +436 -0
  98. fbuild/packages/toolchain_stm32.py +417 -0
  99. fbuild/packages/toolchain_teensy.py +404 -0
  100. fbuild/platform_configs/esp32.json +150 -0
  101. fbuild/platform_configs/esp32c2.json +144 -0
  102. fbuild/platform_configs/esp32c3.json +143 -0
  103. fbuild/platform_configs/esp32c5.json +151 -0
  104. fbuild/platform_configs/esp32c6.json +151 -0
  105. fbuild/platform_configs/esp32p4.json +149 -0
  106. fbuild/platform_configs/esp32s3.json +151 -0
  107. fbuild/platform_configs/imxrt1062.json +56 -0
  108. fbuild/platform_configs/rp2040.json +70 -0
  109. fbuild/platform_configs/rp2350.json +76 -0
  110. fbuild/platform_configs/stm32f1.json +59 -0
  111. fbuild/platform_configs/stm32f4.json +63 -0
  112. fbuild/py.typed +0 -0
  113. fbuild-1.2.8.dist-info/METADATA +468 -0
  114. fbuild-1.2.8.dist-info/RECORD +121 -0
  115. fbuild-1.2.8.dist-info/WHEEL +5 -0
  116. fbuild-1.2.8.dist-info/entry_points.txt +5 -0
  117. fbuild-1.2.8.dist-info/licenses/LICENSE +21 -0
  118. fbuild-1.2.8.dist-info/top_level.txt +2 -0
  119. fbuild_lint/__init__.py +0 -0
  120. fbuild_lint/ruff_plugins/__init__.py +0 -0
  121. fbuild_lint/ruff_plugins/keyboard_interrupt_checker.py +158 -0
@@ -0,0 +1,349 @@
1
+ """RP2040/RP2350 Framework Management.
2
+
3
+ This module handles downloading, extracting, and managing the Arduino-Pico framework
4
+ needed for Raspberry Pi Pico (RP2040) and Pico 2 (RP2350) builds.
5
+
6
+ Framework Download Process:
7
+ 1. Download arduino-pico from GitHub (earlephilhower/arduino-pico)
8
+ 2. Extract to cache directory
9
+ 3. Provide access to cores, variants, and libraries
10
+
11
+ Framework Structure (after extraction):
12
+ cores/
13
+ └── rp2040/ # Arduino core for RP2040/RP2350
14
+ ├── Arduino.h
15
+ ├── main.cpp
16
+ ├── wiring.c
17
+ ├── api/
18
+ └── ...
19
+ variants/
20
+ ├── rpipico/ # Raspberry Pi Pico
21
+ ├── rpipicow/ # Raspberry Pi Pico W
22
+ ├── rpipico2/ # Raspberry Pi Pico 2
23
+ └── ...
24
+
25
+ Key Features:
26
+ - Full Arduino API compatibility
27
+ - Dual-core RP2040 (Cortex-M0+) support
28
+ - Dual-core RP2350 (Cortex-M33) support
29
+ - USB device support
30
+ - WiFi support (Pico W models)
31
+ """
32
+
33
+ from pathlib import Path
34
+ from typing import Any, Dict, List, Optional
35
+
36
+ from .cache import Cache
37
+ from .downloader import DownloadError, ExtractionError, PackageDownloader
38
+ from .package import IFramework, PackageError
39
+
40
+
41
+ class FrameworkErrorRP2040(PackageError):
42
+ """Raised when RP2040/RP2350 framework operations fail."""
43
+
44
+ pass
45
+
46
+
47
+ class FrameworkRP2040(IFramework):
48
+ """Manages RP2040/RP2350 framework download, extraction, and access.
49
+
50
+ This class handles the arduino-pico framework which includes:
51
+ - Arduino core for RP2040/RP2350 (cores/rp2040/)
52
+ - Board variants (variants/)
53
+ - Built-in libraries
54
+ """
55
+
56
+ # arduino-pico repository URL
57
+ FRAMEWORK_REPO_URL = "https://github.com/earlephilhower/arduino-pico"
58
+ FRAMEWORK_ARCHIVE_URL = "https://github.com/earlephilhower/arduino-pico/archive/refs/heads/master.zip"
59
+
60
+ def __init__(
61
+ self,
62
+ cache: Cache,
63
+ show_progress: bool = True,
64
+ ):
65
+ """Initialize RP2040/RP2350 framework manager.
66
+
67
+ Args:
68
+ cache: Cache manager instance
69
+ show_progress: Whether to show download/extraction progress
70
+ """
71
+ self.cache = cache
72
+ self.show_progress = show_progress
73
+ self.downloader = PackageDownloader()
74
+
75
+ # Use master branch as version
76
+ self.version = "master"
77
+ self.framework_url = self.FRAMEWORK_ARCHIVE_URL
78
+
79
+ # Get framework path from cache
80
+ self.framework_path = cache.get_platform_path(self.framework_url, self.version)
81
+
82
+ def ensure_framework(self) -> Path:
83
+ """Ensure framework is downloaded and extracted.
84
+
85
+ Returns:
86
+ Path to the extracted framework directory
87
+
88
+ Raises:
89
+ FrameworkErrorRP2040: If download or extraction fails
90
+ """
91
+ if self.is_installed():
92
+ if self.show_progress:
93
+ print(f"Using cached arduino-pico {self.version}")
94
+ return self.framework_path
95
+
96
+ try:
97
+ if self.show_progress:
98
+ print(f"Downloading arduino-pico {self.version}...")
99
+
100
+ # Download and extract framework package
101
+ self.cache.ensure_directories()
102
+
103
+ # Use downloader to handle download and extraction
104
+ archive_name = "arduino-pico-master.zip"
105
+ archive_path = self.framework_path.parent / archive_name
106
+
107
+ # Download if not cached
108
+ if not archive_path.exists():
109
+ archive_path.parent.mkdir(parents=True, exist_ok=True)
110
+ self.downloader.download(self.framework_url, archive_path, show_progress=self.show_progress)
111
+ else:
112
+ if self.show_progress:
113
+ print("Using cached arduino-pico archive")
114
+
115
+ # Extract to framework directory
116
+ if self.show_progress:
117
+ print("Extracting arduino-pico...")
118
+
119
+ # Create temp extraction directory
120
+ temp_extract = self.framework_path.parent / "temp_extract"
121
+ temp_extract.mkdir(parents=True, exist_ok=True)
122
+
123
+ self.downloader.extract_archive(archive_path, temp_extract, show_progress=self.show_progress)
124
+
125
+ # Find the arduino-pico directory in the extracted content
126
+ # Usually it's a subdirectory like "arduino-pico-master/"
127
+ extracted_dirs = list(temp_extract.glob("arduino-pico-*"))
128
+ if not extracted_dirs:
129
+ # Maybe it extracted directly
130
+ extracted_dirs = [temp_extract]
131
+
132
+ source_dir = extracted_dirs[0]
133
+
134
+ # Move to final location
135
+ if self.framework_path.exists():
136
+ import shutil
137
+
138
+ shutil.rmtree(self.framework_path)
139
+
140
+ source_dir.rename(self.framework_path)
141
+
142
+ # Clean up temp directory
143
+ if temp_extract.exists() and temp_extract != self.framework_path:
144
+ import shutil
145
+
146
+ shutil.rmtree(temp_extract, ignore_errors=True)
147
+
148
+ if self.show_progress:
149
+ print(f"arduino-pico installed to {self.framework_path}")
150
+
151
+ return self.framework_path
152
+
153
+ except (DownloadError, ExtractionError) as e:
154
+ raise FrameworkErrorRP2040(f"Failed to install arduino-pico: {e}")
155
+ except KeyboardInterrupt as ke:
156
+ from fbuild.interrupt_utils import handle_keyboard_interrupt_properly
157
+
158
+ handle_keyboard_interrupt_properly(ke)
159
+ raise # Never reached, but satisfies type checker
160
+ except Exception as e:
161
+ raise FrameworkErrorRP2040(f"Unexpected error installing framework: {e}")
162
+
163
+ def is_installed(self) -> bool:
164
+ """Check if framework is already installed.
165
+
166
+ Returns:
167
+ True if framework directory exists with key files
168
+ """
169
+ if not self.framework_path.exists():
170
+ return False
171
+
172
+ # Verify rp2040 core directory exists
173
+ rp2040_path = self.framework_path / "cores" / "rp2040"
174
+ if not rp2040_path.exists():
175
+ return False
176
+
177
+ # Verify essential files exist
178
+ required_files = [
179
+ rp2040_path / "Arduino.h",
180
+ rp2040_path / "main.cpp",
181
+ ]
182
+
183
+ return all(f.exists() for f in required_files)
184
+
185
+ def get_core_dir(self, core_name: str = "rp2040") -> Path:
186
+ """Get path to specific core directory.
187
+
188
+ Args:
189
+ core_name: Core name (default: "rp2040")
190
+
191
+ Returns:
192
+ Path to the core directory
193
+
194
+ Raises:
195
+ FrameworkErrorRP2040: If core directory doesn't exist
196
+ """
197
+ core_path = self.framework_path / "cores" / core_name
198
+ if not core_path.exists():
199
+ raise FrameworkErrorRP2040(f"Core '{core_name}' not found at {core_path}")
200
+ return core_path
201
+
202
+ def get_core_sources(self, core_name: str = "rp2040") -> List[Path]:
203
+ """Get all source files in a core.
204
+
205
+ Args:
206
+ core_name: Core name (default: "rp2040")
207
+
208
+ Returns:
209
+ List of .c and .cpp source file paths
210
+ """
211
+ core_dir = self.get_core_dir(core_name)
212
+ sources: List[Path] = []
213
+
214
+ # Get all .c and .cpp files in the core directory (recursively)
215
+ sources.extend(core_dir.rglob("*.c"))
216
+ sources.extend(core_dir.rglob("*.cpp"))
217
+
218
+ # Remove duplicates and sort
219
+ return sorted(set(sources))
220
+
221
+ def get_core_includes(self, core_name: str = "rp2040") -> List[Path]:
222
+ """Get include directories for a core.
223
+
224
+ Args:
225
+ core_name: Core name (default: "rp2040")
226
+
227
+ Returns:
228
+ List of include directory paths
229
+ """
230
+ core_dir = self.get_core_dir(core_name)
231
+ includes = [core_dir]
232
+
233
+ # Add api directory if it exists
234
+ api_dir = core_dir / "api"
235
+ if api_dir.exists():
236
+ includes.append(api_dir)
237
+
238
+ return includes
239
+
240
+ def get_variant_dir(self, variant: str = "rpipico") -> Optional[Path]:
241
+ """Get variant directory for a specific board.
242
+
243
+ Args:
244
+ variant: Variant identifier (default: "rpipico")
245
+
246
+ Returns:
247
+ Path to variant directory or None if not found
248
+ """
249
+ variants_dir = self.framework_path / "variants"
250
+ variant_path = variants_dir / variant
251
+
252
+ return variant_path if variant_path.exists() else None
253
+
254
+ def list_cores(self) -> List[str]:
255
+ """List all available cores.
256
+
257
+ Returns:
258
+ List of core names
259
+ """
260
+ cores_dir = self.framework_path / "cores"
261
+ if not cores_dir.exists():
262
+ return []
263
+
264
+ return [d.name for d in cores_dir.iterdir() if d.is_dir()]
265
+
266
+ def get_framework_info(self) -> Dict[str, Any]:
267
+ """Get information about the installed framework.
268
+
269
+ Returns:
270
+ Dictionary with framework information
271
+ """
272
+ info = {
273
+ "version": self.version,
274
+ "path": str(self.framework_path),
275
+ "url": self.framework_url,
276
+ "installed": self.is_installed(),
277
+ }
278
+
279
+ if self.is_installed():
280
+ info["available_cores"] = self.list_cores()
281
+ rp2040_dir = self.framework_path / "cores" / "rp2040"
282
+ if rp2040_dir.exists():
283
+ info["rp2040_path"] = str(rp2040_dir)
284
+ info["rp2040_sources"] = len(self.get_core_sources("rp2040"))
285
+
286
+ return info
287
+
288
+ # Implement IFramework interface methods
289
+ def get_cores_dir(self) -> Path:
290
+ """Get path to cores directory.
291
+
292
+ Returns:
293
+ Path to cores directory containing Arduino core implementation
294
+
295
+ Raises:
296
+ FrameworkErrorRP2040: If cores directory doesn't exist
297
+ """
298
+ cores_dir = self.framework_path / "cores"
299
+ if not cores_dir.exists():
300
+ raise FrameworkErrorRP2040(f"Cores directory not found at {cores_dir}")
301
+ return cores_dir
302
+
303
+ def get_variants_dir(self) -> Path:
304
+ """Get path to variants directory.
305
+
306
+ Returns:
307
+ Path to variants directory
308
+
309
+ Raises:
310
+ FrameworkErrorRP2040: If variants directory doesn't exist
311
+ """
312
+ variants_dir = self.framework_path / "variants"
313
+ if not variants_dir.exists():
314
+ raise FrameworkErrorRP2040(f"Variants directory not found at {variants_dir}")
315
+ return variants_dir
316
+
317
+ def get_libraries_dir(self) -> Path:
318
+ """Get path to built-in libraries directory.
319
+
320
+ Returns:
321
+ Path to libraries directory
322
+
323
+ Raises:
324
+ FrameworkErrorRP2040: If libraries directory doesn't exist
325
+ """
326
+ libraries_dir = self.framework_path / "libraries"
327
+ if not libraries_dir.exists():
328
+ raise FrameworkErrorRP2040(f"Libraries directory not found at {libraries_dir}")
329
+ return libraries_dir
330
+
331
+ # Implement IPackage interface
332
+ def ensure_package(self) -> Path:
333
+ """Ensure package is downloaded and extracted.
334
+
335
+ Returns:
336
+ Path to the extracted package directory
337
+
338
+ Raises:
339
+ PackageError: If download or extraction fails
340
+ """
341
+ return self.ensure_framework()
342
+
343
+ def get_package_info(self) -> Dict[str, Any]:
344
+ """Get information about the package.
345
+
346
+ Returns:
347
+ Dictionary with package metadata (version, path, etc.)
348
+ """
349
+ return self.get_framework_info()