fbuild 1.1.0__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.

Potentially problematic release.


This version of fbuild might be problematic. Click here for more details.

Files changed (93) hide show
  1. fbuild/__init__.py +0 -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_state.py +325 -0
  8. fbuild/build/build_utils.py +98 -0
  9. fbuild/build/compilation_executor.py +422 -0
  10. fbuild/build/compiler.py +165 -0
  11. fbuild/build/compiler_avr.py +574 -0
  12. fbuild/build/configurable_compiler.py +612 -0
  13. fbuild/build/configurable_linker.py +637 -0
  14. fbuild/build/flag_builder.py +186 -0
  15. fbuild/build/library_dependency_processor.py +185 -0
  16. fbuild/build/linker.py +708 -0
  17. fbuild/build/orchestrator.py +67 -0
  18. fbuild/build/orchestrator_avr.py +656 -0
  19. fbuild/build/orchestrator_esp32.py +797 -0
  20. fbuild/build/orchestrator_teensy.py +543 -0
  21. fbuild/build/source_compilation_orchestrator.py +220 -0
  22. fbuild/build/source_scanner.py +516 -0
  23. fbuild/cli.py +566 -0
  24. fbuild/cli_utils.py +312 -0
  25. fbuild/config/__init__.py +16 -0
  26. fbuild/config/board_config.py +457 -0
  27. fbuild/config/board_loader.py +92 -0
  28. fbuild/config/ini_parser.py +209 -0
  29. fbuild/config/mcu_specs.py +88 -0
  30. fbuild/daemon/__init__.py +34 -0
  31. fbuild/daemon/client.py +929 -0
  32. fbuild/daemon/compilation_queue.py +293 -0
  33. fbuild/daemon/daemon.py +474 -0
  34. fbuild/daemon/daemon_context.py +196 -0
  35. fbuild/daemon/error_collector.py +263 -0
  36. fbuild/daemon/file_cache.py +332 -0
  37. fbuild/daemon/lock_manager.py +270 -0
  38. fbuild/daemon/logging_utils.py +149 -0
  39. fbuild/daemon/messages.py +301 -0
  40. fbuild/daemon/operation_registry.py +288 -0
  41. fbuild/daemon/process_tracker.py +366 -0
  42. fbuild/daemon/processors/__init__.py +12 -0
  43. fbuild/daemon/processors/build_processor.py +157 -0
  44. fbuild/daemon/processors/deploy_processor.py +327 -0
  45. fbuild/daemon/processors/monitor_processor.py +146 -0
  46. fbuild/daemon/request_processor.py +401 -0
  47. fbuild/daemon/status_manager.py +216 -0
  48. fbuild/daemon/subprocess_manager.py +316 -0
  49. fbuild/deploy/__init__.py +17 -0
  50. fbuild/deploy/deployer.py +67 -0
  51. fbuild/deploy/deployer_esp32.py +314 -0
  52. fbuild/deploy/monitor.py +495 -0
  53. fbuild/interrupt_utils.py +34 -0
  54. fbuild/packages/__init__.py +53 -0
  55. fbuild/packages/archive_utils.py +1098 -0
  56. fbuild/packages/arduino_core.py +412 -0
  57. fbuild/packages/cache.py +249 -0
  58. fbuild/packages/downloader.py +366 -0
  59. fbuild/packages/framework_esp32.py +538 -0
  60. fbuild/packages/framework_teensy.py +346 -0
  61. fbuild/packages/github_utils.py +96 -0
  62. fbuild/packages/header_trampoline_cache.py +394 -0
  63. fbuild/packages/library_compiler.py +203 -0
  64. fbuild/packages/library_manager.py +549 -0
  65. fbuild/packages/library_manager_esp32.py +413 -0
  66. fbuild/packages/package.py +163 -0
  67. fbuild/packages/platform_esp32.py +383 -0
  68. fbuild/packages/platform_teensy.py +312 -0
  69. fbuild/packages/platform_utils.py +131 -0
  70. fbuild/packages/platformio_registry.py +325 -0
  71. fbuild/packages/sdk_utils.py +231 -0
  72. fbuild/packages/toolchain.py +436 -0
  73. fbuild/packages/toolchain_binaries.py +196 -0
  74. fbuild/packages/toolchain_esp32.py +484 -0
  75. fbuild/packages/toolchain_metadata.py +185 -0
  76. fbuild/packages/toolchain_teensy.py +404 -0
  77. fbuild/platform_configs/esp32.json +150 -0
  78. fbuild/platform_configs/esp32c2.json +144 -0
  79. fbuild/platform_configs/esp32c3.json +143 -0
  80. fbuild/platform_configs/esp32c5.json +151 -0
  81. fbuild/platform_configs/esp32c6.json +151 -0
  82. fbuild/platform_configs/esp32p4.json +149 -0
  83. fbuild/platform_configs/esp32s3.json +151 -0
  84. fbuild/platform_configs/imxrt1062.json +56 -0
  85. fbuild-1.1.0.dist-info/METADATA +447 -0
  86. fbuild-1.1.0.dist-info/RECORD +93 -0
  87. fbuild-1.1.0.dist-info/WHEEL +5 -0
  88. fbuild-1.1.0.dist-info/entry_points.txt +5 -0
  89. fbuild-1.1.0.dist-info/licenses/LICENSE +21 -0
  90. fbuild-1.1.0.dist-info/top_level.txt +2 -0
  91. fbuild_lint/__init__.py +0 -0
  92. fbuild_lint/ruff_plugins/__init__.py +0 -0
  93. fbuild_lint/ruff_plugins/keyboard_interrupt_checker.py +158 -0
@@ -0,0 +1,209 @@
1
+ """
2
+ PlatformIO.ini configuration parser.
3
+
4
+ This module provides functionality to parse platformio.ini files and extract
5
+ environment configurations for building embedded projects.
6
+ """
7
+
8
+ import configparser
9
+ from pathlib import Path
10
+ from typing import Dict, List, Optional
11
+
12
+
13
+ class PlatformIOConfigError(Exception):
14
+ """Exception raised for platformio.ini configuration errors."""
15
+
16
+ pass
17
+
18
+
19
+ class PlatformIOConfig:
20
+ """
21
+ Parser for platformio.ini configuration files.
22
+
23
+ This class handles parsing of PlatformIO-style INI files, extracting
24
+ environment configurations, and validating required fields.
25
+
26
+ Example platformio.ini:
27
+ [env:uno]
28
+ platform = atmelavr
29
+ board = uno
30
+ framework = arduino
31
+
32
+ Usage:
33
+ config = PlatformIOConfig(Path("platformio.ini"))
34
+ envs = config.get_environments()
35
+ uno_config = config.get_env_config("uno")
36
+ """
37
+
38
+ REQUIRED_FIELDS = {"platform", "board", "framework"}
39
+
40
+ def __init__(self, ini_path: Path):
41
+ """
42
+ Initialize the parser with a platformio.ini file.
43
+
44
+ Args:
45
+ ini_path: Path to the platformio.ini file
46
+
47
+ Raises:
48
+ PlatformIOConfigError: If the file doesn't exist or cannot be parsed
49
+ """
50
+ self.ini_path = ini_path
51
+
52
+ if not ini_path.exists():
53
+ raise PlatformIOConfigError(f"Configuration file not found: {ini_path}")
54
+
55
+ self.config = configparser.ConfigParser(allow_no_value=True, interpolation=configparser.ExtendedInterpolation())
56
+
57
+ try:
58
+ self.config.read(ini_path, encoding="utf-8")
59
+ except configparser.Error as e:
60
+ raise PlatformIOConfigError(f"Failed to parse {ini_path}: {e}") from e
61
+
62
+ def get_environments(self) -> List[str]:
63
+ """
64
+ Get list of all environment names defined in the config.
65
+
66
+ Returns:
67
+ List of environment names (e.g., ['uno', 'mega', 'nano'])
68
+
69
+ Example:
70
+ For [env:uno], [env:mega], returns ['uno', 'mega']
71
+ """
72
+ envs = []
73
+ for section in self.config.sections():
74
+ if section.startswith("env:"):
75
+ env_name = section.split(":", 1)[1]
76
+ envs.append(env_name)
77
+ return envs
78
+
79
+ def get_env_config(self, env_name: str) -> Dict[str, str]:
80
+ """
81
+ Get configuration for a specific environment.
82
+
83
+ Args:
84
+ env_name: Name of the environment (e.g., 'uno')
85
+
86
+ Returns:
87
+ Dictionary of configuration key-value pairs
88
+
89
+ Raises:
90
+ PlatformIOConfigError: If environment not found or missing required fields
91
+
92
+ Example:
93
+ config.get_env_config('uno')
94
+ # Returns: {'platform': 'atmelavr', 'board': 'uno', 'framework': 'arduino'}
95
+ """
96
+ section = f"env:{env_name}"
97
+
98
+ if section not in self.config:
99
+ available = ", ".join(self.get_environments())
100
+ raise PlatformIOConfigError(f"Environment '{env_name}' not found. " + f"Available environments: {available or 'none'}")
101
+
102
+ # Collect all key-value pairs from the environment section
103
+ env_config = {}
104
+ for key in self.config[section]:
105
+ value = self.config[section][key]
106
+ # Handle multi-line values (like lib_deps)
107
+ env_config[key] = value.strip()
108
+
109
+ # Also check if there's a base [env] section to inherit from
110
+ if "env" in self.config:
111
+ base_config = dict(self.config["env"])
112
+ # Environment-specific values override base values
113
+ env_config = {**base_config, **env_config}
114
+
115
+ # Validate required fields
116
+ missing_fields = self.REQUIRED_FIELDS - set(env_config.keys())
117
+ if missing_fields:
118
+ raise PlatformIOConfigError(f"Environment '{env_name}' is missing required fields: " + f"{', '.join(sorted(missing_fields))}")
119
+
120
+ return env_config
121
+
122
+ def get_build_flags(self, env_name: str) -> List[str]:
123
+ """
124
+ Parse and return build flags for an environment.
125
+
126
+ Args:
127
+ env_name: Name of the environment
128
+
129
+ Returns:
130
+ List of build flags
131
+
132
+ Example:
133
+ For build_flags = -DDEBUG -DVERSION=1.0
134
+ Returns: ['-DDEBUG', '-DVERSION=1.0']
135
+ """
136
+ env_config = self.get_env_config(env_name)
137
+ build_flags_str = env_config.get("build_flags", "")
138
+
139
+ if not build_flags_str:
140
+ return []
141
+
142
+ # Split on whitespace and newlines, filter empty strings
143
+ flags = build_flags_str.split()
144
+ return [flag for flag in flags if flag]
145
+
146
+ def get_lib_deps(self, env_name: str) -> List[str]:
147
+ """
148
+ Parse and return library dependencies for an environment.
149
+
150
+ Args:
151
+ env_name: Name of the environment
152
+
153
+ Returns:
154
+ List of library dependencies
155
+
156
+ Example:
157
+ For lib_deps =
158
+ SPI
159
+ Wire
160
+ Returns: ['SPI', 'Wire']
161
+ """
162
+ env_config = self.get_env_config(env_name)
163
+ lib_deps_str = env_config.get("lib_deps", "")
164
+
165
+ if not lib_deps_str:
166
+ return []
167
+
168
+ # Split on newlines and commas, strip whitespace, filter empty
169
+ deps = []
170
+ for line in lib_deps_str.split("\n"):
171
+ for dep in line.split(","):
172
+ dep = dep.strip()
173
+ if dep:
174
+ deps.append(dep)
175
+ return deps
176
+
177
+ def has_environment(self, env_name: str) -> bool:
178
+ """
179
+ Check if an environment exists in the configuration.
180
+
181
+ Args:
182
+ env_name: Name of the environment to check
183
+
184
+ Returns:
185
+ True if environment exists, False otherwise
186
+ """
187
+ return f"env:{env_name}" in self.config
188
+
189
+ def get_default_environment(self) -> Optional[str]:
190
+ """
191
+ Get the default environment from platformio.ini.
192
+
193
+ Returns:
194
+ Default environment name, or first available environment, or None
195
+
196
+ Example:
197
+ If [platformio] section has default_envs = uno, returns 'uno'
198
+ Otherwise returns the first environment found
199
+ """
200
+ # Check for explicit default_envs in [platformio] section
201
+ if "platformio" in self.config:
202
+ default_envs = self.config["platformio"].get("default_envs", "").strip()
203
+ if default_envs:
204
+ # Can be comma-separated, take the first one
205
+ return default_envs.split(",")[0].strip()
206
+
207
+ # Fall back to first environment
208
+ envs = self.get_environments()
209
+ return envs[0] if envs else None
@@ -0,0 +1,88 @@
1
+ """
2
+ MCU specifications for various embedded platforms.
3
+
4
+ This module centralizes hardware specifications like flash size and RAM
5
+ for different microcontrollers, making it easier to maintain and extend.
6
+ """
7
+
8
+ from dataclasses import dataclass
9
+ from typing import Optional
10
+
11
+
12
+ @dataclass
13
+ class MCUSpec:
14
+ """Hardware specifications for a microcontroller."""
15
+
16
+ mcu_id: str
17
+ max_flash: int # Maximum flash size in bytes
18
+ max_ram: int # Maximum RAM size in bytes
19
+ bootloader_size: int = 0 # Bootloader size in bytes (subtracted from flash)
20
+
21
+ @property
22
+ def usable_flash(self) -> int:
23
+ """Get usable flash after accounting for bootloader."""
24
+ return self.max_flash - self.bootloader_size
25
+
26
+
27
+ # AVR MCU specifications
28
+ AVR_SPECS = {
29
+ "atmega328p": MCUSpec(
30
+ mcu_id="atmega328p",
31
+ max_flash=32768, # 32KB
32
+ max_ram=2048, # 2KB
33
+ bootloader_size=512, # 512B bootloader
34
+ ),
35
+ "atmega2560": MCUSpec(
36
+ mcu_id="atmega2560",
37
+ max_flash=262144, # 256KB
38
+ max_ram=8192, # 8KB
39
+ bootloader_size=8192, # 8KB bootloader
40
+ ),
41
+ "atmega32u4": MCUSpec(
42
+ mcu_id="atmega32u4",
43
+ max_flash=32768, # 32KB
44
+ max_ram=2560, # 2.5KB
45
+ bootloader_size=4096, # 4KB bootloader
46
+ ),
47
+ }
48
+
49
+
50
+ def get_mcu_spec(mcu_id: str) -> Optional[MCUSpec]:
51
+ """
52
+ Get MCU specifications by ID.
53
+
54
+ Args:
55
+ mcu_id: MCU identifier (e.g., 'atmega328p')
56
+
57
+ Returns:
58
+ MCUSpec if found, None otherwise
59
+ """
60
+ return AVR_SPECS.get(mcu_id.lower())
61
+
62
+
63
+ def get_max_flash(mcu_id: str) -> Optional[int]:
64
+ """
65
+ Get maximum usable flash for an MCU (after bootloader).
66
+
67
+ Args:
68
+ mcu_id: MCU identifier
69
+
70
+ Returns:
71
+ Usable flash size in bytes, or None if MCU not found
72
+ """
73
+ spec = get_mcu_spec(mcu_id)
74
+ return spec.usable_flash if spec else None
75
+
76
+
77
+ def get_max_ram(mcu_id: str) -> Optional[int]:
78
+ """
79
+ Get maximum RAM for an MCU.
80
+
81
+ Args:
82
+ mcu_id: MCU identifier
83
+
84
+ Returns:
85
+ RAM size in bytes, or None if MCU not found
86
+ """
87
+ spec = get_mcu_spec(mcu_id)
88
+ return spec.max_ram if spec else None
@@ -0,0 +1,34 @@
1
+ """
2
+ fbuild Daemon - Concurrent Deploy and Monitor Management
3
+
4
+ This package provides a singleton daemon for managing concurrent deploy and monitor
5
+ operations with proper locking and process tree tracking.
6
+ """
7
+
8
+ from fbuild.daemon.client import (
9
+ ensure_daemon_running,
10
+ get_daemon_status,
11
+ request_deploy,
12
+ request_monitor,
13
+ stop_daemon,
14
+ )
15
+ from fbuild.daemon.messages import (
16
+ DaemonState,
17
+ DaemonStatus,
18
+ DeployRequest,
19
+ MonitorRequest,
20
+ OperationType,
21
+ )
22
+
23
+ __all__ = [
24
+ "DaemonState",
25
+ "DaemonStatus",
26
+ "DeployRequest",
27
+ "MonitorRequest",
28
+ "OperationType",
29
+ "ensure_daemon_running",
30
+ "get_daemon_status",
31
+ "request_deploy",
32
+ "request_monitor",
33
+ "stop_daemon",
34
+ ]