214 lines
10 KiB
Python
214 lines
10 KiB
Python
#!/usr/bin/env python3
|
|
"""3X-UI_KIT (форк hacker07): накатывает наши «швы» на чистый код автора.
|
|
|
|
Это источник правды для форка: единственное место, где описано, ЧТО именно мы правим в
|
|
файлах автора. Всё, что мы дописываем по существу, живёт в scripts/kit-local.sh — файле,
|
|
который автор не трогает, поэтому обновления автора его не ломают.
|
|
|
|
Правила:
|
|
* каждый якорь обязан найтись РОВНО один раз, иначе — стоп (автор изменил код, правку
|
|
надо пересмотреть руками);
|
|
* при любой ошибке ничего не пишется наполовину: сначала прогоняй --check;
|
|
* открытый ключ подписи берётся из tools/fork-signer.pub (закрытая часть — только на
|
|
рабочей станции владельца, в репозиторий не попадает).
|
|
|
|
Использование:
|
|
python3 tools/fork_apply.py --check [корень-репозитория]
|
|
python3 tools/fork_apply.py [корень-репозитория]
|
|
"""
|
|
|
|
import os
|
|
import pathlib
|
|
import re
|
|
import sys
|
|
|
|
GITEA = os.environ.get("FORK_GITEA_BASE", "https://git.rukavishnikoff.ru/hacker07/3X-UI_autoVPS")
|
|
SIGNER_FILE = os.environ.get("FORK_SIGNER_PUB", "tools/fork-signer.pub")
|
|
|
|
HOOK = """
|
|
# --- 3X-UI_KIT (форк hacker07): локальные команды и хуки ---
|
|
# Подключаем scripts/kit-local.sh, если он установлен. Наш файл: правки автора его не касаются.
|
|
# Все команды форка — под «kit local …» (см. kit local help).
|
|
KIT_LOCAL_LIB="${KIT_LOCAL_LIB:-/usr/local/lib/kit/kit-local.sh}"
|
|
if [[ -r $KIT_LOCAL_LIB ]]; then . "$KIT_LOCAL_LIB"; kit_local_dispatch "$@"; fi
|
|
"""
|
|
|
|
|
|
def die(msg):
|
|
print("! " + msg, file=sys.stderr)
|
|
sys.exit(1)
|
|
|
|
|
|
def ok(msg):
|
|
print("==> " + msg)
|
|
|
|
|
|
def count(text, anchor, regex):
|
|
if regex:
|
|
return len(re.findall(anchor, text, re.MULTILINE))
|
|
return text.count(anchor)
|
|
|
|
|
|
def main():
|
|
args = [a for a in sys.argv[1:]]
|
|
check = False
|
|
if "--check" in args:
|
|
check = True
|
|
args.remove("--check")
|
|
root = pathlib.Path(args[0] if args else ".").resolve()
|
|
if not (root / "VERSION").exists():
|
|
die("%s не похож на репозиторий 3X-UI KIT (нет VERSION)" % root)
|
|
os.chdir(root)
|
|
|
|
version = (root / "VERSION").read_text(encoding="utf-8").strip()
|
|
if not re.fullmatch(r"[0-9]+(\.[0-9]+)+", version):
|
|
die("VERSION=%r: нужен числовой номер вида 1.2.1" % version)
|
|
|
|
signer_path = pathlib.Path(SIGNER_FILE)
|
|
if not signer_path.exists():
|
|
die(
|
|
"нет %s — сначала создай ключ подписи:\n"
|
|
" ssh-keygen -t ed25519 -C \"3X-UI KIT fork releases\" -f ~/.ssh/3x-ui-kit-fork/release_key\n"
|
|
" mkdir -p tools && ssh-keygen -y -f ~/.ssh/3x-ui-kit-fork/release_key > tools/fork-signer.pub"
|
|
% SIGNER_FILE
|
|
)
|
|
pub = ""
|
|
for line in signer_path.read_text(encoding="utf-8").splitlines():
|
|
line = line.strip()
|
|
if line.startswith(("ssh-ed25519 ", "ssh-rsa ")):
|
|
pub = line
|
|
break
|
|
if not pub:
|
|
die("%s: не нашёл строку открытого ключа (ssh-ed25519 …)" % signer_path)
|
|
|
|
version_re = r'^KIT_VERSION="[0-9.]+"$'
|
|
edits = [
|
|
# --- scripts/kit.sh -------------------------------------------------
|
|
("scripts/kit.sh", version_re, True, 'KIT_VERSION="%s"' % version, "версия сборки форка"),
|
|
(
|
|
"scripts/kit.sh",
|
|
'KIT_RAW="https://raw.githubusercontent.com/itsnotkubrick/3X-UI_KIT/main"',
|
|
False,
|
|
'KIT_RAW="%s/raw/branch/main"' % GITEA,
|
|
"источник VERSION и подсказки об обновлении",
|
|
),
|
|
(
|
|
"scripts/kit.sh",
|
|
'kit_ref_raw() { echo "https://raw.githubusercontent.com/itsnotkubrick/3X-UI_KIT/v$1"; }',
|
|
False,
|
|
'kit_ref_raw() { echo "%s/raw/tag/v$1"; }' % GITEA + "\n" + HOOK,
|
|
"файлы релиза из нашего тега + подключение kit-local.sh",
|
|
),
|
|
(
|
|
"scripts/kit.sh",
|
|
r' # SHA256:[^\n]*\n "ssh-ed25519 [^\n]*"\n',
|
|
True,
|
|
' # Ключ подписи форка (владелец: hacker07). Закрытая часть — только на рабочей станции.\n'
|
|
' "%s"\n' % pub,
|
|
"ключ проверки подписи релизов",
|
|
),
|
|
(
|
|
"scripts/kit.sh",
|
|
"for f in scripts/kit.sh scripts/kit-sub.py; do",
|
|
False,
|
|
"for f in scripts/kit.sh scripts/kit-sub.py scripts/kit-local.sh; do",
|
|
"наш файл в списке проверяемых и скачиваемых",
|
|
),
|
|
(
|
|
"scripts/kit.sh",
|
|
' install -m 755 "$tmp/kit.sh" /usr/local/bin/kit.new && mv -f /usr/local/bin/kit.new /usr/local/bin/kit',
|
|
False,
|
|
' install -m 755 "$tmp/kit.sh" /usr/local/bin/kit.new && mv -f /usr/local/bin/kit.new /usr/local/bin/kit\n'
|
|
" # Форк: ставим наши локальные дополнения из того же подписанного релиза.\n"
|
|
" install -d -m 755 /usr/local/lib/kit\n"
|
|
' install -m 644 "$tmp/kit-local.sh" /usr/local/lib/kit/kit-local.sh',
|
|
"установка kit-local.sh при обновлении",
|
|
),
|
|
# --- scripts/3x-ui.sh -----------------------------------------------
|
|
("scripts/3x-ui.sh", version_re, True, 'KIT_VERSION="%s"' % version, "версия сборки форка"),
|
|
(
|
|
"scripts/3x-ui.sh",
|
|
'KIT_RAW="https://raw.githubusercontent.com/itsnotkubrick/3X-UI_KIT/v$KIT_VERSION"',
|
|
False,
|
|
'KIT_RAW="%s/raw/tag/v$KIT_VERSION"' % GITEA,
|
|
"запасная загрузка kit из нашего релиза",
|
|
),
|
|
(
|
|
"scripts/3x-ui.sh",
|
|
'KIT_CLI_URL="$KIT_RAW/scripts/kit.sh"',
|
|
False,
|
|
'KIT_CLI_URL="$KIT_RAW/scripts/kit.sh"\nKIT_LOCAL_URL="$KIT_RAW/scripts/kit-local.sh"',
|
|
"адрес нашего файла для установщика",
|
|
),
|
|
(
|
|
"scripts/3x-ui.sh",
|
|
'KIT_INSTALL_CMD="bash <(curl -fsSL https://raw.githubusercontent.com/itsnotkubrick/3X-UI_KIT/main/scripts/3x-ui.sh)"',
|
|
False,
|
|
'KIT_INSTALL_CMD="bash <(curl -fsSL %s/raw/branch/main/scripts/3x-ui.sh)"' % GITEA,
|
|
"команда установки, которую показывает панель",
|
|
),
|
|
(
|
|
"scripts/3x-ui.sh",
|
|
' bash -n /usr/local/bin/kit || die "Команда kit скачалась повреждённой"',
|
|
False,
|
|
" # Форк: ставим наши локальные дополнения (см. scripts/kit-local.sh).\n"
|
|
" install -d -m 755 /usr/local/lib/kit\n"
|
|
' if [[ -n $src && -f $d/kit-local.sh ]]; then\n'
|
|
' install -m 644 "$d/kit-local.sh" /usr/local/lib/kit/kit-local.sh\n'
|
|
" else\n"
|
|
' curl -fsSL --retry 3 -o /usr/local/lib/kit/kit-local.sh "$KIT_LOCAL_URL" \\\n'
|
|
' || warn "Локальные дополнения kit не скачались: kit local не будет работать"\n'
|
|
" fi\n"
|
|
' bash -n /usr/local/bin/kit || die "Команда kit скачалась повреждённой"',
|
|
"установка kit-local.sh установщиком",
|
|
),
|
|
# --- scripts/hysteria2.sh -------------------------------------------
|
|
("scripts/hysteria2.sh", version_re, True, 'KIT_VERSION="%s"' % version, "версия сборки форка"),
|
|
# --- tools/release.sh -----------------------------------------------
|
|
(
|
|
"tools/release.sh",
|
|
"FILES=(scripts/3x-ui.sh scripts/hysteria2.sh scripts/kit.sh scripts/kit-sub.py VERSION)",
|
|
False,
|
|
"FILES=(scripts/3x-ui.sh scripts/hysteria2.sh scripts/kit.sh scripts/kit-sub.py scripts/kit-local.sh VERSION)",
|
|
"наш файл в подписанном списке релиза",
|
|
),
|
|
]
|
|
|
|
bad = 0
|
|
for path, anchor, is_re, new, why in edits:
|
|
p = pathlib.Path(path)
|
|
if not p.exists():
|
|
print("✗ %s: файла нет" % path)
|
|
bad += 1
|
|
continue
|
|
text = p.read_text(encoding="utf-8", newline="")
|
|
n = count(text, anchor, is_re)
|
|
label = anchor if not is_re else anchor
|
|
short = label if len(label) <= 54 else label[:51] + "…"
|
|
if n != 1:
|
|
print("✗ %-20s %-56s найдено %d раз (%s)" % (path, short, n, why))
|
|
bad += 1
|
|
continue
|
|
if check:
|
|
print("✓ %-20s %-56s (%s)" % (path, short, why))
|
|
continue
|
|
if is_re:
|
|
text = re.sub(anchor, new, text, count=1, flags=re.MULTILINE)
|
|
else:
|
|
text = text.replace(anchor, new, 1)
|
|
p.write_text(text, encoding="utf-8", newline="")
|
|
print("✓ %-20s %-56s (%s)" % (path, short, why))
|
|
|
|
if bad:
|
|
if check:
|
|
die("якорей не найдено: %d — автор изменил код, пересмотри правки в tools/fork_apply.py" % bad)
|
|
die("якорей не найдено: %d — правки не применены" % bad)
|
|
if check:
|
|
ok("все якоря на месте (версия сборки %s)" % version)
|
|
else:
|
|
ok("швы накатаны, версия сборки %s" % version)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|