-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathsetup_link.sh
More file actions
executable file
·179 lines (158 loc) · 6.53 KB
/
Copy pathsetup_link.sh
File metadata and controls
executable file
·179 lines (158 loc) · 6.53 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
#!/bin/bash
# --- output helpers -------------------------------------------------
if [[ -t 1 ]]; then
C_RESET=$'\e[0m'; C_BLUE=$'\e[1;34m'; C_GREEN=$'\e[32m'
C_YELLOW=$'\e[33m'; C_RED=$'\e[1;31m'; C_DIM=$'\e[2m'
fi
step() { printf '%s\n' "${C_BLUE}▶ $*${C_RESET}"; } # action in progress
ok() { printf '%s\n' "${C_GREEN}✓ $*${C_RESET}"; } # done / success
skip() { printf '%s\n' "${C_DIM}• $*${C_RESET}"; } # nothing to do
warn() { printf '%s\n' "${C_YELLOW}⚠ $*${C_RESET}"; }
err() { printf '%s\n' "${C_RED}✗ $*${C_RESET}"; }
OS=$(uname -s)
step "Detected OS: $OS"
DOTFILES_DIR="$HOME/.dotfiles"
# Machine-local files (gitignored) must exist in-repo before linking them out.
# Pull a pre-existing real ~/<file> into the repo so its content is preserved.
migrate_local() {
[[ ! -e "$DOTFILES_DIR/$1" && -f "$HOME/$1" && ! -L "$HOME/$1" ]] && mv "$HOME/$1" "$DOTFILES_DIR/$1"
}
migrate_local .zshrc.local
migrate_local .gitconfig.local
# .gitconfig.local is required (git identity), so seed a placeholder if still absent.
GITCONFIG_LOCAL_SEEDED=false
if [[ ! -e "$DOTFILES_DIR/.gitconfig.local" ]]; then
printf '[user]\n name = Your Name\n email = you@example.com\n' > "$DOTFILES_DIR/.gitconfig.local"
GITCONFIG_LOCAL_SEEDED=true
fi
declare -A FILES_TO_LINK
declare -A NEW_FILES_TO_LINK
if [[ "$OS" == "Darwin" ]]; then # macOS
FILES_TO_LINK=(
[".zshrc"]="$HOME/.zshrc"
[".zshrc.local"]="$HOME/.zshrc.local"
[".p10k.zsh"]="$HOME/.p10k.zsh"
[".tmux.conf"]="$HOME/.tmux.conf"
# [".wezterm.lua"]="$HOME/.wezterm.lua"
[".config/ghostty/config"]="$HOME/.config/ghostty/config"
[".hammerspoon"]="$HOME/.hammerspoon"
["nvim"]="$HOME/.config/nvim"
[".config/stylua.toml"]="$HOME/.config/stylua.toml"
[".config/pylintrc"]="$HOME/.config/pylintrc"
[".config/black/pyproject.toml"]="$HOME/.config/black/pyproject.toml"
[".config/marksman/config.toml"]="$HOME/.config/marksman/config.toml"
[".config/latexmk/latexmkrc"]="$HOME/.config/latexmk/latexmkrc"
[".config/yamllint/config"]="$HOME/.config/yamllint/config"
[".config/.gemini/settings.json"]="$HOME/.gemini/settings.json"
[".prettierrc"]="$HOME/.prettierrc"
["eslint.config.mjs"]="$HOME/eslint.config.mjs"
[".gitconfig"]="$HOME/.gitconfig"
[".gitignore_global"]="$HOME/.gitignore_global"
[".gitconfig.local"]="$HOME/.gitconfig.local"
[".config/lazygit/config.yml"]="$HOME/Library/Application Support/lazygit/config.yml"
)
elif [[ "$OS" == "Linux" ]]; then # Linux
FILES_TO_LINK=(
[".zshrc"]="$HOME/.zshrc"
[".zshrc.local"]="$HOME/.zshrc.local"
[".p10k.zsh"]="$HOME/.p10k.zsh"
[".tmux.conf"]="$HOME/.tmux.conf"
# [".wezterm.lua"]="$HOME/.wezterm.lua"
[".config/ghostty/config"]="$HOME/.config/ghostty/config"
["nvim"]="$HOME/.config/nvim"
[".config/stylua.toml"]="$HOME/.config/stylua.toml"
[".config/pylintrc"]="$HOME/.config/pylintrc"
[".config/black/pyproject.toml"]="$HOME/.config/black/pyproject.toml"
[".config/marksman/config.toml"]="$HOME/.config/marksman/config.toml"
[".config/latexmk/latexmkrc"]="$HOME/.config/latexmk/latexmkrc"
[".config/yamllint/config"]="$HOME/.config/yamllint/config"
[".config/.gemini/settings.json"]="$HOME/.gemini/settings.json"
[".prettierrc"]="$HOME/.prettierrc"
["eslint.config.mjs"]="$HOME/eslint.config.mjs"
[".gitconfig"]="$HOME/.gitconfig"
[".gitignore_global"]="$HOME/.gitignore_global"
[".gitconfig.local"]="$HOME/.gitconfig.local"
[".config/lazygit/config.yml"]="$HOME/.config/lazygit/config.yml"
)
else
err "Unsupported OS: $OS"
exit 1
fi
LINK_WIDTH=0
for file in "${!FILES_TO_LINK[@]}"; do
l="${FILES_TO_LINK[$file]}"
(( ${#l} > LINK_WIDTH )) && LINK_WIDTH=${#l}
done
link_line() { # green check, aligned link, dim arrow + target
printf ' %s✓%s %-*s %s→ %s%s\n' \
"$C_GREEN" "$C_RESET" "$LINK_WIDTH" "$1" "$C_DIM" "$2" "$C_RESET"
}
OVERWRITE_LINKS=()
NEW_LINKS=()
step "Checking existing links"
for file in "${!FILES_TO_LINK[@]}"; do
target="${DOTFILES_DIR}/$file"
link="${FILES_TO_LINK[$file]}"
if [[ ! -e "$target" ]]; then
warn "Target '$target' does not exist, skipping"
continue
fi
if [[ -e "$link" || -L "$link" ]]; then
OVERWRITE_LINKS+=("$(printf '%-*s|%s' "$LINK_WIDTH" "$link" "$target")")
else
NEW_LINKS+=("$(printf '%-*s|%s' "$LINK_WIDTH" "$link" "$target")")
NEW_FILES_TO_LINK+=( ["$file"]=${FILES_TO_LINK["$file"]} )
fi
done
print_pending() { # dim bullet, link | target
local link="${1%%|*}" target="${1##*|}"
printf ' %s• %s → %s%s\n' "$C_DIM" "$link" "$target" "$C_RESET"
}
if [[ ${#OVERWRITE_LINKS[@]} -eq 0 ]]; then
skip "No existing links to overwrite"
else
warn "These links already exist and will be overwritten:"
for item in "${OVERWRITE_LINKS[@]}"; do print_pending "$item"; done
printf '%sOverwrite all these links? (y/n): %s' "$C_YELLOW" "$C_RESET"
read -r answer
if [[ "$answer" != "y" ]]; then
if [[ ${#NEW_LINKS[@]} -eq 0 ]]; then
skip "No new links need to be established"
ok "No change being made!"
exit 0
else
step "These are new links and will be added:"
for item in "${NEW_LINKS[@]}"; do print_pending "$item"; done
printf '%sAdd all these links? (y/n): %s' "$C_YELLOW" "$C_RESET"
read -r ans
if [[ "$ans" != "y" ]]; then
ok "No change being made!"
exit 0
else
FILES_TO_LINK=()
for key in "${!NEW_FILES_TO_LINK[@]}"; do
FILES_TO_LINK["$key"]="${NEW_FILES_TO_LINK["$key"]}"
done
fi
fi
fi
fi
step "Creating symbolic links"
for file in "${!FILES_TO_LINK[@]}"; do
target="${DOTFILES_DIR}/$file"
link="${FILES_TO_LINK[$file]}"
[[ -e "$target" ]] || continue
link_dir=$(dirname "$link")
mkdir -p "$link_dir"
if [[ -d "$link" && ! -L "$link" ]]; then
warn "Removing existing directory: $link"
rm -rf "$link"
fi
ln -sfn "$target" "$link"
link_line "$link" "$target"
done
ok "All symbolic links created"
if [[ "$GITCONFIG_LOCAL_SEEDED" == true ]]; then
warn "Seeded .gitconfig.local with a placeholder identity"
warn "→ Set your git identity before committing: edit ~/.dotfiles/.gitconfig.local (name & email)"
fi