#+TITLE: Phundrak-flavored Arch Linux
#+setupfile: headers
#+OPTIONS: auto-id:t
#+HTML_HEAD_EXTRA: <meta name="description" content="Phundrak-flavored Arch Linux" />
#+HTML_HEAD_EXTRA: <meta property="og:title" content="Phundrak-flavored Arch Linux" />
#+HTML_HEAD_EXTRA: <meta property="og:description" content="How to install a Phundrak-flavored Arch Linux" />
#+PROPERTY: header-args :tangle no :exports none
#+PROPERTY: header-args:sh :tangle no :exports code
#+PROPERTY: header-args:fish :exports code :noweb yes
#+PROPERTY: header-args:emacs-lisp :exports none :noweb yes :tangle no :cache yes

* Introduction
  :PROPERTIES:
  :CUSTOM_ID: Introduction-cd5792cd
  :END:
  Here will be  presented what I do to  get my system up and running  on a fresh
  Arch Linux install.  These installation instructions were written  in order to
  get an Arch  Linux distribution up and running with  the same configuration as
  my main computer’s and my travelling laptop’s configuration.

* Install Arch Linux
  :PROPERTIES:
  :CUSTOM_ID: Install_Arch_Linux-ac7ad3b2
  :END:
  I usually install Arch  from the [[https://www.archlinux.org/download/][vanilla ISO]], however I  began using [[https://github.com/MatMoul/archfi][archfi]] to
  install easily  the distro (I’ve done  it so many  times, I know how  it works
  now). Usually, my distros will be installed on two partitions: ~/home~ and ~/~
  (root).

  If the computer supports EFI bootloaders, the EFI partition will be mounted on
  ~/boot/efi~. I generally use ~systemd-boot~ as my boot manager, but if you are
  more comfortable with  another one, just install what you  want. Be aware that
  if you format  your ~/boot~ partition, you will delete  all boot managers that
  already exist; so,  if you are dual-booting,  *DO NOT FORMAT IT*.  Yes, I made
  the mistake of wiping the Windows boot manager when I used to dual-boot.

  In order to use the  ~suspend-then-hibernate~ systemd command, it is necessary
  to have a swap  partition at least twice the size of  your installed RAM. That
  is because  when this command  will be  run, the system  will try to  save the
  current state of your machine, stored in  your RAM, to the swap filesystem. If
  there is not enough space, the command will fail, and you won’t be able to use
  this command.

** Get the latest, fastest mirrors
   :PROPERTIES:
   :CUSTOM_ID: Install_Arch_Linux-Get_the_latest_fastest_mirrors-765401c9
   :END:
   When you boot into the live ISO, execute the following command:
   #+BEGIN_SRC sh
     pacman -Sy reflector
     reflector -c FR -c DE -c BE -l 200 -p http -p https --sort rate \
               --save /etc/pacman.d/mirrorlist --verbose
   #+END_SRC

   This will update the  packages from your live ISO, and you  will get the best
   mirrors for your installation. Of course, change the countries accordingly to
   your  location. In  my case,  I  am only  interested in  French, German,  and
   Belgian mirrors.

** Install the system
   :PROPERTIES:
   :CUSTOM_ID: Install_Arch_Linux-Install_the_system-3ff49aa6
   :END:
   Then you can use a custom script to  ease your installation of Arch if you do
   not wish to do it manually. Personally, I’ve done it several times already, I
   know  how the  distro works,  I just  want to  be able  to install  my distro
   quickly now. I’ll need to download  the script with ~wget~, but apparently it
   isn’t installed by default on Arch ISOs anymore, so I’ll need to install it.
   #+BEGIN_SRC sh
     pacman -S wget
   #+END_SRC

   Now, let’s grab the script. You can check it on [[https://github.com/matmoul/archfi][Github]].
   #+BEGIN_SRC sh
     wget archfi.sf.net/archfi
     # Or from matmoul.github.io/archfi if SourceForge is down
     sh archfi
   #+END_SRC

   Then, follow the instructions and install Arch Linux. Take the opportunity to
   install as many packages as you need,  mainly ~yay~ which I use as my package
   manager  (it   is  just  a  wrapper   for  ~pacman~)  and  AUR   helper,  and
   ~pacman-contrib~ which will help us installing some packages later.

   Once your system is installed, reboot and remove your installation media from
   your computer.

* Execute bootstrap
  :PROPERTIES:
  :HEADER-ARGS:fish: :tangle ~/.config/yadm/bootstrap :shebang "#!/usr/bin/fish" :exports code :mkdirp yes
  :CUSTOM_ID: Execute_bootstrap-e37054ef
  :END:
  With the installation of  Arch with ~archfi~, I will have  [[https://github.com/Jguer/yay][yay]], an AUR helper,
  installed. This will  allow me to have some basic  packages installed in order
  to run  the bootstrap  described below.  So, let’s  install ~fish~  (our shell
  running the script), ~git~, and my dotfiles manager ~yadm~.
  #+BEGIN_SRC sh
    yay -Sy fish git yadm
  #+END_SRC

  ~yadm~  comes with  a very  handy  feature: its  bootstrap script.  It can  be
  executed automatically once the dotfiles are cloned with yadm:
  #+BEGIN_SRC sh
    yadm clone https://labs.phundrak.com/phundrak/dotfiles
    # or if labs.phundrak.com is down or too slow for you
    #yadm clone https://github.com/phundrak/dotfiles
  #+END_SRC

  Let’s take a look at what it does.

** Decrypt private yadm files
   :PROPERTIES:
   :CUSTOM_ID: Execute_bootstrap-Decrypt_private_yadm_files-68af7157
   :END:
   Some  private  files are  stored  encrypted  in  the  repository of  my  yadm
   dotfiles. I will need them later on during the bootstrap execution.
   #+BEGIN_SRC fish
     if test "$USER" = 'phundrak'
         yadm decrypt
     else
         whiptail --yesno "Decrypt private files?" 8 40 && yadm decrypt
     end
   #+END_SRC

** Get a correct keyboard layout
   :PROPERTIES:
   :CUSTOM_ID: Execute_bootstrap-Get_a_correct_keyboard_layout-77d24b30
   :END:
   I use  mainly the [[https://bepo.fr/wiki/Accueil][bépo]]  layout, a French  keyboard layout inspired  by Dvorak
   layouts,  however I  sometimes need  to switch  back to  the standard  French
   AZERTY or the American  QWERTY layout, so I make it so  the Menu key switches
   for me my layout between these three.  This makes it so my xorg configuration
   of my keyboard looks like this:
   #+BEGIN_SRC fish
     set keyboardconf \
     'Section "InputClass"
             Identifier "system-keyboard"
             MatchIsKeyboard "on"
             Option "XkbLayout" "fr"
             Option "XkbModel" "pc104"
             Option "XkbVariant" "bepo_afnor"
             Option "XkbOptions" "caps:ctrl_modifier"
     EndSection'
   #+END_SRC

   So,  let’s  ask  the  user  if  they   want  to  set  it  as  their  keyboard
   configuration.
   #+BEGIN_SRC fish
     printf "\n# Set keyboard layout #########################################################\n\n"
     whiptail --yesno "Would you like to set your keyboard layout to the bépo layout?" 8 55
     if test $status -eq 0
         echo $keyboardconf | sudo tee /etc/X11/xorg.conf.d/00-keyboard.conf
     end
   #+END_SRC

** Set our locale
   :PROPERTIES:
   :CUSTOM_ID: Execute_bootstrap-Set_our_locale-e74d772a
   :END:
   I use two main  locales, the French and US UTF-8 locales, and  I like to keep
   the Japanese locale activated just in case.
   #+BEGIN_SRC fish
     set mylocales "en_US.UTF-8 UTF-8" "fr_FR.UTF-8 UTF-8" "ja_JP.UTF-8 UTF-8"
   #+END_SRC

   I’ll let the user accept them one by one.
   #+BEGIN_SRC fish
     printf "\n# Set locale ##################################################################\n\n"

     for item in $mylocales
         whiptail --yesno "Set the \"$item\" locale?" 8 40
         if test $status -eq 0 -a (grep -e "#$item" /etc/locale.gen)
             sudo sed -i "/$item/s/^#//g" /etc/locale.gen
         end
     end
   #+END_SRC

   This is my configuration I usually use when it comes to my locale.
   #+BEGIN_SRC fish
     set localeconf "LANG=en_US.UTF-8
     LC_COLLATE=C
     LC_NAME=fr_FR.UTF-8
     LC_NUMERIC=fr_FR.UTF-8
     LC_IDENTIFICATION=fr_FR.UTF-8
     LC_TELEPHONE=fr_FR.UTF-8
     LC_MONETARY=fr_FR.UTF-8
     LC_PAPER=fr_FR.UTF-8
     LC_ADDRESS=fr_FR.UTF-8
     LC_TIME=fr_FR.UTF-8
     LC_MEASUREMENT=fr_FR.UTF-8"
   #+END_SRC

   Let’s set it as our system’s locale if the user whishes to.
   #+BEGIN_SRC fish
     whiptail --yesno "Do you agree to have the following locale set?\n\n     $localeconf"  20 43
     if test $status -eq 0
         echo $localeconf | sudo tee /etc/locale.conf
     end
   #+END_SRC

   Now we can generate our locale!
   #+BEGIN_SRC fish
     printf "\n# Generate locale #############################################################\n\n"
     sudo locale-gen
   #+END_SRC

** Create some folders
   :PROPERTIES:
   :CUSTOM_ID: Execute_bootstrap-Create_some_folders-bf701387
   :END:
   Let’s create  some folders  we might  need for  mounting our  drives, Android
   devices and CDs.
   #+BEGIN_SRC fish
     printf "\n# Create directories for mounting #############################################\n\n"
     sudo mkdir -p /mnt/{USB,CD,Android}
     sudo chown $USER:(id -g $USER) /mnt/{USB,CD,Android}
   #+END_SRC

** Set user’s shell to fish
   :PROPERTIES:
   :CUSTOM_ID: Execute_bootstrap-Set_user’s_shell_to_fish-1a794be2
   :END:
   First of all, the bootstrap shell will set the user’s shell to fish.
   #+BEGIN_SRC fish
     printf "\n# Set fish as the default shell ###############################################\n\n"
     whiptail --yesno "Set the current user’s default shell to fish?" 8 50
     if test $status -eq 0 -a ! "$SHELL" = '/usr/bin/fish'
         chsh -s /usr/bin/fish
     end
   #+END_SRC

** Install basic packages
   :PROPERTIES:
   :CUSTOM_ID: Execute_bootstrap-Install_basic_packages-17173316
   :END:
   Let’s set in a custom varible what packages we’ll be needing.
   #+BEGIN_SRC fish
     set PACKAGES \
     acpilight adobe-source-han-sans-jp-fonts arc-gtk-theme asar ascii aspell-en \
     aspell-fr awesome awesome-terminal-fonts awesome-freedesktop-git base-devel \
     bashtop bat biber bitwarden-bin bluez-firmware bluez-utils bookworm bzip2 \
     chicken chromium clisp corrupter-git cppcheck cppreference \
     cppreference-devhelp cpupower discord-canary discount docker docker-compose \
     dockerfile-language-server-bin doxygen emacs emacs-org-mode exa exfat-utils \
     farbfeld fd ffmpegthumbnailer findutils firefox flake8 flat-remix-gtk freeglut \
     fzf gcc-libs gdb gimp gnome-disk-utility gnome-epub-thumbnailer gnu-free-fonts \
     gnuplot go go-tools golangci-lint-bin graphviz htop i3lock-color inetutils \
     isync inter-font javascript-typescript-langserver js-beautify jfsutils jmtpfs \
     lain-git libxft-bgra linux-headers lldb logrotate ly meson minted man-db \
     man-pages mpc mpd mpd-rich-presence-discord-git mpv mupdf-tools nano ncdu \
     ncmpcpp nemo-fileroller nemo-preview neofetch netctl network-manager-applet \
     networkmanager networkmanager-openvpn nitrogen nm-connection-editor nodejs-vmd \
     nomacs nordic-theme-git nordvpn-bin noto-fonts-emoji npm ntfs-3g numlockx \
     obs-studio openssh otf-fandol otf-ipafont p7zip pacman-contrib pandoc-bin pass \
     pavucontrol pdfpc picom-ibhagwan-git powerline-fonts prettier \
     pulseaudio-bluetooth python-autoflake python-epc python-importmagic \
     python-language-server python-nose python-pip python-poetry python-ptvsd \
     python-pytest qt5-imageformats qemu r raw-thumbnailer reflector ripgrep rofi \
     rsync rtv ruby-rb-fsevent ruby-sass rustup samba scrot sent shadow siji-git \
     simplescreenrecorder sshfs st-luke-git sxiv texlive-bin texlive-langchinese \
     texlive-langcyrillic texlive-langgreek texlive-langjapanese texlive-langkorean \
     texlive-latexextra texlive-localmanager-git texlive-most tmux tree \
     ttf-arphic-uming ttf-baekmuk ttf-charis-sil ttf-dejavu \
     ttf-google-fonts-opinionated-git ttf-hanazono ttf-joypixels ttf-koruri \
     ttf-liberation ttf-monapo ttf-sazanami ttf-tibetan-machine typescript \
     typescript-language-server-bin unicode-emoji unrar usbutils valgrind \
     vscode-css-languageserver-bin vscode-html-languageserver-bin w3m wget \
     x11-ssh-askpass xclip xdg-user-dirs-gtk xfce-polkit xidlehook xfsprogs \
     xorg-drivers xorg-server xorg-xinit xss-lock xvkbd yaml-language-server-bin \
     zeal
   #+END_SRC

   These are the  minimum I would have  in my own installation. You  can edit it
   however you want. Let’s install those.
   #+BEGIN_SRC fish
     printf "\n# Installing needed packages ##################################################\n\n"
     sudo pacman -Syu
     for pkg in $PACKAGES
         yay -S --needed $pkg
     end
   #+END_SRC

** Tangle configuration files from Org files
   :PROPERTIES:
   :CUSTOM_ID: Execute_bootstrap-Tangle_configuration_files_from_Org_files-cc524361
   :END:
   Before tangling our  configuration files, we need to  create some directories
   first so our files can be properly tangled. Here’s the list of directories we
   need to create:
   #+NAME: dirs-tangled-files
   | $HOME/.config/awesome       |
   | $HOME/.config/awesome/theme |
   | $HOME/.config/emacs/private |
   | $HOME/.config/fish          |
   | $HOME/.config/gtk-2.0       |
   | $HOME/.config/gtk-3.0       |
   | $HOME/.config/ncmpcpp       |
   | $HOME/.config/neofetch      |
   | $HOME/.config/picom         |
   | $HOME/.config/yadm          |
   | $HOME/.local/bin            |
   | $HOME/org/capture           |

   #+NAME: gen-dirs-tangle
   #+BEGIN_SRC emacs-lisp :var dirs=dirs-tangled-files
     (mapconcat (lambda (x) (format "mkdir -p %s" (car x)))
                dirs
                "\n")
   #+END_SRC

   #+RESULTS[a95e25a5f3ac91b1f884b39dde38e3b51366b188]: gen-dirs-tangle
   #+begin_example
   mkdir -p $HOME/.config/awesome
   mkdir -p $HOME/.config/awesome/theme
   mkdir -p $HOME/.config/emacs/private
   mkdir -p $HOME/.config/fish
   mkdir -p $HOME/.config/gtk-2.0
   mkdir -p $HOME/.config/gtk-3.0
   mkdir -p $HOME/.config/ncmpcpp
   mkdir -p $HOME/.config/neofetch
   mkdir -p $HOME/.config/picom
   mkdir -p $HOME/.config/yadm
   mkdir -p $HOME/.local/bin
   mkdir -p $HOME/org/capture
   #+end_example

   Our code to generate such directories looks like this:
   #+BEGIN_SRC fish :noweb yes
     <<gen-dirs-tangle()>>
   #+END_SRC

   The next step is  to tangle all the Org files. Here is the list of files that
   are to be tangled:
   #+NAME: tangled-files
   | filename    |
   |-------------|
   | awesome.org |
   | bin.org     |
   | emacs.org   |
   | fish.org    |
   | index.org   |
   | picom.org   |
   | rustfmt.org |
   | tmux.org    |

   #+NAME: generate-tangle
   #+BEGIN_SRC emacs-lisp :var files=tangled-files[,0]
     (mapconcat (lambda (x) (concat
                             (format "printf '\\n\\n==== Tangling %s\\n\\n' && \\\n" x)
                             (concat "emacs -q --batch --eval '(require \\'ob-tangle)' \\\n"
                                     "--eval '(setq org-confirm-babel-evaluate nil)' \\\n"
                                     (format "--eval '(org-babel-tangle-file \"~/org/config/%s\")'\n" x))))
                files
                "\n")
   #+END_SRC

   #+RESULTS[87a25d6c524e8d1346452c54aa42ac3ac09d94cf]: generate-tangle
   #+begin_example
   printf '\n\n==== Tangling awesome.org\n\n' && \
   emacs -q --batch --eval '(require \'ob-tangle)' \
   --eval '(setq org-confirm-babel-evaluate nil)' \
   --eval '(org-babel-tangle-file "~/org/config/awesome.org")'

   printf '\n\n==== Tangling bin.org\n\n' && \
   emacs -q --batch --eval '(require \'ob-tangle)' \
   --eval '(setq org-confirm-babel-evaluate nil)' \
   --eval '(org-babel-tangle-file "~/org/config/bin.org")'

   printf '\n\n==== Tangling emacs.org\n\n' && \
   emacs -q --batch --eval '(require \'ob-tangle)' \
   --eval '(setq org-confirm-babel-evaluate nil)' \
   --eval '(org-babel-tangle-file "~/org/config/emacs.org")'

   printf '\n\n==== Tangling fish.org\n\n' && \
   emacs -q --batch --eval '(require \'ob-tangle)' \
   --eval '(setq org-confirm-babel-evaluate nil)' \
   --eval '(org-babel-tangle-file "~/org/config/fish.org")'

   printf '\n\n==== Tangling index.org\n\n' && \
   emacs -q --batch --eval '(require \'ob-tangle)' \
   --eval '(setq org-confirm-babel-evaluate nil)' \
   --eval '(org-babel-tangle-file "~/org/config/index.org")'

   printf '\n\n==== Tangling picom.org\n\n' && \
   emacs -q --batch --eval '(require \'ob-tangle)' \
   --eval '(setq org-confirm-babel-evaluate nil)' \
   --eval '(org-babel-tangle-file "~/org/config/picom.org")'

   printf '\n\n==== Tangling rustfmt.org\n\n' && \
   emacs -q --batch --eval '(require \'ob-tangle)' \
   --eval '(setq org-confirm-babel-evaluate nil)' \
   --eval '(org-babel-tangle-file "~/org/config/rustfmt.org")'

   printf '\n\n==== Tangling tmux.org\n\n' && \
   emacs -q --batch --eval '(require \'ob-tangle)' \
   --eval '(setq org-confirm-babel-evaluate nil)' \
   --eval '(org-babel-tangle-file "~/org/config/tmux.org")'
   #+end_example

   #+BEGIN_SRC fish :noweb yes
     printf "\n# Tangling org files ##########################################################\n\n"
     <<generate-tangle()>>
   #+END_SRC

** Setting up Emacs: Installing Spacemacs
   :PROPERTIES:
   :CUSTOM_ID: Execute_bootstrap-Setting_up_Emacs:_Installing_Spacemacs-0b3d44b2
   :END:
   Now,  the first  thing we  want to  do with  Emacs is  install its  Spacemacs
   distribution.  We’ll clone  its =develop=  branch into  =~/.config/emacs=. We
   need to  do this prior  to our dotfiles’  cloning because of  some submodules
   that are cloned within our =~/.config/emacs=  directory, and git won’t let us
   clone Spacemacs in an already existing  and non-empty directory. To make sure
   it  isn’t  one,  let’s  delete  any  potentially  existing  =~/.config/emacs=
   directory:
   #+BEGIN_SRC fish
     printf "\n# Installing Spacemacs ########################################################\n\n"
     rm -rf $HOME/.config/emacs $HOME/.emacs* .spacemacs
   #+END_SRC

   Now we can clone Spacemacs:
   #+BEGIN_SRC fish
     git clone --branch develop https://github.com/syl20bnr/spacemacs ~/.config/emacs
   #+END_SRC

   And we can  restore what might have been deleted  in our =~/.emacs.d/private=
   directory:
   #+BEGIN_SRC fish
     yadm checkout -- ~/.config/emacs/private/
   #+END_SRC

** Set up dotfiles’ git repository
   :PROPERTIES:
   :CUSTOM_ID: Execute_bootstrap-Set_up_dotfiles-ab372bd9
   :END:
*** Update our dotfiles’ remotes
    :PROPERTIES:
    :CUSTOM_ID: Execute_bootstrap-Set_up_dotfiles-Update_our_dotfiles’_remotes-5a0fe6f7
    :END:
    This line in the bootstrap script will  test if the current user is using my
    username. If yes, it’s probably me.
    #+BEGIN_SRC fish
      if test "$USER" = 'phundrak'
    #+END_SRC

    If it is  me installing and using  these dotfiles, I want the  remotes of my
    dotfiles to be set to ssh remotes using my ssh keys.
    #+BEGIN_SRC fish
      printf "\n# Update yadm’s remotes #######################################################\n\n"
      yadm remote set-url origin git@labs.phundrak.com:phundrak/dotfiles.git
      yadm remote add github git@github.com:phundrak/dotfiles.git
    #+END_SRC

    I will also want to decrypt my encrypted files, such as said ssh keys.
    #+BEGIN_SRC fish
      printf "\n# Decrypt encrypted dotfiles ##################################################\n\n"
      yadm decrypt
    #+END_SRC

    Finally, let’s close this ~if~ statement.
    #+BEGIN_SRC fish
      end
    #+END_SRC

*** Update our submodules
    :PROPERTIES:
    :CUSTOM_ID: Execute_bootstrap-Set_up_dotfiles-Update_our_submodules-3e921579
    :END:
    Now we  can download  the various  dependencies of our  dotfiles. To  do so,
    let’s run the following command:
    #+BEGIN_SRC fish
      printf "\n# Getting yadm susbmodules ####################################################\n\n"
      yadm submodule update --init --recursive
    #+END_SRC

** Enable some services
   :PROPERTIES:
   :CUSTOM_ID: Execute_bootstrap-Enable_some_services-3d38d98e
   :END:
   We have  installed some packages  which require  some services to  run. Let’s
   enable them.

*** Systemd-timesyncd
    :PROPERTIES:
    :CUSTOM_ID: Execute_bootstrap-Enable_some_services-Systemd-timesyncd-d887e45b
    :END:
    This service enables time syncing with the NTP protocol, so I can be sure my
    computer’s time is correct. The service first needs to be enabled:
    #+BEGIN_SRC fish
      printf "\n# Enabling timesync ###########################################################\n\n"
      sudo systemctl enable --now systemd-timesyncd
    #+END_SRC

    Now, let systemd know  I want to use the NTP protocol  to keep my computer’s
    time synced.
    #+BEGIN_SRC fish
      sudo timedatectl set-ntp true
    #+END_SRC

*** Docker
    :PROPERTIES:
    :CUSTOM_ID: Execute_bootstrap-Enable_some_services-Docker-305e8309
    :END:
    First, let’s activate Docker.
    #+BEGIN_SRC fish
      printf "\n# Enabling and starting Docker ################################################\n\n"
      sudo systemctl enable --now docker
    #+END_SRC

    Now, if we wish  it, we can be added to the =docker=  group so we won’t have
    to type =sudo= each time we call Docker or Docker Compose.
    #+BEGIN_SRC fish
      read --prompt "echo 'Do you wish to be added to the `docker` group? (Y/n): ' " -l adddockergroup
      if test $adddockergroup = 'y' || test $adddockergroup = "Y" || test $adddockergroup = ''
          sudo usermod -aG docker $USER
      end
    #+END_SRC

*** Emacs
    :PROPERTIES:
    :CUSTOM_ID: Execute_bootstrap-Enable_some_services-Emacs-c7785c21
    :END:
    Emacs will run as a user service,  which means it won’t be launched until we
    log  in. However,  the service  won’t be  started immediately,  I personally
    prefer to start a standalone instance  in which installing and compiling the
    Emacs packages  will happen,  and then once  that is done  I will  start the
    service.
    #+BEGIN_SRC fish
      printf "\n# Enabling Emacs as user service ##############################################\n\n"
      systemctl --user enable emacs
    #+END_SRC

*** Mpd
    :PROPERTIES:
    :CUSTOM_ID: Execute_bootstrap-Enable_some_services-Mpd-f0f5b9b7
    :END:
    Mpd will  also use as a  user service in order  to get rid of  some lines of
    code in my configuration.
    #+BEGIN_SRC fish
      printf "\n# Enabling Mpd as a user service ##############################################\n\n"
      mkdir -p ~/.config/mpd/playlists
      systemctl --user enable --now mpd
    #+END_SRC

*** SSH server
    :PROPERTIES:
    :CUSTOM_ID: Execute_bootstrap-Enable_some_services-SSH_server-204f5997
    :END:
    Maybe we want to activate an SSH server on our machine. If so, we can enable
    it. Let’s ask the question.
    #+BEGIN_SRC fish
      whiptail --yesno 'Do you want to activate the ssh server?' 8 50
      if test $status -eq 0
          printf "\n# Enabling ssh server #########################################################\n\n"
          sudo systemctl enable --now sshd
      end
    #+END_SRC

*** Ly
    :PROPERTIES:
    :CUSTOM_ID: Execute_bootstrap-Enable_some_services-Ly-f4b161c0
    :END:
    Ly is a display manager based on ncurses  which I find nice enough for me to
    use (I  generally don’t like using  display managers). Let’s enable  it, and
    let’s disable tty2 while we’re at it (Ly uses it to run X).
    #+BEGIN_SRC fish
      sudo systemctl disable getty@tty2
      sudo systemctl enable --now ly
    #+END_SRC

*** Acpilight
    :PROPERTIES:
    :CUSTOM_ID: Execute_bootstrap-Enable_some_services-Acpilight-39152794
    :END:
    ~acpilight~ is our  utility managing the brightness of our  screen. There is
    actually no service to  enable here, but we must ensure the  user is part of
    the ~video~  group so  we can  modify the brightness  of our  screen without
    using ~sudo~.
    #+BEGIN_SRC fish
      sudo usermod -aG video $USER
    #+END_SRC

*** NordVPN
    :PROPERTIES:
    :CUSTOM_ID: Execute_bootstrap-Enable_some_services-NordVPN-75c1bd88
    :END:
    Thanks  to the  AUR  package ~nordvpn-bin~,  I no  longer  have to  manually
    maintain my  VPN connections  with OpenVPN. However,  it requires  a service
    that we should activate:
    #+BEGIN_SRC fish
      sudo systemctl enable --now nordvpnd
    #+END_SRC

    Let’s also set  its default protocol to  UDP. This will allow me  to use any
    port while  connected to  any WiFi  as long  as the  443 port  is available.
    Because yes, I do  connect to a WiFi that blocks  some important ports, such
    as  the IMAP  and SMTP  ports. Thanks  University of  Paris 8  for being  SO
    paranoid.
    #+BEGIN_SRC fish
      nordvpn s protocol udp
    #+END_SRC

** Symlink some system config files
   :PROPERTIES:
   :CUSTOM_ID: Execute_bootstrap-Symlink_some_system_config_files-1dd95175
   :END:
   We have some files in [[file:ect/][etc/]] that are to be symlinked to =/etc=.
   #+BEGIN_SRC fish
     for f in (find ~/.etc -type f)
         set dest (echo $f | sed -n 's|^.*etc\(.*\)$|/etc\1|p')
         sudo ln -s $f $dest
     end
   #+END_SRC

** Install packages from git
   :PROPERTIES:
   :CUSTOM_ID: Execute_bootstrap-Install_packages_from_git-7c6a6ea4
   :END:
   Now, let’s install some packages from git directly.
   #+BEGIN_SRC fish
     mkdir -p ~/fromGIT
   #+END_SRC

*** Reveal.JS
    :PROPERTIES:
    :CUSTOM_ID: Execute_bootstrap-Install_packages_from_git-Reveal.JS-bb4da0bf
    :END:
    I sometimes use  Reveal.JS to make presentations, and I  set its location in
    my [[file:.spacemacs][dotspacemacs]] file to be in =~/fromGIT=, so let’s clone it there.
    #+BEGIN_SRC fish
      printf "\n# Install Reveal.JS ###########################################################\n\n"
      cd ~/fromGIT
      git clone https://github.com/hakimel/reveal.js.git
    #+END_SRC

** Install Rust
   :PROPERTIES:
   :CUSTOM_ID: Execute_bootstrap-Install_Rust-1839c4d0
   :END:
*** Install the toolchains
    :PROPERTIES:
    :CUSTOM_ID: Execute_bootstrap-Install_Rust-Install_the_toolchains-3480764a
    :END:
    When using Rust, I bounce between two toolchains, the ~stable~ toolchain and
    the  ~nightly~ toolchain,  although  I try  to stick  with  Rust Stable.  To
    install  them,  I  will  use  ~rustup~  which  has  already  been  installed
    previously.
    #+BEGIN_SRC fish
      printf "\n# Install the rust toolchains, nightly is the default one #####################\n\n"
      rustup default stable
    #+END_SRC

    This will both download the stable toolchain  and set it as the default one.
    Now to install the nightly toolchain, let’s run this:
    #+BEGIN_SRC fish
      rustup toolchain install nightly
    #+END_SRC

*** Install some utilities
    :PROPERTIES:
    :CUSTOM_ID: Execute_bootstrap-Install_Rust-Install_some_utilities-c4a7c785
    :END:
    We’ll need some utilities when  developing Rust from Emacs, namely ~rustfmt~
    and ~racer~. Let’s install them with ~cargo~.
    #+BEGIN_SRC fish
      printf "\n# Add rust utilities ##########################################################\n\n"
      cargo install rustfmt racer
    #+END_SRC

    We will also need some components for development purposes.
    #+NAME: rust-components-table
    | Component | Why                                         |
    |-----------+---------------------------------------------|
    | rust-src  | Rust documentation in Emacs                 |
    | rls       | LSP backend for Emacs                       |
    | clippy    | A better version of cargo’s ~check~ command |

    #+NAME: rust-components-gen
    #+BEGIN_SRC emacs-lisp :var components=rust-components-table[,0]
      (mapconcat (lambda (x) (format "rustup component add %s" x))
                 components
                 "\n")
    #+END_SRC

    #+RESULTS[b3935b1c09d86fe506b43670f52960306a1e9809]:
    : rustup component add rust-src
    : rustup component add rls
    : rustup component add clippy

    Here is the code to do so:
    #+BEGIN_SRC fish :noweb yes
      <<rust-components-gen()>>
    #+END_SRC

** Install some python packages
   :PROPERTIES:
   :CUSTOM_ID: Execute_bootstrap-Install_some_python_packages-a4447a6f
   :END:
   Some  packages will  be needed  from  pip in  order  to get  our Emacs  setup
   correctly working.
   #+NAME: python-packages-table
   | Package                     | Why                     |
   |-----------------------------+-------------------------|
   | python-language-server[all] | Python LSP packages     |
   | pyls-isort                  | Import sortings for LSP |
   | pyls-mypy                   | Mypy linter for LSP     |
   | pyls-black                  | Black plugin for pyls   |

   #+NAME: python-packages-gen
   #+BEGIN_SRC emacs-lisp :var packages=python-packages-table[,0]
     (format "pip install --user %s"
             (s-join " " packages))
   #+END_SRC

   #+RESULTS[cb6abaea9d7130a67569af2b4d1a545651bf29ab]: python-packages-gen
   : pip install --user python-language-server[all] pyls-isort pyls-mypy pyls-black

   Let’s install them locally for our user.
   #+BEGIN_SRC fish :noweb yes
     printf "\n# Installing Python packages ##################################################\n\n"
     <<python-packages-gen()>>
   #+END_SRC

** Set up Chicken (Scheme interpreter/compiler)
   :PROPERTIES:
   :CUSTOM_ID: Execute_bootstrap-Set_up_Chicken_(Scheme_interpreter-compiler)-3c1a3c4a
   :END:
   Chicken needs to be  set up before being used. First, we  need to install its
   documentation.
   #+BEGIN_SRC fish
     printf "\n# Setting up Chicken ##########################################################\n\n"
     chicken-install -s apropos chicken-doc
   #+END_SRC

   Then, we’ll complete the documentation like so:
   #+BEGIN_SRC fish
     cd (chicken-csi -b -e "(import (chicken platform))" -p "(chicken-home)")
     curl https://3e8.org/pub/chicken-doc/chicken-doc-repo.tgz | sudo tar zx
   #+END_SRC

** Set up our fish shell
   :PROPERTIES:
   :CUSTOM_ID: Execute_bootstrap-Set_up_our_fish_shell-f0741c22
   :END:
   The last thing we want to do is to set up our fish shell with some extensions
   in order to improve the user experience.

*** Install ~fisher~
    :PROPERTIES:
    :CUSTOM_ID: Execute_bootstrap-Set_up_our_fish_shell-Install_=fisher=-3a44531b
    :END:
    We will be using ~fisher~ as  our extensions manager for Fish. Let’s install
    it.
    #+BEGIN_SRC fish
      printf "\n# Installing fisher ###########################################################\n\n"
      curl https://git.io/fisher --create-dirs -sLo ~/.config/fish/functions/fisher.fish
    #+END_SRC

*** Install our extensions
    :PROPERTIES:
    :CUSTOM_ID: Execute_bootstrap-Set_up_our_fish_shell-Install_our_extensions-188e4566
    :END:
    I generally use the following extensions in my Fish shell.
    #+NAME: fish-extensions-table
    #+CAPTION: Fish extensions managed by Fisher
    | Package name                | Description                                                      |
    |-----------------------------+------------------------------------------------------------------|
    | decors/fish-colored-man     | Color man pages to make them more readable                       |
    | franciscolourenco/done      | Automatically receive notifications when a long process finishes |
    | jethrokuan/fzf              | Improved key bindings for [[https://github.com/junegunn/fzf][junegunn/fzf]]                           |
    | jethrokuan/z                | Pure-fish [[https://github.com/rupa/z][rupa/z]]-like directory jumping                          |
    | jorgebucaran/fish-bax       | Run bash scripts, replaying environment changes in fish          |
    | jorgebucaran/fish-getopts   | CLI options parser; alternative to the [[https://fishshell.com/docs/current/commands.html#argparse][argparse]] fish builtin     |
    | laughedelic/pisces          | Autoclose parentheses, braces, quotes and other paired symbols   |
    | oh-my-fish/theme-bobthefish | A Powerline-style, Git-aware fish theme optimized for awesome.   |

    #+NAME: fish-extensions-gen
    #+BEGIN_SRC emacs-lisp :var extensions=fish-extensions-table[,0]
      (mapconcat (lambda (x) (format "fisher add %s" x))
                 extensions
                 "\n")
    #+END_SRC

    #+RESULTS[a88b321ba9148acc8c28c7fb1aaf924c23b6b072]: fish-extensions-gen
    : fisher add decors/fish-colored-man
    : fisher add franciscolourenco/done
    : fisher add jethrokuan/fzf
    : fisher add jethrokuan/z
    : fisher add jorgebucaran/fish-bax
    : fisher add jorgebucaran/fish-getopts
    : fisher add laughedelic/pisces
    : fisher add oh-my-fish/theme-bobthefish

    #+BEGIN_SRC fish :noweb yes
      printf "\n# Installing Fisher Extensions ################################################\n\n"
      <<fish-extensions-gen()>>
    #+END_SRC
