gitgrip 1.5.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.
- gitgrip-1.5.0.dist-info/METADATA +13 -0
- gitgrip-1.5.0.dist-info/RECORD +80 -0
- gitgrip-1.5.0.dist-info/WHEEL +5 -0
- gitgrip-1.5.0.dist-info/entry_points.txt +2 -0
- gitgrip-1.5.0.dist-info/top_level.txt +2 -0
- gr2/__init__.py +0 -0
- gr2/overlay/__init__.py +6 -0
- gr2/overlay/activate.py +196 -0
- gr2/overlay/agent_manifest.py +138 -0
- gr2/overlay/cli.py +181 -0
- gr2/overlay/cross_repo.py +124 -0
- gr2/overlay/drivers.py +113 -0
- gr2/overlay/introspection.py +155 -0
- gr2/overlay/language_drivers.py +115 -0
- gr2/overlay/objects.py +412 -0
- gr2/overlay/perf.py +251 -0
- gr2/overlay/refs.py +36 -0
- gr2/overlay/trust.py +150 -0
- gr2/overlay/types.py +69 -0
- gr2/overlay/units.py +313 -0
- gr2/overlay/workspace_spec.py +59 -0
- gr2/prototypes/__init__.py +0 -0
- gr2/prototypes/cache_materialization_probe.py +190 -0
- gr2/prototypes/concurrent_event_stress.py +199 -0
- gr2/prototypes/concurrent_lease_stress.py +240 -0
- gr2/prototypes/concurrent_workspace_cap_stress.py +231 -0
- gr2/prototypes/contribution_protocol.py +665 -0
- gr2/prototypes/cross_mode_lane_stress.py +986 -0
- gr2/prototypes/jsonl_store.py +158 -0
- gr2/prototypes/lane_workspace_prototype.py +2088 -0
- gr2/prototypes/layout_model_probe.py +139 -0
- gr2/prototypes/propagation_daemon.py +546 -0
- gr2/prototypes/propagation_state_machine.py +1478 -0
- gr2/prototypes/python_exec_playground.py +194 -0
- gr2/prototypes/python_hook_runtime_playground.py +240 -0
- gr2/prototypes/python_migration_playground.py +144 -0
- gr2/prototypes/python_review_checkout_playground.py +242 -0
- gr2/prototypes/python_spec_apply_playground.py +282 -0
- gr2/prototypes/real_git_lane_materialization.py +248 -0
- gr2/prototypes/real_git_playground.py +334 -0
- gr2/prototypes/recall_lane_history.py +274 -0
- gr2/prototypes/repo_maintenance_prototype.py +659 -0
- gr2/prototypes/repo_transport_probe.py +147 -0
- gr2/python_cli/__init__.py +2 -0
- gr2/python_cli/__main__.py +6 -0
- gr2/python_cli/add.py +51 -0
- gr2/python_cli/app.py +2516 -0
- gr2/python_cli/branch.py +67 -0
- gr2/python_cli/channel_bridge.py +131 -0
- gr2/python_cli/clone_exec.py +1019 -0
- gr2/python_cli/commit.py +199 -0
- gr2/python_cli/config.py +291 -0
- gr2/python_cli/env_exec.py +419 -0
- gr2/python_cli/events.py +529 -0
- gr2/python_cli/execops.py +372 -0
- gr2/python_cli/failures.py +98 -0
- gr2/python_cli/file_exec.py +256 -0
- gr2/python_cli/gitops.py +226 -0
- gr2/python_cli/grip.py +1337 -0
- gr2/python_cli/grip_cli.py +493 -0
- gr2/python_cli/hooks.py +450 -0
- gr2/python_cli/launch_exec.py +786 -0
- gr2/python_cli/merge_verification.py +274 -0
- gr2/python_cli/migration.py +985 -0
- gr2/python_cli/open_gr_review.py +699 -0
- gr2/python_cli/platform.py +441 -0
- gr2/python_cli/pr.py +487 -0
- gr2/python_cli/project_review.py +314 -0
- gr2/python_cli/prune.py +365 -0
- gr2/python_cli/push.py +172 -0
- gr2/python_cli/review.py +462 -0
- gr2/python_cli/review_ephemeral.py +143 -0
- gr2/python_cli/review_run.py +621 -0
- gr2/python_cli/spec_apply.py +1285 -0
- gr2/python_cli/staging_cleanup.py +205 -0
- gr2/python_cli/syncops.py +920 -0
- gr2/python_cli/target.py +100 -0
- gr2/python_cli/workspace_snapshot.py +105 -0
- gr2/schemas/gr2-materialization-plan-v1.schema.json +191 -0
- gr2_overlay/__init__.py +37 -0
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
"""Torn-line-safe JSONL primitives, shared by the lane prototypes.
|
|
2
|
+
|
|
3
|
+
Both lane prototypes carried a BYTE-IDENTICAL ``append_jsonl`` and a reader with
|
|
4
|
+
the same body under two names. They were not two instances of a defect class;
|
|
5
|
+
they were one function, copied. Fixing them separately would have written the
|
|
6
|
+
same fix and the same witnesses twice and left the copies free to diverge again,
|
|
7
|
+
which is how the situation arose. One home, two consumers.
|
|
8
|
+
|
|
9
|
+
The defect, measured on the sibling surface this shape came from:
|
|
10
|
+
|
|
11
|
+
* the writer appended with no terminator repair and no ``fsync``, so a writer
|
|
12
|
+
killed mid-write left a remnant and the NEXT record glued onto it — a record
|
|
13
|
+
that had itself completed became part of one unparseable line and was lost;
|
|
14
|
+
* the reader parsed with a bare ``json.loads`` over ``read_text().splitlines()``,
|
|
15
|
+
so the remnant raised, and the whole-file decode meant one invalid byte
|
|
16
|
+
anywhere destroyed every record in the file rather than its own line.
|
|
17
|
+
|
|
18
|
+
A line passes through four layers — read, decode, parse, shape-check — and the
|
|
19
|
+
last three are each guarded where they happen. Types are VALIDATED rather than
|
|
20
|
+
coerced, because a coercion over untrusted bytes forces the caller to enumerate
|
|
21
|
+
the exceptions it might raise, which is a denylist, and a denylist leaks.
|
|
22
|
+
Unbounded line length is a resource limit on the READ layer and is deliberately
|
|
23
|
+
NOT defended here; it is named rather than left to be discovered.
|
|
24
|
+
"""
|
|
25
|
+
|
|
26
|
+
from __future__ import annotations
|
|
27
|
+
|
|
28
|
+
import json
|
|
29
|
+
import os
|
|
30
|
+
import sys
|
|
31
|
+
from dataclasses import dataclass, field
|
|
32
|
+
from pathlib import Path
|
|
33
|
+
|
|
34
|
+
from gr2.prototypes.propagation_state_machine import MalformedLine
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
@dataclass(frozen=True)
|
|
38
|
+
class JsonlRead:
|
|
39
|
+
"""Rows that could be read, and the lines that could not.
|
|
40
|
+
|
|
41
|
+
The count travels WITH the data. These are module-level functions with no
|
|
42
|
+
object to hang health on, and a module-level accumulator would be hidden
|
|
43
|
+
state and wrong under concurrent readers — so the health of the scan is a
|
|
44
|
+
return value instead. A caller that ignores ``malformed`` still gets correct
|
|
45
|
+
rows; a caller that wants to report health already holds it. Skipping alone
|
|
46
|
+
is silent, and silence is the defect: the remnant sits in the file while the
|
|
47
|
+
caller sees a healthy-looking result.
|
|
48
|
+
"""
|
|
49
|
+
|
|
50
|
+
rows: list[dict]
|
|
51
|
+
malformed: tuple[MalformedLine, ...] = field(default=())
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
def _decode_line(raw: bytes) -> tuple[str | None, str]:
|
|
55
|
+
"""Bytes become text HERE, so the failure that can happen HERE is guarded here."""
|
|
56
|
+
|
|
57
|
+
try:
|
|
58
|
+
return raw.decode("utf-8"), ""
|
|
59
|
+
except UnicodeDecodeError as exc:
|
|
60
|
+
return None, str(exc)
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
def _read_object(line: str) -> tuple[dict | None, str]:
|
|
64
|
+
"""``json.loads`` is the only operation over a decoded line that can raise."""
|
|
65
|
+
|
|
66
|
+
try:
|
|
67
|
+
obj = json.loads(line)
|
|
68
|
+
except (ValueError, RecursionError) as exc:
|
|
69
|
+
return None, str(exc)
|
|
70
|
+
if not isinstance(obj, dict):
|
|
71
|
+
return None, f"line is a {type(obj).__name__}, not an object"
|
|
72
|
+
return obj, ""
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
def append_jsonl(path: Path, payload: dict) -> None:
|
|
76
|
+
"""Append one record, repairing a missing terminator first, then fsync.
|
|
77
|
+
|
|
78
|
+
Without the repair a remnant GLUES the next record onto itself and the next
|
|
79
|
+
record is lost. Without the fsync the record is not durable against the very
|
|
80
|
+
crash that produces remnants.
|
|
81
|
+
"""
|
|
82
|
+
|
|
83
|
+
path.parent.mkdir(parents=True, exist_ok=True)
|
|
84
|
+
unterminated = False
|
|
85
|
+
try:
|
|
86
|
+
with path.open("rb") as probe:
|
|
87
|
+
if probe.seek(0, os.SEEK_END):
|
|
88
|
+
probe.seek(-1, os.SEEK_END)
|
|
89
|
+
unterminated = probe.read(1) != b"\n"
|
|
90
|
+
except FileNotFoundError:
|
|
91
|
+
pass
|
|
92
|
+
with path.open("ab") as handle:
|
|
93
|
+
if unterminated:
|
|
94
|
+
handle.write(b"\n")
|
|
95
|
+
handle.write((json.dumps(payload) + "\n").encode("utf-8"))
|
|
96
|
+
handle.flush()
|
|
97
|
+
os.fsync(handle.fileno())
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
def read_jsonl(path: Path) -> JsonlRead:
|
|
101
|
+
"""Read every line that can be read, and report every line that cannot."""
|
|
102
|
+
|
|
103
|
+
if not path.exists():
|
|
104
|
+
return JsonlRead(rows=[])
|
|
105
|
+
rows: list[dict] = []
|
|
106
|
+
malformed: list[MalformedLine] = []
|
|
107
|
+
for index, raw in enumerate(path.read_bytes().split(b"\n")):
|
|
108
|
+
stripped = raw.strip()
|
|
109
|
+
if not stripped:
|
|
110
|
+
continue
|
|
111
|
+
line, reason = _decode_line(stripped)
|
|
112
|
+
if line is not None:
|
|
113
|
+
obj, reason = _read_object(line)
|
|
114
|
+
if obj is not None:
|
|
115
|
+
rows.append(obj)
|
|
116
|
+
continue
|
|
117
|
+
malformed.append(
|
|
118
|
+
MalformedLine(
|
|
119
|
+
index=index,
|
|
120
|
+
excerpt=stripped[:120].decode("utf-8", "replace"),
|
|
121
|
+
reason=reason,
|
|
122
|
+
)
|
|
123
|
+
)
|
|
124
|
+
return JsonlRead(rows=rows, malformed=tuple(malformed))
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
def warn_unreadable(read: JsonlRead, what: str, stream: object = None) -> bool:
|
|
128
|
+
"""Report unreadable lines on STDERR. Returns whether anything was reported.
|
|
129
|
+
|
|
130
|
+
Lives HERE, beside the primitives it reports on, because the first version of
|
|
131
|
+
this fix put a helper in one consumer and an inline copy of the same three
|
|
132
|
+
lines in the other — which is byte-adjacent duplication of a reporting rule
|
|
133
|
+
across two files, the same shape as the copied ``append_jsonl`` this module
|
|
134
|
+
exists to eliminate. One home for the rule, or the message formats drift.
|
|
135
|
+
|
|
136
|
+
STDERR specifically: a ``--json`` caller's stdout must stay machine-readable.
|
|
137
|
+
And it is reported at ALL because a count nobody surfaces is the same silence
|
|
138
|
+
as no count — the CLI is the layer that already looks.
|
|
139
|
+
"""
|
|
140
|
+
|
|
141
|
+
if not read.malformed:
|
|
142
|
+
return False
|
|
143
|
+
first = read.malformed[0]
|
|
144
|
+
print(
|
|
145
|
+
f"warning: {len(read.malformed)} unreadable line(s) in {what}; "
|
|
146
|
+
f"first at line {first.index}: {first.reason}",
|
|
147
|
+
file=stream if stream is not None else sys.stderr,
|
|
148
|
+
)
|
|
149
|
+
return True
|
|
150
|
+
|
|
151
|
+
|
|
152
|
+
__all__ = [
|
|
153
|
+
"JsonlRead",
|
|
154
|
+
"MalformedLine",
|
|
155
|
+
"append_jsonl",
|
|
156
|
+
"read_jsonl",
|
|
157
|
+
"warn_unreadable",
|
|
158
|
+
]
|