Dotfiles
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

292 lines
7.8 KiB

#!/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."