fix: macOS install — bash 3.2, remotes и awk для SSH config

setup-git-ssh.sh работает без declare -A; Set-GitRemotes не дублирует .git и не падает на пустом legacy; shell-скрипты executable.
This commit is contained in:
2026-06-21 19:46:41 +10:00
parent e1ba24eb74
commit 3c111887d1
7 changed files with 86 additions and 41 deletions
+2
View File
@@ -0,0 +1,2 @@
.cursor/
.cursorignore
Regular → Executable
View File
Regular → Executable
View File
+16 -11
View File
@@ -16,9 +16,11 @@ if ! git rev-parse --is-inside-work-tree >/dev/null 2>&1; then
fi fi
repo_name_from_url() { repo_name_from_url() {
local url="$1" local url="$1" name=""
if [[ "$url" =~ /([^/]+)(\.git)?/?$ ]]; then if [[ "$url" =~ /([^/]+)/?$ ]]; then
echo "${BASH_REMATCH[1]}" name="${BASH_REMATCH[1]}"
name="${name%.git}"
printf '%s\n' "$name"
fi fi
} }
@@ -32,6 +34,7 @@ if [[ -z "$repo_name" ]]; then
done done
fi fi
repo_name="${repo_name:-$(basename "$(git rev-parse --show-toplevel)")}" repo_name="${repo_name:-$(basename "$(git rev-parse --show-toplevel)")}"
repo_name="${repo_name%.git}"
home_url="ssh://git@git.papatramp.ru:2222/${OWNER}/${repo_name}.git" home_url="ssh://git@git.papatramp.ru:2222/${OWNER}/${repo_name}.git"
kalinamall_url="ssh://git@git.kalinamall.ru:2222/${OWNER}/${repo_name}.git" kalinamall_url="ssh://git@git.kalinamall.ru:2222/${OWNER}/${repo_name}.git"
github_url="git@github.com:${GITHUB_ORG}/${repo_name}.git" github_url="git@github.com:${GITHUB_ORG}/${repo_name}.git"
@@ -83,14 +86,16 @@ set_remote() {
*) legacy=() ;; *) legacy=() ;;
esac esac
for old in "${legacy[@]}"; do if ((${#legacy[@]} > 0)); then
if git remote | grep -Fxq "$old"; then for old in "${legacy[@]}"; do
git remote rename "$old" "$name" if git remote | grep -Fxq "$old"; then
git remote set-url "$name" "$url" git remote rename "$old" "$name"
log_ok "remote $old renamed to $name -> $url" git remote set-url "$name" "$url"
return 0 log_ok "remote $old renamed to $name -> $url"
fi return 0
done fi
done
fi
git remote add "$name" "$url" git remote add "$name" "$url"
log_ok "remote $name added -> $url" log_ok "remote $name added -> $url"
View File
View File
+68 -30
View File
@@ -1,5 +1,6 @@
#!/usr/bin/env bash #!/usr/bin/env bash
# Генерирует SSH-ключи и ~/.ssh/config для Git-хостов из local/git-ssh-hosts.conf. # Генерирует SSH-ключи и ~/.ssh/config для Git-хостов из local/git-ssh-hosts.conf.
# Совместим с macOS bash 3.2 (без declare -A).
set -euo pipefail set -euo pipefail
CONFIG_DIR="${CONFIG_DIR:-$HOME/CursorRules/local}" CONFIG_DIR="${CONFIG_DIR:-$HOME/CursorRules/local}"
@@ -10,6 +11,28 @@ log_step() { printf '[*] %s\n' "$1"; }
log_ok() { printf '[+] %s\n' "$1"; } log_ok() { printf '[+] %s\n' "$1"; }
log_warn() { 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 if [[ ! -f "$HOSTS_CONFIG" ]]; then
echo "Config not found: $HOSTS_CONFIG" >&2 echo "Config not found: $HOSTS_CONFIG" >&2
exit 1 exit 1
@@ -20,9 +43,8 @@ SSH_CONFIG="$SSH_DIR/config"
mkdir -p "$SSH_DIR" mkdir -p "$SSH_DIR"
chmod 700 "$SSH_DIR" chmod 700 "$SSH_DIR"
declare -A PROFILE_KEYNAME PROFILE_COMMENT PROFILE_GITEA PROFILE_LIST=()
declare -A HOST_HOSTNAME HOST_PORT HOST_USER HOST_PROFILE HOST_LIST=()
current_section='' current_section=''
current_name='' current_name=''
@@ -34,12 +56,14 @@ while IFS= read -r line || [[ -n "$line" ]]; do
if [[ "$line" =~ ^\[profile:(.+)\]$ ]]; then if [[ "$line" =~ ^\[profile:(.+)\]$ ]]; then
current_section='profile' current_section='profile'
current_name="${BASH_REMATCH[1]}" current_name="${BASH_REMATCH[1]}"
PROFILE_LIST+=("$current_name")
continue continue
fi fi
if [[ "$line" =~ ^\[host:(.+)\]$ ]]; then if [[ "$line" =~ ^\[host:(.+)\]$ ]]; then
current_section='host' current_section='host'
current_name="${BASH_REMATCH[1]}" current_name="${BASH_REMATCH[1]}"
HOST_HOSTNAME["$current_name"]='' HOST_LIST+=("$current_name")
set_host_field "$current_name" HostName ''
continue continue
fi fi
if [[ "$line" != *=* ]]; then if [[ "$line" != *=* ]]; then
@@ -53,29 +77,31 @@ while IFS= read -r line || [[ -n "$line" ]]; do
if [[ "$current_section" == 'profile' ]]; then if [[ "$current_section" == 'profile' ]]; then
case "$key" in case "$key" in
KeyName) PROFILE_KEYNAME["$current_name"]="$value" ;; KeyName|KeyComment|GiteaConfig) set_profile_field "$current_name" "$key" "$value" ;;
KeyComment) PROFILE_COMMENT["$current_name"]="$value" ;;
GiteaConfig) PROFILE_GITEA["$current_name"]="$value" ;;
esac esac
elif [[ "$current_section" == 'host' ]]; then elif [[ "$current_section" == 'host' ]]; then
case "$key" in case "$key" in
HostName) HOST_HOSTNAME["$current_name"]="$value" ;; HostName|Port|User|Profile) set_host_field "$current_name" "$key" "$value" ;;
Port) HOST_PORT["$current_name"]="$value" ;;
User) HOST_USER["$current_name"]="$value" ;;
Profile) HOST_PROFILE["$current_name"]="$value" ;;
esac esac
fi fi
done < "$HOSTS_CONFIG" done < "$HOSTS_CONFIG"
declare -A SEEN_KEYS KEYS_SEEN=()
for profile in "${!PROFILE_KEYNAME[@]}"; do for profile in "${PROFILE_LIST[@]}"; do
key_name="${PROFILE_KEYNAME[$profile]}" key_name="$(get_profile_field "$profile" KeyName)"
[[ -z "$key_name" || -n "${SEEN_KEYS[$key_name]:-}" ]] && continue [[ -z "$key_name" ]] && continue
SEEN_KEYS["$key_name"]=1
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" key_path="$SSH_DIR/$key_name"
comment="${PROFILE_COMMENT[$profile]:-$key_name}" comment="$(get_profile_field "$profile" KeyComment)"
comment="${comment:-$key_name}"
if [[ ! -f "$key_path" ]]; then if [[ ! -f "$key_path" ]]; then
log_step "Generating $key_name" log_step "Generating $key_name"
@@ -96,25 +122,33 @@ update_ssh_block() {
local block="$2" local block="$2"
local begin="# BEGIN Setup-SshAccess:$host_alias" local begin="# BEGIN Setup-SshAccess:$host_alias"
local end="# END Setup-SshAccess:$host_alias" local end="# END Setup-SshAccess:$host_alias"
local tmp local tmp block_file
tmp="$(mktemp)" tmp="$(mktemp)"
block_file="$(mktemp)"
printf '%s\n' "$block" > "$block_file"
if [[ -f "$SSH_CONFIG" ]]; then if [[ -f "$SSH_CONFIG" ]]; then
awk -v begin="$begin" -v end="$end" -v block="$block" ' awk -v begin="$begin" -v end="$end" -v blockfile="$block_file" '
$0 == begin { skip=1; next } $0 == begin { skip=1; next }
$0 == end { skip=0; next } $0 == end { skip=0; next }
skip { next } skip { next }
{ print } { print }
END { END {
if (block != "") { if (blockfile != "") {
print block while ((getline line < blockfile) > 0) {
print line
}
close(blockfile)
} }
} }
' block="$block" "$SSH_CONFIG" > "$tmp" ' "$SSH_CONFIG" > "$tmp"
else else
printf '%s\n' "$block" > "$tmp" cp "$block_file" "$tmp"
fi fi
rm -f "$block_file"
if [[ "$WHAT_IF" != '1' ]]; then if [[ "$WHAT_IF" != '1' ]]; then
mv "$tmp" "$SSH_CONFIG" mv "$tmp" "$SSH_CONFIG"
chmod 600 "$SSH_CONFIG" chmod 600 "$SSH_CONFIG"
@@ -123,9 +157,13 @@ update_ssh_block() {
fi fi
} }
for host_alias in $(printf '%s\n' "${!HOST_HOSTNAME[@]}" | sort); do IFS=$'\n'
profile="${HOST_PROFILE[$host_alias]:-}" sorted_hosts=($(printf '%s\n' "${HOST_LIST[@]}" | sort))
key_name="${PROFILE_KEYNAME[$profile]:-}" 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 if [[ -z "$profile" || -z "$key_name" ]]; then
echo "Host $host_alias: unknown profile" >&2 echo "Host $host_alias: unknown profile" >&2
exit 1 exit 1
@@ -133,9 +171,9 @@ for host_alias in $(printf '%s\n' "${!HOST_HOSTNAME[@]}" | sort); do
block="# BEGIN Setup-SshAccess:$host_alias block="# BEGIN Setup-SshAccess:$host_alias
Host $host_alias Host $host_alias
HostName ${HOST_HOSTNAME[$host_alias]} HostName $(get_host_field "$host_alias" HostName)
User ${HOST_USER[$host_alias]} User $(get_host_field "$host_alias" User)
Port ${HOST_PORT[$host_alias]} Port $(get_host_field "$host_alias" Port)
IdentityFile ~/.ssh/$key_name IdentityFile ~/.ssh/$key_name
IdentitiesOnly yes IdentitiesOnly yes
AddKeysToAgent yes AddKeysToAgent yes
@@ -152,7 +190,7 @@ done
if [[ "$WHAT_IF" != '1' ]]; then if [[ "$WHAT_IF" != '1' ]]; then
eval "$(ssh-agent -s)" >/dev/null eval "$(ssh-agent -s)" >/dev/null
for key_name in "${!SEEN_KEYS[@]}"; do for key_name in "${KEYS_SEEN[@]:-}"; do
[[ -f "$SSH_DIR/$key_name" ]] && ssh-add "$SSH_DIR/$key_name" >/dev/null 2>&1 || true [[ -f "$SSH_DIR/$key_name" ]] && ssh-add "$SSH_DIR/$key_name" >/dev/null 2>&1 || true
done done
fi fi