#!/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 <&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<"$(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 ## TODO: Stow Gaming, Dictionaries, etc. section "Gaming" lnn "$SOURCEDIR/games/games.scm.gpg" ~/.config/guix-gaming-channels/ section "Dictionaries" lnn "$SOURCEDIR/dictionaries/.aspell.en.pws" ~/ lnn "$SOURCEDIR/dictionaries/.aspell.fr.pws" ~/ 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 <