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.
Files changed (80) hide show
  1. gitgrip-1.5.0.dist-info/METADATA +13 -0
  2. gitgrip-1.5.0.dist-info/RECORD +80 -0
  3. gitgrip-1.5.0.dist-info/WHEEL +5 -0
  4. gitgrip-1.5.0.dist-info/entry_points.txt +2 -0
  5. gitgrip-1.5.0.dist-info/top_level.txt +2 -0
  6. gr2/__init__.py +0 -0
  7. gr2/overlay/__init__.py +6 -0
  8. gr2/overlay/activate.py +196 -0
  9. gr2/overlay/agent_manifest.py +138 -0
  10. gr2/overlay/cli.py +181 -0
  11. gr2/overlay/cross_repo.py +124 -0
  12. gr2/overlay/drivers.py +113 -0
  13. gr2/overlay/introspection.py +155 -0
  14. gr2/overlay/language_drivers.py +115 -0
  15. gr2/overlay/objects.py +412 -0
  16. gr2/overlay/perf.py +251 -0
  17. gr2/overlay/refs.py +36 -0
  18. gr2/overlay/trust.py +150 -0
  19. gr2/overlay/types.py +69 -0
  20. gr2/overlay/units.py +313 -0
  21. gr2/overlay/workspace_spec.py +59 -0
  22. gr2/prototypes/__init__.py +0 -0
  23. gr2/prototypes/cache_materialization_probe.py +190 -0
  24. gr2/prototypes/concurrent_event_stress.py +199 -0
  25. gr2/prototypes/concurrent_lease_stress.py +240 -0
  26. gr2/prototypes/concurrent_workspace_cap_stress.py +231 -0
  27. gr2/prototypes/contribution_protocol.py +665 -0
  28. gr2/prototypes/cross_mode_lane_stress.py +986 -0
  29. gr2/prototypes/jsonl_store.py +158 -0
  30. gr2/prototypes/lane_workspace_prototype.py +2088 -0
  31. gr2/prototypes/layout_model_probe.py +139 -0
  32. gr2/prototypes/propagation_daemon.py +546 -0
  33. gr2/prototypes/propagation_state_machine.py +1478 -0
  34. gr2/prototypes/python_exec_playground.py +194 -0
  35. gr2/prototypes/python_hook_runtime_playground.py +240 -0
  36. gr2/prototypes/python_migration_playground.py +144 -0
  37. gr2/prototypes/python_review_checkout_playground.py +242 -0
  38. gr2/prototypes/python_spec_apply_playground.py +282 -0
  39. gr2/prototypes/real_git_lane_materialization.py +248 -0
  40. gr2/prototypes/real_git_playground.py +334 -0
  41. gr2/prototypes/recall_lane_history.py +274 -0
  42. gr2/prototypes/repo_maintenance_prototype.py +659 -0
  43. gr2/prototypes/repo_transport_probe.py +147 -0
  44. gr2/python_cli/__init__.py +2 -0
  45. gr2/python_cli/__main__.py +6 -0
  46. gr2/python_cli/add.py +51 -0
  47. gr2/python_cli/app.py +2516 -0
  48. gr2/python_cli/branch.py +67 -0
  49. gr2/python_cli/channel_bridge.py +131 -0
  50. gr2/python_cli/clone_exec.py +1019 -0
  51. gr2/python_cli/commit.py +199 -0
  52. gr2/python_cli/config.py +291 -0
  53. gr2/python_cli/env_exec.py +419 -0
  54. gr2/python_cli/events.py +529 -0
  55. gr2/python_cli/execops.py +372 -0
  56. gr2/python_cli/failures.py +98 -0
  57. gr2/python_cli/file_exec.py +256 -0
  58. gr2/python_cli/gitops.py +226 -0
  59. gr2/python_cli/grip.py +1337 -0
  60. gr2/python_cli/grip_cli.py +493 -0
  61. gr2/python_cli/hooks.py +450 -0
  62. gr2/python_cli/launch_exec.py +786 -0
  63. gr2/python_cli/merge_verification.py +274 -0
  64. gr2/python_cli/migration.py +985 -0
  65. gr2/python_cli/open_gr_review.py +699 -0
  66. gr2/python_cli/platform.py +441 -0
  67. gr2/python_cli/pr.py +487 -0
  68. gr2/python_cli/project_review.py +314 -0
  69. gr2/python_cli/prune.py +365 -0
  70. gr2/python_cli/push.py +172 -0
  71. gr2/python_cli/review.py +462 -0
  72. gr2/python_cli/review_ephemeral.py +143 -0
  73. gr2/python_cli/review_run.py +621 -0
  74. gr2/python_cli/spec_apply.py +1285 -0
  75. gr2/python_cli/staging_cleanup.py +205 -0
  76. gr2/python_cli/syncops.py +920 -0
  77. gr2/python_cli/target.py +100 -0
  78. gr2/python_cli/workspace_snapshot.py +105 -0
  79. gr2/schemas/gr2-materialization-plan-v1.schema.json +191 -0
  80. gr2_overlay/__init__.py +37 -0
@@ -0,0 +1,147 @@
1
+ #!/usr/bin/env python3
2
+ """Probe whether repo remotes are reachable/authenticated before gr2 apply.
3
+
4
+ This is a UX prototype, not a full transport manager. Its job is to answer:
5
+
6
+ - will this remote likely clone successfully from this environment?
7
+ - if not, is the problem transport reachability or authentication?
8
+ - what should the user try next?
9
+ """
10
+
11
+ from __future__ import annotations
12
+
13
+ import argparse
14
+ import json
15
+ import os
16
+ import re
17
+ import subprocess
18
+ import sys
19
+ import tomllib
20
+ from pathlib import Path
21
+
22
+
23
+ SSH_TIMEOUT_SECONDS = 5
24
+
25
+
26
+ def parse_args() -> argparse.Namespace:
27
+ parser = argparse.ArgumentParser(description="Probe repo transport/auth readiness")
28
+ parser.add_argument("workspace_spec", type=Path, help="path to workspace_spec.toml")
29
+ parser.add_argument("--json", action="store_true", help="emit structured JSON")
30
+ return parser.parse_args()
31
+
32
+
33
+ def detect_transport(url: str) -> str:
34
+ if url.startswith("git@") or url.startswith("ssh://"):
35
+ return "ssh"
36
+ if url.startswith("https://") or url.startswith("http://"):
37
+ return "https"
38
+ return "unknown"
39
+
40
+
41
+ def classify_failure(stderr: str, transport: str) -> tuple[str, str]:
42
+ text = stderr.lower()
43
+ if "operation timed out" in text or "connection timed out" in text:
44
+ return ("transport-unreachable", f"{transport} transport timed out")
45
+ if "connection refused" in text:
46
+ return ("transport-unreachable", f"{transport} transport refused connection")
47
+ if "permission denied (publickey)" in text:
48
+ return ("auth-failed", "ssh key was rejected")
49
+ if "could not read username" in text or "authentication failed" in text:
50
+ return ("auth-failed", "https authentication is missing or invalid")
51
+ if "repository not found" in text:
52
+ return ("repo-not-found", "repository not found or not visible to current auth")
53
+ if "could not resolve host" in text:
54
+ return ("dns-failed", "host could not be resolved")
55
+ return ("probe-failed", stderr.strip().splitlines()[-1] if stderr.strip() else "unknown error")
56
+
57
+
58
+ def recommendation(status: str, transport: str) -> str:
59
+ if status == "ok":
60
+ return "selected transport looks usable"
61
+ if status == "transport-unreachable" and transport == "ssh":
62
+ return "try HTTPS or fix SSH network reachability"
63
+ if status == "transport-unreachable":
64
+ return "check network access or remote availability"
65
+ if status == "auth-failed" and transport == "ssh":
66
+ return "load the correct SSH key or switch to HTTPS"
67
+ if status == "auth-failed":
68
+ return "configure GitHub HTTPS auth or switch to SSH"
69
+ if status == "repo-not-found":
70
+ return "verify repo visibility and credentials"
71
+ if status == "dns-failed":
72
+ return "fix host resolution before retrying"
73
+ return "inspect stderr and retry with an explicit transport"
74
+
75
+
76
+ def probe_url(url: str) -> tuple[str, str]:
77
+ transport = detect_transport(url)
78
+ env = None
79
+ if transport == "ssh":
80
+ env = {
81
+ **dict(os.environ),
82
+ "GIT_SSH_COMMAND": (
83
+ f"ssh -o BatchMode=yes -o ConnectTimeout={SSH_TIMEOUT_SECONDS} "
84
+ "-o StrictHostKeyChecking=accept-new"
85
+ ),
86
+ }
87
+
88
+ result = subprocess.run(
89
+ ["git", "ls-remote", "--symref", url, "HEAD"],
90
+ text=True,
91
+ capture_output=True,
92
+ env=env,
93
+ )
94
+ if result.returncode == 0:
95
+ head_ref = ""
96
+ for line in result.stdout.splitlines():
97
+ match = re.match(r"ref: refs/heads/(.+)\s+HEAD", line)
98
+ if match:
99
+ head_ref = match.group(1)
100
+ break
101
+ return ("ok", head_ref or "HEAD reachable")
102
+ status, detail = classify_failure(result.stderr, transport)
103
+ return (status, detail)
104
+
105
+
106
+ def load_spec(path: Path) -> list[dict[str, str]]:
107
+ with path.open("rb") as fh:
108
+ doc = tomllib.load(fh)
109
+ return list(doc.get("repos", []))
110
+
111
+
112
+ def main() -> int:
113
+ args = parse_args()
114
+ repos = load_spec(args.workspace_spec)
115
+ rows: list[dict[str, str]] = []
116
+ exit_code = 0
117
+ for repo in repos:
118
+ url = repo["url"]
119
+ transport = detect_transport(url)
120
+ status, detail = probe_url(url)
121
+ if status != "ok":
122
+ exit_code = 1
123
+ rows.append(
124
+ {
125
+ "repo": repo["name"],
126
+ "url": url,
127
+ "transport": transport,
128
+ "status": status,
129
+ "detail": detail,
130
+ "recommendation": recommendation(status, transport),
131
+ }
132
+ )
133
+
134
+ if args.json:
135
+ print(json.dumps(rows, indent=2))
136
+ else:
137
+ print("REPO\tTRANSPORT\tSTATUS\tDETAIL\tNEXT")
138
+ for row in rows:
139
+ print(
140
+ f'{row["repo"]}\t{row["transport"]}\t{row["status"]}\t'
141
+ f'{row["detail"]}\t{row["recommendation"]}'
142
+ )
143
+ return exit_code
144
+
145
+
146
+ if __name__ == "__main__":
147
+ sys.exit(main())
@@ -0,0 +1,2 @@
1
+ """Python-first gr2 CLI package."""
2
+
@@ -0,0 +1,6 @@
1
+ from .app import app
2
+
3
+
4
+ if __name__ == "__main__":
5
+ app()
6
+
gr2/python_cli/add.py ADDED
@@ -0,0 +1,51 @@
1
+ """Native single-repository staging for the Python gr2 CLI."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from dataclasses import dataclass
6
+ from pathlib import Path
7
+
8
+ from .gitops import git
9
+
10
+
11
+ class AddError(Exception):
12
+ pass
13
+
14
+
15
+ @dataclass(frozen=True)
16
+ class AddResult:
17
+ requested_paths: tuple[str, ...]
18
+ staged_files: tuple[str, ...]
19
+
20
+
21
+ def stage_files(repo: Path, paths: list[str]) -> AddResult:
22
+ """Stage only the requested pathspecs and report their observed index rows.
23
+
24
+ ``git add --all`` is deliberate. A deleted tracked path does not exist on
25
+ disk, so a filesystem existence precheck turns a valid deletion into a
26
+ false "missing" error. Git's index is the authority for pathspec validity.
27
+ """
28
+ if not paths:
29
+ raise AddError("at least one path is required")
30
+
31
+ requested = tuple(paths)
32
+ try:
33
+ staged = git(repo, "add", "--all", "--", *requested)
34
+ except OSError as exc:
35
+ raise AddError(f"failed to launch git add in {repo}: {exc}") from exc
36
+ if staged.returncode != 0:
37
+ detail = (staged.stderr or staged.stdout).strip()
38
+ raise AddError(detail or f"git add failed with exit {staged.returncode}")
39
+
40
+ try:
41
+ observed = git(repo, "diff", "--cached", "--name-only", "-z", "--", *requested)
42
+ except OSError as exc:
43
+ raise AddError(
44
+ f"git add succeeded but staged-path evidence was unavailable: {exc}"
45
+ ) from exc
46
+ if observed.returncode != 0:
47
+ detail = (observed.stderr or observed.stdout).strip()
48
+ raise AddError(detail or "git add succeeded but staged-path evidence was unavailable")
49
+
50
+ staged_files = tuple(sorted(name for name in observed.stdout.split("\0") if name))
51
+ return AddResult(requested_paths=requested, staged_files=staged_files)