bakar 0.5.0__tar.gz

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 (57) hide show
  1. bakar-0.5.0/PKG-INFO +52 -0
  2. bakar-0.5.0/README.md +28 -0
  3. bakar-0.5.0/pyproject.toml +172 -0
  4. bakar-0.5.0/src/bakar/__init__.py +3 -0
  5. bakar-0.5.0/src/bakar/__main__.py +6 -0
  6. bakar-0.5.0/src/bakar/bsp_detect.py +189 -0
  7. bakar-0.5.0/src/bakar/bsp_model.py +260 -0
  8. bakar-0.5.0/src/bakar/cli.py +72 -0
  9. bakar-0.5.0/src/bakar/commands/__init__.py +9 -0
  10. bakar-0.5.0/src/bakar/commands/_app.py +63 -0
  11. bakar-0.5.0/src/bakar/commands/_helpers.py +361 -0
  12. bakar-0.5.0/src/bakar/commands/build.py +371 -0
  13. bakar-0.5.0/src/bakar/commands/clean.py +61 -0
  14. bakar-0.5.0/src/bakar/commands/clean_sstate.py +191 -0
  15. bakar-0.5.0/src/bakar/commands/diff.py +63 -0
  16. bakar-0.5.0/src/bakar/commands/doctor.py +137 -0
  17. bakar-0.5.0/src/bakar/commands/dump.py +87 -0
  18. bakar-0.5.0/src/bakar/commands/for_all.py +111 -0
  19. bakar-0.5.0/src/bakar/commands/gen_kas.py +87 -0
  20. bakar-0.5.0/src/bakar/commands/hashserv.py +136 -0
  21. bakar-0.5.0/src/bakar/commands/layers.py +63 -0
  22. bakar-0.5.0/src/bakar/commands/lock.py +98 -0
  23. bakar-0.5.0/src/bakar/commands/log.py +141 -0
  24. bakar-0.5.0/src/bakar/commands/override.py +117 -0
  25. bakar-0.5.0/src/bakar/commands/prefetch.py +79 -0
  26. bakar-0.5.0/src/bakar/commands/report.py +104 -0
  27. bakar-0.5.0/src/bakar/commands/settings.py +74 -0
  28. bakar-0.5.0/src/bakar/commands/shell.py +150 -0
  29. bakar-0.5.0/src/bakar/commands/stress_parse.py +174 -0
  30. bakar-0.5.0/src/bakar/commands/sync.py +142 -0
  31. bakar-0.5.0/src/bakar/commands/triage.py +100 -0
  32. bakar-0.5.0/src/bakar/config.py +357 -0
  33. bakar-0.5.0/src/bakar/diagnostics.py +1307 -0
  34. bakar-0.5.0/src/bakar/fork_race_signatures.py +58 -0
  35. bakar-0.5.0/src/bakar/hashserv.py +264 -0
  36. bakar-0.5.0/src/bakar/kas.py +406 -0
  37. bakar-0.5.0/src/bakar/layers.py +223 -0
  38. bakar-0.5.0/src/bakar/manifest_diff.py +84 -0
  39. bakar-0.5.0/src/bakar/observability.py +151 -0
  40. bakar-0.5.0/src/bakar/overlays/bakar-tuning-generic.yml +129 -0
  41. bakar-0.5.0/src/bakar/overlays/bakar-tuning-hashequiv.yml +27 -0
  42. bakar-0.5.0/src/bakar/overlays/bakar-tuning-nxp.yml +104 -0
  43. bakar-0.5.0/src/bakar/overlays/bakar-tuning-ti.yml +79 -0
  44. bakar-0.5.0/src/bakar/report.py +148 -0
  45. bakar-0.5.0/src/bakar/steps/__init__.py +1 -0
  46. bakar-0.5.0/src/bakar/steps/bitbake_override.py +544 -0
  47. bakar-0.5.0/src/bakar/steps/kas_build.py +944 -0
  48. bakar-0.5.0/src/bakar/steps/repo.py +76 -0
  49. bakar-0.5.0/src/bakar/steps/run_qemu.py +61 -0
  50. bakar-0.5.0/src/bakar/steps/setup_env.py +45 -0
  51. bakar-0.5.0/src/bakar/steps/stress_parse.py +376 -0
  52. bakar-0.5.0/src/bakar/steps/ti_layertool.py +136 -0
  53. bakar-0.5.0/src/bakar/steps/ti_setup_env.py +64 -0
  54. bakar-0.5.0/src/bakar/triage.py +257 -0
  55. bakar-0.5.0/src/bakar/user_config.py +339 -0
  56. bakar-0.5.0/src/bakar/vendor_config.py +63 -0
  57. bakar-0.5.0/src/bakar/workspace.py +327 -0
bakar-0.5.0/PKG-INFO ADDED
@@ -0,0 +1,52 @@
1
+ Metadata-Version: 2.4
2
+ Name: bakar
3
+ Version: 0.5.0
4
+ Summary: kas wrapper for Yocto BSP builds - repo tool sync, pre-flight checks, triage
5
+ Keywords: bitbake,bsp,embedded,imx,kas,nxp,ti-sitara,yocto
6
+ Author: Javier Tia
7
+ License-Expression: Apache-2.0
8
+ Classifier: Development Status :: 3 - Alpha
9
+ Classifier: Intended Audience :: Developers
10
+ Classifier: Programming Language :: Python :: 3
11
+ Classifier: Programming Language :: Python :: 3.14
12
+ Classifier: Programming Language :: Python :: 3.15
13
+ Classifier: Topic :: Software Development :: Build Tools
14
+ Classifier: Topic :: System :: Operating System Kernels :: Linux
15
+ Requires-Dist: pyyaml>=6.0
16
+ Requires-Dist: rich>=13.0.0
17
+ Requires-Dist: tomli-w>=1.0
18
+ Requires-Dist: typer>=0.12.0
19
+ Requires-Python: >=3.14
20
+ Project-URL: Bug Tracker, https://github.com/jetm/bakar/issues
21
+ Project-URL: Homepage, https://github.com/jetm/bakar
22
+ Project-URL: Repository, https://github.com/jetm/bakar
23
+ Description-Content-Type: text/markdown
24
+
25
+ [![CI](https://github.com/jetm/bakar/actions/workflows/ci.yml/badge.svg)](https://github.com/jetm/bakar/actions/workflows/ci.yml)
26
+
27
+ # bakar
28
+
29
+ kas-based BSP build orchestrator for Yocto. Wraps `kas-container` with manifest-driven sync, pre-flight checks, structured telemetry, and post-mortem tooling. Works with NXP i.MX (repo XML), TI Sitara (oe-layertool), bitbake-setup workspaces, and any bring-your-own kas YAML.
30
+
31
+ ## Install
32
+
33
+ ```bash
34
+ uv tool install git+https://github.com/jetm/bakar.git
35
+ ```
36
+
37
+ ## Quickstart
38
+
39
+ ```bash
40
+ # NXP i.MX manifest-driven build
41
+ bakar build -f imx-6.12.49-2.2.0.xml -m imx8mp-var-dart
42
+
43
+ # Bring-your-own kas YAML
44
+ bakar build my-project.yml
45
+
46
+ # Post-mortem a failed build
47
+ bakar triage
48
+ ```
49
+
50
+ ## Documentation
51
+
52
+ Full command reference, workflow guides, and configuration: **[docs/index.md](docs/index.md)**
bakar-0.5.0/README.md ADDED
@@ -0,0 +1,28 @@
1
+ [![CI](https://github.com/jetm/bakar/actions/workflows/ci.yml/badge.svg)](https://github.com/jetm/bakar/actions/workflows/ci.yml)
2
+
3
+ # bakar
4
+
5
+ kas-based BSP build orchestrator for Yocto. Wraps `kas-container` with manifest-driven sync, pre-flight checks, structured telemetry, and post-mortem tooling. Works with NXP i.MX (repo XML), TI Sitara (oe-layertool), bitbake-setup workspaces, and any bring-your-own kas YAML.
6
+
7
+ ## Install
8
+
9
+ ```bash
10
+ uv tool install git+https://github.com/jetm/bakar.git
11
+ ```
12
+
13
+ ## Quickstart
14
+
15
+ ```bash
16
+ # NXP i.MX manifest-driven build
17
+ bakar build -f imx-6.12.49-2.2.0.xml -m imx8mp-var-dart
18
+
19
+ # Bring-your-own kas YAML
20
+ bakar build my-project.yml
21
+
22
+ # Post-mortem a failed build
23
+ bakar triage
24
+ ```
25
+
26
+ ## Documentation
27
+
28
+ Full command reference, workflow guides, and configuration: **[docs/index.md](docs/index.md)**
@@ -0,0 +1,172 @@
1
+ [project]
2
+ name = "bakar"
3
+ version = "0.5.0"
4
+ description = "kas wrapper for Yocto BSP builds - repo tool sync, pre-flight checks, triage"
5
+ readme = "README.md"
6
+ requires-python = ">=3.14"
7
+ license = "Apache-2.0"
8
+ authors = [{ name = "Javier Tia" }]
9
+ keywords = [
10
+ "bitbake",
11
+ "bsp",
12
+ "embedded",
13
+ "imx",
14
+ "kas",
15
+ "nxp",
16
+ "ti-sitara",
17
+ "yocto"
18
+ ]
19
+ classifiers = [
20
+ "Development Status :: 3 - Alpha",
21
+ "Intended Audience :: Developers",
22
+ "Programming Language :: Python :: 3",
23
+ "Programming Language :: Python :: 3.14",
24
+ "Programming Language :: Python :: 3.15",
25
+ "Topic :: Software Development :: Build Tools",
26
+ "Topic :: System :: Operating System Kernels :: Linux",
27
+ ]
28
+ dependencies = [
29
+ "pyyaml>=6.0",
30
+ "rich>=13.0.0",
31
+ "tomli-w>=1.0",
32
+ "typer>=0.12.0",
33
+ ]
34
+
35
+ [project.urls]
36
+ "Bug Tracker" = "https://github.com/jetm/bakar/issues"
37
+ Homepage = "https://github.com/jetm/bakar"
38
+ Repository = "https://github.com/jetm/bakar"
39
+
40
+ [project.scripts]
41
+ bakar = "bakar.cli:main"
42
+
43
+ [dependency-groups]
44
+ dev = [
45
+ "bump-my-version",
46
+ "pre-commit",
47
+ "pytest>=9",
48
+ "pytest-cov>=6",
49
+ "pytest-randomly",
50
+ "pytest-timeout",
51
+ "ruff",
52
+ "ty",
53
+ ]
54
+
55
+ [build-system]
56
+ requires = ["uv_build>=0.6,<0.13"]
57
+ build-backend = "uv_build"
58
+
59
+ [tool.bumpversion]
60
+ current_version = "0.4.0"
61
+ commit = true
62
+ tag = true
63
+ allow_dirty = true
64
+ tag_name = "v{new_version}"
65
+ message = "Bump version: {current_version} → {new_version}"
66
+ pre_commit_hook = "uv sync && git add uv.lock"
67
+ commit_args = "--no-verify"
68
+ parse = "(?P<major>\\d+)\\.(?P<minor>\\d+)\\.(?P<patch>\\d+)"
69
+ serialize = ["{major}.{minor}.{patch}"]
70
+
71
+ [[tool.bumpversion.files]]
72
+ filename = "pyproject.toml"
73
+ search = "version = \"{current_version}\""
74
+ replace = "version = \"{new_version}\""
75
+
76
+ [[tool.bumpversion.files]]
77
+ filename = "src/bakar/__init__.py"
78
+ search = "__version__ = \"{current_version}\""
79
+ replace = "__version__ = \"{new_version}\""
80
+
81
+ [[tool.bumpversion.files]]
82
+ filename = "CHANGELOG.md"
83
+ search = "## [Unreleased]"
84
+ replace = "## [Unreleased]\n\n## [{new_version}] - {now:%Y-%m-%d}"
85
+
86
+ [[tool.bumpversion.files]]
87
+ filename = "CHANGELOG.md"
88
+ search = "[Unreleased]: https://github.com/jetm/bakar/compare/v{current_version}...HEAD"
89
+ replace = "[Unreleased]: https://github.com/jetm/bakar/compare/v{new_version}...HEAD\n[{new_version}]: https://github.com/jetm/bakar/compare/v{current_version}...v{new_version}"
90
+
91
+ [tool.coverage.run]
92
+ branch = true
93
+ source = ["bakar"]
94
+ omit = [
95
+ "tests/*",
96
+ # Steps that exec external Yocto/repo/kas tools directly - integration-test only
97
+ "src/bakar/steps/kas_build.py",
98
+ "src/bakar/steps/repo.py",
99
+ "src/bakar/steps/setup_env.py",
100
+ "src/bakar/steps/ti_layertool.py",
101
+ "src/bakar/steps/ti_setup_env.py",
102
+ ]
103
+
104
+ [tool.coverage.report]
105
+ precision = 2
106
+ fail_under = 63
107
+ show_missing = true
108
+ exclude_lines = [
109
+ "pragma: no cover",
110
+ "if TYPE_CHECKING:",
111
+ "if __name__ == .__main__.",
112
+ "@overload",
113
+ ]
114
+
115
+ [tool.pytest.ini_options]
116
+ addopts = ["-v", "--tb=short", "--cov=bakar", "--cov-report=term-missing"]
117
+ markers = [
118
+ "unit: fast hermetic tests with no external tools or services",
119
+ "integration: tests requiring external tools or services",
120
+ ]
121
+ pythonpath = ["src"]
122
+ testpaths = ["tests"]
123
+ timeout = 30
124
+
125
+ [tool.ruff]
126
+ target-version = "py314"
127
+ line-length = 120
128
+
129
+ [tool.ruff.lint]
130
+ select = [
131
+ "E", # pycodestyle errors
132
+ "F", # Pyflakes
133
+ "I", # isort
134
+ "N", # pep8-naming
135
+ "W", # pycodestyle warnings
136
+ "UP", # pyupgrade
137
+ "B", # flake8-bugbear
138
+ "SIM", # flake8-simplify
139
+ "TC", # flake8-type-checking
140
+ ]
141
+ ignore = [
142
+ "SIM102", # Use single if statement - often reduces readability
143
+ "SIM105", # Use contextlib.suppress - adds import for minimal benefit
144
+ "SIM108", # Use ternary operator - can reduce readability for complex conditions
145
+ "SIM110", # Use any() instead of for loop - sometimes less clear
146
+ ]
147
+
148
+ [tool.ruff.lint.isort]
149
+ known-first-party = ["bakar"]
150
+
151
+ [tool.ruff.lint.per-file-ignores]
152
+ "src/bakar/cli.py" = ["B008"]
153
+ # Typer evaluates annotations at runtime via inspect.signature(eval_str=True);
154
+ # Path and other stdlib types used in command signatures must not be TYPE_CHECKING-guarded.
155
+ "src/bakar/commands/*.py" = ["TC003"]
156
+
157
+ [tool.ty.rules]
158
+ # Noisy without full type annotations - project uses gradual typing
159
+ call-non-callable = "ignore"
160
+ invalid-argument-type = "ignore"
161
+ invalid-assignment = "ignore"
162
+ invalid-return-type = "ignore"
163
+ invalid-type-form = "ignore"
164
+ no-matching-overload = "ignore"
165
+ not-subscriptable = "ignore"
166
+
167
+ [tool.uv]
168
+ package = true
169
+
170
+ [tool.uv.build-backend]
171
+ module-name = "bakar"
172
+ module-root = "src"
@@ -0,0 +1,3 @@
1
+ """bakar: practical kas wrapper for Yocto BSP development."""
2
+
3
+ __version__ = "0.5.0"
@@ -0,0 +1,6 @@
1
+ """Entry point for `python -m bakar`."""
2
+
3
+ from bakar.cli import app
4
+
5
+ if __name__ == "__main__":
6
+ app()
@@ -0,0 +1,189 @@
1
+ """Inspect a kas YAML and classify the BSP family.
2
+
3
+ Used by the BYO (Form A) path of ``bakar build``: when the user hands
4
+ bakar a kas YAML directly, we cannot rely on the manifest filename
5
+ regex in :func:`bakar.bsp_model.detect_bsp_family`. Instead the
6
+ classifier reads ``machine:`` and ``repos:`` from the YAML and applies
7
+ a small first-match-wins rule set:
8
+
9
+ * machine starts with ``imx`` -> ``nxp``
10
+ * machine starts with ``am`` / ``k3-`` / ``j7-`` -> ``ti``
11
+ * repos contains ``meta-imx`` / ``meta-freescale*`` / ``meta-nxp*`` -> ``nxp``
12
+ * repos contains ``meta-ti-bsp`` / ``meta-ti`` / ``meta-arago`` -> ``ti``
13
+ * parseable YAML with at least ``machine:`` or ``repos:`` -> ``generic``
14
+ * unparseable / empty -> ``unknown``
15
+
16
+ The ``generic`` classification is the BSP-agnostic fallback for kas
17
+ YAMLs that look like real builds but do not target an NXP/TI SoM
18
+ (e.g. qemuarm64 + poky + meta-arm). Callers layer the
19
+ ``bakar-tuning-generic.yml`` overlay - which carries only the
20
+ BSP-agnostic optimizations (ccache, MIRRORS, PREMIRRORS, FETCHCMD_wget,
21
+ PYTHONMALLOC) - onto these YAMLs.
22
+
23
+ The function never raises - I/O on the YAML is wrapped defensively so
24
+ ``bakar build my.yml`` can fail with a single typer.Exit(2) instead of
25
+ a Python traceback.
26
+
27
+ See also :func:`bakar.bsp_model.detect_bsp_family`, which classifies
28
+ by manifest *filename* (no I/O, pure regex). The two classifiers serve
29
+ different entry points: this module handles the BYO-yaml path
30
+ (``bakar build my.yml``); ``detect_bsp_family`` handles the manifest
31
+ path (``bakar build -f imx-*.xml``). Both encode NXP/TI family
32
+ markers; if either set of markers changes, update the other.
33
+ """
34
+
35
+ from __future__ import annotations
36
+
37
+ import json
38
+ from typing import TYPE_CHECKING, Any, Literal
39
+
40
+ import yaml
41
+
42
+ if TYPE_CHECKING:
43
+ from pathlib import Path
44
+
45
+ # Repo-name substrings that identify each BSP. Order matters within a
46
+ # family: the first matching substring wins. The lists are kept short
47
+ # and explicit so a future BSP addition does not collide silently.
48
+ _NXP_REPO_NAMES: tuple[str, ...] = (
49
+ "meta-imx",
50
+ "meta-freescale",
51
+ "meta-nxp",
52
+ "meta-variscite-bsp-imx",
53
+ "meta-variscite-sdk-imx",
54
+ )
55
+
56
+ _TI_REPO_NAMES: tuple[str, ...] = (
57
+ "meta-ti-bsp",
58
+ "meta-ti-extras",
59
+ "meta-ti",
60
+ "meta-tisdk",
61
+ "meta-arago",
62
+ "meta-variscite-bsp-ti",
63
+ "meta-variscite-sdk-ti",
64
+ )
65
+
66
+
67
+ def _machine_family(machine: str) -> Literal["nxp", "ti", "unknown"]:
68
+ if not machine:
69
+ return "unknown"
70
+ name = machine.lower()
71
+ if name.startswith("imx"):
72
+ return "nxp"
73
+ if name.startswith(("am", "k3-", "j7-", "j72", "j78", "j784")):
74
+ return "ti"
75
+ return "unknown"
76
+
77
+
78
+ def _repos_family(repos: dict[str, Any] | None) -> Literal["nxp", "ti", "unknown"]:
79
+ if not isinstance(repos, dict):
80
+ return "unknown"
81
+ names = set(repos.keys())
82
+ for hit in _NXP_REPO_NAMES:
83
+ if hit in names:
84
+ return "nxp"
85
+ for hit in _TI_REPO_NAMES:
86
+ if hit in names:
87
+ return "ti"
88
+ return "unknown"
89
+
90
+
91
+ def detect_bsp_from_yaml(yaml_path: Path) -> Literal["nxp", "ti", "generic", "unknown"]:
92
+ """Inspect a kas YAML and classify the BSP family.
93
+
94
+ Pure function over a parsed YAML dict. Returns ``"generic"`` for a
95
+ kas YAML that parses cleanly but lacks NXP/TI markers; callers
96
+ use that to layer the BSP-agnostic tuning overlay. Returns
97
+ ``"unknown"`` only for unparseable, empty, or shape-incomplete
98
+ YAMLs - those exit with a typer.Exit(2) and a hint.
99
+ """
100
+ if yaml_path is None or not yaml_path.is_file():
101
+ return "unknown"
102
+ try:
103
+ with yaml_path.open("r", encoding="utf-8") as fh:
104
+ data = yaml.safe_load(fh)
105
+ except OSError, yaml.YAMLError:
106
+ return "unknown"
107
+ if not isinstance(data, dict):
108
+ return "unknown"
109
+
110
+ machine = data.get("machine", "")
111
+ machine_hit = _machine_family(machine if isinstance(machine, str) else "")
112
+ if machine_hit != "unknown":
113
+ return machine_hit
114
+
115
+ repos_hit = _repos_family(data.get("repos"))
116
+ if repos_hit != "unknown":
117
+ return repos_hit
118
+
119
+ # No NXP/TI markers but the YAML has at least a machine string or a
120
+ # repos block - treat as a generic kas build. Reject only YAMLs
121
+ # that lack both anchors (typo or empty file).
122
+ has_machine = isinstance(machine, str) and bool(machine.strip())
123
+ has_repos = isinstance(data.get("repos"), dict) and bool(data["repos"])
124
+ if has_machine or has_repos:
125
+ return "generic"
126
+ return "unknown"
127
+
128
+
129
+ def is_bbsetup_workspace(path: Path) -> bool:
130
+ """Return True if ``path`` is an initialized ``bitbake-setup`` workspace.
131
+
132
+ A directory qualifies only when all of the following hold:
133
+
134
+ * ``<path>/config/config-upstream.json`` exists and parses as JSON
135
+ with top-level ``data`` and ``bitbake-config`` keys.
136
+ * ``<path>/build/init-build-env`` exists (the Yocto environment
137
+ setup script that ``bitbake-setup init`` writes).
138
+
139
+ Detection is structure-based: bitbake-setup workspaces have no
140
+ manifest filename to match against the regex dispatch used for
141
+ NXP/TI families. The function never raises - a missing file,
142
+ unreadable config, or malformed JSON all return False so callers
143
+ can fall through to the next detection path.
144
+ """
145
+ cfg = path / "config" / "config-upstream.json"
146
+ env = path / "build" / "init-build-env"
147
+ if not (cfg.exists() and env.exists()):
148
+ return False
149
+ try:
150
+ data = json.loads(cfg.read_text(encoding="utf-8"))
151
+ except json.JSONDecodeError, OSError:
152
+ return False
153
+ return isinstance(data, dict) and "data" in data and "bitbake-config" in data
154
+
155
+
156
+ def is_meta_avocado_yaml(yaml_path: Path) -> bool:
157
+ """Return True if the YAML lives inside a meta-avocado repository.
158
+
159
+ Walks the resolved path and checks whether any ancestor directory is
160
+ named ``meta-avocado``. This is how bakar detects that a generic kas
161
+ YAML belongs to the Avocado OS build system and needs the
162
+ ``init-build``-style build-directory setup before kas can run.
163
+ """
164
+ try:
165
+ return "meta-avocado" in yaml_path.resolve().parts
166
+ except Exception:
167
+ return False
168
+
169
+
170
+ def detect_kas_workspace(yaml_path: Path) -> Path:
171
+ """Return the effective workspace root for a generic kas YAML.
172
+
173
+ For meta-avocado YAMLs the YAML sits several levels deep inside the
174
+ ``meta-avocado`` repository (e.g. ``sources/meta-avocado/kas/machine/
175
+ qemux86-64.yml``). kas must run from a build directory that is a
176
+ *sibling* of ``meta-avocado/`` (e.g. ``sources/build-qemux86-64/``),
177
+ not from inside the repo. This function walks up from the YAML to
178
+ find the ``meta-avocado`` boundary and returns its parent
179
+ (e.g. ``sources/``) so :func:`bakar.config.BuildConfig.bsp_root`
180
+ can derive the correct build-directory path.
181
+
182
+ For every other generic kas YAML the workspace is simply the YAML's
183
+ parent directory (preserving the existing behavior).
184
+ """
185
+ resolved = yaml_path.resolve()
186
+ for parent in resolved.parents:
187
+ if parent.name == "meta-avocado":
188
+ return parent.parent
189
+ return resolved.parent