mirror of
https://github.com/razzant/ouroboros.git
synced 2026-08-06 00:59:46 +00:00
Add stable-by-default managed update channels with explicit QA and development feeds. Keep clean updates deterministic, invoke assisted merging only for real conflicts, and reserve hard reset for explicit recovery. Preserve local work, Colab migration, process custody, and complete binary-aware review evidence without adding path-specific restrictions. Co-authored-by: Ouroboros <311266734+ouroboros-agent@users.noreply.github.com> Co-authored-by: Claudexor <noreply@claudexor.dev>
184 lines
6.4 KiB
Python
184 lines
6.4 KiB
Python
"""Official managed-update source selection and bounded git network calls."""
|
|
|
|
from __future__ import annotations
|
|
|
|
import os
|
|
import re
|
|
import subprocess
|
|
from typing import Callable, List, Optional, Tuple
|
|
|
|
|
|
FETCH_TIMEOUT_RC = 124
|
|
MANAGED_TAG_NAMESPACE = "refs/ouroboros-managed/tags"
|
|
_RELEASE_TAG_RE = re.compile(r"^v(\d+)\.(\d+)\.(\d+)$")
|
|
|
|
|
|
def official_ref_has_constitution(
|
|
ref: str, *, repo_dir: os.PathLike[str] | str | None = None
|
|
) -> bool:
|
|
"""Whether *ref* contains the non-empty regular ``BIBLE.md`` required by P4."""
|
|
if repo_dir is None:
|
|
from supervisor import git_ops as _g
|
|
|
|
repo_dir = _g.REPO_DIR
|
|
try:
|
|
result = subprocess.run(
|
|
["git", "ls-tree", "-l", ref, "--", "BIBLE.md"],
|
|
cwd=str(repo_dir),
|
|
capture_output=True,
|
|
text=True,
|
|
check=False,
|
|
)
|
|
except OSError:
|
|
return False
|
|
fields = (result.stdout or "").strip().split(maxsplit=4)
|
|
return bool(
|
|
result.returncode == 0
|
|
and len(fields) == 5
|
|
and fields[0] in {"100644", "100755"}
|
|
and fields[1] == "blob"
|
|
and fields[3].isdigit()
|
|
and int(fields[3]) > 0
|
|
and fields[4] == "BIBLE.md"
|
|
)
|
|
|
|
|
|
def _git_network_bounded(
|
|
args: List[str], *, timeout: Optional[float] = None
|
|
) -> Tuple[int, str, str]:
|
|
"""Run one non-interactive git network command under the shared ceiling."""
|
|
from ouroboros.platform_layer import kill_process_tree, subprocess_new_group_kwargs
|
|
from ouroboros.tools.shell import _active_subprocesses, _subprocess_lock
|
|
from ouroboros.update_channels import get_managed_update_fetch_timeout_sec
|
|
from supervisor import git_ops as _g
|
|
|
|
limit = float(timeout or get_managed_update_fetch_timeout_sec())
|
|
env = {**os.environ, "LC_ALL": "C", "LANG": "C", "GIT_TERMINAL_PROMPT": "0"}
|
|
try:
|
|
proc = subprocess.Popen(
|
|
["git", "-c", "http.lowSpeedLimit=1024", "-c", "http.lowSpeedTime=30", *args],
|
|
cwd=str(_g.REPO_DIR),
|
|
stdout=subprocess.PIPE,
|
|
stderr=subprocess.PIPE,
|
|
text=True,
|
|
env=env,
|
|
**subprocess_new_group_kwargs(),
|
|
)
|
|
except OSError as exc:
|
|
return 127, "", str(exc)
|
|
with _subprocess_lock:
|
|
_active_subprocesses.add(proc)
|
|
try:
|
|
try:
|
|
out, err = proc.communicate(timeout=limit)
|
|
except subprocess.TimeoutExpired:
|
|
kill_process_tree(proc)
|
|
try:
|
|
proc.communicate(timeout=10)
|
|
except Exception:
|
|
pass
|
|
return FETCH_TIMEOUT_RC, "", (
|
|
f"git {' '.join(args[:2])} exceeded {limit:.0f}s and was terminated"
|
|
)
|
|
return proc.returncode, (out or "").strip(), (err or "").strip()
|
|
finally:
|
|
with _subprocess_lock:
|
|
_active_subprocesses.discard(proc)
|
|
|
|
|
|
def git_fetch_bounded(remote_name: str, *, timeout: Optional[float] = None) -> Tuple[int, str, str]:
|
|
"""Fetch the official remote under one cross-platform wall-clock ceiling."""
|
|
return _git_network_bounded(
|
|
[
|
|
"fetch",
|
|
"--quiet",
|
|
remote_name,
|
|
f"+refs/heads/*:refs/remotes/{remote_name}/*",
|
|
f"+refs/tags/*:{MANAGED_TAG_NAMESPACE}/*",
|
|
],
|
|
timeout=timeout,
|
|
)
|
|
|
|
|
|
def _managed_update_target() -> Tuple[str, str, str]:
|
|
"""Return the runtime-selected official ref, independent from launcher provenance."""
|
|
from supervisor import git_ops as _g
|
|
|
|
managed_meta = _g._read_managed_repo_meta()
|
|
if not managed_meta:
|
|
return "", "", ""
|
|
from ouroboros.update_channels import get_update_branch
|
|
|
|
remote_name = _g._managed_remote_name(managed_meta)
|
|
remote_branch = get_update_branch()
|
|
target_ref = f"{remote_name}/{remote_branch}" if remote_name and remote_branch else ""
|
|
return remote_name, remote_branch, target_ref
|
|
|
|
|
|
def resolve_managed_update_target(
|
|
remote_name: str,
|
|
remote_branch: str,
|
|
branch_ref: str,
|
|
*,
|
|
update_channel: str,
|
|
capture: Callable[[List[str]], Tuple[int, str, str]],
|
|
) -> Tuple[str, str, str]:
|
|
"""Resolve the selected feed to one immutable commit.
|
|
|
|
QA and Development follow their branch tips. Stable follows the newest plain
|
|
``vX.Y.Z`` release whose commit is reachable from both ``main`` and
|
|
``ouroboros-stable``. This keeps an untagged main commit out of the stable
|
|
feed without creating a second channel-specific updater.
|
|
"""
|
|
if not remote_name or not remote_branch or not branch_ref:
|
|
return "", "", "managed update target is unavailable"
|
|
if str(update_channel or "") != "stable":
|
|
rc, sha, error = capture(
|
|
["git", "rev-parse", "--verify", f"{branch_ref}^{{commit}}"]
|
|
)
|
|
return (branch_ref, sha, "") if rc == 0 and sha else ("", "", error or branch_ref)
|
|
|
|
main_ref = f"{remote_name}/main"
|
|
qa_ref = f"{remote_name}/ouroboros-stable"
|
|
for required_ref in (main_ref, qa_ref):
|
|
rc, _sha, error = capture(
|
|
["git", "rev-parse", "--verify", f"{required_ref}^{{commit}}"]
|
|
)
|
|
if rc != 0:
|
|
return "", "", error or f"stable release branch is unavailable: {required_ref}"
|
|
|
|
rc, raw_tags, error = capture(
|
|
[
|
|
"git",
|
|
"for-each-ref",
|
|
"--format=%(refname:strip=3)",
|
|
f"{MANAGED_TAG_NAMESPACE}/v*",
|
|
]
|
|
)
|
|
if rc != 0:
|
|
return "", "", error or "could not list release tags"
|
|
candidates = []
|
|
for tag in raw_tags.splitlines():
|
|
match = _RELEASE_TAG_RE.fullmatch(tag.strip())
|
|
if match:
|
|
candidates.append((tuple(int(part) for part in match.groups()), tag.strip()))
|
|
candidates.sort(reverse=True)
|
|
|
|
for _version, tag in candidates:
|
|
tag_ref = f"{MANAGED_TAG_NAMESPACE}/{tag}"
|
|
rc, sha, _error = capture(
|
|
["git", "rev-parse", "--verify", f"{tag_ref}^{{commit}}"]
|
|
)
|
|
if rc != 0 or not sha:
|
|
continue
|
|
present_in_both = True
|
|
for release_branch_ref in (main_ref, qa_ref):
|
|
ancestor_rc, _out, _ancestor_error = capture(
|
|
["git", "merge-base", "--is-ancestor", sha, release_branch_ref]
|
|
)
|
|
if ancestor_rc != 0:
|
|
present_in_both = False
|
|
break
|
|
if present_in_both:
|
|
return tag_ref, sha, ""
|
|
return "", "", "no shared stable vX.Y.Z release exists on main and ouroboros-stable"
|