Files
felhom-controller/controller/scripts/offbox_rename_gate.py
T

102 lines
4.5 KiB
Python

# -*- coding: utf-8 -*-
"""Offbox-rename gate (v0.123.0) — the Tier-3 feature is branded "Távoli mentés" everywhere
customer-facing: the productized target is the Storage Box and the tier concept is "offsite",
so "NAS-mentés"-style branding must not reappear in the offbox feature's customer strings.
Python, not grep: Hungarian multibyte (the Windows-grep false-negative rule).
Scope: ONLY the offbox feature's files — discovered by pattern since R-425, see scoped_files(). The "Hálózati tárhely" NAS network-storage feature is a
DIFFERENT feature and keeps its device-truthful NAS wording (its files are not scanned). Allowed
by construction (no banned token): the intro's "saját NAS vagy Felhom offsite tárhely" and the
manual-target form's "NAS vagy SFTP-kiszolgáló" mentions, comments, code identifiers/routes.
Run from controller/: python scripts/offbox_rename_gate.py
"""
import glob, io, json, os, re, sys
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
import i18n_bundle # noqa: E402
# R-425 — THE SCOPE IS DISCOVERED, NOT LISTED. The gate used to scan a fixed three-entry FILES list,
# correct when written, and narrower every time the feature grew a file: measured 2026-09-01, a
# `NAS-mentés` in a new `backups_offbox_extra.html` passed. And since localisation the customer copy of
# the listed template lives in the i18n bundle, which no entry named — so the gate had become largely
# hollow, not only narrow. The scope is now, by pattern:
# * every backup-surface template (`templates/**/backups*.html`, `recovery.html`), judged AS IT
# RENDERS in Hungarian (bundle markers expanded), so copy that moved into hu.json is still seen;
# * every off-site Go file (`internal/web/offbox*.go`, `internal/backup/offbox*.go`, not tests);
# * every hu.json value whose KEY one of those Go files names (flash/note/err keys travel by key).
# A new file matching the patterns is scanned the day it is added. Decoys: test_gate_decoys.py.
_HERE = os.path.dirname(os.path.abspath(__file__))
_CTRL = os.path.dirname(_HERE)
TEMPLATE_GLOBS = ["internal/web/templates/**/backups*.html", "internal/web/templates/**/recovery.html"]
GO_GLOBS = ["internal/web/offbox*.go", "internal/backup/offbox*.go"]
TEMPLATE_COMMENT = re.compile(r"\{\{/\*.*?\*/\}\}", re.S)
KEY_LIT = re.compile(r'"([a-z][a-z0-9_]*(?:\.[a-z0-9_\-]+)+)"')
def scoped_files():
out = []
for pats in (TEMPLATE_GLOBS, GO_GLOBS):
for pat in pats:
for f in glob.glob(os.path.join(_CTRL, pat), recursive=True):
if not f.endswith("_test.go"):
out.append(f)
return sorted(set(out))
BANNED = [
"NAS-mentés",
"NAS mentési",
"NAS-visszaállítás",
"a NAS-ra",
"a NAS-ról",
"NAS címe",
"a NAS-on",
"NAS ismert-host",
]
def is_comment(line):
s = line.strip()
return s.startswith("//") or s.startswith("<!--") or s.startswith("/*") or s.startswith("*")
def main():
files = scoped_files()
if not files:
print("OFFBOX RENAME GATE INCONCLUSIVE: no offbox file matched %s" % (TEMPLATE_GLOBS + GO_GLOBS))
sys.exit(2)
hu = json.load(io.open(os.path.join(_CTRL, "internal", "i18n", "locales", "hu.json"), encoding="utf-8"))
sources = [] # (label, text)
named = set()
for path in files:
rel = os.path.relpath(path, _CTRL)
raw = io.open(path, encoding="utf-8").read()
if path.endswith(".html"):
raw = TEMPLATE_COMMENT.sub("", i18n_bundle.expand(raw, "hu"))
else:
named.update(k for k in KEY_LIT.findall(raw) if k in hu)
sources.append((rel, raw))
for key in sorted(named):
if isinstance(hu[key], str):
sources.append(("hu.json[%s]" % key, hu[key]))
total = 0
for label, text in sources:
for lineno, line in enumerate(text.splitlines(), 1):
if is_comment(line):
continue
for tok in BANNED:
if tok in line:
total += 1
print("%s:%d [%s] %s" % (label, lineno, tok,
line.strip()[:100].encode("ascii", "backslashreplace").decode()))
if total:
print("OFFBOX RENAME GATE FAILED: %d customer-facing NAS-branding string(s) remain" % total)
sys.exit(1)
print("offbox rename gate OK — Tier-3 is 'Tavoli mentes' everywhere customer-facing "
"(%d file(s) + %d bundle value(s) named by them)" % (len(files), len(named)))
if __name__ == "__main__":
main()