Rewrite setup.sh to use an allowlist instead of a denylist for linking config files

This commit is contained in:
Eryn Wells 2026-02-07 18:41:56 -08:00
parent 6721b754a2
commit d7b3e73e66

220
setup.sh
View file

@ -3,171 +3,141 @@
dotfiles_dir=$(cd "$(dirname "$0")" && pwd) dotfiles_dir=$(cd "$(dirname "$0")" && pwd)
sys=`uname -s | tr A-Z a-z` sys=`uname -s | tr A-Z a-z`
skipitems=( \ items=( \
'.*\.orig' \ emacs .config/emacs \
'.*~' \ fish .config/fish \
Alfred \ git .config/git \
Ansible \ hgrc .hgrc
bin \ mutt .config/mutt \
Colors \ nethackrc .nethackrc \
Dotfiles \ nvim .config/nvim \
Fortune \ tmux .config/tmux \
LaunchAgents \ vim .config/vim \
py \ zsh/zprofile .zprofile \
Python \ zsh/zshenv .zshenv \
README.md \ zsh/zshrc .zshrc \
setup.sh \
Web \
Xcode \
) )
function link { function print-heading
local action {
local dest print -P "%B==>%b $@"
if [[ -z $2 ]]; then
local dotfile_basename=`basename "$1"`
dest="$HOME/.$dotfile_basename"
else
dest="$2"
fi
if [[ ! -e "$dest" ]]; then
action='Linking'
ln -fs "$1" "$dest"
else
action='Skipping'
fi
printf " %8s: %s\n" $action "$dest"
} }
function matches_skip_item { # link --
local string_to_match=$1 #
# Link a source file (in the repo) to a destination path in the user's home
# directory. If the file already exists AND it's a symlink AND it points to the
# source path, it will be skipped.
#
# Arguments:
# $1 : a "source" path to a file, relative to the dotfiles repo root
# $2 : a "destination" path, relative to the user's home directory
#
# Returns: 0 if the dotfile was installed, 1 otherwise
function link
{
local src="$dotfiles_dir/$1"
local dst="$HOME/$2"
for item in $skipitems; do local should_install=1
if [[ $string_to_match =~ $item ]]; then if [[ -e "$dst" ]]; then
return 0 if [[ -h "$dst" ]]; then
local link_target=$(readlink "$dst")
if [[ "$link_target" == "$src" ]]; then
should_install=0
fi fi
done elif [[ -f "$dst" ]]; then
should_install=0
else
echo "$dst is not a regular file or symbolic link"
return 1 return 1
fi
fi
if (( $should_install )); then
print "Link $dst"
install -ls "$src" "$dst"
return 0
else
print "Skip $dst"
return 1
fi
} }
function build_fortunes { function build_fortunes {
echo "Building fortunes file" print-heading Building fortunes file
(cd Fortune && make) (cd Fortune && make)
} }
print -P " %BHome:%b $HOME" print -P " %BHome:%b $HOME"
print -P " %BDotfiles:%b $dotfiles_dir" print -P " %BDotfiles:%b $dotfiles_dir\n"
print -P "%BSkip Items:%b $skipitems\n"
print -P "%BRemoving stray dotfile symlinks from $HOME%b" print-heading Symlinking config files
local link_dest
local link_dirname
local did_remove_at_least_one_symlink=0
for file in ~/.?*; do
link_dest=`readlink "$file"`
if [[ $? -ne 0 ]]; then
# Not a symlink.
continue
fi
link_dirname=`dirname "$link_dest"`
if [[ "$link_dirname" != "$dotfiles_dir" ]]; then
continue
fi
if ! matches_skip_item `basename "$link_dest"`; then
if [[ -e "$link_dest" ]]; then
continue
fi
fi
printf " Removing: %s\n" "$file"
rm "$file"
did_remove_at_least_one_symlink=1
done
if [[ $did_remove_at_least_one_symlink -ne 1 ]]; then
print " Nothing to remove"
fi
print -P "%BSymlinking config files%b"
local did_link_at_least_one_dotfile=0 local did_link_at_least_one_dotfile=0
for dotfile in $dotfiles_dir/*; do for (( idx = 1; idx <= $#items; idx += 2 )); do
local dotfile_basename=`basename "$dotfile"` local dotfile=$items[$idx]
local dest=$items[$idx+1]
if matches_skip_item "$dotfile_basename"; then
continue
fi
if [[ "$dotfile_basename" == "config" ]]; then
# Recurse into config and link each item individually
mkdir -p "$HOME/.config"
for config_dotfile in $dotfiles_dir/config/*; do
config_dotfile_basename=`basename "$config_dotfile"`
link "$config_dotfile" "$HOME/.config/$config_dotfile_basename"
done
else
link "$dotfile"
fi
if link "$dotfile" "$dest"; then
did_link_at_least_one_dotfile=1 did_link_at_least_one_dotfile=1
fi
done done
if [[ ! -f "$HOME/.hushlogin" ]]; then
print " touch $HOME/.hushlogin"
touch "$HOME/.hushlogin"
did_link_at_least_one_dotfile=1
fi
if [[ $did_link_at_least_one_dotfile -ne 1 ]]; then
print " Nothing to link"
fi
local configure_vim=1 local configure_vim=1
while getopts "v" arg $@; do local hush_login=0
while getopts "vl" arg $@; do
case $arg in case $arg in
"v") configure_vim=1 ;; "v") configure_vim=1 ;;
"+v") configure_vim=0 ;; "+v") configure_vim=0 ;;
"l") hush_login=1 ;;
"+l") hush_login=0 ;;
*) *)
echo "Usage: setup.sh [+v|-v]" local script_name=$(basename $0)
echo " +v|-v Configure (Neo)vim. Default yes; +v skips." echo "Usage: $script_name [+l|-l] [+v|-v]"
echo " +l|-l Tell the shell not to print last login information. (default: no)"
echo " +v|-v Install (neo)vim plugins. (default: yes)"
exit 1
;; ;;
esac esac
done done
print "Creating Python virtual environment" if (( $hush_login )); then
local venv_path=~/.local/share/python-virtual-environments/eryn if [[ ! -a "$HOME/.hushlogin" ]]; then
python3 -m venv --system-site-packages "$venv_path" print " touch $HOME/.hushlogin"
"$venv_path/bin/pip" install "$dotfiles_dir/Python/eryntools" touch "$HOME/.hushlogin"
fi
fi
local venv_path="${XDG_DATA_HOME:-$HOME/.local/share}/python-virtual-environments/eryn"
if [[ ! -d "$venv_path" ]]; then
print-heading "Creating Python virtual environment"
python3 -m venv --system-site-packages "$venv_path"
"$venv_path/bin/pip" install "$dotfiles_dir/Python/eryntools"
fi
if (( $configure_vim )); then if (( $configure_vim )); then
print -P "%BConfiguring Vim%b" print-heading Configuring neovim and vim
VIM=nvim print-heading "Downloading vim-plug from Github"
if ! whence -cp nvim >& -; then
VIM=vim
fi
if [[ $VIM = "nvim" ]]; then local tmp_file="/tmp/vim-plug.vim"
print -P " Downloading vim-plug from Github"
curl --create-dirs -fL \ curl --create-dirs -fL \
-o "${XDG_DATA_HOME:-$HOME/.local/share}/nvim/site/autoload/plug.vim" \ -o "$tmp_file" \
"https://raw.githubusercontent.com/junegunn/vim-plug/master/plug.vim" \ "https://raw.githubusercontent.com/junegunn/vim-plug/master/plug.vim" \
1>/dev/null 1>/dev/null
if whence -cp python3 >& -; then # nvim
print -P " Installing pynvim" install -m 0644 "$tmp_file" "${XDG_DATA_HOME:-$HOME/.local/share}/nvim/site/autoload/plug.vim"
python3 -m pip install --user --upgrade pynvim 1>/dev/null # vim
fi install -m 0644 "$tmp_file" "${XDG_CONFIG_HOME:-$HOME/.config}/vim/autoload/plug.vim"
if whence -cp python3 >/dev/null; then
print-heading "Installing Python modules for vim and nvim"
python3 -m pip install --user --upgrade pynvim pyvim
fi fi
$VIM +PlugInstall +qall command nvim +PlugInstall +qall
fi fi
build_fortunes build_fortunes
exit 0