homeinit 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329
  1. #!/bin/sh
  2. # TODO: Guix pull on commit specified in package-lists/guix-version?
  3. # TODO: On foreign distro, use local package manager to install Guix. (Start with pacman.)
  4. # TODO: Make functions to make it easier to re-order calls?
  5. HTTPS_ROOT=https://gitlab.com/
  6. SSH_ROOT=git@gitlab.com:
  7. ROOT=$HTTPS_ROOT
  8. PROFILE=/tmp/homeinit-$USER/homeinit
  9. USER_NAME=Ambrevar
  10. SUBSTITUTE_URLS=https://ci.guix.gnu.org
  11. EXTRA_SUBSTITUTE_URLS=
  12. ## Hardcoded in .mbsyncrc:
  13. MAIL_CACHE="$HOME/.cache/mail"
  14. [ -z "$SOURCEDIR" ] && SOURCEDIR="$PERSONAL"
  15. [ -z "$XDG_CONFIG_HOME" ] && XDG_CONFIG_HOME="$HOME/.config"
  16. [ -z "$XDG_DATA_HOME" ] && XDG_DATA_HOME="$HOME/.local/share"
  17. [ -z "$XDG_BIN_HOME" ] && XDG_BIN_HOME="$XDG_DATA_HOME/../bin"
  18. usage() {
  19. cat <<EOF>&2
  20. Usage: ${0##*/}
  21. Initialize user profile: install packages, set up folders, etc.
  22. Options:
  23. -g DEVICE: Device where to sync ~/.gnupg from, e.g. '/dev/sda1'.
  24. -u: Skip large updates (large packages, email cache, etc.)
  25. -s URLS: Extra substitute URLs for Guix (space separated).
  26. Example: 'http://192.168.1.2:8080'.
  27. Environment variables:
  28. SOURCEDIR=$SOURCEDIR
  29. XDG_CONFIG_HOME=$XDG_CONFIG_HOME
  30. XDG_DATA_HOME=$XDG_DATA_HOME
  31. XDG_BIN_HOME=$XDG_BIN_HOME
  32. Tips:
  33. - Run the following command to install the Guix corresponding to your substitute
  34. server:
  35. guix pull -C my-channels.scm
  36. - Copy the email cache to '$MAIL_CACHE' to speed up the process.
  37. Direct link:
  38. ${HTTPS_ROOT}ambrevar/dotfiles/raw/master/.local/bin/homeinit
  39. EOF
  40. exit
  41. }
  42. OPT_UPDATE=true
  43. OPT_DEVICE=""
  44. while getopts ":hg:s:u" opt; do
  45. case $opt in
  46. h)
  47. usage
  48. exit ;;
  49. g)
  50. OPT_DEVICE="$OPTARG" ;;
  51. s)
  52. EXTRA_SUBSTITUTE_URLS="$OPTARG $EXTRA_SUBSTITUTE_URLS" ;;
  53. u)
  54. OPT_UPDATE=false ;;
  55. \?)
  56. usage
  57. exit 1 ;;
  58. esac
  59. done
  60. shift $(($OPTIND - 1))
  61. RED='\033[0;31m\033[1m'
  62. GREEN='\033[0;32m\033[1m'
  63. YELLOW='\033[0;33m\033[1m'
  64. BOLD='\033[0m\033[1m'
  65. NORMAL='\033[0m'
  66. section() {
  67. echo -e "$GREEN==> $@$NORMAL"
  68. }
  69. message() {
  70. echo -e "$YELLOW:: $@$NORMAL"
  71. }
  72. info() {
  73. echo -e "$@"
  74. }
  75. warning() {
  76. echo -e "${YELLOW}WARNING:: $@$NORMAL"
  77. }
  78. ## "ln" wrapper.
  79. ## If $2 is a folder, create the link in it using the basename of $1.
  80. ## Existing files are no clobbered, unless they already are a symlink.
  81. lnn() { # $1=TARGET $2=LINK|FOLDER
  82. if [ -d "$2" ]; then
  83. set -- "$1" "$2/$(basename "$1")"
  84. fi
  85. if [ ! -e "$2" ] || [ -h "$2" ]; then
  86. ln -svnf "$1" "$2"
  87. fi
  88. }
  89. inpath() {
  90. for i; do
  91. if ! command -v "$i" >/dev/null 2>&1; then
  92. return 1
  93. fi
  94. done
  95. return 0
  96. }
  97. ## Pass substitute URLs dynamically to avoid overriding the daemon settings.
  98. run_guix() {
  99. if [ -z "$EXTRA_SUBSTITUTE_URLS" ]; then
  100. guix "$@"
  101. else
  102. guix --substitute-urls="$EXTRA_SUBSTITUTE_URLS $SUBSTITUTE_URLS" "$@"
  103. fi
  104. }
  105. run_current_guix() {
  106. if [ -z "$EXTRA_SUBSTITUTE_URLS" ]; then
  107. ~/.config/guix/current/bin/guix "$@"
  108. else
  109. ~/.config/guix/current/bin/guix --substitute-urls="$EXTRA_SUBSTITUTE_URLS $SUBSTITUTE_URLS" "$@"
  110. fi
  111. }
  112. ################################################################################
  113. #
  114. section "Initial packages"
  115. if inpath guix; then
  116. mkdir -p ~/.config/guix
  117. ## OpenSSH is not an input of Git, upstream does not want to increase the
  118. ## closure size that much.
  119. mkdir -p "$(dirname "$PROFILE")"
  120. run_guix package --profile="$PROFILE" --install openssh gnupg git stow password-store pinentry-tty pinentry-gtk2 cryptsetup recutils
  121. source "$PROFILE"/etc/profile
  122. fi
  123. has_gpg_keys() {
  124. [ -n "$(ls -1 ~/.gnupg/private-*)" ]
  125. }
  126. is_laptop() {
  127. [ -n "$(ls -1 /sys/class/power_supply/ 2>/dev/null)" ]
  128. }
  129. if ! has_gpg_keys; then
  130. section "GPG sync"
  131. if [ -n "$OPT_DEVICE" ]; then
  132. section "GnuPG"
  133. sudo cryptsetup open "$OPT_DEVICE" gpg_backup
  134. sudo mount -o compress=zstd /dev/mapper/gpg_backup /mnt
  135. cp -a /mnt/public/.gnupg ~/
  136. sudo umount /mnt
  137. sudo cryptsetup close gpg_backup
  138. else
  139. warning "No device specified."
  140. fi
  141. fi
  142. section "GPG"
  143. if has_gpg_keys; then
  144. ROOT=$SSH_ROOT
  145. ## Set up gpg-agent to authenticate to SSH_ROOT.
  146. chmod -R go-rwx ~/.gnupg
  147. export SSH_AUTH_SOCK=$(gpgconf --list-dirs agent-ssh-socket)
  148. if [ "$GPG_TTY" != "not a tty" ] || [ -z "$INSIDE_EMACS" ]; then
  149. ## If a TTY, since our ~/.gnupg/gpg-agent.conf exists and specifies the Emacs
  150. ## pinentry, we must force the TTY version or else it won't work from a TTY.
  151. ## Same if not in Emacs (e.g. Xterm).
  152. gpgconf --kill gpg-agent
  153. cat<<EOF>"$(dirname "$PROFILE")/gpg-agent.conf"
  154. ## 1-day timeout
  155. default-cache-ttl 86400
  156. max-cache-ttl 86400
  157. ## SSH
  158. enable-ssh-support
  159. default-cache-ttl-ssh 86400
  160. max-cache-ttl-ssh 86400
  161. ## Force pinentry (should be pinentry-tty)
  162. pinentry-program $(readlink -f $(which pinentry))
  163. EOF
  164. gpg-agent --homedir ~/.gnupg --daemon --options "$(dirname "$PROFILE")/gpg-agent.conf"
  165. fi
  166. ## Start gpg-agent manually since SSH requests do not do it automatically.
  167. gpg-connect-agent updatestartuptty /bye
  168. if [ -e "$SOURCEDIR" ]; then
  169. git -C "$SOURCEDIR" pull
  170. else
  171. git clone ${SSH_ROOT}$USER_NAME/personal "$SOURCEDIR"
  172. fi
  173. if [ -e ~/.password-store ]; then
  174. git -C ~/.password-store pull
  175. else
  176. git clone ${SSH_ROOT}$USER_NAME/password-store ~/.password-store
  177. ## The following is necessary to make sure the 'diff' GPG filter is properly set up.
  178. pass git init
  179. fi
  180. else
  181. warning "~/.gnupg not found."
  182. fi
  183. section "Persistent folders"
  184. for i in "$MAIL_CACHE" ~/.config ~/.config/guix ~/.config/guix-gaming-channels ~/.config/transmission-daemon ~/.emacs.d "$XDG_DATA_HOME" ~/.mpv ~/projects; do
  185. mkdir -pv "$i"
  186. done
  187. section "Gaming"
  188. lnn "$SOURCEDIR/games/games.scm.gpg" ~/.config/guix-gaming-channels/
  189. section "dotfiles"
  190. if [ -e ~/dotfiles ]; then
  191. git -C ~/dotfiles remote set-url origin ${ROOT}$USER_NAME/dotfiles
  192. git -C ~/dotfiles pull
  193. else
  194. git clone ${ROOT}$USER_NAME/dotfiles ~/dotfiles || exit 1
  195. fi
  196. pushd ~/dotfiles
  197. ## .bash_profile may prevent .profile from being parsed, so we move it.
  198. for i in ~/.bash_profile ~/.bashrc; do
  199. [ -e "$i" ] && mv -v "$i" "$i".old
  200. done
  201. stow -v . || exit 1
  202. popd
  203. guix_install_profile() {
  204. local profile
  205. local manifest
  206. manifest=$HOME/.package-lists/guix-$1-manifest.scm
  207. if [ -f "$manifest" ]; then
  208. if [ "$1" = "default" ]; then
  209. info "Installing default profile..."
  210. run_current_guix package --manifest="$manifest" --keep-failed
  211. . ~/.guix-profile/etc/profile
  212. else
  213. profile=$HOME/.guix-extra-profiles/$1/$1
  214. if [ ! -d "$HOME/.guix-extra-profiles/$1/$1" ]; then
  215. info "Installing profile '$profile'..."
  216. mkdir -p $(dirname "$profile")
  217. run_current_guix package --manifest="$manifest" --keep-failed --profile="$profile"
  218. if [ -f "$profile"/etc/profile ]; then
  219. . "$profile"/etc/profile
  220. fi
  221. else
  222. info "Profile '$profile' already installed."
  223. fi
  224. fi
  225. else
  226. warning "Manifest '$manifest' not found."
  227. fi
  228. }
  229. section "System packages"
  230. if inpath guix; then
  231. if [ ! -e ~/.cache/guix ]; then
  232. message "First 'guix pull'"
  233. run_guix pull
  234. hash guix
  235. fi
  236. for i in default main emacs nyxt texlive; do
  237. guix_install_profile "$i"
  238. done
  239. if is_laptop; then
  240. guix_install_profile laptop
  241. guix_install_profile laptop-gaming
  242. else
  243. guix_install_profile gaming
  244. fi
  245. if $OPT_UPDATE; then
  246. for i in blender chromium electrum racket; do
  247. guix_install_profile "$i"
  248. done
  249. fi
  250. else
  251. warning "Package manager not supported. Install Guix."
  252. fi
  253. if inpath emacs; then
  254. message "Emacs cache folder"
  255. mkdir -pv "$HOME/.cache/emacs/"
  256. message "Emacs local packages"
  257. if [ -e "$XDG_DATA_HOME"/emacs/site-lisp ]; then
  258. for i in "$XDG_DATA_HOME"/emacs/site-lisp/*; do
  259. echo "$i"
  260. git -C "$i" pull
  261. done
  262. else
  263. mkdir -pv "$XDG_DATA_HOME"/emacs/site-lisp
  264. fi
  265. fi
  266. if inpath guix; then
  267. section "Cleanup initial packages"
  268. rm -rv "$(dirname "$PROFILE")"
  269. fi
  270. if [ -x "$XDG_BIN_HOME"/updatedb-local ]; then
  271. section "locate db"
  272. "$XDG_BIN_HOME"/updatedb-local
  273. fi
  274. section "Mail"
  275. # lnn "$SOURCEDIR/mail/authinfo.gpg" "$HOME/.authinfo.gpg" ## Only if not using password-store.
  276. mkdir -pv "$MAIL_CACHE"
  277. while IFS= read -r i; do
  278. ## Warning: We need to eval here to expand the "~".
  279. mkdir -pv $(eval echo $i)
  280. done <<EOF
  281. $(awk '/^Path/ {print $2}' ~/.mbsyncrc)
  282. EOF
  283. if $OPT_UPDATE; then
  284. mbsync -aV
  285. # mu index --maildir="$MAIL_CACHE"
  286. notmuch new
  287. fi