Compare commits

...
7 Commits
13 changed files with 120 additions and 28 deletions
+32
View File
@@ -1,3 +1,35 @@
## v1.2.1.8: подсказка меню исправлена, установка стала тише
* **«Выбор [0-10]» при 11 пунктах** — подсказка главного меню отстала, когда мы добавили пункт «Доступ к
панели, ссылки и заглушка». Теперь «Выбор [0-11]». Чтобы это не повторилось, добавлен тест
`tools/check-menus.py`: он сверяет подсказку каждого меню с числом пунктов и запускается в релизном
гейте — если мы снова добавим пункт и забудем подсказку, выпуск остановится.
* **`kit fix` больше не выполняется при установке** (в выводе это выглядело как «Чинить нечего: всё в
порядке»). Нужен — запускается из меню или ключом `--time`.
* **Вывод про автообновления безопасности сокращён до одной строки** («автообновления безопасности
включены…»): три строки про ядро и перезагрузку убраны из установки.
## v1.2.1.7: исправлена установка (моя регрессия в 1.2.1.6)
* В 1.2.1.6 я переписал загрузку файлов релиза и оставил проверку SHA256 установщика **раньше**
скачивания — установка обрывалась на первой же строке: `sha256sum: .../scripts/3x-ui.sh: No such file
or directory`. Теперь сначала скачиваются все файлы релиза (каждый сверяется с подписанным списком),
и только потом проверяется установщик.
* Проверено не на глаз: воспроизвёл ошибку у себя тем же путём (`--verify-only`) — красное, затем после
правки зелёное. Этот прогон добавлен в процедуру выпуска: перед подписью я запускаю установщик в режиме
`--verify-only` и убеждаюсь, что путь «скачать и проверить релиз» проходит целиком.
## v1.2.1.6: доступы к панели в конце установки и рабочая заглушка
* **Исправлено: доступы к панели не выводились.** Автор пишет строки в `/root/3x-ui.txt` без ведущих
пробелов, а наш фильтр требовал два пробела — отсюда «данных панели нет». Теперь адрес панели, логин и
пароль печатаются в конце установки (и в пункте меню «9. Доступ к панели, ссылки и заглушка»).
Рядом указывается, что подписка и ссылки по протоколам лежат в том же файле.
* **Исправлено: наша заглушка не готовилась до установщика.** Обёртка скачивала из релиза только три файла,
а `scripts/kit-local.sh` (там функция страницы) не качала — падало с «kl_site_html: command not found».
Теперь качаются все файлы релиза, и каждый сверяется с подписанным списком (проверка целостности стала
полной, а не только для установщика).
## v1.2.1.5: доступ к панели, ссылки и заглушка — одним пунктом меню ## v1.2.1.5: доступ к панели, ссылки и заглушка — одним пунктом меню
* **В меню kit пункт «9. Доступ к панели, ссылки и заглушка»** — открывает одним экраном: адрес панели, * **В меню kit пункт «9. Доступ к панели, ссылки и заглушка»** — открывает одним экраном: адрес панели,
+4
View File
@@ -191,6 +191,10 @@ bash tools/fork-sync.sh # подтянуть автора, перен
bash tools/release.sh ~/.ssh/3x-ui-kit-fork/release_key # SHA256SUMS + подпись нашим ключом bash tools/release.sh ~/.ssh/3x-ui-kit-fork/release_key # SHA256SUMS + подпись нашим ключом
**Перед подписью — обязательный прогон.** `bash scripts/3x-ui-local.sh --verify-only` проверяет ровно тот
путь установки, которым пойдут серверы: скачивание всех файлов релиза и сверка каждого с подписанным
списком. На Windows запускать с `TMPDIR=C:/…` (нативные утилиты не понимают MSYS-пути).
**Нумерация версий.** Основа — версия автора, наша надстройка добавляется через точку с единицы: **Нумерация версий.** Основа — версия автора, наша надстройка добавляется через точку с единицы:
у автора 1.2.1 → наша сборка 1.2.1.1; вышла его 1.2.2 → наша 1.2.2.1. Так на сервере всегда видно, у автора 1.2.1 → наша сборка 1.2.1.1; вышла его 1.2.2 → наша 1.2.2.1. Так на сервере всегда видно,
на чьей базе собрана сборка. на чьей базе собрана сборка.
+8 -8
View File
@@ -1,9 +1,9 @@
# 3X-UI KIT 1.2.1.5 # 3X-UI KIT 1.2.1.8
# 3X-UI_autoVPS 1.2.1.5 # 3X-UI_autoVPS 1.2.1.8
e1ab2a1736228e332226bb857998ecf8a82ca6fd9aa8d2e590cffac65be02c14 scripts/3x-ui.sh 9776e75232d9e65614130cd350e5d7f0dd97ffaa5640729479cc1ced927869c8 scripts/3x-ui.sh
f27933e32e8424ef556046e99710cccef3a53ba7fe9f996851512cdea39c0a1e scripts/hysteria2.sh 81ae4f2c3d512f352e64596149174a9141f8a29e2fbd44f0e16db5387f8d31f0 scripts/hysteria2.sh
0b5fec8694b8793e3721040b54661629346cf91af5619df684657d0448d765df scripts/kit.sh 17d118d5aa7ba22d4541e7d4874d31b5fb1950b3b7cc09b2fc97885eb537ec8e scripts/kit.sh
f214671464e1c2e174e5af9df42c95567a9b4a9141f31a39f7df2e971e89d240 scripts/kit-sub.py f214671464e1c2e174e5af9df42c95567a9b4a9141f31a39f7df2e971e89d240 scripts/kit-sub.py
857e7c7e08dd80fe0fe1963e908094f8e8ff4d439eb72ae55b96aa92cddbb169 scripts/kit-local.sh 5d07c87452057e1c73e0f3af008074f94f5be6175817b2d6f94a93f69b0533b7 scripts/kit-local.sh
c5bb4070427effe3717ae733e8eb1f519df6ebcc462aa45d8eca1f57abe60f35 scripts/3x-ui-local.sh 483355bf1c0e9b75f15cf783a730ea59f5fc17038b9e212c952f792bcc57d0d8 scripts/3x-ui-local.sh
d9aefff7d6235afc8a7f1581041719422d58b84b93b89c25d3ecb8f7d74567cb VERSION a9762073937784114e8467c57045aa83784f14ab0c0e62906ec5c4c164baf4ef VERSION
+2 -2
View File
@@ -1,6 +1,6 @@
-----BEGIN SSH SIGNATURE----- -----BEGIN SSH SIGNATURE-----
U1NIU0lHAAAAAQAAADMAAAALc3NoLWVkMjU1MTkAAAAgozRJ+f9RB6qO9S9j3BWCDtC0bV U1NIU0lHAAAAAQAAADMAAAALc3NoLWVkMjU1MTkAAAAgozRJ+f9RB6qO9S9j3BWCDtC0bV
FHakRSSqtQPljLoQUAAAARM3gtdWkta2l0LXJlbGVhc2UAAAAAAAAABnNoYTUxMgAAAFMA FHakRSSqtQPljLoQUAAAARM3gtdWkta2l0LXJlbGVhc2UAAAAAAAAABnNoYTUxMgAAAFMA
AAALc3NoLWVkMjU1MTkAAABABuQ7Bk9OINTS/AAmMA/6YpaWINss4u0QgANgvIpQr+PxXV AAALc3NoLWVkMjU1MTkAAABAKCus5+Q0q6U/kWCLOJxk/TURjxPuy+TLbudsY80iVGf4sR
XBYxM0M/XtgQ7vsC6bOrH6f2KgANdwJ4ieSjlkCQ== +Nohbd9U5s7OlYRoHWVN60bRDhesIqsYfxzWirDA==
-----END SSH SIGNATURE----- -----END SSH SIGNATURE-----
+1 -1
View File
@@ -1 +1 @@
1.2.1.5 1.2.1.8
+22 -8
View File
@@ -32,7 +32,7 @@
# --no-harden не трогать ping и автообновления # --no-harden не трогать ping и автообновления
# --ssh-port N добавить порт SSH N (прежний порт продолжает работать) # --ssh-port N добавить порт SSH N (прежний порт продолжает работать)
# --yes ни о чём не спрашивать (ping закрою, автообновления включу, порт и пароль — нет) # --yes ни о чём не спрашивать (ping закрою, автообновления включу, порт и пароль — нет)
# --no-time не запускать kit fix # --time запустить kit fix (по умолчанию не запускается)
# --no-check не запускать в конце kit check # --no-check не запускать в конце kit check
# --clean убрать прошлую установку и поставить заново (SSH не трогает) # --clean убрать прошлую установку и поставить заново (SSH не трогает)
# --auto-sni не предлагать выбор сайта маскировки (иначе покажем меню по скану подсети) # --auto-sni не предлагать выбор сайта маскировки (иначе покажем меню по скану подсети)
@@ -44,7 +44,7 @@
set -Eeuo pipefail set -Eeuo pipefail
KIT_VERSION="1.2.1.5" # версия сборки форка; должна совпадать с VERSION релиза KIT_VERSION="1.2.1.8" # версия сборки форка; должна совпадать с VERSION релиза
GITEA="${KIT_FORK_BASE:-https://git.rukavishnikoff.ru/hacker07/3X-UI_autoVPS}" GITEA="${KIT_FORK_BASE:-https://git.rukavishnikoff.ru/hacker07/3X-UI_autoVPS}"
NS="3x-ui-kit-release" NS="3x-ui-kit-release"
SIG_ID="releases@3x-ui-kit" SIG_ID="releases@3x-ui-kit"
@@ -83,7 +83,7 @@ usage() {
--no-sub не показывать в конце подписку, доступ к панели и QR-код --no-sub не показывать в конце подписку, доступ к панели и QR-код
--clean снести прошлую установку и поставить заново (если прошлый запуск оборвался) --clean снести прошлую установку и поставить заново (если прошлый запуск оборвался)
--auto-sni не предлагать выбор сайта маскировки (автоподбор автора) --auto-sni не предлагать выбор сайта маскировки (автоподбор автора)
--no-time не запускать kit fix (время и безопасные починки) --time запустить kit fix (время и безопасные починки; по умолчанию не запускается)
--no-check не запускать в конце kit check --no-check не запускать в конце kit check
--verify-only только проверить релиз (подпись и SHA256) и выйти --verify-only только проверить релиз (подпись и SHA256) и выйти
--dry-run показать план и ничего не делать --dry-run показать план и ничего не делать
@@ -93,7 +93,7 @@ EOF
# ------------------------------------------------------------------ разбор флагов # ------------------------------------------------------------------ разбор флагов
INSTALLER_ARGS=(); harden=auto; ssh_port=""; fix_time=yes; do_check=yes; dry=no; verify_only=no; assume_yes=no INSTALLER_ARGS=(); harden=auto; ssh_port=""; fix_time=no; do_check=yes; dry=no; verify_only=no; assume_yes=no
site=random # заглушка: случайный сайт из нашего набора (off — не трогать) site=random # заглушка: случайный сайт из нашего набора (off — не трогать)
show_sub=yes # в самом конце показать подписку, QR-код и ссылки show_sub=yes # в самом конце показать подписку, QR-код и ссылки
clean=no # --clean: убрать прошлую установку перед новой clean=no # --clean: убрать прошлую установку перед новой
@@ -112,6 +112,7 @@ while (($#)); do
--clean) clean=yes ;; --clean) clean=yes ;;
--auto-sni) pick_sni=no ;; --auto-sni) pick_sni=no ;;
--no-time) fix_time=no ;; --no-time) fix_time=no ;;
--time) fix_time=yes ;;
--no-check) do_check=no ;; --no-check) do_check=no ;;
--verify-only) verify_only=yes ;; --verify-only) verify_only=yes ;;
--dry-run) dry=yes ;; --dry-run) dry=yes ;;
@@ -162,7 +163,6 @@ if [[ $dry == yes ]]; then
random) pre "заглушка: случайный ИТ-сайт из нашего набора (10 штук)" ;; random) pre "заглушка: случайный ИТ-сайт из нашего набора (10 штук)" ;;
*) pre "заглушка: сайт №$site из нашего набора (список: kit local site --list)" ;; *) pre "заглушка: сайт №$site из нашего набора (список: kit local site --list)" ;;
esac esac
[[ $fix_time == yes ]] && pre "после: kit fix (время, безопасные починки)"
[[ $do_check == yes ]] && pre "проверка: kit check + kit local hardening" [[ $do_check == yes ]] && pre "проверка: kit check + kit local hardening"
[[ $show_sub == yes ]] && pre "в самом конце: доступ к панели 3X-UI, подписка, QR-код и ссылки (--no-sub — не надо)" [[ $show_sub == yes ]] && pre "в самом конце: доступ к панели 3X-UI, подписка, QR-код и ссылки (--no-sub — не надо)"
echo echo
@@ -179,7 +179,7 @@ say "беру релиз v$KIT_VERSION и проверяю подпись"
tmp=$(mktemp -d) tmp=$(mktemp -d)
trap 'rm -rf "$tmp"' EXIT trap 'rm -rf "$tmp"' EXIT
raw="$GITEA/raw/tag/v$KIT_VERSION" raw="$GITEA/raw/tag/v$KIT_VERSION"
for f in SHA256SUMS SHA256SUMS.sig scripts/3x-ui.sh; do for f in SHA256SUMS SHA256SUMS.sig; do
mkdir -p "$tmp/$(dirname "$f")" mkdir -p "$tmp/$(dirname "$f")"
curl -fsSL --retry 3 -m 60 -o "$tmp/$f" "$raw/$f" || die "не скачался $f из $raw (Gitea доступна с сервера?)" curl -fsSL --retry 3 -m 60 -o "$tmp/$f" "$raw/$f" || die "не скачался $f из $raw (Gitea доступна с сервера?)"
done done
@@ -188,9 +188,21 @@ ssh-keygen -Y verify -f "$tmp/allowed_signers" -I "$SIG_ID" -n "$NS" -s "$tmp/SH
|| die "подпись релиза v$KIT_VERSION не сошлась с ключом форка — это не наш релиз, ничего не запускаю" || die "подпись релиза v$KIT_VERSION не сошлась с ключом форка — это не наш релиз, ничего не запускаю"
sum=$(awk '{f = $2; sub(/^\*/, "", f)} f == "scripts/3x-ui.sh" {print $1}' "$tmp/SHA256SUMS") sum=$(awk '{f = $2; sub(/^\*/, "", f)} f == "scripts/3x-ui.sh" {print $1}' "$tmp/SHA256SUMS")
[[ $(printf '%s' "$sum" | wc -c) -eq 64 ]] || die "в SHA256SUMS нет установщика — релиз собран неверно" [[ $(printf '%s' "$sum" | wc -c) -eq 64 ]] || die "в SHA256SUMS нет установщика — релиз собран неверно"
# Качаем ВСЕ файлы релиза и сверяем каждый с подписанным списком. Так у нас есть и scripts/3x-ui.sh
# (установщик), и scripts/kit-local.sh (наша страница-заглушка), и всё остальное. Раньше брали только
# установщик: заглушка не готовилась («kl_site_html: command not found»), а проверка целостности была неполной.
while read -r sum2 name2; do
case $sum2 in \#* | "") continue ;; esac
case $name2 in SHA256SUMS | SHA256SUMS.sig) continue ;; esac
mkdir -p "$tmp/$(dirname "$name2")"
curl -fsSL --retry 3 -m 60 -o "$tmp/$name2" "$raw/$name2" || die "не скачался $name2 из $raw (Gitea доступна с сервера?)"
got2=$(sha256sum "$tmp/$name2" | awk '{print $1}')
[[ $got2 == "$sum2" ]] || die "SHA256 не совпал у $name2 — не запускаю"
done <"$tmp/SHA256SUMS"
got=$(sha256sum "$tmp/scripts/3x-ui.sh" | awk '{print $1}') got=$(sha256sum "$tmp/scripts/3x-ui.sh" | awk '{print $1}')
[[ $got == "$sum" ]] || die "SHA256 установщика не совпал с подписанным — не запускаю" [[ $got == "$sum" ]] || die "SHA256 установщика не совпал с подписанным — не запускаю"
bash -n "$tmp/scripts/3x-ui.sh" || die "установщик не проходит проверку синтаксиса" bash -n "$tmp/scripts/3x-ui.sh" || die "установщик не проходит проверку синтаксиса"
[[ -r $tmp/scripts/kit-local.sh ]] || die "в релизе нет scripts/kit-local.sh — сборка неполная"
printf ' ✓ подпись сошлась, SHA256 установщика совпал\n' printf ' ✓ подпись сошлась, SHA256 установщика совпал\n'
if [[ $verify_only == yes ]]; then if [[ $verify_only == yes ]]; then
@@ -557,8 +569,10 @@ ${B}─────────────────────────
${B}Доступ к панели${N} (файл /root/3x-ui.txt, виден только root) ${B}Доступ к панели${N} (файл /root/3x-ui.txt, виден только root)
EOF EOF
if grep -aqE '^ (Панель|Логин|Пароль):' /root/3x-ui.txt 2>/dev/null; then # Автор пишет эти строки без ведущих пробелов (RESULT=/root/3x-ui.txt), поэтому ищем их как есть.
grep -aE '^ (Панель|Логин|Пароль):' /root/3x-ui.txt | sed 's/^/ /' if grep -aqE '^[[:space:]]*(Панель|Логин|Пароль):' /root/3x-ui.txt 2>/dev/null; then
grep -aE '^[[:space:]]*(Панель|Логин|Пароль):' /root/3x-ui.txt | sed 's/^[[:space:]]*/ /'
printf ' файл целиком (там же подписка и ссылки по протоколам): /root/3x-ui.txt\n'
else else
warn "данных панели в /root/3x-ui.txt нет — смотрите вывод установщика выше" warn "данных панели в /root/3x-ui.txt нет — смотрите вывод установщика выше"
fi fi
+1 -1
View File
@@ -39,7 +39,7 @@ wait_apt_idle() {
XUI_VERSION="v3.9.0" XUI_VERSION="v3.9.0"
# SHA256 установщика 3X-UI этой версии: тег могут передвинуть, а хеш – нет (проверено 2026-09-30). # SHA256 установщика 3X-UI этой версии: тег могут передвинуть, а хеш – нет (проверено 2026-09-30).
XUI_INSTALL_SHA256="18616fe26c8f6c92db6daa2dcd7cd53c5143ee69ecfd26d8ea6dc9b2c78607a6" XUI_INSTALL_SHA256="18616fe26c8f6c92db6daa2dcd7cd53c5143ee69ecfd26d8ea6dc9b2c78607a6"
KIT_VERSION="1.2.1.5" KIT_VERSION="1.2.1.8"
# kit и kit-sub берём из того же релиза, что и этот скрипт, а не из меняющейся ветки main. # kit и kit-sub берём из того же релиза, что и этот скрипт, а не из меняющейся ветки main.
KIT_RAW="https://git.rukavishnikoff.ru/hacker07/3X-UI_autoVPS/raw/tag/v$KIT_VERSION" KIT_RAW="https://git.rukavishnikoff.ru/hacker07/3X-UI_autoVPS/raw/tag/v$KIT_VERSION"
# Ядро Xray для панели. С 26.7.x клиенты на Mihomo и sing-box (Hiddify, FlClash, # Ядро Xray для панели. С 26.7.x клиенты на Mihomo и sing-box (Hiddify, FlClash,
+1 -1
View File
@@ -8,7 +8,7 @@
# Код выхода 1 при любом запуске (и при `__update_binary`) – старый `hy2 update` на нём # Код выхода 1 при любом запуске (и при `__update_binary`) – старый `hy2 update` на нём
# останавливается и не заменяет команду hy2. # останавливается и не заменяет команду hy2.
KIT_VERSION="1.2.1.5" KIT_VERSION="1.2.1.8"
cat >&2 <<'MSG' cat >&2 <<'MSG'
Отдельный установщик Hysteria2 больше не поддерживается. Отдельный установщик Hysteria2 больше не поддерживается.
+4 -5
View File
@@ -423,9 +423,8 @@ Unattended-Upgrade::Automatic-Reboot "false";
Unattended-Upgrade::Remove-Unused-Kernel-Packages "true"; Unattended-Upgrade::Remove-Unused-Kernel-Packages "true";
EOF EOF
systemctl enable --now unattended-upgrades >/dev/null 2>&1 || kl_warn "служба не включилась — проверьте: systemctl status unattended-upgrades" systemctl enable --now unattended-upgrades >/dev/null 2>&1 || kl_warn "служба не включилась — проверьте: systemctl status unattended-upgrades"
kl_ok "включено: обновления безопасности ставятся сами" # Одна строка: подробности нужны редко, а в выводе установки они превращались в шум.
kl_ok "панель и ядро это не затрагивает — они ставятся не из apt, а из своих релизов" kl_ok "автообновления безопасности включены (панель и ядро это не затрагивает, сервер сам не перезагружается)"
kl_warn "обновление ядра применится только после перезагрузки, сам сервер не перезагружается"
return 0 return 0
} }
@@ -967,8 +966,8 @@ kit_local_ports() { # [--close-extra] — что открыто в ufw, что
kit_local_access() { # доступ к панели, ссылки на подключения, заглушка и сертификат — одним экраном kit_local_access() { # доступ к панели, ссылки на подключения, заглушка и сертификат — одним экраном
local u=${1:-} till2 local u=${1:-} till2
printf '%s\n' "${B:-}Доступ к панели 3X-UI${N:-} (файл /root/3x-ui.txt, виден только root)" printf '%s\n' "${B:-}Доступ к панели 3X-UI${N:-} (файл /root/3x-ui.txt, виден только root)"
if grep -aqE '^ (Панель|Логин|Пароль):' /root/3x-ui.txt 2>/dev/null; then if grep -aqE '^[[:space:]]*(Панель|Логин|Пароль):' /root/3x-ui.txt 2>/dev/null; then
grep -aE '^ (Панель|Логин|Пароль):' /root/3x-ui.txt | sed 's/^/ /' grep -aE '^[[:space:]]*(Панель|Логин|Пароль):' /root/3x-ui.txt | sed 's/^[[:space:]]*/ /'
else else
kl_warn "данных панели в /root/3x-ui.txt нет" kl_warn "данных панели в /root/3x-ui.txt нет"
fi fi
+2 -2
View File
@@ -12,7 +12,7 @@
set -Eeuo pipefail set -Eeuo pipefail
export LC_ALL=C.UTF-8 # ширина колонок по символам, а не байтам export LC_ALL=C.UTF-8 # ширина колонок по символам, а не байтам
KIT_VERSION="1.2.1.5" KIT_VERSION="1.2.1.8"
KIT_RAW="https://git.rukavishnikoff.ru/hacker07/3X-UI_autoVPS/raw/branch/main" KIT_RAW="https://git.rukavishnikoff.ru/hacker07/3X-UI_autoVPS/raw/branch/main"
# Файлы новой версии берём из её тега, а не из меняющейся ветки main. # Файлы новой версии берём из её тега, а не из меняющейся ветки main.
kit_ref_raw() { echo "https://git.rukavishnikoff.ru/hacker07/3X-UI_autoVPS/raw/tag/v$1"; } kit_ref_raw() { echo "https://git.rukavishnikoff.ru/hacker07/3X-UI_autoVPS/raw/tag/v$1"; }
@@ -3199,7 +3199,7 @@ menu_main() {
menu_status menu_status
update_hint update_hint
echo echo
ask_num "Выбор [0-10]: "; c=$REPLY ask_num "Выбор [0-11]: "; c=$REPLY
case $c in case $c in
1) menu_users ;; 1) menu_users ;;
2) menu_net ;; 2) menu_net ;;
+31
View File
@@ -0,0 +1,31 @@
#!/usr/bin/env python3
"""Проверка: подсказка «Выбор [0-N]» в каждом меню kit должна совпадать с числом пунктов.
Пункты считаются по строкам box (с учётом переносов через «\\»). Смысл проверки: мы добавляем в меню
свои пункты — однажды подсказка осталась «0-10» при 11 пунктах, и человек не мог выбрать последний.
"""
import re
import sys
import pathlib
path = pathlib.Path(sys.argv[1] if len(sys.argv) > 1 else "scripts/kit.sh")
text = path.read_text(encoding="utf-8").replace("\\\n", "")
lines = text.splitlines()
bad = 0
for i, line in enumerate(lines):
m = re.search(r'\bbox\s+"([^"]+)"(.*)$', line)
if not m:
continue
items = re.findall(r'"(\d+)\.\s', m.group(2))
maxn = max((int(x) for x in items), default=0)
prompt = None
for j in range(i + 1, min(i + 120, len(lines))):
pm = re.search(r'ask_num\s+"Выбор \[0-(\d+)\]', lines[j])
if pm:
prompt = int(pm.group(1))
break
if prompt != maxn:
print(f"! меню «{m.group(1)}»: пунктов {maxn}, а подсказка «Выбор [0-{prompt}]»", file=sys.stderr)
bad += 1
print(f"меню проверены: {len(lines) and sum(1 for l in lines if 'box \"' in l)} · рассинхронов: {bad}")
sys.exit(1 if bad else 0)
+7
View File
@@ -219,6 +219,13 @@ def main():
' "7. Резервная копия" "8. Версии" "" "9. Доступ к панели, ссылки и заглушка" "10. Панель x-ui" "11. Удалить KIT с сервера" "0. Выход"\n', ' "7. Резервная копия" "8. Версии" "" "9. Доступ к панели, ссылки и заглушка" "10. Панель x-ui" "11. Удалить KIT с сервера" "0. Выход"\n',
'авто-шов: replace, строк 1', 'авто-шов: replace, строк 1',
), ),
(
'scripts/kit.sh',
' ask_num "Выбор [0-10]: "; c=$REPLY\n',
False,
' ask_num "Выбор [0-11]: "; c=$REPLY\n',
'авто-шов: replace, строк 1',
),
( (
'scripts/kit.sh', 'scripts/kit.sh',
' 9) command -v x-ui >/dev/null && x-ui || echo "Меню x-ui не найдено." ;;\n 10) run_action cmd_uninstall; pause ;;\n', ' 9) command -v x-ui >/dev/null && x-ui || echo "Меню x-ui не найдено." ;;\n 10) run_action cmd_uninstall; pause ;;\n',
+5
View File
@@ -59,6 +59,11 @@ for fn in ask_yes ask_ssh_port ssh_ports_now ask_protocols proto_parse proto_men
[[ -z $c || $c -gt $d ]] || die "scripts/3x-ui-local.sh: $fn вызывается (строка $c) раньше, чем определена ($d)" [[ -z $c || $c -gt $d ]] || die "scripts/3x-ui-local.sh: $fn вызывается (строка $c) раньше, чем определена ($d)"
done done
ok "Все наши функции определены раньше своих вызовов" ok "Все наши функции определены раньше своих вызовов"
# python3 есть не везде (на Windows обычно только python) — берём тот, что есть.
py=$(command -v python3 || command -v python || true)
[[ -n $py ]] || die "нет python — им проверяются меню (tools/check-menus.py)"
"$py" tools/check-menus.py >/dev/null || die "подсказка «Выбор [0-N]» не совпадает с числом пунктов меню (tools/check-menus.py)"
ok "Подсказки меню совпадают с числом пунктов"
[[ -z $(git status --porcelain -- "${FILES[@]}" CHANGELOG.md FORK-CHANGELOG.md) ]] || die "Есть незакоммиченные изменения в файлах релиза – сначала коммит." [[ -z $(git status --porcelain -- "${FILES[@]}" CHANGELOG.md FORK-CHANGELOG.md) ]] || die "Есть незакоммиченные изменения в файлах релиза – сначала коммит."