Files
Rules/scripts/setup-git-ssh.sh
T
PapaTramp 3c111887d1 fix: macOS install — bash 3.2, remotes и awk для SSH config
setup-git-ssh.sh работает без declare -A; Set-GitRemotes не дублирует .git и не падает на пустом legacy; shell-скрипты executable.
2026-06-21 19:46:41 +10:00

199 lines
5.0 KiB
Bash
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/usr/bin/env bash
# Генерирует SSH-ключи и ~/.ssh/config для Git-хостов из local/git-ssh-hosts.conf.
# Совместим с macOS bash 3.2 (без declare -A).
set -euo pipefail
CONFIG_DIR="${CONFIG_DIR:-$HOME/CursorRules/local}"
HOSTS_CONFIG="${HOSTS_CONFIG:-$CONFIG_DIR/git-ssh-hosts.conf}"
WHAT_IF="${WHAT_IF:-0}"
log_step() { printf '[*] %s\n' "$1"; }
log_ok() { printf '[+] %s\n' "$1"; }
log_warn() { printf '[!] %s\n' "$1"; }
cfg_key() { printf '%s' "$1" | tr '.-' '__'; }
set_profile_field() {
local profile="$1" field="$2" value="$3"
eval "__pf_$(cfg_key "$profile")_${field}=\"\$value\""
}
get_profile_field() {
local profile="$1" field="$2"
eval "printf '%s' \"\${__pf_$(cfg_key "$profile")_${field}:-}\""
}
set_host_field() {
local host="$1" field="$2" value="$3"
eval "__hf_$(cfg_key "$host")_${field}=\"\$value\""
}
get_host_field() {
local host="$1" field="$2"
eval "printf '%s' \"\${__hf_$(cfg_key "$host")_${field}:-}\""
}
if [[ ! -f "$HOSTS_CONFIG" ]]; then
echo "Config not found: $HOSTS_CONFIG" >&2
exit 1
fi
SSH_DIR="$HOME/.ssh"
SSH_CONFIG="$SSH_DIR/config"
mkdir -p "$SSH_DIR"
chmod 700 "$SSH_DIR"
PROFILE_LIST=()
HOST_LIST=()
current_section=''
current_name=''
while IFS= read -r line || [[ -n "$line" ]]; do
line="${line%%#*}"
line="${line%"${line##*[![:space:]]}"}"
[[ -z "$line" ]] && continue
if [[ "$line" =~ ^\[profile:(.+)\]$ ]]; then
current_section='profile'
current_name="${BASH_REMATCH[1]}"
PROFILE_LIST+=("$current_name")
continue
fi
if [[ "$line" =~ ^\[host:(.+)\]$ ]]; then
current_section='host'
current_name="${BASH_REMATCH[1]}"
HOST_LIST+=("$current_name")
set_host_field "$current_name" HostName ''
continue
fi
if [[ "$line" != *=* ]]; then
continue
fi
key="${line%%=*}"
value="${line#*=}"
key="${key%"${key##*[![:space:]]}"}"
value="${value#"${value%%[![:space:]]*}"}"
if [[ "$current_section" == 'profile' ]]; then
case "$key" in
KeyName|KeyComment|GiteaConfig) set_profile_field "$current_name" "$key" "$value" ;;
esac
elif [[ "$current_section" == 'host' ]]; then
case "$key" in
HostName|Port|User|Profile) set_host_field "$current_name" "$key" "$value" ;;
esac
fi
done < "$HOSTS_CONFIG"
KEYS_SEEN=()
for profile in "${PROFILE_LIST[@]}"; do
key_name="$(get_profile_field "$profile" KeyName)"
[[ -z "$key_name" ]] && continue
seen=0
for existing in "${KEYS_SEEN[@]:-}"; do
[[ "$existing" == "$key_name" ]] && seen=1 && break
done
[[ "$seen" -eq 1 ]] && continue
KEYS_SEEN+=("$key_name")
key_path="$SSH_DIR/$key_name"
comment="$(get_profile_field "$profile" KeyComment)"
comment="${comment:-$key_name}"
if [[ ! -f "$key_path" ]]; then
log_step "Generating $key_name"
if [[ "$WHAT_IF" == '1' ]]; then
log_warn "WhatIf: ssh-keygen -t ed25519 -f $key_path"
else
ssh-keygen -t ed25519 -f "$key_path" -N '' -C "$comment" -q
chmod 600 "$key_path"
log_ok "key $key_name created"
fi
else
log_ok "key $key_name exists"
fi
done
update_ssh_block() {
local host_alias="$1"
local block="$2"
local begin="# BEGIN Setup-SshAccess:$host_alias"
local end="# END Setup-SshAccess:$host_alias"
local tmp block_file
tmp="$(mktemp)"
block_file="$(mktemp)"
printf '%s\n' "$block" > "$block_file"
if [[ -f "$SSH_CONFIG" ]]; then
awk -v begin="$begin" -v end="$end" -v blockfile="$block_file" '
$0 == begin { skip=1; next }
$0 == end { skip=0; next }
skip { next }
{ print }
END {
if (blockfile != "") {
while ((getline line < blockfile) > 0) {
print line
}
close(blockfile)
}
}
' "$SSH_CONFIG" > "$tmp"
else
cp "$block_file" "$tmp"
fi
rm -f "$block_file"
if [[ "$WHAT_IF" != '1' ]]; then
mv "$tmp" "$SSH_CONFIG"
chmod 600 "$SSH_CONFIG"
else
rm -f "$tmp"
fi
}
IFS=$'\n'
sorted_hosts=($(printf '%s\n' "${HOST_LIST[@]}" | sort))
unset IFS
for host_alias in "${sorted_hosts[@]}"; do
profile="$(get_host_field "$host_alias" Profile)"
key_name="$(get_profile_field "$profile" KeyName)"
if [[ -z "$profile" || -z "$key_name" ]]; then
echo "Host $host_alias: unknown profile" >&2
exit 1
fi
block="# BEGIN Setup-SshAccess:$host_alias
Host $host_alias
HostName $(get_host_field "$host_alias" HostName)
User $(get_host_field "$host_alias" User)
Port $(get_host_field "$host_alias" Port)
IdentityFile ~/.ssh/$key_name
IdentitiesOnly yes
AddKeysToAgent yes
StrictHostKeyChecking accept-new
# END Setup-SshAccess:$host_alias"
if [[ "$WHAT_IF" == '1' ]]; then
log_step "WhatIf: ssh config block for $host_alias"
else
update_ssh_block "$host_alias" "$block"
log_ok "ssh config: $host_alias"
fi
done
if [[ "$WHAT_IF" != '1' ]]; then
eval "$(ssh-agent -s)" >/dev/null
for key_name in "${KEYS_SEEN[@]:-}"; do
[[ -f "$SSH_DIR/$key_name" ]] && ssh-add "$SSH_DIR/$key_name" >/dev/null 2>&1 || true
done
fi
log_ok 'SSH setup complete'