With the color definitions being in profile, non-login shells don't get the definitions. So out they go back to their own file.
239 lines
6.6 KiB
Bash
Executable file
239 lines
6.6 KiB
Bash
Executable file
#!/bin/sh
|
|
set -eu
|
|
|
|
usage() {
|
|
echo "Usage: $(basename $0) [-h] [-f]"
|
|
echo ""
|
|
echo " -h print this help and exit"
|
|
echo " -f modify filesystem rather than dry run"
|
|
}
|
|
|
|
DRY_RUN=true
|
|
while getopts 'fh' opt; do case "$opt" in
|
|
f) DRY_RUN=false;;
|
|
h) usage; exit 0;;
|
|
*) usage; exit 1;;
|
|
esac done
|
|
|
|
DEFAULT_GIT_USER="Fernando Schauenburg"
|
|
DEFAULT_GIT_EMAIL="fernando@schauenburg.me"
|
|
|
|
XDG_CACHE_HOME="${XDG_CACHE_HOME:-$HOME/.cache}"
|
|
XDG_CONFIG_HOME="${XDG_CONFIG_HOME:-$HOME/.config}"
|
|
XDG_DATA_HOME="${XDG_DATA_HOME:-$HOME/.local/share}"
|
|
|
|
DOTFILES_DIR="$(dirname "$(realpath "$0")")"
|
|
|
|
DIRS=$(cat <<EOF
|
|
${HOME}/.local/bin
|
|
${HOME}/.local/etc/git
|
|
${HOME}/.jupyter/custom
|
|
${HOME}/.jupyter/nbconfig
|
|
${HOME}/.ssh
|
|
${XDG_CONFIG_HOME}/alacritty
|
|
${XDG_CONFIG_HOME}/git
|
|
${XDG_CONFIG_HOME}/mintty
|
|
${XDG_CONFIG_HOME}/python
|
|
${XDG_CONFIG_HOME}/readline
|
|
${XDG_CONFIG_HOME}/tmux
|
|
${XDG_CONFIG_HOME}/nvim
|
|
${XDG_CONFIG_HOME}/nvim/autoload
|
|
${XDG_CONFIG_HOME}/shell
|
|
${XDG_CONFIG_HOME}/zsh
|
|
${XDG_DATA_HOME}/bash
|
|
${XDG_DATA_HOME}/bash-completion/completions
|
|
${XDG_DATA_HOME}/less
|
|
${XDG_DATA_HOME}/python
|
|
${XDG_DATA_HOME}/nvim
|
|
${XDG_DATA_HOME}/nvim/plugged
|
|
${XDG_DATA_HOME}/nvim/shada
|
|
EOF
|
|
)
|
|
|
|
FILES="$DOTFILES_DIR/files"
|
|
DOTFILES=$(cat <<EOF
|
|
${XDG_CONFIG_HOME}/alacritty/alacritty.yml $FILES/alacritty.yml
|
|
${XDG_CONFIG_HOME}/git/config $FILES/gitconfig
|
|
${XDG_CONFIG_HOME}/git/ignore $FILES/gitignore
|
|
${XDG_CONFIG_HOME}/readline/inputrc $FILES/inputrc
|
|
${XDG_CONFIG_HOME}/mintty/config $FILES/minttyrc
|
|
${XDG_CONFIG_HOME}/nvim/autoload/plug.vim $FILES/plug.vim
|
|
${XDG_CONFIG_HOME}/python/startup.py $FILES/python-startup.py
|
|
${XDG_CONFIG_HOME}/tmux/tmux.conf $FILES/tmux.conf
|
|
${XDG_CONFIG_HOME}/nvim/init.vim $FILES/init.vim
|
|
${XDG_CONFIG_HOME}/shell/aliases $FILES/aliases.sh
|
|
${XDG_CONFIG_HOME}/shell/profile $FILES/profile.sh
|
|
${XDG_CONFIG_HOME}/shell/solarized $FILES/solarized.sh
|
|
${XDG_CONFIG_HOME}/zsh/.zshrc $FILES/zshrc
|
|
${HOME}/.XCompose $FILES/xcompose
|
|
${HOME}/.bashrc $FILES/bashrc
|
|
${HOME}/.bash_profile $FILES/bash_profile
|
|
${HOME}/.jupyter/custom/custom.js $FILES/jupyter_custom.js
|
|
${HOME}/.jupyter/nbconfig/notebook.json $FILES/jupyter_notebook.json
|
|
${HOME}/.zprofile ${XDG_CONFIG_HOME}/shell/profile
|
|
${HOME}/.ssh/config $FILES/ssh_config
|
|
EOF
|
|
)
|
|
|
|
rst=$(tput sgr0)
|
|
red=$(tput setaf 1)
|
|
green=$(tput setaf 2)
|
|
yellow=$(tput setaf 3)
|
|
blue=$(tput setaf 4)
|
|
|
|
heading() { printf '%s\n' "${blue}===== $1 ==========${rst}"; }
|
|
info() { printf '%s\n' "${green}${1}${rst}"; }
|
|
warn() { printf '%s\n' "${yellow}${1}${rst}"; }
|
|
error() { printf '%s\n' "${red}${1}${rst}"; }
|
|
|
|
directory_present() { # Make sure directory $1 exists.
|
|
if [ -d "$1" ]; then
|
|
info "OK: $1"
|
|
else
|
|
warn "creating $1"
|
|
$DRY_RUN || mkdir -p "$1"
|
|
fi
|
|
}
|
|
|
|
file_absent() { # Make sure file $1 does not exist.
|
|
if [ ! -f "$1" ]; then
|
|
info "OK: $1"
|
|
else
|
|
warn "removing $1"
|
|
$DRY_RUN || rm "$1"
|
|
fi
|
|
}
|
|
|
|
file_touch() { # Make sure file $1 exists (content is irrelevant).
|
|
if [ -f "$1" ]; then
|
|
info "OK: $1"
|
|
else
|
|
warn "creating $1"
|
|
$DRY_RUN || touch "$1"
|
|
fi
|
|
}
|
|
|
|
prune_link() { # Remove $1 if it's a broken link to a dotfile script.
|
|
if [ -h "$1" ]; then # it's a symbolic link
|
|
target="$(readlink "$1")"
|
|
case "$target" in
|
|
"$DOTFILES_DIR/bin/"*) # it points into dotfiles bin
|
|
if [ ! -e "$1" ]; then # target of the link missing
|
|
warn "pruning $1 -> $target"
|
|
$DRY_RUN || rm -f "$1"
|
|
fi
|
|
;;
|
|
esac
|
|
fi
|
|
}
|
|
|
|
file_link() { # Make sure $1 is a link to $2.
|
|
target="$(realpath -s "$2")"
|
|
if [ "$(readlink "$1")" = "$target" ]; then
|
|
info "OK: $1"
|
|
else
|
|
warn "linking $1 -> $target"
|
|
$DRY_RUN || ln -sf "$target" "$1"
|
|
fi
|
|
}
|
|
|
|
file_content() { # Ensure $1 and $2 contents are equal, updating $1 if needed.
|
|
if diff "$1" "$2" >/dev/null 2>&1; then
|
|
info "OK: $1"
|
|
else
|
|
warn "overwriting $1 with $2:"
|
|
cat "$2"
|
|
$DRY_RUN || cp -f "$2" "$1"
|
|
fi
|
|
}
|
|
|
|
task_gather_user_info() {
|
|
heading "Gather user information"
|
|
printf 'git name [%s]: ' "$DEFAULT_GIT_USER"
|
|
read -r git_user
|
|
printf 'git e-mail [%s]: ' "$DEFAULT_GIT_EMAIL"
|
|
read -r git_email
|
|
}
|
|
|
|
task_remove_bash_profile() {
|
|
heading "Remove pre-installed bash profile"
|
|
for f in .bash_logout .profile; do
|
|
file_absent "$HOME/$f"
|
|
done
|
|
}
|
|
|
|
task_ensure_directories() {
|
|
heading "Ensure existence of directories used by dotfiles"
|
|
echo "$DIRS" | while read -r d; do directory_present "$d"; done
|
|
}
|
|
|
|
task_link_dotfiles() {
|
|
heading "Link dotfiles"
|
|
echo "$DOTFILES" | while read -r src dest; do
|
|
file_link "$src" "$dest"
|
|
done
|
|
}
|
|
|
|
task_deploy_templates() {
|
|
heading "Deploy templates"
|
|
temp_git="$(mktemp)"
|
|
cat >"$temp_git" <<EOF
|
|
# *************************************
|
|
# * DO NOT EDIT THIS FILE *
|
|
# *************************************
|
|
#
|
|
# This file was generated by the bootstrap script and any changes will be
|
|
# overwritten the next time it is run. For local settings, use this instead:
|
|
#
|
|
# ~/.local/etc/git/config
|
|
#
|
|
EOF
|
|
git config -f "$temp_git" user.name "${git_user:-$DEFAULT_GIT_USER}"
|
|
git config -f "$temp_git" user.email "${git_email:-$DEFAULT_GIT_EMAIL}"
|
|
file_content "$HOME/.local/etc/git/config.host" "$temp_git"
|
|
}
|
|
|
|
task_prune_broken_bin() {
|
|
heading "Prune broken links to commands"
|
|
for cmd in $HOME/.local/bin/*; do
|
|
prune_link "$cmd"
|
|
done
|
|
}
|
|
|
|
task_link_local_bin() {
|
|
heading "Link local commands"
|
|
for cmd in "$DOTFILES_DIR/bin/"*; do
|
|
file_link "$HOME/.local/bin/$(basename "$cmd")" "$cmd"
|
|
done
|
|
}
|
|
|
|
task_make_logins_silent() {
|
|
heading "Make logins silent"
|
|
file_touch "$HOME/.hushlogin"
|
|
}
|
|
|
|
task_install_nvim_plugins() {
|
|
heading "Install neovim plugins"
|
|
if command -v nvim >/dev/null 2>&1; then
|
|
warn "Installing neovim plugins"
|
|
$DRY_RUN || nvim -nes -u "$XDG_CONFIG_HOME/nvim/init.vim" -c 'PlugInstall | qall!'
|
|
else
|
|
error "neovim is not installed; skipping plugin installation..."
|
|
fi
|
|
}
|
|
|
|
main() {
|
|
$DRY_RUN && warn "Dry run: no changes will actually be made."
|
|
task_gather_user_info
|
|
task_remove_bash_profile
|
|
task_ensure_directories
|
|
task_link_dotfiles
|
|
task_deploy_templates
|
|
task_prune_broken_bin
|
|
task_link_local_bin
|
|
task_make_logins_silent
|
|
task_install_nvim_plugins
|
|
}
|
|
|
|
main
|
|
|