rocket-engine 0.0.2b1__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.
- rocket_engine/__init__.py +8 -0
- rocket_engine/__main__.py +12 -0
- rocket_engine/adapters/README.md +54 -0
- rocket_engine/adapters/__init__.py +7 -0
- rocket_engine/adapters/api.py +39 -0
- rocket_engine/adapters/base.py +46 -0
- rocket_engine/adapters/cace/__init__.py +163 -0
- rocket_engine/adapters/circulax/README.md +10 -0
- rocket_engine/adapters/circulax/__init__.py +112 -0
- rocket_engine/adapters/circulax/_driver.py +190 -0
- rocket_engine/adapters/circulax/adapter.py +538 -0
- rocket_engine/adapters/circulax/results.py +291 -0
- rocket_engine/adapters/cli/README.md +34 -0
- rocket_engine/adapters/cli/__init__.py +305 -0
- rocket_engine/adapters/connectivity/__init__.py +196 -0
- rocket_engine/adapters/connectivity/results.py +214 -0
- rocket_engine/adapters/cosim/README.md +9 -0
- rocket_engine/adapters/cosim/__init__.py +1390 -0
- rocket_engine/adapters/cosim/results.py +214 -0
- rocket_engine/adapters/devsim/__init__.py +171 -0
- rocket_engine/adapters/digital_flow/README.md +9 -0
- rocket_engine/adapters/digital_flow/__init__.py +1121 -0
- rocket_engine/adapters/digital_flow/results.py +227 -0
- rocket_engine/adapters/digital_flow/state.py +462 -0
- rocket_engine/adapters/drc/README.klayout.md +7 -0
- rocket_engine/adapters/drc/README.md +7 -0
- rocket_engine/adapters/drc/__init__.py +1 -0
- rocket_engine/adapters/drc/klayout.py +952 -0
- rocket_engine/adapters/drc/magic.py +287 -0
- rocket_engine/adapters/drc/results.py +184 -0
- rocket_engine/adapters/drc/results_kl.py +188 -0
- rocket_engine/adapters/elmer/__init__.py +163 -0
- rocket_engine/adapters/envelope.py +120 -0
- rocket_engine/adapters/equivalence/__init__.py +156 -0
- rocket_engine/adapters/errors.py +181 -0
- rocket_engine/adapters/extract_magic/README.md +15 -0
- rocket_engine/adapters/extract_magic/__init__.py +425 -0
- rocket_engine/adapters/extract_magic/results.py +209 -0
- rocket_engine/adapters/formal_sby/README.md +7 -0
- rocket_engine/adapters/formal_sby/__init__.py +773 -0
- rocket_engine/adapters/formal_sby/formal_edge.py +195 -0
- rocket_engine/adapters/formal_sby/results.py +185 -0
- rocket_engine/adapters/gdsfactory/__init__.py +194 -0
- rocket_engine/adapters/gdsfactory/_driver.py +459 -0
- rocket_engine/adapters/gdsfactory/adapter.py +609 -0
- rocket_engine/adapters/gdsfactory/results.py +181 -0
- rocket_engine/adapters/hdl_sim/README.md +7 -0
- rocket_engine/adapters/hdl_sim/__init__.py +369 -0
- rocket_engine/adapters/hdl_sim/ghdl.py +155 -0
- rocket_engine/adapters/hdl_sim/results.py +178 -0
- rocket_engine/adapters/hdl_sim/verilator.py +167 -0
- rocket_engine/adapters/http/README.md +15 -0
- rocket_engine/adapters/http/__init__.py +458 -0
- rocket_engine/adapters/http/events.py +63 -0
- rocket_engine/adapters/ipc/README.md +9 -0
- rocket_engine/adapters/ipc/__init__.py +111 -0
- rocket_engine/adapters/lvs_netgen/README.md +20 -0
- rocket_engine/adapters/lvs_netgen/__init__.py +889 -0
- rocket_engine/adapters/lvs_netgen/results.py +168 -0
- rocket_engine/adapters/mcp/README.md +19 -0
- rocket_engine/adapters/mcp/__init__.py +85 -0
- rocket_engine/adapters/mcp/api-schema.json +6107 -0
- rocket_engine/adapters/mcp/pull.py +246 -0
- rocket_engine/adapters/mcp/server.py +794 -0
- rocket_engine/adapters/meep/__init__.py +167 -0
- rocket_engine/adapters/meow/README.md +7 -0
- rocket_engine/adapters/meow/__init__.py +190 -0
- rocket_engine/adapters/meow/_driver.py +227 -0
- rocket_engine/adapters/meow/_envelope.py +108 -0
- rocket_engine/adapters/meow/adapter.py +491 -0
- rocket_engine/adapters/meow/results.py +218 -0
- rocket_engine/adapters/mutation/__init__.py +192 -0
- rocket_engine/adapters/ngspice/README.md +28 -0
- rocket_engine/adapters/ngspice/__init__.py +627 -0
- rocket_engine/adapters/ngspice/results.py +215 -0
- rocket_engine/adapters/postlayout/README.md +28 -0
- rocket_engine/adapters/postlayout/__init__.py +17 -0
- rocket_engine/adapters/postlayout/adapter.py +1062 -0
- rocket_engine/adapters/postlayout/results.py +330 -0
- rocket_engine/adapters/postlayout/translate.py +71 -0
- rocket_engine/adapters/profile.py +220 -0
- rocket_engine/adapters/sax/README.md +23 -0
- rocket_engine/adapters/sax/__init__.py +516 -0
- rocket_engine/adapters/sax/_driver.py +148 -0
- rocket_engine/adapters/sax/results.py +291 -0
- rocket_engine/adapters/stdio_console.py +1151 -0
- rocket_engine/adapters/syntax/README.md +5 -0
- rocket_engine/adapters/syntax/__init__.py +366 -0
- rocket_engine/adapters/syntax/results.py +181 -0
- rocket_engine/adapters/synth_yosys/README.md +7 -0
- rocket_engine/adapters/synth_yosys/__init__.py +655 -0
- rocket_engine/adapters/synth_yosys/amaranth.py +120 -0
- rocket_engine/adapters/synth_yosys/ghdl.py +128 -0
- rocket_engine/adapters/synth_yosys/results.py +173 -0
- rocket_engine/adapters/timing_sta/README.md +9 -0
- rocket_engine/adapters/timing_sta/__init__.py +726 -0
- rocket_engine/adapters/view_sync/__init__.py +185 -0
- rocket_engine/adapters/view_sync/results.py +189 -0
- rocket_engine/adapters/vlsir/__init__.py +142 -0
- rocket_engine/adapters/xschem/__init__.py +440 -0
- rocket_engine/adapters/xschem/deck.py +266 -0
- rocket_engine/clients/__init__.py +5 -0
- rocket_engine/clients/runtime.py +255 -0
- rocket_engine/composition.py +2279 -0
- rocket_engine/execution/README.md +30 -0
- rocket_engine/execution/__init__.py +150 -0
- rocket_engine/execution/apig/__init__.py +1 -0
- rocket_engine/execution/apig/pool.py +463 -0
- rocket_engine/execution/apig/submit.py +124 -0
- rocket_engine/execution/block_runs_scope.py +479 -0
- rocket_engine/execution/coalesce.py +414 -0
- rocket_engine/execution/console/__init__.py +1 -0
- rocket_engine/execution/console/apply_session.py +318 -0
- rocket_engine/execution/console/lifecycle.py +265 -0
- rocket_engine/execution/dispatch.py +205 -0
- rocket_engine/execution/errors.py +31 -0
- rocket_engine/execution/ports.py +797 -0
- rocket_engine/execution/pyexec/__init__.py +1 -0
- rocket_engine/execution/pyexec/apply_context.py +547 -0
- rocket_engine/execution/pyexec/approvals.py +173 -0
- rocket_engine/execution/pyexec/runner.py +404 -0
- rocket_engine/execution/pyexec/support.py +464 -0
- rocket_engine/execution/python_exec.py +897 -0
- rocket_engine/execution/queue.py +85 -0
- rocket_engine/execution/replay_safe.py +601 -0
- rocket_engine/execution/routing/__init__.py +1 -0
- rocket_engine/execution/routing/calls.py +364 -0
- rocket_engine/execution/routing/namespace.py +785 -0
- rocket_engine/execution/routing/ports.py +102 -0
- rocket_engine/execution/routing/tools.py +346 -0
- rocket_engine/execution/runner.py +311 -0
- rocket_engine/execution/runtime.py +1149 -0
- rocket_engine/execution/service.py +279 -0
- rocket_engine/execution/worker.py +464 -0
- rocket_engine/interfaces/README.md +26 -0
- rocket_engine/interfaces/__init__.py +58 -0
- rocket_engine/interfaces/apig_assets.py +407 -0
- rocket_engine/interfaces/celllink.py +461 -0
- rocket_engine/interfaces/documents.py +92 -0
- rocket_engine/interfaces/envelopes.py +131 -0
- rocket_engine/interfaces/errors.py +16 -0
- rocket_engine/interfaces/layout.py +410 -0
- rocket_engine/interfaces/layout_schema.yaml +278 -0
- rocket_engine/interfaces/paths.py +223 -0
- rocket_engine/interfaces/pdks.py +550 -0
- rocket_engine/interfaces/ports.py +72 -0
- rocket_engine/interfaces/references.py +115 -0
- rocket_engine/interfaces/refs.py +85 -0
- rocket_engine/interfaces/runparams.py +304 -0
- rocket_engine/interfaces/setup.py +552 -0
- rocket_engine/interfaces/setup_catalogue.yaml +243 -0
- rocket_engine/interfaces/setup_probes.py +66 -0
- rocket_engine/interfaces/vocabulary.py +58 -0
- rocket_engine/interfaces/yaml_dump.py +31 -0
- rocket_engine/library/README.md +22 -0
- rocket_engine/library/__init__.py +13 -0
- rocket_engine/library/apig_catalog.py +371 -0
- rocket_engine/library/catalog.py +185 -0
- rocket_engine/library/errors.py +16 -0
- rocket_engine/mutate/__init__.py +776 -0
- rocket_engine/mutate/operators.py +700 -0
- rocket_engine/ops/__init__.py +1 -0
- rocket_engine/ops/deferred.py +279 -0
- rocket_engine/ops/editors.py +404 -0
- rocket_engine/ops/evidence.py +194 -0
- rocket_engine/ops/gates.py +262 -0
- rocket_engine/ops/ports.py +76 -0
- rocket_engine/ops/queries.py +417 -0
- rocket_engine/ops/runs.py +553 -0
- rocket_engine/ops/submit.py +614 -0
- rocket_engine/project/README.md +27 -0
- rocket_engine/project/__init__.py +6 -0
- rocket_engine/project/canvas/__init__.py +55 -0
- rocket_engine/project/canvas/compile.py +109 -0
- rocket_engine/project/canvas/integrate.py +48 -0
- rocket_engine/project/canvas/schema.py +241 -0
- rocket_engine/project/canvas/templates.py +46 -0
- rocket_engine/project/canvas/validate.py +603 -0
- rocket_engine/project/edit/__init__.py +5 -0
- rocket_engine/project/edit/cas.py +87 -0
- rocket_engine/project/edit/transactions.py +282 -0
- rocket_engine/project/errors.py +16 -0
- rocket_engine/project/frontend13.py +685 -0
- rocket_engine/project/geometry/__init__.py +23 -0
- rocket_engine/project/geometry/ops.py +451 -0
- rocket_engine/project/geometry/snap.py +103 -0
- rocket_engine/project/ip/__init__.py +1 -0
- rocket_engine/project/ip/blocks.py +195 -0
- rocket_engine/project/ip/entry.schema.json +78 -0
- rocket_engine/project/ip/lifecycle.py +402 -0
- rocket_engine/project/ip/verbs.py +123 -0
- rocket_engine/project/layers/__init__.py +6 -0
- rocket_engine/project/layers/bindings.py +115 -0
- rocket_engine/project/layers/catalog.py +228 -0
- rocket_engine/project/layers/presets.py +43 -0
- rocket_engine/project/ledger/__init__.py +1 -0
- rocket_engine/project/ledger/docs.py +167 -0
- rocket_engine/project/ledger/entities.py +176 -0
- rocket_engine/project/ledger/events.py +29 -0
- rocket_engine/project/ledger/runs.py +257 -0
- rocket_engine/project/ledger/shared.py +174 -0
- rocket_engine/project/ledger/snapshots.py +385 -0
- rocket_engine/project/ledger/wires.py +552 -0
- rocket_engine/project/process/__init__.py +14 -0
- rocket_engine/project/process/model.py +193 -0
- rocket_engine/project/process/recipes.py +121 -0
- rocket_engine/project/schematic/__init__.py +1 -0
- rocket_engine/project/schematic/hierarchy.py +312 -0
- rocket_engine/project/schematic/instances.py +393 -0
- rocket_engine/project/schematic/sheets.py +198 -0
- rocket_engine/project/service.py +2941 -0
- rocket_engine/project/symbols/__init__.py +1 -0
- rocket_engine/project/symbols/cells.py +324 -0
- rocket_engine/project/symbols/linkage.py +356 -0
- rocket_engine/project/symbols/symbols.py +352 -0
- rocket_engine/project/templates/__init__.py +303 -0
- rocket_engine/project/templates/errors.py +25 -0
- rocket_engine/project/testbench/__init__.py +49 -0
- rocket_engine/project/testbench/blocks.py +619 -0
- rocket_engine/project/testbench/templates.py +134 -0
- rocket_engine/stores/README.md +12 -0
- rocket_engine/stores/__init__.py +6 -0
- rocket_engine/stores/ecs.py +1508 -0
- rocket_engine/stores/layers.py +1023 -0
- rocket_engine/stores/settings.py +1188 -0
- rocket_engine/stores/wireplace.py +1324 -0
- rocket_engine/workflows/README.md +18 -0
- rocket_engine/workflows/__init__.py +53 -0
- rocket_engine/workflows/capability_plan.py +102 -0
- rocket_engine/workflows/completion.py +228 -0
- rocket_engine/workflows/connectgraph.py +734 -0
- rocket_engine/workflows/connectgraph_emit.py +336 -0
- rocket_engine/workflows/gates.py +144 -0
- rocket_engine/workflows/photonic_wire.py +76 -0
- rocket_engine/workflows/stages.py +324 -0
- rocket_engine/workflows/viewsync.py +399 -0
- rocket_engine-0.0.2b1.dist-info/METADATA +200 -0
- rocket_engine-0.0.2b1.dist-info/RECORD +241 -0
- rocket_engine-0.0.2b1.dist-info/WHEEL +4 -0
- rocket_engine-0.0.2b1.dist-info/entry_points.txt +2 -0
- rocket_engine-0.0.2b1.dist-info/licenses/LICENSE +21 -0
|
@@ -0,0 +1,417 @@
|
|
|
1
|
+
"""Engine ops mixin: Wired query handlers (events, apig, jobs, layers, logs)."""
|
|
2
|
+
|
|
3
|
+
from ..execution.apig.pool import stored_completion_from_events
|
|
4
|
+
from ..execution.errors import ExecutionError
|
|
5
|
+
from ..execution.python_exec import PythonExecService
|
|
6
|
+
from ..project.errors import ProjectError
|
|
7
|
+
from ..project.service import ProjectService
|
|
8
|
+
|
|
9
|
+
#: Severity order for ledger-backed findings pages, mirroring the
|
|
10
|
+
#: execution record's errors-first paging.
|
|
11
|
+
_SEVERITY_RANK = {"error": 0, "warning": 1}
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def completion_event_for(events, run_id):
|
|
15
|
+
"""Latest run event naming one run, or None.
|
|
16
|
+
|
|
17
|
+
Args:
|
|
18
|
+
events: Ledger events in seq order.
|
|
19
|
+
run_id: Run to find.
|
|
20
|
+
|
|
21
|
+
Returns:
|
|
22
|
+
The latest run_completed/run_failed event data for the
|
|
23
|
+
run, or None when the run never finished.
|
|
24
|
+
"""
|
|
25
|
+
found = None
|
|
26
|
+
for event in events or ():
|
|
27
|
+
if event.get("event") not in ("run_completed", "run_failed"):
|
|
28
|
+
continue
|
|
29
|
+
if (event.get("data") or {}).get("run_id") == run_id:
|
|
30
|
+
found = event.get("data") or {}
|
|
31
|
+
return found
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def findings_page_for(data, limit=50, cursor=None):
|
|
35
|
+
"""Page ledger-stored findings like the execution record does.
|
|
36
|
+
|
|
37
|
+
Args:
|
|
38
|
+
data: Completion event data with findings,
|
|
39
|
+
findings_truncated, and a verdict carrying the full
|
|
40
|
+
finding_counts.
|
|
41
|
+
limit: Maximum findings in this page.
|
|
42
|
+
cursor: Opaque position from a previous page, if any.
|
|
43
|
+
|
|
44
|
+
Returns:
|
|
45
|
+
Finding page with total counts, findings, next cursor,
|
|
46
|
+
and truncation flag.
|
|
47
|
+
"""
|
|
48
|
+
stored = list(data.get("findings") or [])
|
|
49
|
+
ordered = sorted(
|
|
50
|
+
stored,
|
|
51
|
+
key=lambda f: _SEVERITY_RANK.get(f.get("severity"), 2),
|
|
52
|
+
)
|
|
53
|
+
counts = dict((data.get("verdict") or {}).get("finding_counts") or {})
|
|
54
|
+
if not counts:
|
|
55
|
+
for finding in ordered:
|
|
56
|
+
severity = finding.get("severity", "unknown")
|
|
57
|
+
counts[severity] = counts.get(severity, 0) + 1
|
|
58
|
+
start = int(cursor) if cursor else 0
|
|
59
|
+
page = ordered[start : start + limit]
|
|
60
|
+
remaining = len(ordered) - (start + len(page))
|
|
61
|
+
return {
|
|
62
|
+
"total_counts": counts,
|
|
63
|
+
"findings": page,
|
|
64
|
+
"next_cursor": str(start + len(page)) if remaining > 0 else None,
|
|
65
|
+
"truncated": bool(data.get("findings_truncated")) or remaining > 0,
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
class _QueryMixin:
|
|
70
|
+
"""Wired query handlers (events, apig, jobs, layers, logs)."""
|
|
71
|
+
|
|
72
|
+
def _describe_op(self, name):
|
|
73
|
+
"""Resolve one cataloged name to its live serving handler.
|
|
74
|
+
|
|
75
|
+
The live twin of the MCP server's describe_tool over engine
|
|
76
|
+
objects, so api_search/api_info/api_help report the same
|
|
77
|
+
summaries the generated docs and MCP descriptions serve.
|
|
78
|
+
|
|
79
|
+
Args:
|
|
80
|
+
name: Cataloged operation or query name.
|
|
81
|
+
|
|
82
|
+
Returns:
|
|
83
|
+
(kind, wired, summary, handlers) with the handler
|
|
84
|
+
refs in generated-spec form.
|
|
85
|
+
"""
|
|
86
|
+
from ..composition import (
|
|
87
|
+
ENGINE_OP_METHODS,
|
|
88
|
+
QUERY_ENGINE_METHODS,
|
|
89
|
+
QUERY_METHODS,
|
|
90
|
+
_CRUD_OPERATIONS,
|
|
91
|
+
)
|
|
92
|
+
from ..interfaces.vocabulary import OPERATIONS
|
|
93
|
+
|
|
94
|
+
solvers = self._solvers.get(name) or {}
|
|
95
|
+
if solvers:
|
|
96
|
+
adapter = next(iter(solvers.values()))
|
|
97
|
+
cls = type(adapter)
|
|
98
|
+
doc = cls.__doc__ or ""
|
|
99
|
+
summary = doc.splitlines()[0].strip() if doc.splitlines() else ""
|
|
100
|
+
return (
|
|
101
|
+
"operation", True, summary,
|
|
102
|
+
[f"{cls.__module__}.{cls.__qualname__}"],
|
|
103
|
+
)
|
|
104
|
+
if name == "run_job":
|
|
105
|
+
from ..composition import Engine as _Engine
|
|
106
|
+
|
|
107
|
+
return (
|
|
108
|
+
"operation", True,
|
|
109
|
+
(_Engine._run_queued.__doc__ or "").splitlines()[0].strip(),
|
|
110
|
+
[
|
|
111
|
+
"rocket_engine.composition.Engine.run",
|
|
112
|
+
"rocket_engine.composition.Engine._run_queued",
|
|
113
|
+
],
|
|
114
|
+
)
|
|
115
|
+
if name == "python_execute":
|
|
116
|
+
return (
|
|
117
|
+
"operation", True,
|
|
118
|
+
(PythonExecService.request_execution.__doc__ or ""
|
|
119
|
+
).splitlines()[0].strip(),
|
|
120
|
+
[
|
|
121
|
+
"rocket_engine.composition.Engine.submit",
|
|
122
|
+
"rocket_engine.execution.python_exec."
|
|
123
|
+
"PythonExecService.request_execution",
|
|
124
|
+
],
|
|
125
|
+
)
|
|
126
|
+
if name in _CRUD_OPERATIONS and hasattr(ProjectService, name):
|
|
127
|
+
target = getattr(ProjectService, name)
|
|
128
|
+
doc = target.__doc__ or ""
|
|
129
|
+
summary = doc.splitlines()[0].strip() if doc.splitlines() else ""
|
|
130
|
+
return (
|
|
131
|
+
"operation", True, summary,
|
|
132
|
+
[f"rocket_engine.project.service.ProjectService.{name}"],
|
|
133
|
+
)
|
|
134
|
+
method = QUERY_METHODS.get(name)
|
|
135
|
+
if method is not None:
|
|
136
|
+
target = getattr(ProjectService, method)
|
|
137
|
+
doc = target.__doc__ or ""
|
|
138
|
+
summary = doc.splitlines()[0].strip() if doc.splitlines() else ""
|
|
139
|
+
return (
|
|
140
|
+
"query", True, summary,
|
|
141
|
+
[f"rocket_engine.project.service.ProjectService.{method}"],
|
|
142
|
+
)
|
|
143
|
+
emethod = QUERY_ENGINE_METHODS.get(name)
|
|
144
|
+
if emethod is not None:
|
|
145
|
+
from ..composition import Engine as _Engine
|
|
146
|
+
|
|
147
|
+
target = getattr(_Engine, emethod)
|
|
148
|
+
doc = target.__doc__ or ""
|
|
149
|
+
summary = doc.splitlines()[0].strip() if doc.splitlines() else ""
|
|
150
|
+
return (
|
|
151
|
+
"query", True, summary,
|
|
152
|
+
[f"rocket_engine.composition.Engine.{emethod}"],
|
|
153
|
+
)
|
|
154
|
+
kind = "operation" if name in OPERATIONS else "query"
|
|
155
|
+
return (
|
|
156
|
+
kind, False,
|
|
157
|
+
f"Declared {kind} `{name}`; no handler wired yet.", [],
|
|
158
|
+
)
|
|
159
|
+
|
|
160
|
+
def _query_events_since(self, arguments):
|
|
161
|
+
"""Serve the wired get_events_since query (cursor + resync)."""
|
|
162
|
+
cursor = arguments.get("cursor", 0)
|
|
163
|
+
if not isinstance(cursor, int) or isinstance(cursor, bool):
|
|
164
|
+
raise ProjectError(
|
|
165
|
+
"invalid_command", f"Cursor must be an int, got {cursor!r}."
|
|
166
|
+
)
|
|
167
|
+
demand = arguments.get("require_contiguous_from")
|
|
168
|
+
if (
|
|
169
|
+
demand is not None
|
|
170
|
+
and (not isinstance(demand, int) or isinstance(demand, bool))
|
|
171
|
+
):
|
|
172
|
+
raise ProjectError(
|
|
173
|
+
"invalid_command",
|
|
174
|
+
f"require_contiguous_from must be an int, got {demand!r}.",
|
|
175
|
+
)
|
|
176
|
+
events = self._project.events_since(
|
|
177
|
+
cursor, require_contiguous_from=demand
|
|
178
|
+
)
|
|
179
|
+
return {
|
|
180
|
+
"project_id": self._project_id,
|
|
181
|
+
"events": events,
|
|
182
|
+
"cursor": self._project.snapshot()["event_cursor"],
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
def _query_apig(self, name, arguments):
|
|
186
|
+
"""Route a catalogue/asset query to its Engine reader."""
|
|
187
|
+
if name == "list_cells":
|
|
188
|
+
return self.catalog_cells(pdk=arguments.get("pdk"))
|
|
189
|
+
if name == "serve_asset":
|
|
190
|
+
return self.serve_asset(
|
|
191
|
+
arguments.get("pdk_id"),
|
|
192
|
+
arguments.get("revision"),
|
|
193
|
+
arguments.get("path"),
|
|
194
|
+
engine_root=arguments.get("engine_root"),
|
|
195
|
+
)
|
|
196
|
+
if name == "list_assets":
|
|
197
|
+
return self.list_assets(
|
|
198
|
+
arguments.get("pdk_id"),
|
|
199
|
+
arguments.get("revision"),
|
|
200
|
+
prefix=arguments.get("prefix"),
|
|
201
|
+
engine_root=arguments.get("engine_root"),
|
|
202
|
+
)
|
|
203
|
+
raise ProjectError("unsupported_operation", f"Operation not wired yet: {name}.")
|
|
204
|
+
|
|
205
|
+
def _query_job(self, name, arguments):
|
|
206
|
+
"""Route a job-result query to its Engine reader."""
|
|
207
|
+
if name == "get_job_status":
|
|
208
|
+
return self.job_status(arguments.get("run_id"))
|
|
209
|
+
if name == "get_check_results":
|
|
210
|
+
return self.check_results(arguments.get("operation"))
|
|
211
|
+
if name == "get_logs":
|
|
212
|
+
return self.run_logs(
|
|
213
|
+
arguments.get("run_id"),
|
|
214
|
+
query=arguments.get("query"),
|
|
215
|
+
offset=arguments.get("offset", 0),
|
|
216
|
+
limit=arguments.get("limit", 40),
|
|
217
|
+
)
|
|
218
|
+
if name == "list_job_kinds":
|
|
219
|
+
return self.job_kinds()
|
|
220
|
+
if name == "get_findings":
|
|
221
|
+
return self.findings(
|
|
222
|
+
arguments.get("run_id"),
|
|
223
|
+
limit=arguments.get("limit", 50),
|
|
224
|
+
cursor=arguments.get("cursor"))
|
|
225
|
+
raise ProjectError("unsupported_operation", f"Operation not wired yet: {name}.")
|
|
226
|
+
|
|
227
|
+
def _query_completion(self, name, arguments):
|
|
228
|
+
"""Route a completion query to its Engine reader."""
|
|
229
|
+
if name == "plan_checks":
|
|
230
|
+
return self.plan_checks(arguments.get("flow"))
|
|
231
|
+
if name == "get_design_completion":
|
|
232
|
+
return self.design_completion(arguments.get("flow"))
|
|
233
|
+
raise ProjectError("unsupported_operation", f"Operation not wired yet: {name}.")
|
|
234
|
+
|
|
235
|
+
def _query_layer(self, name, arguments):
|
|
236
|
+
"""Route a layer-serving query to its Engine reader."""
|
|
237
|
+
if name == "get_layer_stackup":
|
|
238
|
+
return self.layer_stackup(
|
|
239
|
+
arguments.get("pdk_id"),
|
|
240
|
+
revision=arguments.get("revision"),
|
|
241
|
+
engine_root=arguments.get("engine_root"),
|
|
242
|
+
)
|
|
243
|
+
if name == "get_layer_rows":
|
|
244
|
+
return self.layer_rows(
|
|
245
|
+
arguments.get("pdk_id"),
|
|
246
|
+
preset=arguments.get("preset"),
|
|
247
|
+
overrides=arguments.get("overrides"),
|
|
248
|
+
active=arguments.get("active"),
|
|
249
|
+
revision=arguments.get("revision"),
|
|
250
|
+
engine_root=arguments.get("engine_root"),
|
|
251
|
+
)
|
|
252
|
+
if name == "list_layer_presets":
|
|
253
|
+
return self.layer_presets()
|
|
254
|
+
if name == "save_layer_preset":
|
|
255
|
+
return self.layer_preset_save(
|
|
256
|
+
arguments.get("pdk_id"),
|
|
257
|
+
arguments.get("name"),
|
|
258
|
+
arguments.get("layers"),
|
|
259
|
+
render_layers=arguments.get("render_layers"),
|
|
260
|
+
flip=arguments.get("flip", False),
|
|
261
|
+
active=arguments.get("active"),
|
|
262
|
+
overwrite=arguments.get("overwrite", False),
|
|
263
|
+
revision=arguments.get("revision"),
|
|
264
|
+
engine_root=arguments.get("engine_root"),
|
|
265
|
+
)
|
|
266
|
+
if name == "delete_layer_preset":
|
|
267
|
+
return self.layer_preset_delete(arguments.get("name"))
|
|
268
|
+
if name == "apply_layer_preset":
|
|
269
|
+
return self.layer_preset_apply(
|
|
270
|
+
arguments.get("pdk_id"),
|
|
271
|
+
arguments.get("name"),
|
|
272
|
+
revision=arguments.get("revision"),
|
|
273
|
+
engine_root=arguments.get("engine_root"),
|
|
274
|
+
)
|
|
275
|
+
raise ProjectError("unsupported_operation", f"Operation not wired yet: {name}.")
|
|
276
|
+
|
|
277
|
+
def _ledger_findings(self, run_id, limit=50, cursor=None):
|
|
278
|
+
"""Findings page from the ledger, after a reboot.
|
|
279
|
+
|
|
280
|
+
In-memory verdicts answer first; across a reboot the
|
|
281
|
+
completion event answers instead. Runs that never
|
|
282
|
+
finished (or never ran) answer unknown_run.
|
|
283
|
+
|
|
284
|
+
Args:
|
|
285
|
+
run_id: Run whose findings to read.
|
|
286
|
+
limit: Maximum findings in this page.
|
|
287
|
+
cursor: Opaque position from a previous page, if any.
|
|
288
|
+
|
|
289
|
+
Returns:
|
|
290
|
+
Finding page for the run.
|
|
291
|
+
|
|
292
|
+
Raises:
|
|
293
|
+
ExecutionError: unknown_run for an id with no
|
|
294
|
+
completion event.
|
|
295
|
+
"""
|
|
296
|
+
data = completion_event_for(self._project.events_since(0), run_id)
|
|
297
|
+
if data is None:
|
|
298
|
+
raise ExecutionError("unknown_run", f"Unknown run: {run_id}.")
|
|
299
|
+
return findings_page_for(data, limit=limit, cursor=cursor)
|
|
300
|
+
|
|
301
|
+
def _ledger_logs_page(self, arguments):
|
|
302
|
+
"""Log page from the ledger excerpt, after a reboot.
|
|
303
|
+
|
|
304
|
+
Serves the stored tail with true trailing line numbers;
|
|
305
|
+
the unrecoverable head reads as an excerpt, flagged so.
|
|
306
|
+
|
|
307
|
+
Args:
|
|
308
|
+
arguments: run_logs arguments with run_id, query,
|
|
309
|
+
offset, and limit.
|
|
310
|
+
|
|
311
|
+
Returns:
|
|
312
|
+
Page mapping with numbered lines, totals, a more
|
|
313
|
+
flag, and excerpt True.
|
|
314
|
+
|
|
315
|
+
Raises:
|
|
316
|
+
ExecutionError: unknown_run for an id with no
|
|
317
|
+
completion event.
|
|
318
|
+
"""
|
|
319
|
+
from ..composition import _LOG_PAGE_MAX # deferred: breaks the ops<->composition cycle
|
|
320
|
+
run_id = arguments.get("run_id")
|
|
321
|
+
data = completion_event_for(self._project.events_since(0), run_id)
|
|
322
|
+
if data is None:
|
|
323
|
+
raise ExecutionError("unknown_run", f"Unknown run: {run_id}.")
|
|
324
|
+
excerpt = (data.get("log_excerpt") or "").splitlines()
|
|
325
|
+
total = data.get("log_lines") or len(excerpt)
|
|
326
|
+
base = total - len(excerpt)
|
|
327
|
+
numbered = [
|
|
328
|
+
(base + index + 1, line) for index, line in enumerate(excerpt)
|
|
329
|
+
]
|
|
330
|
+
query = arguments.get("query")
|
|
331
|
+
if query:
|
|
332
|
+
numbered = [(n, line) for n, line in numbered if query.lower() in line.lower()]
|
|
333
|
+
try:
|
|
334
|
+
offset = max(0, int(arguments.get("offset", 0)))
|
|
335
|
+
except (TypeError, ValueError):
|
|
336
|
+
raise ProjectError(
|
|
337
|
+
"invalid_command",
|
|
338
|
+
f"get_logs offset must be an int, got {arguments.get('offset')!r}.",
|
|
339
|
+
) from None
|
|
340
|
+
try:
|
|
341
|
+
limit = max(1, min(int(arguments.get("limit", 40)), _LOG_PAGE_MAX))
|
|
342
|
+
except (TypeError, ValueError):
|
|
343
|
+
raise ProjectError(
|
|
344
|
+
"invalid_command", f"get_logs limit must be an int, got {arguments.get('limit')!r}."
|
|
345
|
+
) from None
|
|
346
|
+
page = numbered[offset : offset + limit]
|
|
347
|
+
return {
|
|
348
|
+
"run_id": run_id,
|
|
349
|
+
"total_lines": total,
|
|
350
|
+
"matched": len(numbered),
|
|
351
|
+
"offset": offset,
|
|
352
|
+
"lines": [f"{n}: {line}" for n, line in page],
|
|
353
|
+
"more": offset + limit < len(numbered),
|
|
354
|
+
"excerpt": True,
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
def _logs_page(self, arguments):
|
|
358
|
+
from ..composition import _LOG_PAGE_MAX # deferred: breaks the ops<->composition cycle
|
|
359
|
+
run_id = arguments.get("run_id")
|
|
360
|
+
try:
|
|
361
|
+
self._execution.status(run_id) # unknown runs raise unknown_run
|
|
362
|
+
except ExecutionError:
|
|
363
|
+
return self._ledger_logs_page(arguments)
|
|
364
|
+
lines = self._logs.get(run_id, "").splitlines()
|
|
365
|
+
numbered = [(index + 1, line) for index, line in enumerate(lines)]
|
|
366
|
+
query = arguments.get("query")
|
|
367
|
+
if query:
|
|
368
|
+
numbered = [(n, line) for n, line in numbered if query.lower() in line.lower()]
|
|
369
|
+
try:
|
|
370
|
+
offset = max(0, int(arguments.get("offset", 0)))
|
|
371
|
+
except (TypeError, ValueError):
|
|
372
|
+
raise ProjectError(
|
|
373
|
+
"invalid_command",
|
|
374
|
+
f"get_logs offset must be an int, got {arguments.get('offset')!r}.",
|
|
375
|
+
) from None
|
|
376
|
+
try:
|
|
377
|
+
limit = max(1, min(int(arguments.get("limit", 40)), _LOG_PAGE_MAX))
|
|
378
|
+
except (TypeError, ValueError):
|
|
379
|
+
raise ProjectError(
|
|
380
|
+
"invalid_command", f"get_logs limit must be an int, got {arguments.get('limit')!r}."
|
|
381
|
+
) from None
|
|
382
|
+
page = numbered[offset : offset + limit]
|
|
383
|
+
return {
|
|
384
|
+
"run_id": run_id,
|
|
385
|
+
"total_lines": len(lines),
|
|
386
|
+
"matched": len(numbered),
|
|
387
|
+
"offset": offset,
|
|
388
|
+
"lines": [f"{n}: {line}" for n, line in page],
|
|
389
|
+
"more": offset + limit < len(numbered),
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
def _stored_completion(self, run_id):
|
|
393
|
+
"""Stored completion for a finished run, without executing.
|
|
394
|
+
|
|
395
|
+
In-memory verdicts answer first; across a reboot the
|
|
396
|
+
ledger's run event answers instead. Runs that never
|
|
397
|
+
finished (or never ran) answer None.
|
|
398
|
+
"""
|
|
399
|
+
try:
|
|
400
|
+
status = self._execution.status(run_id)
|
|
401
|
+
except ExecutionError:
|
|
402
|
+
status = None
|
|
403
|
+
if (
|
|
404
|
+
status is not None
|
|
405
|
+
and status.get("state") in ("completed", "cancelled")
|
|
406
|
+
and status.get("verdict") is not None
|
|
407
|
+
):
|
|
408
|
+
pending = self._run_jobs.get(run_id, {})
|
|
409
|
+
return {
|
|
410
|
+
"run_id": run_id,
|
|
411
|
+
"state": status["state"],
|
|
412
|
+
"verdict": status["verdict"],
|
|
413
|
+
"operation": pending.get("operation"),
|
|
414
|
+
}
|
|
415
|
+
return stored_completion_from_events(
|
|
416
|
+
self._project.events_since(0), run_id
|
|
417
|
+
)
|