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,282 @@
|
|
|
1
|
+
"""Atomic typed edit transactions with alias resolution.
|
|
2
|
+
|
|
3
|
+
One transaction is a list of entity changes applied as a group:
|
|
4
|
+
alias-based creation resolves LocalRef-style "$alias" references
|
|
5
|
+
before persistence, every change validates CAS before anything
|
|
6
|
+
lands, and a failed late change rolls back the earlier ones so
|
|
7
|
+
the ledger never keeps a partial batch.
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
try:
|
|
11
|
+
from .cas import read_entity_revision
|
|
12
|
+
except ImportError: # pragma: no cover - standalone spec loading
|
|
13
|
+
import importlib.util as _ilu
|
|
14
|
+
from pathlib import Path as _Path
|
|
15
|
+
|
|
16
|
+
_spec = _ilu.spec_from_file_location(
|
|
17
|
+
"edit_cas_sibling", _Path(__file__).with_name("cas.py"))
|
|
18
|
+
_cas = _ilu.module_from_spec(_spec)
|
|
19
|
+
_spec.loader.exec_module(_cas)
|
|
20
|
+
read_entity_revision = _cas.read_entity_revision
|
|
21
|
+
|
|
22
|
+
_CREATES = ("create",)
|
|
23
|
+
_WRITES = ("set", "attach", "detach", "delete")
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def _live(service, entity):
|
|
27
|
+
"""Read the live entity revision an unnamed write may build on.
|
|
28
|
+
|
|
29
|
+
Args:
|
|
30
|
+
service: ProjectService handle to read through.
|
|
31
|
+
entity: Entity id to inspect.
|
|
32
|
+
|
|
33
|
+
Returns:
|
|
34
|
+
Live entity revision for the gate.
|
|
35
|
+
"""
|
|
36
|
+
return read_entity_revision(service, entity)
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
def _resolve(value, aliases):
|
|
40
|
+
"""Resolve one alias reference to its minted entity id.
|
|
41
|
+
|
|
42
|
+
Args:
|
|
43
|
+
value: Candidate entity id or "$alias" reference.
|
|
44
|
+
aliases: Mapping of alias name to minted entity id.
|
|
45
|
+
|
|
46
|
+
Returns:
|
|
47
|
+
Minted entity id for known aliases, else the value.
|
|
48
|
+
|
|
49
|
+
Raises:
|
|
50
|
+
ValueError: For an alias with no minted entity yet.
|
|
51
|
+
"""
|
|
52
|
+
if isinstance(value, str) and value.startswith("$"):
|
|
53
|
+
name = value[1:]
|
|
54
|
+
if name not in aliases:
|
|
55
|
+
error = ValueError(f"Unknown alias reference: {value}.")
|
|
56
|
+
error.code = "invalid_ref"
|
|
57
|
+
raise error
|
|
58
|
+
return aliases[name]
|
|
59
|
+
return value
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
def _validate_change(change):
|
|
63
|
+
"""Check one change dict carries its required keys.
|
|
64
|
+
|
|
65
|
+
Args:
|
|
66
|
+
change: Change mapping with an op discriminator.
|
|
67
|
+
|
|
68
|
+
Returns:
|
|
69
|
+
The op string of the change.
|
|
70
|
+
|
|
71
|
+
Raises:
|
|
72
|
+
ValueError: invalid_command naming the missing field.
|
|
73
|
+
"""
|
|
74
|
+
op = change.get("op")
|
|
75
|
+
if op in _CREATES:
|
|
76
|
+
return op
|
|
77
|
+
if op not in _WRITES:
|
|
78
|
+
error = ValueError(f"Unknown change op: {op!r}.")
|
|
79
|
+
error.code = "invalid_command"
|
|
80
|
+
raise error
|
|
81
|
+
if "entity" not in change:
|
|
82
|
+
error = ValueError("Change is missing its entity.")
|
|
83
|
+
error.code = "invalid_command"
|
|
84
|
+
raise error
|
|
85
|
+
if op in ("set", "attach") and (
|
|
86
|
+
"component" not in change or "data" not in change
|
|
87
|
+
):
|
|
88
|
+
error = ValueError("Set/attach needs component and data.")
|
|
89
|
+
error.code = "invalid_command"
|
|
90
|
+
raise error
|
|
91
|
+
if op == "detach" and "component" not in change:
|
|
92
|
+
error = ValueError("Detach needs a component.")
|
|
93
|
+
error.code = "invalid_command"
|
|
94
|
+
raise error
|
|
95
|
+
return op
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
def apply_transaction(service, request_id, command_text, changes,
|
|
99
|
+
expected_revision=None):
|
|
100
|
+
"""Apply one batch of entity changes atomically.
|
|
101
|
+
|
|
102
|
+
Args:
|
|
103
|
+
service: ProjectService handle to write through.
|
|
104
|
+
request_id: Client envelope id; sub-envelopes derive
|
|
105
|
+
from it so replays stay idempotent.
|
|
106
|
+
command_text: Command text for identity comparison.
|
|
107
|
+
changes: List of change mappings (create with optional
|
|
108
|
+
alias, set, attach, detach, delete). Set/attach
|
|
109
|
+
may name expected_entity_revision for CAS; create
|
|
110
|
+
steps mint engine ids and register their alias.
|
|
111
|
+
expected_revision: Global head the batch was read at;
|
|
112
|
+
None skips the head gate for pure CAS batches.
|
|
113
|
+
|
|
114
|
+
Returns:
|
|
115
|
+
Receipt with request id, applied count, minted entity
|
|
116
|
+
ids, alias mapping, and revision transition.
|
|
117
|
+
|
|
118
|
+
Raises:
|
|
119
|
+
Exception: The first failing change error after rolling
|
|
120
|
+
back earlier changes (revision_conflict,
|
|
121
|
+
unknown_entity, invalid_ref, or invalid_command).
|
|
122
|
+
|
|
123
|
+
Caution: Rollback writes compensating revisions, so the
|
|
124
|
+
head advances even when the batch fails — history stays
|
|
125
|
+
append-only, never rewritten.
|
|
126
|
+
"""
|
|
127
|
+
for change in changes:
|
|
128
|
+
_validate_change(change)
|
|
129
|
+
revision_from = service.snapshot()["current_revision"]
|
|
130
|
+
if expected_revision is not None:
|
|
131
|
+
head = service.snapshot()["current_revision"]
|
|
132
|
+
if head != expected_revision:
|
|
133
|
+
pure_cas = all(
|
|
134
|
+
change.get("expected_entity_revision") is not None
|
|
135
|
+
for change in changes
|
|
136
|
+
if change.get("op") in _WRITES
|
|
137
|
+
)
|
|
138
|
+
if not (pure_cas and changes):
|
|
139
|
+
error = ValueError(
|
|
140
|
+
f"Stale head {expected_revision}, live {head}."
|
|
141
|
+
)
|
|
142
|
+
error.code = "revision_conflict"
|
|
143
|
+
raise error
|
|
144
|
+
aliases = {}
|
|
145
|
+
minted = []
|
|
146
|
+
undo = []
|
|
147
|
+
applied = 0
|
|
148
|
+
try:
|
|
149
|
+
for index, change in enumerate(changes):
|
|
150
|
+
sub_id = f"{request_id}:txn:{index}"
|
|
151
|
+
sub_text = f"{command_text} [{index}]"
|
|
152
|
+
op = change["op"]
|
|
153
|
+
if op == "create":
|
|
154
|
+
created = service.create_entity(
|
|
155
|
+
sub_id, sub_text,
|
|
156
|
+
kind=change.get("kind", ""),
|
|
157
|
+
components=dict(change.get("components", {})),
|
|
158
|
+
)
|
|
159
|
+
entity = created["entity"]
|
|
160
|
+
minted.append(entity)
|
|
161
|
+
if "alias" in change:
|
|
162
|
+
aliases[change["alias"]] = entity
|
|
163
|
+
undo.append(("delete", entity))
|
|
164
|
+
applied += 1
|
|
165
|
+
continue
|
|
166
|
+
entity = _resolve(change["entity"], aliases)
|
|
167
|
+
named = change.get("expected_entity_revision")
|
|
168
|
+
if named is not None:
|
|
169
|
+
live = read_entity_revision(service, entity)
|
|
170
|
+
if live != named:
|
|
171
|
+
error = ValueError(
|
|
172
|
+
f"Entity {entity} at revision {live}, "
|
|
173
|
+
f"writer expected {named}.",
|
|
174
|
+
)
|
|
175
|
+
error.code = "revision_conflict"
|
|
176
|
+
raise error
|
|
177
|
+
expected = named
|
|
178
|
+
else:
|
|
179
|
+
try:
|
|
180
|
+
expected = _live(service, entity)
|
|
181
|
+
except Exception:
|
|
182
|
+
expected = None
|
|
183
|
+
if op == "set":
|
|
184
|
+
try:
|
|
185
|
+
prior = service.get_component(
|
|
186
|
+
entity, change["component"])["data"]
|
|
187
|
+
except Exception:
|
|
188
|
+
prior = None
|
|
189
|
+
service.set_component(
|
|
190
|
+
entity, change["component"], change["data"],
|
|
191
|
+
sub_id, sub_text,
|
|
192
|
+
expected_revision=None,
|
|
193
|
+
expected_entity_revision=expected,
|
|
194
|
+
)
|
|
195
|
+
undo.append(
|
|
196
|
+
("restore", entity, change["component"], prior))
|
|
197
|
+
elif op == "attach":
|
|
198
|
+
service.attach_component(
|
|
199
|
+
entity, change["component"], change["data"],
|
|
200
|
+
sub_id, sub_text,
|
|
201
|
+
expected_revision=None,
|
|
202
|
+
expected_entity_revision=expected,
|
|
203
|
+
)
|
|
204
|
+
undo.append(
|
|
205
|
+
("detach", entity, change["component"]))
|
|
206
|
+
elif op == "detach":
|
|
207
|
+
prior = service.get_component(
|
|
208
|
+
entity, change["component"])["data"]
|
|
209
|
+
service.detach_component(
|
|
210
|
+
entity, change["component"], sub_id,
|
|
211
|
+
sub_text, expected_revision=None,
|
|
212
|
+
expected_entity_revision=expected,
|
|
213
|
+
)
|
|
214
|
+
undo.append(
|
|
215
|
+
("restore", entity, change["component"], prior))
|
|
216
|
+
elif op == "delete":
|
|
217
|
+
service.delete_entity(
|
|
218
|
+
entity, sub_id, sub_text,
|
|
219
|
+
expected_revision=None,
|
|
220
|
+
expected_entity_revision=expected,
|
|
221
|
+
)
|
|
222
|
+
undo.append(("deleted", entity))
|
|
223
|
+
applied += 1
|
|
224
|
+
except Exception:
|
|
225
|
+
for step in reversed(undo):
|
|
226
|
+
try:
|
|
227
|
+
if step[0] == "delete":
|
|
228
|
+
try:
|
|
229
|
+
gate = _live(service, step[1])
|
|
230
|
+
except Exception:
|
|
231
|
+
gate = None
|
|
232
|
+
service.delete_entity(
|
|
233
|
+
step[1], f"{request_id}:undo:{step[1]}",
|
|
234
|
+
"transaction rollback",
|
|
235
|
+
expected_entity_revision=gate,
|
|
236
|
+
)
|
|
237
|
+
elif step[0] == "detach":
|
|
238
|
+
try:
|
|
239
|
+
gate = _live(service, step[1])
|
|
240
|
+
except Exception:
|
|
241
|
+
gate = None
|
|
242
|
+
service.detach_component(
|
|
243
|
+
step[1], step[2],
|
|
244
|
+
f"{request_id}:undo:{step[1]}:{step[2]}",
|
|
245
|
+
"transaction rollback",
|
|
246
|
+
expected_entity_revision=gate,
|
|
247
|
+
)
|
|
248
|
+
elif step[0] == "restore":
|
|
249
|
+
_, entity, component, prior = step
|
|
250
|
+
try:
|
|
251
|
+
gate = _live(service, entity)
|
|
252
|
+
except Exception:
|
|
253
|
+
gate = None
|
|
254
|
+
if prior is None:
|
|
255
|
+
try:
|
|
256
|
+
service.detach_component(
|
|
257
|
+
entity, component,
|
|
258
|
+
f"{request_id}:undo:{entity}:{component}",
|
|
259
|
+
"transaction rollback",
|
|
260
|
+
expected_entity_revision=gate,
|
|
261
|
+
)
|
|
262
|
+
except Exception:
|
|
263
|
+
pass
|
|
264
|
+
else:
|
|
265
|
+
service.set_component(
|
|
266
|
+
entity, component, prior,
|
|
267
|
+
f"{request_id}:undo:{entity}:{component}",
|
|
268
|
+
"transaction rollback",
|
|
269
|
+
expected_entity_revision=gate,
|
|
270
|
+
)
|
|
271
|
+
except Exception:
|
|
272
|
+
pass
|
|
273
|
+
raise
|
|
274
|
+
revision_to = service.snapshot()["current_revision"]
|
|
275
|
+
return {
|
|
276
|
+
"aliases": dict(aliases),
|
|
277
|
+
"applied": applied,
|
|
278
|
+
"entities": list(minted),
|
|
279
|
+
"request_id": request_id,
|
|
280
|
+
"revision_from": revision_from,
|
|
281
|
+
"revision_to": revision_to,
|
|
282
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
"""Error type for project-service violations. Carries a stable machine code."""
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class ProjectError(Exception):
|
|
5
|
+
"""Project-service violation with a stable machine code.
|
|
6
|
+
|
|
7
|
+
Args:
|
|
8
|
+
code: Stable machine-readable error code.
|
|
9
|
+
message: Human-readable detail.
|
|
10
|
+
fields: Itemized fields, when the error names any.
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
def __init__(self, code, message, fields=None):
|
|
14
|
+
super().__init__(message)
|
|
15
|
+
self.code = code
|
|
16
|
+
self.fields = fields or []
|