|
|
|
#!/bin/zsh
|
|
|
|
# .files/install
|
|
|
|
# (c) 2014-2021 MORI Taeyeon
|
|
|
|
|
|
|
|
# Paths & Utils
|
|
|
|
DOT="$(realpath "$(dirname "$0")")"
|
|
|
|
cd "$DOT"
|
|
|
|
|
|
|
|
setopt EXTENDED_GLOB
|
|
|
|
source "$DOT/lib/libzsh-utils.zsh"
|
|
|
|
|
|
|
|
|
|
|
|
# Parse commandline
|
|
|
|
# =============================
|
|
|
|
OVERWRITE=false
|
|
|
|
ASK=true
|
|
|
|
INSTALL_ZSH=true
|
|
|
|
INSTALL_DOT=true
|
|
|
|
INSTALL_CNF=true
|
|
|
|
INSTALL_GIT=true
|
|
|
|
INSTALL_CHSH=true
|
|
|
|
INSTALL_EXTRA=true
|
|
|
|
|
|
|
|
function print_usage() {
|
|
|
|
echo "Usage: $1 [--help] [--overwrite] [--dont-ask]"
|
|
|
|
echo
|
|
|
|
echo "Install Tae's dotfiles"
|
|
|
|
echo
|
|
|
|
echo "Parameters:"
|
|
|
|
echo " -h, --help Display this help message"
|
|
|
|
echo " --overwrite Just overwrite existing dotfiles"
|
|
|
|
echo " --dont-ask Don't ask questions. Use default values"
|
|
|
|
echo " --no-{zsh,dotfiles,config,git,chsh,extra}"
|
|
|
|
echo " Don't set up the specific component"
|
|
|
|
}
|
|
|
|
|
|
|
|
for arg in "$@"; do
|
|
|
|
[[ -z "$STATE" ]] && {
|
|
|
|
case "$arg" in
|
|
|
|
-h|--help) print_usage "$0"; exit 0;;
|
|
|
|
--overwrite) OVERWRITE=true;;
|
|
|
|
--dont-ask) ASK=false;;
|
|
|
|
--no-zsh) INSTALL_ZSH=false;;
|
|
|
|
--no-dotfiles) INSTALL_DOT=false;;
|
|
|
|
--no-config) INSTALL_CNF=false;;
|
|
|
|
--no-git) INSTALL_GIT=false;;
|
|
|
|
--no-chsh) INSTALL_CHSH=false;;
|
|
|
|
--no-extra) INSTALL_EXTRA=false;;
|
|
|
|
*) print_usage "$0"; exit 1;;
|
|
|
|
esac
|
|
|
|
} || {
|
|
|
|
case "$STATE" in
|
|
|
|
# handle options with parameters
|
|
|
|
esac
|
|
|
|
STATE=
|
|
|
|
}
|
|
|
|
done
|
|
|
|
[[ -n "$STATE" ]] && err "Option $STATE is missing it's parameter!" && exit 1
|
|
|
|
|
|
|
|
|
|
|
|
# Helper functions
|
|
|
|
# =============================
|
|
|
|
function generate() {
|
|
|
|
[[ -e "$1" ]] && ! $OVERWRITE && ! grep -q "Generated by .files/install" "$1" && \
|
|
|
|
err "Custom version of $1 detected. Please delete it before running .files/install" && exit 1
|
|
|
|
echo "${2-#} Generated by .files/install" >"$1"
|
|
|
|
echo "${2-#} `date "+%m/%d/%Y %H:%M:%S"`" >>"$1"
|
|
|
|
echo >>"$1"
|
|
|
|
cat >>"$1"
|
|
|
|
}
|
|
|
|
|
|
|
|
function relink() {
|
|
|
|
[[ ! -e "$1" ]] && err "No such file or directory: '$1'" && return 1
|
|
|
|
[[ -L "$2" ]] && rm -f "$2"
|
|
|
|
[[ -e "$2" ]] && ! $OVERWRITE && err "File already exists and isn't a symbolic link: '$2'" && return 1
|
|
|
|
[[ ! -d "`dirname "$2"`" ]] && mkdir -p "`dirname "$2"`"
|
|
|
|
color 31 ln -sr "$1" "$2"
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
# Prepare
|
|
|
|
# =============================
|
|
|
|
# Update git modules
|
|
|
|
msg "Updating git submodules..."
|
|
|
|
git submodule update --init --recursive
|
|
|
|
|
|
|
|
# Ask questions about user
|
|
|
|
$ASK && msg "Asking questions..." || err "Not asking any questions:"
|
|
|
|
|
|
|
|
# Try to load previous configuration
|
|
|
|
[[ -e "$DOT/etc/user-info" ]] && source "$DOT/etc/user-info"
|
|
|
|
[[ -e "$DOT/etc/hostname" ]] && HOSTNAME=`cat "$DOT/etc/hostname"`
|
|
|
|
|
|
|
|
# Retrieve realname from /etc/passwd GECOS
|
|
|
|
[[ -z "$REALNAME" ]] && REALNAME=`grep "^$USER:[^:]*:$UID:" /etc/passwd | cut -d: -f5 | cut -d, -f1`
|
|
|
|
[[ -z "$HOSTNAME" ]] && HOSTNAME=`hostname`
|
|
|
|
|
|
|
|
if $ASK; then
|
|
|
|
ask " Real name" REALNAME
|
|
|
|
ask " E-Mail address" EMAIL
|
|
|
|
ask " Computer name" HOSTNAME
|
|
|
|
else
|
|
|
|
color 36 echo " default REALNAME=\"$REALNAME\""
|
|
|
|
color 36 echo " default EMAIL=\"$EMAIL\""
|
|
|
|
color 36 echo " default HOSTNAME=\"$HOSTNAME\""
|
|
|
|
fi
|
|
|
|
|
|
|
|
# Write down answers
|
|
|
|
color 32 echo " Writing etc/user-info"
|
|
|
|
generate "$DOT/etc/user-info" <<EOF
|
|
|
|
REALNAME="$REALNAME"
|
|
|
|
EMAIL="$EMAIL"
|
|
|
|
EOF
|
|
|
|
|
|
|
|
color 32 echo " Writing etc/hostname"
|
|
|
|
echo $HOSTNAME >"$DOT/etc/hostname"
|
|
|
|
|
|
|
|
# Handle local-only alternatives
|
|
|
|
HOST_LC=${(L)HOSTNAME}
|
|
|
|
|
|
|
|
function refset() {
|
|
|
|
eval "$1=\$2"
|
|
|
|
}
|
|
|
|
|
|
|
|
function inspect_name() {
|
|
|
|
# gimme namerefs...
|
|
|
|
#local -n name=$1 prio=$2
|
|
|
|
#local filename=$3
|
|
|
|
# Check local-only files
|
|
|
|
refset $1 ${3%.local}
|
|
|
|
if [[ ${(P)1} != $3 ]]; then
|
|
|
|
refset $2 3
|
|
|
|
return 0
|
|
|
|
fi
|
|
|
|
# Check hostname-specific file
|
|
|
|
refset $1 ${3%@*}
|
|
|
|
if [[ ${(P)1} != $3 ]]; then
|
|
|
|
refset $2 2
|
|
|
|
[[ ${3##*@} == $HOST_LC ]]
|
|
|
|
return $?
|
|
|
|
fi
|
|
|
|
# Standard file
|
|
|
|
refset $2 1
|
|
|
|
return 0
|
|
|
|
}
|
|
|
|
|
|
|
|
function add_names() {
|
|
|
|
local an_name an_prio
|
|
|
|
#local -n names=$1 prios=$2
|
|
|
|
for an_file in ${(@)argv[3,$#]}; do
|
|
|
|
if inspect_name an_name an_prio $an_file && [[ $an_prio -gt ${${(P)2}[$an_name]} ]]; then
|
|
|
|
refset $1\[\$an_name\] $an_file
|
|
|
|
refset $2\[\$an_name\] $an_prio
|
|
|
|
fi
|
|
|
|
done
|
|
|
|
}
|
|
|
|
|
|
|
|
# Write files to $HOME
|
|
|
|
# =============================
|
|
|
|
# Setup dotfiles
|
|
|
|
if $INSTALL_DOT; then
|
|
|
|
msg "Linking dotfiles..."
|
|
|
|
(){
|
|
|
|
local -A names prios
|
|
|
|
pushd $DOT/dotfiles
|
|
|
|
add_names names prios *
|
|
|
|
for name src in ${(@kv)names}; do
|
|
|
|
color 32 echo " Adding .$name"
|
|
|
|
relink $src $HOME/.$name
|
|
|
|
done
|
|
|
|
popd
|
|
|
|
}
|
|
|
|
else
|
|
|
|
msg "Skipped dotfiles."
|
|
|
|
fi
|
|
|
|
|
|
|
|
# Setup .config
|
|
|
|
if $INSTALL_CNF; then
|
|
|
|
: ${XDG_CONFIG_HOME:=~/.config}
|
|
|
|
msg "Linking .config files... ($XDG_CONFIG_HOME)"
|
|
|
|
(){
|
|
|
|
function relink_r() {
|
|
|
|
local target=$1 dest=$2 name=${3:-$2} from
|
|
|
|
[[ ${target:t} != ${dest:t} ]] && from=" (${target:t})"
|
|
|
|
if [[ ! -d $target ]]; then
|
|
|
|
color 32 echo " Adding $name$from"
|
|
|
|
relink $target $dest
|
|
|
|
else
|
|
|
|
if [[ ! -d $dest ]]; then
|
|
|
|
color 32 echo " Creating directory $name/$from"
|
|
|
|
mkdir $dest
|
|
|
|
elif [[ -n $from ]]; then
|
|
|
|
color 32 echo " Adding directory $name/$from"
|
|
|
|
fi
|
|
|
|
# This is still slightly ugly
|
|
|
|
local -A names prios
|
|
|
|
add_names names prios $target/*
|
|
|
|
for dst src in ${(@kv)names}; do
|
|
|
|
relink_r $src $dest/${dst:t} $name/${dst:t}
|
|
|
|
done
|
|
|
|
fi
|
|
|
|
}
|
|
|
|
pushd $DOT/config
|
|
|
|
local -A names prios
|
|
|
|
add_names names prios *
|
|
|
|
for dst src in ${(@kv)names}; do
|
|
|
|
relink_r $src $XDG_CONFIG_HOME/$dst $dst
|
|
|
|
done
|
|
|
|
popd
|
|
|
|
}
|
|
|
|
else
|
|
|
|
msg "Skipped .config"
|
|
|
|
fi
|
|
|
|
|
|
|
|
# Setup git
|
|
|
|
# =============================
|
|
|
|
if $INSTALL_GIT; then
|
|
|
|
msg "Setting up Git configuration..."
|
|
|
|
|
|
|
|
GIT="$DOT/git"
|
|
|
|
[[ -e "$HOME/.gitconfig" ]] && ! grep -q ".files/install" "$HOME/.gitconfig" && err "Custom ~/.gitconfig already exists! Please remove it before running .files/install" && exit 1
|
|
|
|
|
|
|
|
color 32 echo " Writing .gitconfig"
|
|
|
|
generate "$HOME/.gitconfig" <<EOF
|
|
|
|
[include]
|
|
|
|
path = $(relpath "$GIT" "$HOME")/config
|
|
|
|
path = $(relpath "$GIT" "$HOME")/user-info
|
|
|
|
EOF
|
|
|
|
|
|
|
|
[ "`uname -s`" = "Darwin" ] && \
|
|
|
|
cat >>"$HOME/.gitconfig" <<EOF
|
|
|
|
path = $(relpath "$GIT" "$HOME")/osx
|
|
|
|
EOF
|
|
|
|
|
|
|
|
color 32 echo " Writing git/user-info"
|
|
|
|
generate "$GIT/user-info" <<EOF
|
|
|
|
[user]
|
|
|
|
name = $REALNAME
|
|
|
|
email = $EMAIL
|
|
|
|
EOF
|
|
|
|
else
|
|
|
|
msg "Skipped git configuration"
|
|
|
|
fi
|
|
|
|
|
|
|
|
# Setup ZSH/Prezto
|
|
|
|
# =============================
|
|
|
|
if $INSTALL_ZSH; then
|
|
|
|
msg "Setting up ZSH configuration..."
|
|
|
|
ZSH="$DOT/zsh"
|
|
|
|
|
|
|
|
color 32 echo " Writing .zshenv"
|
|
|
|
generate "$HOME/.zshenv" <<EOF
|
|
|
|
export DOTFILES="\$HOME/$(relpath "$DOT" "$HOME")"
|
|
|
|
ZDOTDIR="\$DOTFILES/zsh"
|
|
|
|
[[ -f "\$ZDOTDIR/zshenv" ]] && source "\$ZDOTDIR/zshenv"
|
|
|
|
[[ ! -o LOGIN && "\$SHLVL" == 1 && -f "\$ZDOTDIR/zprofile" ]] && source "\$ZDOTDIR/zprofile"
|
|
|
|
EOF
|
|
|
|
|
|
|
|
for file in zshrc zpreztorc zlogin zlogout zprofile; do
|
|
|
|
color 32 echo " Adding .$file"
|
|
|
|
relink "$ZSH/$file" "$ZSH/.$file"
|
|
|
|
done
|
|
|
|
else
|
|
|
|
msg "Skipped ZSH configuration."
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
|
|
# Do misc setup
|
|
|
|
# =============================
|
|
|
|
if [ -x "$DOT/install.extra" ]; then
|
|
|
|
if $INSTALL_EXTRA; then
|
|
|
|
msg "Running install.extra..."
|
|
|
|
"$DOT/install.extra"
|
|
|
|
else
|
|
|
|
msg "Not running install.extra."
|
|
|
|
fi
|
|
|
|
fi
|
|
|
|
|
|
|
|
# Check login shell
|
|
|
|
if $INSTALL_CHSH; then
|
|
|
|
if getent passwd $(id -un) | grep -q 'zsh$'; then
|
|
|
|
msg "Login shell is already set to zsh, you're good to go!"
|
|
|
|
else
|
|
|
|
msg "Setting login shell to '$(which zsh)'..."
|
|
|
|
chsh -s "$(which zsh)"
|
|
|
|
fi
|
|
|
|
fi
|
|
|
|
|
|
|
|
# Done.
|
|
|
|
warn "You may need to relog for all changes to take effect."
|
|
|
|
$INSTALL_ZSH && warn "If you're currently running zsh, you definitely need to at least restart the shell to apply changes."
|
|
|
|
|