refactor(wsl): унифицирована логика hproxy.local и добавлена миграция legacy boot command
- Зачем:
- setup-hproxy.sh удалял запись из hosts до проверки gateway — при ошибке hosts ломался.
- update_hproxy() дублировала логику скрипта с багами и не тестировалась.
- legacy inline boot command в wsl.conf не мигрировался автоматически.
- Что:
- setup-hproxy.sh: безопасный порядок (gateway → hosts), set -e, экранированная точка в sed.
- update_hproxy() заменена на thin wrapper с проверкой wsl.conf и ошибок sudo.
- install.sh: интерактивная замена legacy boot command, детекция существующих [boot] command,
принимает русскую «у» наравне с «y».
- README.md: описаны три сценария (WSL NAT, WSL mirrored — host-side resolution, native Linux).
- добавлены тесты: existing boot command preserved, legacy command migration hint.
- Проверка:
- bash tests/test_install.sh
- ./install.sh (интерактивно, ответить «y» на миграцию legacy command)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
1 parent
1963b6a117
commit
898db1098d
5 files changed
+131
-66
No files matched your search
@@ -113,13 +113,21 @@ EOF
|
|||||||
|
|
||||||
После изменения `wsl.conf` — `wsl --shutdown`. Обновить без перезапуска: `sudo scripts/setup-hproxy.sh` или `update_hproxy`.
|
После изменения `wsl.conf` — `wsl --shutdown`. Обновить без перезапуска: `sudo scripts/setup-hproxy.sh` или `update_hproxy`.
|
||||||
|
|
||||||
**WSL Mirror mode** (`networkingMode=mirrored`) — IP не меняется, достаточно одной записи:
|
**WSL mirrored mode** (`networkingMode=mirrored`) — имя резолвится из WSL через DNS/hosts хоста. Достаточно записи на стороне Windows:
|
||||||
|
|
||||||
```
|
```
|
||||||
# C:\Windows\System32\drivers\etc\hosts
|
# C:\Windows\System32\drivers\etc\hosts
|
||||||
192.168.1.100 hproxy.local
|
192.168.1.100 hproxy.local
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Проверка: `getent hosts hproxy.local` (запись в Linux `/etc/hosts` не обязательна).
|
||||||
|
|
||||||
|
**Native Linux** — прокси на localhost, нужна запись в `/etc/hosts`:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
echo '127.0.0.1 hproxy.local' | sudo tee -a /etc/hosts
|
||||||
|
```
|
||||||
|
|
||||||
**VS Code Server** — `vscode/.vscode-server/server-env-setup` автоматически подхватывает `hproxy.local` и выставляет все proxy-переменные (HTTP_PROXY, HTTPS_PROXY, ALL_PROXY, NO_PROXY и lowercase-варианты). Если `hproxy.local` не резолвится — прокси не включается, запуск не блокируется.
|
**VS Code Server** — `vscode/.vscode-server/server-env-setup` автоматически подхватывает `hproxy.local` и выставляет все proxy-переменные (HTTP_PROXY, HTTPS_PROXY, ALL_PROXY, NO_PROXY и lowercase-варианты). Если `hproxy.local` не резолвится — прокси не включается, запуск не блокируется.
|
||||||
|
|
||||||
**Windows pwsh** — `proxy_on` / `proxy_off` / `myip` работают аналогично bash-версиям.
|
**Windows pwsh** — `proxy_on` / `proxy_off` / `myip` работают аналогично bash-версиям.
|
||||||
@@ -161,7 +169,7 @@ EOF
|
|||||||
| `proxy_on` | Включает HTTP/HTTPS/SOCKS5 прокси через `hproxy.local:12334` |
|
| `proxy_on` | Включает HTTP/HTTPS/SOCKS5 прокси через `hproxy.local:12334` |
|
||||||
| `proxy_off` | Очищает proxy-переменные |
|
| `proxy_off` | Очищает proxy-переменные |
|
||||||
| `myip` | Показывает текущий внешний IP |
|
| `myip` | Показывает текущий внешний IP |
|
||||||
| `update_hproxy` | Обновляет `hproxy.local` в `/etc/hosts` (WSL NAT mode) |
|
| `update_hproxy` | Обновляет `hproxy.local` в `/etc/hosts` через `setup-hproxy.sh` (WSL NAT) |
|
||||||
|
|
||||||
### PowerShell-функции (`~/.config/powershell/profile.ps1`)
|
### PowerShell-функции (`~/.config/powershell/profile.ps1`)
|
||||||
|
|
||||||
|
|||||||
+15
-37
@@ -3,46 +3,24 @@
|
|||||||
# export HTTP_PROXY="http://127.0.0.1:10809"
|
# export HTTP_PROXY="http://127.0.0.1:10809"
|
||||||
# export HTTPS_PROXY="http://127.0.0.1:10809"
|
# export HTTPS_PROXY="http://127.0.0.1:10809"
|
||||||
|
|
||||||
# --- WSL Host Update ---
|
# --- WSL Host Update (только WSL NAT) ---
|
||||||
update_hproxy() {
|
update_hproxy() {
|
||||||
echo "🔄 Обновление IP-адреса для hproxy.local..."
|
local script
|
||||||
|
script="$(dirname "$(readlink -f "${BASH_SOURCE[0]}")")/../scripts/setup-hproxy.sh"
|
||||||
local host_ip=""
|
if [ ! -f "$script" ]; then
|
||||||
local wslconfig=$(ls /mnt/c/Users/*/.wslconfig 2>/dev/null | head -n 1)
|
echo "❌ Скрипт не найден: $script"
|
||||||
local win_hosts="/mnt/c/Windows/System32/drivers/etc/hosts"
|
|
||||||
|
|
||||||
# Проверяем наличие параметра networkingMode=mirror в конфиге Windows
|
|
||||||
if [ -f "$wslconfig" ] && grep -qiE '^[[:space:]]*networkingMode[[:space:]]*=[[:space:]]*mirror' "$wslconfig"; then
|
|
||||||
echo "🔍 Обнаружен режим Mirror."
|
|
||||||
|
|
||||||
# Читаем hosts из Windows
|
|
||||||
if [ -f "$win_hosts" ] && grep -qiw "hproxy.local" "$win_hosts"; then
|
|
||||||
# Извлекаем IP (первый столбец) и чистим от виндовых символов возврата каретки (\r)
|
|
||||||
host_ip=$(grep -iw "hproxy.local" "$win_hosts" | awk '{print $1}' | tr -d '\r' | head -n 1)
|
|
||||||
echo "📂 Взят IP из Windows hosts: $host_ip"
|
|
||||||
else
|
|
||||||
# Фолбэк на случай, если записи в Windows нет
|
|
||||||
host_ip="127.0.0.1"
|
|
||||||
echo "⚠️ Запись hproxy.local в Windows hosts не найдена, используем дефолтный $host_ip"
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
echo "🔍 Обнаружен режим NAT."
|
|
||||||
|
|
||||||
# Формируем IP на лету из маршрута по умолчанию
|
|
||||||
host_ip=$(ip route show default | awk '{print $3}')
|
|
||||||
echo "🌐 Вычислен IP шлюза WSL: $host_ip"
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ -z "$host_ip" ]; then
|
|
||||||
echo "❌ Ошибка: Не удалось определить IP-адрес."
|
|
||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
|
if ! awk '/^\[boot\]$/{b=1;next} /^\[/{b=0} b && /^[[:space:]]*command[[:space:]]*=/ && /setup-hproxy\.sh/' \
|
||||||
# Обновляем /etc/hosts в Ubuntu
|
"${WSL_CONF_PATH:-/etc/wsl.conf}" 2>/dev/null | grep -q .; then
|
||||||
sudo sed -i '/hproxy.local/d' /etc/hosts
|
echo "⚠️ Boot command не настроен — update_hproxy работает только для WSL NAT"
|
||||||
echo "$host_ip hproxy.local" | sudo tee -a /etc/hosts > /dev/null
|
return 1
|
||||||
|
fi
|
||||||
echo "✅ Готово! hproxy.local теперь указывает на $host_ip"
|
if ! sudo "$script"; then
|
||||||
|
echo "❌ Ошибка обновления hproxy.local"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
echo "✅ hproxy.local -> $(getent hosts hproxy.local 2>/dev/null | awk '{print $1}')"
|
||||||
}
|
}
|
||||||
|
|
||||||
# Удобные функции-переключатели для терминала
|
# Удобные функции-переключатели для терминала
|
||||||
|
|||||||
+43
-25
@@ -115,6 +115,15 @@ is_interactive() {
|
|||||||
esac
|
esac
|
||||||
}
|
}
|
||||||
|
|
||||||
|
wsl_conf_has_boot_command() {
|
||||||
|
awk '
|
||||||
|
/^\[boot\]$/ { in_boot=1; next }
|
||||||
|
/^\[/ { in_boot=0 }
|
||||||
|
in_boot && /^[[:space:]]*command[[:space:]]*=/ { found=1 }
|
||||||
|
END { exit !found }
|
||||||
|
' "$1" 2>/dev/null
|
||||||
|
}
|
||||||
|
|
||||||
# --- Проверка stow ---
|
# --- Проверка stow ---
|
||||||
if ! command -v "$STOW_BIN" &>/dev/null; then
|
if ! command -v "$STOW_BIN" &>/dev/null; then
|
||||||
error "stow не найден. Установите: sudo apt install stow"
|
error "stow не найден. Установите: sudo apt install stow"
|
||||||
@@ -241,40 +250,49 @@ fi
|
|||||||
if [ -n "${WSL_DISTRO_NAME:-}" ]; then
|
if [ -n "${WSL_DISTRO_NAME:-}" ]; then
|
||||||
HPROXY_SCRIPT="$DOTFILES_DIR/scripts/setup-hproxy.sh"
|
HPROXY_SCRIPT="$DOTFILES_DIR/scripts/setup-hproxy.sh"
|
||||||
WSL_BOOT_COMMAND="command = \"$HPROXY_SCRIPT\""
|
WSL_BOOT_COMMAND="command = \"$HPROXY_SCRIPT\""
|
||||||
|
LEGACY_WSL_BOOT_COMMAND="command = \"ip route show default | awk '{print \$3 \\\" hproxy.local\\\"}' >> /etc/hosts\""
|
||||||
if grep -Fq "$WSL_BOOT_COMMAND" "$WSL_CONF_PATH" 2>/dev/null; then
|
if grep -Fq "$WSL_BOOT_COMMAND" "$WSL_CONF_PATH" 2>/dev/null; then
|
||||||
warn "/etc/wsl.conf уже содержит boot command для setup-hproxy.sh, пропускаю"
|
warn "/etc/wsl.conf уже содержит boot command для setup-hproxy.sh, пропускаю"
|
||||||
elif ! is_interactive; then
|
elif grep -Fq "$LEGACY_WSL_BOOT_COMMAND" "$WSL_CONF_PATH" 2>/dev/null; then
|
||||||
warn "WSL обнаружен, но stdin не интерактивный. Пропускаю настройку /etc/wsl.conf"
|
warn "/etc/wsl.conf содержит legacy boot command для hproxy.local"
|
||||||
info "Добавьте вручную: $WSL_BOOT_COMMAND"
|
info "Рекомендуется заменить на: $WSL_BOOT_COMMAND"
|
||||||
else
|
if is_interactive; then
|
||||||
if awk '
|
echo -ne "${YELLOW}[?]${NC} Заменить legacy command на setup-hproxy.sh? [y/N] "
|
||||||
/^\[boot\]$/ { in_boot=1; next }
|
|
||||||
/^\[/ { in_boot=0 }
|
|
||||||
in_boot && /^[[:space:]]*command[[:space:]]*=/ { found=1 }
|
|
||||||
END { exit !found }
|
|
||||||
' "$WSL_CONF_PATH" 2>/dev/null; then
|
|
||||||
warn "/etc/wsl.conf уже содержит [boot] command. Добавьте setup-hproxy.sh вручную"
|
|
||||||
info "Нужная строка: $WSL_BOOT_COMMAND"
|
|
||||||
else
|
|
||||||
echo ""
|
|
||||||
info "Обнаружен WSL. Скрипт $HPROXY_SCRIPT может автоматически"
|
|
||||||
info "прописывать hproxy.local в /etc/hosts при каждом старте WSL (NAT mode)."
|
|
||||||
echo -ne "${YELLOW}[?]${NC} Добавить boot command в /etc/wsl.conf? [y/N] "
|
|
||||||
answer=""
|
answer=""
|
||||||
if ! read -r answer; then
|
if ! read -r answer; then
|
||||||
answer=""
|
answer=""
|
||||||
fi
|
fi
|
||||||
if [[ "$answer" =~ ^[Yy]$ ]]; then
|
if [[ "$answer" =~ ^[YyУу]$ ]]; then
|
||||||
# Добавляем [boot] секцию, если её нет
|
"$SUDO_BIN" sed -i '/ip route.*hproxy\.local/d' "$WSL_CONF_PATH"
|
||||||
if ! grep -q '^\[boot\]' "$WSL_CONF_PATH" 2>/dev/null; then
|
|
||||||
printf '\n[boot]\n' | "$SUDO_BIN" tee -a "$WSL_CONF_PATH" > /dev/null
|
|
||||||
fi
|
|
||||||
"$SUDO_BIN" sed -i "/^\[boot\]/a command = \"$HPROXY_SCRIPT\"" "$WSL_CONF_PATH"
|
"$SUDO_BIN" sed -i "/^\[boot\]/a command = \"$HPROXY_SCRIPT\"" "$WSL_CONF_PATH"
|
||||||
info "Добавлено в /etc/wsl.conf. Перезапустите WSL: wsl --shutdown"
|
info "Заменено. Перезапустите WSL: wsl --shutdown"
|
||||||
else
|
|
||||||
warn "Пропущено. Можно настроить вручную — см. README.md"
|
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
elif wsl_conf_has_boot_command "$WSL_CONF_PATH"; then
|
||||||
|
warn "/etc/wsl.conf уже содержит [boot] command. Добавьте setup-hproxy.sh вручную"
|
||||||
|
info "Нужная строка: $WSL_BOOT_COMMAND"
|
||||||
|
elif ! is_interactive; then
|
||||||
|
warn "WSL обнаружен, но stdin не интерактивный. Пропускаю настройку /etc/wsl.conf"
|
||||||
|
info "Добавьте вручную: $WSL_BOOT_COMMAND"
|
||||||
|
else
|
||||||
|
echo ""
|
||||||
|
info "Обнаружен WSL. Скрипт $HPROXY_SCRIPT может автоматически"
|
||||||
|
info "прописывать hproxy.local в /etc/hosts при каждом старте WSL (NAT mode)."
|
||||||
|
echo -ne "${YELLOW}[?]${NC} Добавить boot command в /etc/wsl.conf? [y/N] "
|
||||||
|
answer=""
|
||||||
|
if ! read -r answer; then
|
||||||
|
answer=""
|
||||||
|
fi
|
||||||
|
if [[ "$answer" =~ ^[YyУу]$ ]]; then
|
||||||
|
# Добавляем [boot] секцию, если её нет
|
||||||
|
if ! grep -q '^\[boot\]' "$WSL_CONF_PATH" 2>/dev/null; then
|
||||||
|
printf '\n[boot]\n' | "$SUDO_BIN" tee -a "$WSL_CONF_PATH" > /dev/null
|
||||||
|
fi
|
||||||
|
"$SUDO_BIN" sed -i "/^\[boot\]/a command = \"$HPROXY_SCRIPT\"" "$WSL_CONF_PATH"
|
||||||
|
info "Добавлено в /etc/wsl.conf. Перезапустите WSL: wsl --shutdown"
|
||||||
|
else
|
||||||
|
warn "Пропущено. Можно настроить вручную — см. README.md"
|
||||||
|
fi
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|||||||
+10
-2
@@ -8,5 +8,13 @@
|
|||||||
# [boot]
|
# [boot]
|
||||||
# command = "/path/to/setup-hproxy.sh"
|
# command = "/path/to/setup-hproxy.sh"
|
||||||
|
|
||||||
sed -i '/hproxy.local/d' /etc/hosts
|
set -e
|
||||||
ip route show default | awk '{print $3 " hproxy.local"}' >> /etc/hosts
|
|
||||||
|
gateway=$(ip route show default | awk '{print $3}')
|
||||||
|
if [ -z "$gateway" ]; then
|
||||||
|
echo "setup-hproxy: no default gateway" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
sed -i '/hproxy\.local/d' /etc/hosts
|
||||||
|
printf '%s hproxy.local\n' "$gateway" >> /etc/hosts
|
||||||
@@ -236,6 +236,57 @@ test_wsl_noninteractive_skips_file_changes() {
|
|||||||
printf '%s' "$output" | grep -Fq 'Добавьте вручную:' || fail "Expected manual WSL hint"
|
printf '%s' "$output" | grep -Fq 'Добавьте вручную:' || fail "Expected manual WSL hint"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
test_wsl_noninteractive_existing_boot_command_is_preserved() {
|
||||||
|
local fixture repo_root home_dir wsl_conf output
|
||||||
|
fixture="$(setup_fixture)"
|
||||||
|
repo_root="$fixture/repo"
|
||||||
|
home_dir="$fixture/home"
|
||||||
|
wsl_conf="$fixture/wsl.conf"
|
||||||
|
mkdir -p "$home_dir"
|
||||||
|
cat > "$wsl_conf" <<'EOF'
|
||||||
|
[boot]
|
||||||
|
command = "/usr/local/bin/existing.sh"
|
||||||
|
EOF
|
||||||
|
|
||||||
|
output="$(
|
||||||
|
run_install "$repo_root" "$home_dir" \
|
||||||
|
env WSL_DISTRO_NAME=Ubuntu INSTALL_INTERACTIVE_MODE=never WSL_CONF_PATH="$wsl_conf"
|
||||||
|
)"
|
||||||
|
|
||||||
|
assert_file_contains "$wsl_conf" 'command = "/usr/local/bin/existing.sh"'
|
||||||
|
if grep -Fq 'setup-hproxy.sh' "$wsl_conf"; then
|
||||||
|
fail "Expected existing boot command to stay untouched"
|
||||||
|
fi
|
||||||
|
printf '%s' "$output" | grep -Fq 'уже содержит [boot] command' || fail "Expected warning about existing boot command"
|
||||||
|
if printf '%s' "$output" | grep -Fq 'Добавьте вручную:'; then
|
||||||
|
fail "Did not expect manual add hint when [boot] command already exists"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
test_wsl_legacy_boot_command_suggests_migration() {
|
||||||
|
local fixture repo_root home_dir wsl_conf output command_line
|
||||||
|
fixture="$(setup_fixture)"
|
||||||
|
repo_root="$fixture/repo"
|
||||||
|
home_dir="$fixture/home"
|
||||||
|
wsl_conf="$fixture/wsl.conf"
|
||||||
|
mkdir -p "$home_dir"
|
||||||
|
cat > "$wsl_conf" <<'EOF'
|
||||||
|
[boot]
|
||||||
|
command = "ip route show default | awk '{print $3 \" hproxy.local\"}' >> /etc/hosts"
|
||||||
|
EOF
|
||||||
|
command_line="command = \"$repo_root/scripts/setup-hproxy.sh\""
|
||||||
|
|
||||||
|
output="$(
|
||||||
|
run_install "$repo_root" "$home_dir" \
|
||||||
|
env WSL_DISTRO_NAME=Ubuntu INSTALL_INTERACTIVE_MODE=never WSL_CONF_PATH="$wsl_conf"
|
||||||
|
)"
|
||||||
|
|
||||||
|
assert_file_contains "$wsl_conf" 'command = "ip route show default | awk '\''{print $3 \" hproxy.local\"}'\'' >> /etc/hosts"'
|
||||||
|
printf '%s' "$output" | grep -Fq 'legacy boot command' || fail "Expected legacy boot command warning"
|
||||||
|
printf '%s' "$output" | grep -Fq 'Рекомендуется заменить' || fail "Expected migration hint to replace legacy command"
|
||||||
|
printf '%s' "$output" | grep -Fq "$command_line" || fail "Expected suggested setup-hproxy.sh command"
|
||||||
|
}
|
||||||
|
|
||||||
test_wsl_interactive_adds_boot_command() {
|
test_wsl_interactive_adds_boot_command() {
|
||||||
local fixture repo_root home_dir wsl_conf command_line
|
local fixture repo_root home_dir wsl_conf command_line
|
||||||
fixture="$(setup_fixture)"
|
fixture="$(setup_fixture)"
|
||||||
@@ -289,6 +340,8 @@ main() {
|
|||||||
test_broken_claude_symlink_does_not_fail
|
test_broken_claude_symlink_does_not_fail
|
||||||
test_absolute_symlinks_in_home_do_not_break_install
|
test_absolute_symlinks_in_home_do_not_break_install
|
||||||
test_wsl_noninteractive_skips_file_changes
|
test_wsl_noninteractive_skips_file_changes
|
||||||
|
test_wsl_noninteractive_existing_boot_command_is_preserved
|
||||||
|
test_wsl_legacy_boot_command_suggests_migration
|
||||||
test_wsl_interactive_adds_boot_command
|
test_wsl_interactive_adds_boot_command
|
||||||
test_wsl_existing_boot_command_is_preserved
|
test_wsl_existing_boot_command_is_preserved
|
||||||
|
|
||||||
|
|||||||
Reference in new issue
Block a user