348 lines
9.3 KiB
Bash
Executable File
348 lines
9.3 KiB
Bash
Executable File
#!/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
|