dotfiles/install.sh

350 lines
10 KiB
Bash
Raw Permalink Normal View History

2023-12-23 20:13:47 -07:00
#!/usr/bin/env bash
declare MODE=""
declare -r UNIX_CONFIGS=(\
# Shell
bash/.profile ~/.profile
bash/.inputrc ~/.inputrc
bash/.bashrc ~/.bashrc
bash/.bash_profile ~/.bash_profile
bash/.bash_env ~/.bash_env
bash/.bash_prompt ~/.bash_prompt
bash/.bash_aliases ~/.bash_aliases
bash/.bash_functions ~/.bash_functions
aerc ~/.config/aerc
alacritty ~/.config/alacritty
git/.gitignore_global ~/.gitignore_global
gnupg/gpg-agent.conf ~/.gnupg/gpg-agent.conf
mako ~/.config/mako
mpv ~/.config/mpv
chromium/chromium-flags.conf ~/.config/chromium-flags.conf
2023-12-23 20:14:04 -07:00
chromium/electron-flags.conf ~/.config/electron-flags.conf
2023-12-23 20:13:47 -07:00
ripgrep ~/.config/ripgrep
swappy ~/.config/swappy
tmux ~/.config/tmux
vifm ~/.config/vifm
vimiv ~/.config/vimiv
warpd ~/.config/warpd
# Vim and Neovim
vim/.vim ~/.vim
vim/.vimrc ~/.vimrc
vim/nvim ~/.config/nvim
vim/.vim/plugin ~/.config/nvim/plugin
vim/.vim/colors ~/.config/nvim/colors
) \
LINUX_ONLY=(\
# Swayland
2023-12-23 20:14:15 -07:00
i3 ~/.config/i3
2024-04-30 23:43:49 -06:00
kanshi ~/.config/kanshi
2023-12-23 20:13:47 -07:00
sway ~/.config/sway
swaylock ~/.config/swaylock
xremap ~/.config/xremap
yofi ~/.config/yofi
) \
MAC_ONLY=(\
skhd ~/.config/skhd
yabai ~/.config/yabai
sketchybar ~/.config/sketchybar
skhd/com.skhd.launcher.plist ~/Library/LaunchAgents/com.skhd.launcher.plist
sketchybar/com.sketchybar.launcher.plist ~/Library/LaunchAgents/com.sketchybar.launcher.plist
warpd/com.warpd.launcher.plist ~/Library/LaunchAgents/com.warpd.launcher.plist
other/vlcrc ~/Library/Preferences/org.videolan.vlc/vlcrc
)
print_help() {
cat <<HELP
Install or query config files
ARGS:
mode: One of "status", "install"
FLAGS:
-s, --silent Silences printout for properly installed configs
-b, --basename Printout includes basename of file for properly installed configs
-h, --help Print this menu and exit
USAGE:
./install.sh [flags] <mode>
bash install.sh [flags] <mode>
HELP
}
main() {
# Verify we're in the right directory ====
if [[ "$(is_configs_directory)" != "true" ]]; then
printf 'Please move to the top level git directory with this script\n'
printf 'Aborting...\n'
exit 1
fi
# Verify or install ~/.configs_pointer ====
local configs_pointer="$(configs_pointer_is_setup)"
if [[ "${configs_pointer}" != "valid" ]]; then
if [[ "${configs_pointer}" == "does not exist" ]]; then
if ! ln -s "$PWD" ~/.configs_pointer; then
printf 'Failed to link present directory to ~/.config_pointer\n'
printf 'Aborting...\n'
exit 1
fi
else
printf '~/.configs_pointer does not point to this directory\n'
printf 'Remove ~/.configs_pointer and rerun this script\n'
printf 'Aborting...\n'
exit 1
fi
fi
# Default is status
if [[ $# -eq 0 ]]; then
iterate_over_configs 'status'
exit 0
fi
# Parse arguments ====
while [[ $# -gt 0 ]]
do
case "$1" in
-s | --silent) MODE="${MODE} silent" ;;
-b | --basename) MODE="${MODE} basename" ;;
-h | --help) MODE="${MODE} help" ;;
status) MODE="${MODE} status" ;;
install) MODE="${MODE} install" ;;
*)
printf 'Invalid argument: "%s"\n' "$1"
print_help
exit 1
;;
esac
shift
done
# Run ====
if [[ "${MODE}" =~ "help" ]]; then
print_help
exit 0
elif [[ "${MODE}" =~ "status" ]]; then
iterate_over_configs 'status'
elif [[ "${MODE}" =~ "install" ]]; then
fix_launchd_plists
iterate_over_configs 'install'
create_directory_paths
other_setup
print_install_completion_msg
else
print_help
fi
exit 0
}
#######################################
# Checks if the script is being run from the configs directory.
# Return code:
# 0 if it is the configs directory, 1 otherwise.
# Return string:
# Describes why this likely isn't the configs directory.
#######################################
is_configs_directory() {
if ! [[ -d ./.git ]]; then
printf "Git folder not found in pwd\n"
printf "no .git directory"
return 1
elif ! [[ -x ./install.sh ]]; then
printf "install.sh not found in pwd\n"
printf "file install.sh not in pwd"
return 1
fi
printf "true"
return 0
}
configs_pointer_is_setup() {
if ! [[ -e ~/.configs_pointer ]]; then
printf "does not exist"
return 1
elif ! [[ -L ~/.configs_pointer ]]; then
printf "not a symlink"
return 1
elif ! [[ -x ~/.configs_pointer/install.sh ]]; then
printf "no install.sh at symlink"
return 1
elif ! cmp -s ~/.configs_pointer/install.sh ./install.sh; then
printf "install.sh files differ"
return 1
else
printf "valid"
return 0
fi
}
#######################################
# Return the status of a config.
# Arguments:
# 1: Path in configs directory. "from"
# 2: Path on the system. "to"
#######################################
config_status() {
if [[ "$1" -ef "$2" ]]; then
printf "linked"
return 0
elif [[ -e "$2" ]]; then
printf "conflict"
return 1
elif ! [[ -e "$1" ]]; then
printf "missing"
return 1
else
printf "not_linked"
return 1
fi
}
#╔─────────────────────────────────────────────────────────────────────────────╗
#│ Usεr iητεrfαcε fμηcτiδηs |
#╚─────────────────────────────────────────────────────────────────────────────╝
#######################################
# Prints the status of a config.
# Arguments:
# 1: Status in {"not_linked", "conflict", "linked"}
# 2: System path to config file
# Outputs:
# Writes status to stdout
#######################################
print_config_status() {
if [[ "${MODE}" =~ "basename" ]]; then
local name="$(basename "$2")"
else
local name="$(printf '%s' "$2" | sed 's#'"${HOME}"'#~#')"
fi
if ! [[ "${MODE}" =~ "silent" ]] || [[ "$1" != "linked" ]]; then
case "$1" in
newly_linked)
printf "★ %s :: Newly linked" "${name}" ;;
not_linked) printf "✗ %s :: Not Linked" "${name}" ;;
conflict) printf "≠ %s :: Conflicting file" "${name}" ;;
missing) printf "φ %s :: Missing config file" "${name}" ;;
linked) printf "✓ %s :: Linked" "${name}" ;;
*) printf "? %s :: Status unclear" "${name}" ;;
esac
printf "\n"
fi
}
print_install_completion_msg() {
cat <<END
Dotfile installation complete.
2023-12-23 20:13:47 -07:00
2023-12-23 20:14:22 -07:00
To install packages, run: \`./package_install.py help\`
To check additional options, run: \`./post_install.sh help\`
2023-12-23 20:13:47 -07:00
END
}
#╔─────────────────────────────────────────────────────────────────────────────╗
#│ Cδηfig liηkiηg αrrαys |
#╚─────────────────────────────────────────────────────────────────────────────╝
create_directory_paths() {
local a=(\
~/.config/vifm/fzf-read
~/bin
~/safe
)
if [[ "$(uname -s)" == "Darwin" ]]; then
a=("${a[@]}"
~/Library/KeyBindings
~/Library/Preferences/org.videolan.vlc
)
fi
for d in "${a[@]}"; do
mkdir -p "$d"
done
}
# Launchd plists require absolute paths. To make this portable we bundle a
# .template file which has HOMEPATH in place of absolute paths to $HOME. These
# are replaced at install time to create the .plist.
fix_launchd_plists() {
local a=(
skhd/com.skhd.launcher.plist skhd/com.skhd.launcher.template
sketchybar/com.sketchybar.launcher.plist sketchybar/com.sketchybar.launcher.template
warpd/com.warpd.launcher.plist warpd/com.warpd.launcher.template
)
for ((i = 0; i < "${#a[@]}"; i=(i+2) )); do
local plist="${HOME}/.configs_pointer/${a[$i]}"
local template="${HOME}/.configs_pointer/${a[$i + 1]}"
sed -e 's#HOMEPATH#'"${HOME}"'#g' < "${template}" > "${plist}"
done
}
# Launchd requires an absolute path for sketchbar, which isn't available to brew
other_setup() {
if which sketchybar &>/dev/null && ! [[ -e ~/.configs_pointer/sketchybar/sketchybar ]]; then
ln -s "$(which sketchybar)" ~/.configs_pointer/sketchybar/sketchybar &>/dev/null
fi
}
#######################################
# Prints the status of a config.
# Arguments:
# 1: Path to config file. The "from" path.
# 2: Path to system file. The "to" path.
# Outputs:
# Writes status to stdout
#######################################
install_config() {
local status=$(config_status "$1" "$2")
if [[ "${status}" != "not_linked" ]]; then
printf '%s\n' "${status}"
return 1
fi
[[ -d "$1" ]] || mkdir -p "$(dirname "$2")"
if ln -s "$1" "$2"; then
printf "newly_linked"
return 0
else
return 1
fi
}
# Arguments
# 1: Mode in {"status", "install"}
iterate_over_configs() {
if [[ "$(uname -s)" == "Darwin" ]]; then
local a=("${UNIX_CONFIGS[@]}" "${MAC_ONLY[@]}")
else
local a=("${UNIX_CONFIGS[@]}" "${LINUX_ONLY[@]}")
fi
for ((i = 0; i < "${#a[@]}"; i=(i+2) )); do
local from="${HOME}/.configs_pointer/${a[$i]}"
local to="${a[$i + 1]}"
if [[ "$1" == "status" ]]; then
local status="$(config_status "${from}" "${to}")"
print_config_status "${status}" "${to}"
elif [[ "$1" == "install" ]]; then
local status="$(install_config "${from}" "${to}")"
print_config_status "${status}" "${to}"
else
printf 'Invalid mode "%s" provided\n' "$1"
exit 1
fi
done
}
main "$@"