ambevar-dotfiles/.local/bin/homeinit

348 lines
9.3 KiB
Bash
Executable File
Raw Blame History

This file contains invisible Unicode characters!

This file contains invisible Unicode characters that may be processed differently from what appears below. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to reveal hidden characters.

#!/bin/sh
# TODO: Guix pull on commit specified in package-lists/guix-version?
# TODO: On foreign distro, use local package manager to install Guix. (Start with pacman.)
# TODO: Make functions to make it easier to re-order calls?
HTTPS_ROOT=https://gitlab.com/
SSH_ROOT=git@gitlab.com:
ROOT=$HTTPS_ROOT
PROFILE=/tmp/homeinit-$USER/homeinit
USER_NAME=Ambrevar
[ -z "$SOURCEDIR" ] && SOURCEDIR="$HOME/personal"
[ -z "$XDG_CONFIG_HOME" ] && XDG_CONFIG_HOME="$HOME/.config"
[ -z "$XDG_DATA_HOME" ] && XDG_DATA_HOME="$HOME/.local/share"
[ -z "$EMACS_MIN_VERSION" ] && EMACS_MIN_VERSION=26
usage() {
cat <<EOF>&2
Usage: ${0##*/}
Initialize user profile: install packages, set up folders, etc.
Options:
-g DEVICE: Device where to sync ~/.gnupg.
-u: Skip large updates (packages, emails, etc.)
Environment variables:
SOURCEDIR=$SOURCEDIR
XDG_CONFIG_HOME=$XDG_CONFIG_HOME
XDG_DATA_HOME=$XDG_DATA_HOME
EMACS_MIN_VERSION=$EMACS_MIN_VERSION
Direct link:
${HTTPS_ROOT}ambrevar/dotfiles/raw/master/.local/bin/homeinit
EOF
exit
}
OPT_UPDATE=true
OPT_DEVICE=""
while getopts ":hg:u" opt; do
case $opt in
h)
usage
exit ;;
g)
OPT_DEVICE="$OPTARG" ;;
u)
OPT_UPDATE=true ;;
\?)
usage
exit 1 ;;
esac
done
shift $(($OPTIND - 1))
RED='\033[0;31m\033[1m'
GREEN='\033[0;32m\033[1m'
YELLOW='\033[0;33m\033[1m'
BOLD='\033[0m\033[1m'
NORMAL='\033[0m'
section() {
echo -e "$GREEN==> $@$NORMAL"
}
message() {
echo -e "$YELLOW:: $@$NORMAL"
}
info() {
echo -e "$@"
}
warning() {
echo -e "${YELLOW}WARNING:: $@$NORMAL"
}
## "ln" wrapper.
## If $2 is a folder, create the link in it using the basename of $1.
## Existing files are no clobbered, unless they already are a symlink.
lnn() { # $1=TARGET $2=LINK|FOLDER
if [ -d "$2" ]; then
set -- "$1" "$2/$(basename "$1")"
fi
if [ ! -e "$2" ] || [ -h "$2" ]; then
ln -svnf "$1" "$2"
fi
}
inpath() {
for i; do
if ! command -v "$i" >/dev/null 2>&1; then
return 1
fi
done
return 0
}
################################################################################
#
section "Initial packages"
if inpath guix; then
mkdir -p ~/.config/guix
## OpenSSH is not an input of Git, upstream does not want to increase the
## closure size that much.
mkdir -p "$(dirname "$PROFILE")"
guix package --profile="$PROFILE" --install openssh gnupg git stow password-store pinentry-tty pinentry-gtk2 cryptsetup
source "$PROFILE"/etc/profile
fi
if [ ! -d ~/.gnupg ]; then
section "GPG sync"
if [ -n "$OPT_DEVICE" ]; then
section "GnuPG"
sudo cryptsetup open "$OPT_DEVICE" gpg_backup
sudo mount -o compress=zstd /dev/mapper/gpg_backup /mnt
cp -a /mnt/public/.gnupg ~/
sudo umount /mnt
sudo cryptsetup close gpg_backup
else
warning "No device specified."
fi
fi
section "GPG"
if [ -d ~/.gnupg ]; then
ROOT=$SSH_ROOT
## Set up gpg-agent to authenticate to SSH_ROOT.
chmod -R go-rwx ~/.gnupg
export SSH_AUTH_SOCK=$(gpgconf --list-dirs agent-ssh-socket)
if [ "$GPG_TTY" != "not a tty" ]; then
## If a TTY, since our ~/.gnupg/gpg-agent.conf exists and specifies a
## pinentry, we must force the TTY version or else it won't work from a TTY.
gpgconf --kill gpg-agent
cat<<EOF>"$(dirname "$PROFILE")/gpg-agent.conf"
## 1-day timeout
default-cache-ttl 86400
max-cache-ttl 86400
## SSH
enable-ssh-support
default-cache-ttl-ssh 86400
max-cache-ttl-ssh 86400
## Force pinentry (should be pinentry-tty)
pinentry-program $(readlink -f $(which pinentry))
EOF
gpg-agent --homedir ~/.gnupg --daemon --options "$(dirname "$PROFILE")/gpg-agent.conf"
fi
## Start gpg-agent manually since SSH requests do not do it automatically.
gpg-connect-agent updatestartuptty /bye
if [ -e "$SOURCEDIR" ]; then
git -C "$SOURCEDIR" pull
else
git clone ${SSH_ROOT}$USER_NAME/personal ~/personal
fi
if [ -e ~/.password-store ]; then
git -C ~/.password-store pull
else
git clone ${SSH_ROOT}$USER_NAME/password-store ~/.password-store
## The following is necessary to make sure the 'diff' GPG filter is properly set up.
pass git init
fi
else
warning "~/.gnupg not found."
fi
section "Persistent folders"
for i in .cache/mail .config .config/guix .config/transmission-daemon .emacs.d .local/share .mpv projects temp; do
mkdir -pv "$HOME/$i"
done
section "dotfiles"
if [ -e ~/dotfiles ]; then
git -C ~/dotfiles remote set-url origin ${ROOT}$USER_NAME/dotfiles
git -C ~/dotfiles pull
else
git clone ${ROOT}$USER_NAME/dotfiles ~/dotfiles || exit 1
fi
pushd ~/dotfiles
## .bash_profile may prevent .profile from being parsed, so we move it.
[ -e ~/.bash_profile ] && mv -v ~/.bash_profile ~/.bash_profile.old
stow -v . || exit 1
popd
section "System packages"
if inpath guix; then
if [ ! -e ~/.cache/guix/pull ]; then
message "Update Guix to yesterday's version"
## TODO: This clones the repository twice, which is a bit dumb, but cloning
## locally and then running `guix pull --url=/tmp/guix` produces a different
## hash in ~/.cache/guix/...
git clone https://git.savannah.gnu.org/git/guix.git /tmp/guix
YESTERDAY_COMMIT=$(git -C /tmp/guix log --until=yesterday -n 1 --format=%H)
guix pull --commit=$YESTERDAY_COMMIT
hash guix
unset YESTERDAY_COMMIT
rm -rf /tmp/guix
elif $OPT_UPDATE; then
CURRENT_COMMIT=$(guix --version 2>/dev/null | awk '{print $4; exit}')
for i in $HOME/.cache/guix/pull/*; do
if [ "$(git -C "$i" config --get remote.origin.url)" = "https://git.savannah.gnu.org/git/guix.git" ]; then
REPO="$i"
break
fi
done
CURRENT_COMMIT_DATE=$(git -C "$REPO" log -n 1 --format=%ct $CURRENT_COMMIT)
git -C $REPO pull
hash guix
LATEST_COMMIT_DATE=$(git -C "$REPO" log -n 1 --format=%ct)
[ -z "$GUIX_DISTRO_AGE_WARNING" ] && GUIX_DISTRO_AGE_WARNING=$((7 * 24 * 60 * 60))
info "Current commit date: $(date --date="@$CURRENT_COMMIT_DATE") ($CURRENT_COMMIT_DATE)"
info "Last commit date: $(date --date="@$LATEST_COMMIT_DATE") ($LATEST_COMMIT_DATE)"
info "Difference (in seconds): $(($LATEST_COMMIT_DATE - $CURRENT_COMMIT_DATE))"
if [ $(($LATEST_COMMIT_DATE - $CURRENT_COMMIT_DATE)) -gt $GUIX_DISTRO_AGE_WARNING ]; then
message "Update Guix since it's older than GUIX_DISTRO_AGE_WARNING ($GUIX_DISTRO_AGE_WARNING)."
YESTERDAY_COMMIT=$(git -C "$REPO" log --until=yesterday -n 1 --format=%H)
guix pull --commit=$YESTERDAY_COMMIT
unset YESTERDAY_COMMIT
fi
unset LATEST_COMMIT_DATE
unset CURRENT_COMMIT_DATE
unset REPO
unset CURRENT_COMMIT
fi
## TODO: The manifest will uninstall other unspecified packages. Is this
## really what we want?
# export GUIX_PACKAGE_PATH=$HOME/.guix-packages
~/.config/guix/current/bin/guix package --manifest=$HOME/.package-lists/guix-manifest.scm --keep-failed
. ~/.guix-profile/etc/profile
fi
section "Quicklisp"
QUICKLISP_DIR=$HOME/.quicklisp
QUICKLISP_URL=https://beta.quicklisp.org/quicklisp.lisp
DOWNLOAD_AGENT=curl
DOWNLOAD_AGENT_FLAGS=--output
LISP=sbcl
LISP_FLAGS=--no-userinit
if [ ! -d "$QUICKLISP_DIR" ] && inpath $LISP && inpath $DOWNLOAD_AGENT; then
$DOWNLOAD_AGENT $DOWNLOAD_AGENT_FLAGS /tmp/setup.lisp $QUICKLISP_URL
$LISP $LISP_FLAGS \
--eval '(require "asdf")' \
--load /tmp/setup.lisp \
--eval '(quicklisp-quickstart:install :path "'$QUICKLISP_DIR'/")' \
--eval '(uiop:quit)'
rm -v /tmp/setup.lisp
fi
section "Bookmarks"
if inpath qutebrowser; then
mkdir -pv "$XDG_CONFIG_HOME/qutebrowser/bookmarks"
lnn "$SOURCEDIR/bookmarks/bookmarks" "$XDG_CONFIG_HOME/qutebrowser/bookmarks/urls"
lnn "$SOURCEDIR/bookmarks/quickmarks" "$XDG_CONFIG_HOME/qutebrowser/"
fi
section "Emacs"
if ! inpath emacs; then
message "Emacs: Installing latest development version"
pushd "$HOME/projects"
[ -e emacs ] || git clone https://git.savannah.gnu.org/git/emacs.git
mkdir -pv ../emacs-build
cd ../emacs-build
../emacs/configure \
--disable-gtk-deprecation-warnings \
--without-pop \
--without-kerberos \
--without-kerberos5 \
--with-x-toolkit=gtk3 \
--with-jpeg \
--with-tiff \
--with-gif \
--with-png \
--with-rsvg \
--with-xml2 \
--with-imagemagick \
--with-xft \
--with-libotf \
--without-gsettings \
--without-gconf \
--with-gnutls \
--with-modules \
--with-threads
sudo make install
popd
fi
if inpath emacs; then
message "Emacs cache folder"
mkdir -pv "$HOME/.cache/emacs/"
if ! inpath guix; then
if $OPT_UPDATE; then
message "Emacs ELPA packages"
yes | emacs --batch -l ~/.emacs.d/init.el --eval '(progn (package-refresh-contents) (package-install-selected-packages))'
fi
fi
message "Emacs local packages"
if [ -e ~/.local/share/emacs/site-lisp ]; then
for i in ~/.local/share/emacs/site-lisp/*; do
echo "$i"
git -C "$i" pull
done
else
mkdir -pv ~/.local/share/emacs/site-lisp
fi
fi
if inpath guix; then
section "Cleanup initial packages"
rm -rv "$(dirname "$PROFILE")"
fi
if [ -x ~/.local/bin/updatedb-local ]; then
section "locate db"
~/.local/bin/updatedb-local
fi
if [ -f ~/personal/history/eshell.gpg ]; then
section "Shell history"
mkdir -pv ~/.cache/emacs/eshell/
gpg --output ~/.cache/emacs/eshell/history --decrypt ~/personal/history/eshell.gpg
fi
section "Mail"
# lnn "$SOURCEDIR/mail/authinfo.gpg" "$HOME/.authinfo.gpg" ## Only if no using password-store.
mkdir -pv "$HOME/.cache/mail/"
while IFS= read -r i; do
## Warning: We need to eval here to expand the "~".
mkdir -pv $(eval echo $i)
done <<EOF
$(awk '/^Path/ {print $2}' ~/.mbsyncrc)
EOF
if $OPT_UPDATE; then
mbsync -aV
# mu index --maildir=~/.cache/mail
notmuch new
fi