123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329 |
- #!/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
- SUBSTITUTE_URLS=https://ci.guix.gnu.org
- EXTRA_SUBSTITUTE_URLS=
- ## Hardcoded in .mbsyncrc:
- MAIL_CACHE="$HOME/.cache/mail"
- [ -z "$SOURCEDIR" ] && SOURCEDIR="$PERSONAL"
- [ -z "$XDG_CONFIG_HOME" ] && XDG_CONFIG_HOME="$HOME/.config"
- [ -z "$XDG_DATA_HOME" ] && XDG_DATA_HOME="$HOME/.local/share"
- [ -z "$XDG_BIN_HOME" ] && XDG_BIN_HOME="$XDG_DATA_HOME/../bin"
- usage() {
- cat <<EOF>&2
- Usage: ${0##*/}
- Initialize user profile: install packages, set up folders, etc.
- Options:
- -g DEVICE: Device where to sync ~/.gnupg from, e.g. '/dev/sda1'.
- -u: Skip large updates (large packages, email cache, etc.)
- -s URLS: Extra substitute URLs for Guix (space separated).
- Example: 'http://192.168.1.2:8080'.
- Environment variables:
- SOURCEDIR=$SOURCEDIR
- XDG_CONFIG_HOME=$XDG_CONFIG_HOME
- XDG_DATA_HOME=$XDG_DATA_HOME
- XDG_BIN_HOME=$XDG_BIN_HOME
- Tips:
- - Run the following command to install the Guix corresponding to your substitute
- server:
- guix pull -C my-channels.scm
- - Copy the email cache to '$MAIL_CACHE' to speed up the process.
- Direct link:
- ${HTTPS_ROOT}ambrevar/dotfiles/raw/master/.local/bin/homeinit
- EOF
- exit
- }
- OPT_UPDATE=true
- OPT_DEVICE=""
- while getopts ":hg:s:u" opt; do
- case $opt in
- h)
- usage
- exit ;;
- g)
- OPT_DEVICE="$OPTARG" ;;
- s)
- EXTRA_SUBSTITUTE_URLS="$OPTARG $EXTRA_SUBSTITUTE_URLS" ;;
- u)
- OPT_UPDATE=false ;;
- \?)
- 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
- }
- ## Pass substitute URLs dynamically to avoid overriding the daemon settings.
- run_guix() {
- if [ -z "$EXTRA_SUBSTITUTE_URLS" ]; then
- guix "$@"
- else
- guix --substitute-urls="$EXTRA_SUBSTITUTE_URLS $SUBSTITUTE_URLS" "$@"
- fi
- }
- run_current_guix() {
- if [ -z "$EXTRA_SUBSTITUTE_URLS" ]; then
- ~/.config/guix/current/bin/guix "$@"
- else
- ~/.config/guix/current/bin/guix --substitute-urls="$EXTRA_SUBSTITUTE_URLS $SUBSTITUTE_URLS" "$@"
- fi
- }
- ################################################################################
- #
- 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")"
- run_guix package --profile="$PROFILE" --install openssh gnupg git stow password-store pinentry-tty pinentry-gtk2 cryptsetup recutils
- source "$PROFILE"/etc/profile
- fi
- has_gpg_keys() {
- [ -n "$(ls -1 ~/.gnupg/private-*)" ]
- }
- is_laptop() {
- [ -n "$(ls -1 /sys/class/power_supply/ 2>/dev/null)" ]
- }
- if ! has_gpg_keys; 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 has_gpg_keys; 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" ] || [ -z "$INSIDE_EMACS" ]; then
- ## If a TTY, since our ~/.gnupg/gpg-agent.conf exists and specifies the Emacs
- ## pinentry, we must force the TTY version or else it won't work from a TTY.
- ## Same if not in Emacs (e.g. Xterm).
- 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 "$SOURCEDIR"
- 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 "$MAIL_CACHE" ~/.config ~/.config/guix ~/.config/guix-gaming-channels ~/.config/transmission-daemon ~/.emacs.d "$XDG_DATA_HOME" ~/.mpv ~/projects; do
- mkdir -pv "$i"
- done
- section "Gaming"
- lnn "$SOURCEDIR/games/games.scm.gpg" ~/.config/guix-gaming-channels/
- 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.
- for i in ~/.bash_profile ~/.bashrc; do
- [ -e "$i" ] && mv -v "$i" "$i".old
- done
- stow -v . || exit 1
- popd
- guix_install_profile() {
- local profile
- local manifest
- manifest=$HOME/.package-lists/guix-$1-manifest.scm
- if [ -f "$manifest" ]; then
- if [ "$1" = "default" ]; then
- info "Installing default profile..."
- run_current_guix package --manifest="$manifest" --keep-failed
- . ~/.guix-profile/etc/profile
- else
- profile=$HOME/.guix-extra-profiles/$1/$1
- if [ ! -d "$HOME/.guix-extra-profiles/$1/$1" ]; then
- info "Installing profile '$profile'..."
- mkdir -p $(dirname "$profile")
- run_current_guix package --manifest="$manifest" --keep-failed --profile="$profile"
- if [ -f "$profile"/etc/profile ]; then
- . "$profile"/etc/profile
- fi
- else
- info "Profile '$profile' already installed."
- fi
- fi
- else
- warning "Manifest '$manifest' not found."
- fi
- }
- section "System packages"
- if inpath guix; then
- if [ ! -e ~/.cache/guix ]; then
- message "First 'guix pull'"
- run_guix pull
- hash guix
- fi
- for i in default main emacs nyxt texlive; do
- guix_install_profile "$i"
- done
- if is_laptop; then
- guix_install_profile laptop
- guix_install_profile laptop-gaming
- else
- guix_install_profile gaming
- fi
- if $OPT_UPDATE; then
- for i in blender chromium electrum racket; do
- guix_install_profile "$i"
- done
- fi
- else
- warning "Package manager not supported. Install Guix."
- fi
- if inpath emacs; then
- message "Emacs cache folder"
- mkdir -pv "$HOME/.cache/emacs/"
- message "Emacs local packages"
- if [ -e "$XDG_DATA_HOME"/emacs/site-lisp ]; then
- for i in "$XDG_DATA_HOME"/emacs/site-lisp/*; do
- echo "$i"
- git -C "$i" pull
- done
- else
- mkdir -pv "$XDG_DATA_HOME"/emacs/site-lisp
- fi
- fi
- if inpath guix; then
- section "Cleanup initial packages"
- rm -rv "$(dirname "$PROFILE")"
- fi
- if [ -x "$XDG_BIN_HOME"/updatedb-local ]; then
- section "locate db"
- "$XDG_BIN_HOME"/updatedb-local
- fi
- section "Mail"
- # lnn "$SOURCEDIR/mail/authinfo.gpg" "$HOME/.authinfo.gpg" ## Only if not using password-store.
- mkdir -pv "$MAIL_CACHE"
- 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="$MAIL_CACHE"
- notmuch new
- fi
|