import json import os import sys from pathlib import Path PLACEHOLDERS = { "{{KSU_VERSION}}": lambda: os.environ.get("KSU_VERSION", "unknown"), "{{KSU_GIT_TAG}}": lambda: os.environ.get("KSU_GIT_TAG", "no-tag"), "{{KSUN_BRANCH}}": lambda: os.environ.get("KSUN_BRANCH", "dev"), "{{KSUN_COMMIT}}": lambda: os.environ.get("KSUN_COMMIT", "unknown"), "{{KSU_MANAGER}}": lambda: os.environ.get("KSU_MANAGER", "Placeholder"), "{{KSU_MANAGER_NOTE}}": lambda: os.environ.get("KSU_MANAGER_NOTE", ""), "{{SUSFS_BRANCHES}}": lambda: os.environ.get("SUSFS_COMMIT", "latest on auto-derived gki-{version} branch"), "{{SUSFS_BRANCHS}}": lambda: os.environ.get("SUSFS_COMMIT", "latest on auto-derived gki-{version} branch"), } def build_managers_markdown(text: str) -> str: raw = os.environ.get("MANAGER_LIST", "").strip() if not raw: return text try: managers = json.loads(raw) except Exception: return text if not isinstance(managers, list) or not managers: return text # Build markdown list for all selected managers flavor_labels = {"next": "KernelSU-Next", "kernelsu": "KernelSU", "resukisu": "ReSukiSU"} lines = [] for m in managers: flavor = m.get("flavor", "") label = flavor_labels.get(flavor, flavor or "unknown") run_id = m.get("run_id") owner = m.get("owner", "") repo = m.get("repo", "") stock = m.get("stock", "") if run_id and owner and repo: url = f"https://github.com/{owner}/{repo}/actions/runs/{run_id}" note = f" — stock `{stock[:12]}`" if stock else "" lines.append(f"- **{label}:** [build-manager run]({url}){note}") else: lines.append(f"- **{label}** manager (no run ID)") replacement = "**Managers:**\n" + "\n".join(lines) # Replace the single-manager line in template # Template has: **Manager:** [build-manager run]({{KSU_MANAGER}}) — {{KSU_MANAGER_NOTE}} # Replace that whole line if present import re text = re.sub(r"\*\*Manager:\*\*.*\n", replacement + "\n", text, count=1) return text def filter_sections(text: str) -> str: # Map heading substring -> required env flag # If flag is "false", that section is dropped. flag_map = { "SUSFS": os.environ.get("USE_SUSFS", "true") == "true", "Baseband Guard": os.environ.get("USE_BBG", "true") == "true", "BBG": os.environ.get("USE_BBG", "true") == "true", "DroidSpaces": os.environ.get("USE_DS", "true") == "true", "Networking": os.environ.get("USE_NET", "true") == "true", "NTSync": os.environ.get("USE_NTSYNC", "true") == "true", "Ptrace": os.environ.get("USE_PTRACE", "true") == "true", "Unicode": os.environ.get("USE_UNICODE", "true") == "true", "BPF": os.environ.get("USE_BPF", "true") == "true", } # Split keeping delimiters: first chunk is preamble before first ## parts = text.split("\n## ") if len(parts) <= 1: return text kept = [parts[0]] for part in parts[1:]: heading_line = part.split("\n", 1)[0] keep = True for key, enabled in flag_map.items(): if key.lower() in heading_line.lower() and not enabled: keep = False break # Also drop specific subsections inside Misc/Other Features if relevant # For now only top-level headings filtered; keep is per heading. if keep: kept.append("## " + part) return "\n".join(kept) if len(kept) > 1 else parts[0] + "\n## ".join(kept[1:]) def inject_feature_summary(text: str) -> str: feature_set = os.environ.get("FEATURE_SET", "").strip() root_flavor = os.environ.get("ROOT_FLAVOR", "").strip() if not feature_set and not root_flavor: return text summary_lines = [] if root_flavor: summary_lines.append(f"**Root:** {root_flavor}") if feature_set: summary_lines.append(f"**Features:** {feature_set}") # Insert after the Features anchor list or after disclaimer summary = "> " + " | ".join(summary_lines) + "\n" if summary_lines else "" # Find the Features anchor list end (line with