From deb1c2cfd2a5ef4a7705dd86a669457bb02e4fe7 Mon Sep 17 00:00:00 2001 From: delta-cloud-208e Date: Sun, 8 Mar 2026 10:58:16 +0000 Subject: [PATCH] fix(codex): drop Python 3.11 requirement, auto-install python3 - tomllib fallback: try tomllib (3.11+) -> tomli -> minimal parser - Works with Python 3.8+ (Ubuntu 20.04, Debian 11, etc.) - Auto-install python3 if not found (like Gemini/Qwen scripts) Co-Authored-By: Claude Opus 4.6 --- codex/codex_patcher.py | 51 ++++++++++++++++++++++++++++++- codex/ucodex_install.sh | 31 +++++++++++++------ codex/updater/config_validator.py | 37 +++++++++++++++++++++- 3 files changed, 108 insertions(+), 11 deletions(-) diff --git a/codex/codex_patcher.py b/codex/codex_patcher.py index b1b21aa..8a683d4 100755 --- a/codex/codex_patcher.py +++ b/codex/codex_patcher.py @@ -21,7 +21,56 @@ import shutil import platform import subprocess import argparse -import tomllib +try: + import tomllib +except ModuleNotFoundError: + try: + import tomli as tomllib + except ModuleNotFoundError: + # Minimal TOML reader for Python < 3.11 + import re as _re + class _T: + @staticmethod + def load(f): + raw = f.read() + return _T._parse(raw.decode("utf-8") if isinstance(raw, bytes) else raw) + @staticmethod + def loads(s): + return _T._parse(s) + @staticmethod + def _parse(text): + result, cur = {}, None + for line in text.split("\n"): + line = line.strip() + if not line or line.startswith("#"): + continue + m = _re.match(r'^\[([^\]]+)\]$', line) + if m: + keys = [k.strip() for k in m.group(1).split(".")] + cur = result + for k in keys: + cur = cur.setdefault(k, {}) + continue + m = _re.match(r'^([^=]+?)\s*=\s*(.+)$', line) + if m and cur is not None: + k, v = m.group(1).strip(), m.group(2).strip() + if v.startswith('"') and v.endswith('"'): v = v[1:-1] + elif v == "true": v = True + elif v == "false": v = False + elif _re.match(r'^-?\d+$', v): v = int(v) + elif v.startswith("[") and v.endswith("]"): + inner = v[1:-1].strip() + v = [x.strip().strip('"') for x in inner.split(",")] if inner else [] + cur[k] = v + elif m: + k, v = m.group(1).strip(), m.group(2).strip() + if v.startswith('"') and v.endswith('"'): v = v[1:-1] + elif v == "true": v = True + elif v == "false": v = False + elif _re.match(r'^-?\d+$', v): v = int(v) + result[k] = v + return result + tomllib = _T() from pathlib import Path from datetime import datetime diff --git a/codex/ucodex_install.sh b/codex/ucodex_install.sh index ff1cc89..020995d 100755 --- a/codex/ucodex_install.sh +++ b/codex/ucodex_install.sh @@ -37,21 +37,34 @@ echo -e "${NC}" # ---- Check prerequisites ---- -for cmd in python3 curl tar; do +install_pkg() { + if command -v apt-get >/dev/null 2>&1; then + apt-get update -qq && apt-get install -y -qq "$@" + elif command -v dnf >/dev/null 2>&1; then + dnf install -y -q "$@" + elif command -v yum >/dev/null 2>&1; then + yum install -y -q "$@" + elif command -v brew >/dev/null 2>&1; then + brew install "$@" + else + err "No package manager found. Install $* manually." + return 1 + fi +} + +if ! command -v python3 &>/dev/null; then + info "python3 not found, installing..." + install_pkg python3 +fi + +for cmd in curl tar; do if ! command -v "$cmd" &>/dev/null; then err "$cmd is required but not found" exit 1 fi done -PY_VER=$(python3 -c "import sys; print(f'{sys.version_info.major}.{sys.version_info.minor}')") -PY_MAJOR=$(echo "$PY_VER" | cut -d. -f1) -PY_MINOR=$(echo "$PY_VER" | cut -d. -f2) -if [ "$PY_MAJOR" -lt 3 ] || ([ "$PY_MAJOR" -eq 3 ] && [ "$PY_MINOR" -lt 11 ]); then - err "Python 3.11+ required (found $PY_VER)" - exit 1 -fi -log "Python3 $PY_VER" +log "Python3 $(python3 --version | awk '{print $2}')" # ---- Step 1: Install Codex binary from GitHub ---- diff --git a/codex/updater/config_validator.py b/codex/updater/config_validator.py index 4d54e73..5c160ba 100755 --- a/codex/updater/config_validator.py +++ b/codex/updater/config_validator.py @@ -5,7 +5,42 @@ checks config.toml values and environment variables. """ import os -import tomllib +try: + import tomllib +except ModuleNotFoundError: + try: + import tomli as tomllib + except ModuleNotFoundError: + import re as _re + class _T: + @staticmethod + def load(f): + raw = f.read() + return _T._parse(raw.decode("utf-8") if isinstance(raw, bytes) else raw) + @staticmethod + def _parse(text): + result, cur = {}, None + for line in text.split("\n"): + line = line.strip() + if not line or line.startswith("#"): + continue + m = _re.match(r'^\[([^\]]+)\]$', line) + if m: + keys = [k.strip() for k in m.group(1).split(".")] + cur = result + for k in keys: + cur = cur.setdefault(k, {}) + continue + m = _re.match(r'^([^=]+?)\s*=\s*(.+)$', line) + if m: + k, v = m.group(1).strip(), m.group(2).strip() + if v.startswith('"') and v.endswith('"'): v = v[1:-1] + elif v == "true": v = True + elif v == "false": v = False + elif _re.match(r'^-?\d+$', v): v = int(v) + (cur if cur is not None else result)[k] = v + return result + tomllib = _T() from dataclasses import dataclass from typing import Callable, Optional