norisa.sh 10.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292
  1. #!/bin/bash
  2. # SPDX-License-Identifier: GPL-3.0-or-later
  3. # ASSUMED STATE OF TARGET SYSTEM:
  4. # - internet access
  5. # - root user login
  6. # - ~30 GB of free disk space
  7. # working 1.) base 2.) linux packages
  8. readonly C_RESET='\e[0m'
  9. readonly C_INFO='\e[1;36m' # Cyan
  10. readonly C_OK='\e[1;32m' # Green
  11. readonly C_CHANGE='\e[1;33m' # Yellow
  12. readonly C_ERR='\e[1;31m' # Red
  13. log_info() {
  14. echo -e "${C_INFO}[ INFO ]${C_RESET} $1"
  15. }
  16. log_ok() {
  17. echo -e "${C_OK}[ OK ]${C_RESET} $1"
  18. }
  19. log_changed() {
  20. echo -e "${C_CHANGE}[ CHANGE ]${C_RESET} $1"
  21. }
  22. log_error() {
  23. echo -e "${C_ERR}[ ERROR ]${C_RESET} $1" >&2
  24. }
  25. error_exit() {
  26. log_error "$1"
  27. exit 1
  28. }
  29. # Install opendoas and (base-devel, devtools minus sudo), libxft
  30. readonly BASE_PKGS="archlinux-keyring opendoas autoconf automake binutils bison debugedit fakeroot file findutils flex gawk gcc gettext grep groff gzip libtool m4 make pacman patch pkgconf sed texinfo which libxft breezy coreutils curl diffutils expac git glow gum jq mercurial openssh parallel reuse rsync subversion util-linux"
  31. pkg_install_error_exit() {
  32. error_exit "Package installation command was not successfull. Exiting ..."
  33. }
  34. cd_error_exit() {
  35. log_info "Current working directory:"
  36. pwd
  37. error_exit "Could not change into '$1'. Exiting ..."
  38. }
  39. cd_into() {
  40. cd "$1" || cd_error_exit "$1"
  41. }
  42. ensure_pkgs_installed() {
  43. MISSING_PKGS="$(pacman -T $1)"
  44. log_info "Ensuring $2 packages are installed"
  45. if [ -n "$MISSING_PKGS" ]; then
  46. "$3" -Sy --noconfirm --needed "$MISSING_PKGS" || pkg_install_error_exit
  47. log_changed "$2 packages are now installed"
  48. else
  49. log_ok "$2 packages are already installed"
  50. fi
  51. }
  52. setup_temporary_doas() {
  53. log_info "Setting up temporary doas config"
  54. printf "permit nopass :wheel
  55. permit nopass root as $username\n" >/etc/doas.conf
  56. chown -c root:root /etc/doas.conf
  57. chmod -c 0400 /etc/doas.conf
  58. }
  59. setup_final_doas() {
  60. log_info "Setting up final doas config"
  61. printf "permit persist :wheel
  62. permit nopass $username as root cmd mount
  63. permit nopass $username as root cmd umount
  64. permit nopass root as $username\n" >/etc/doas.conf
  65. chown -c root:root /etc/doas.conf
  66. chmod -c 0400 /etc/doas.conf
  67. }
  68. create_new_user() {
  69. echo -e "\e[0;30;42m Enter your desired username \e[0m"
  70. read -rp " >>> " username
  71. useradd -m -g users -G wheel "$username"
  72. while true; do
  73. passwd "$username" && break
  74. done
  75. }
  76. choose_user() {
  77. echo -e "\e[0;30;46m Available users: \e[0m"
  78. ls /home
  79. while true; do
  80. echo -e "\e[0;30;42m Enter in your chosen user \e[0m"
  81. read -rp " >>> " username
  82. ls /home/ | grep -q "^$username$" && break
  83. done
  84. }
  85. ensure_user_is_part_of_needed_groups() {
  86. log_info "Verify $username is part of video and input groups"
  87. if ! groups "$username" | grep "input" | grep -q "video"; then
  88. log_info "Adding $username to video and input groups"
  89. usermod -aG video "$username"
  90. usermod -aG input "$username"
  91. else
  92. log_ok "$username is already part of these groups"
  93. fi
  94. }
  95. ensure_history_file_exists() {
  96. log_info "Ensure history file exists"
  97. if ! [ -f /home/"$username"/.cache/zsh/history ]; then
  98. echo -e "\e[0;30;34mEnsuring initial zsh history file exists ...\e[0m"
  99. mkdir -vp /home/"$username"/.cache/zsh
  100. touch /home/"$username"/.cache/zsh/history
  101. log_changed "Created history file"
  102. else
  103. log_ok "history file is already present"
  104. fi
  105. }
  106. ensure_login_shell_is_zsh() {
  107. log_info "Ensure login shell is zsh"
  108. if ! grep "^$username.*::/home/$username" /etc/passwd | sed 's/^.*://' |
  109. grep -q "^$(which zsh)$"; then
  110. echo -e "\e[0;30;34mSetting default shell to $(which zsh)...\e[0m"
  111. chsh -s "$(which zsh)" "$username" || exit 1
  112. log_changed "changed shell to zsh"
  113. fi
  114. }
  115. ensure_pkgs_installed "$BASE_PKGS" "some basic" "pacman"
  116. ensure_user_selected() {
  117. if [ -d /home ]; then
  118. mapfile -t home_users < <(ls -A /home)
  119. user_count=${#home_users[@]}
  120. else
  121. user_count=0
  122. fi
  123. if [ "$user_count" -eq 1 ]; then
  124. username="${home_users[0]}"
  125. echo -e "\e[0;30;46m A single user was found: $username \e[0m"
  126. elif [ "$user_count" -gt 1 ]; then
  127. echo -e "\e[0;30;46m /home/ not empty, $user_count users already available \e[0m"
  128. while true; do
  129. echo -e "\e[0;30;42m Do you want to create another user? [y/n] \e[0m"
  130. read -rp " >>> " want_new_user
  131. if [[ "$want_new_user" =~ ^[yY]$ ]]; then
  132. create_new_user
  133. break
  134. elif [[ "$want_new_user" =~ ^[nN]$ ]]; then
  135. choose_user
  136. break
  137. fi
  138. done
  139. else
  140. want_new_user=y
  141. create_new_user
  142. fi
  143. }
  144. ensure_user_selected
  145. ensure_needed_dirs_created() {
  146. log_info "Creating needed ~/ directories"
  147. needed_dirs=(
  148. "/home/$username/dox"
  149. "/home/$username/pix"
  150. "/home/$username/dl"
  151. "/home/$username/vids"
  152. "/home/$username/mus"
  153. "/home/$username/.local/bin"
  154. "/home/$username/.config"
  155. "/home/$username/.local/share"
  156. "/home/$username/.local/src"
  157. )
  158. mkdir -vp "${needed_dirs[@]}"
  159. chown -v "$username:users" "${needed_dirs[@]}"
  160. }
  161. ensure_needed_dirs_created
  162. setup_temporary_doas
  163. ensure_user_is_part_of_needed_groups
  164. # add xdg-repo
  165. # if ! grep -q "^\s*\[xdg-repo\]\s*$" /etc/pacman.conf; then
  166. # echo -e "\e[0;30;34mAdding Noah's xdg-repo ...\e[0m"
  167. # pacman-key --recv-keys 7FA7BB604F2A4346 --keyserver keyserver.ubuntu.com
  168. # pacman-key --lsign-key 7FA7BB604F2A4346
  169. # echo "[xdg-repo]
  170. # Server = https://git.noahvogt.com/noah/\$repo/raw/master/\$arch" >> /etc/pacman.conf
  171. # fi
  172. # Add chaotic-aur
  173. if ! grep -q "^\s*\[chaotic-aur\]\s*$" /etc/pacman.conf; then
  174. echo -e "\e[0;30;34mAdding the chaotic aur repo ...\e[0m"
  175. pacman-key --recv-key 3056513887B78AEB --keyserver keyserver.ubuntu.com
  176. pacman-key --lsign-key 3056513887B78AEB
  177. pacman -U --noconfirm 'https://cdn-mirror.chaotic.cx/chaotic-aur/chaotic-keyring.pkg.tar.zst'
  178. pacman -U --noconfirm 'https://cdn-mirror.chaotic.cx/chaotic-aur/chaotic-mirrorlist.pkg.tar.zst'
  179. echo "[chaotic-aur]
  180. Include = /etc/pacman.d/chaotic-mirrorlist" >>/etc/pacman.conf
  181. fi
  182. # Install AUR Helper (paru as paru-bin is out-of-date)
  183. ensure_paru_installed() {
  184. log_info "Ensuring paru is installed"
  185. if ! pacman -Q | grep -q paru; then
  186. pacman -S --noconfirm paru
  187. log_changed "Installed AUR helper (paru)"
  188. else
  189. log_ok "AUR helper (paru) is already installed"
  190. fi
  191. }
  192. ensure_sudo_is_symlinked_to_doas() {
  193. log_info "Ensure sudo is symlinked to doas"
  194. if [ ! -f /usr/bin/sudo ]; then
  195. ln -s /usr/bin/doas /usr/bin/sudo
  196. log_changed "sudo was symlinked to doas"
  197. else
  198. log_ok "sudo is already symlinked to doas"
  199. fi
  200. }
  201. ensure_dotfiles_are_fetched() {
  202. log_info "Ensuring dotfiles are fetched"
  203. if [ ! -d /home/"$username"/.local/src/dotfiles ]; then
  204. echo -e "\e[0;30;34mFetching dotfiles ...\e[0m"
  205. cd_into /home/"$username"/.local/src
  206. while true; do
  207. git clone https://git.noahvogt.com/noah/dotfiles.git && break
  208. done
  209. log_changed "dotfiles were fetched successfully"
  210. else
  211. log_ok "dotfiles were already fetched"
  212. fi
  213. }
  214. apply_dotfiles() {
  215. log_info "Applying dotfiles"
  216. cd_into /home/"$username"/.local/src/dotfiles
  217. doas -u "$username" /home/"$username"/.local/src/dotfiles/apply-dotfiles
  218. }
  219. apply_dotfiles
  220. # TODO: add element-desktop back
  221. MAIN_PKGS="xorg-server xf86-video-vesa xf86-video-fbdev shellcheck neovim ranger xournalpp ffmpeg obs-studio sxiv arandr man-db brightnessctl unzip python mupdf-gl mediainfo highlight pulseaudio-alsa pulsemixer pamixer ttf-linux-libertine calcurse xclip noto-fonts-emoji imagemagick gimp xorg-setxkbmap wavemon texlive dash unifetch htop wireless_tools alsa-utils acpi zip libreoffice nm-connection-editor dunst libnotify dosfstools mpv xorg-xinput cpupower zsh zsh-syntax-highlighting newsboat nomacs pcmanfm openbsd-netcat powertop mupdf-tools nomacs stow zsh-autosuggestions xf86-video-amdgpu xf86-video-intel xf86-video-nouveau npm fzf unclutter ccls mpd mpc ncmpcpp pavucontrol strawberry smartmontools firefox python-pynvim python-pylint tesseract-data-deu tesseract-data-eng keepassxc ueberzug img2pdf dust ctags python-wand python-termcolor python-black jdk-openjdk ripgrep lf ungoogled-chromium-bin ttf-jetbrains-mono-nerd foliate coreutils curl fish foot fuzzel gjs gnome-bluetooth-3.0 gnome-control-center gnome-keyring gobject-introspection grim gtk3 gtk-layer-shell libdbusmenu-gtk3 meson nlohmann-json plasma-browser-integration playerctl polkit-gnome python-pywal sassc slurp swayidle typescript xorg-xrandr webp-pixbuf-loader wireplumber yad ydotool gojq hyprland python-poetry python-build python-pillow ttf-material-symbols-variable-git ttf-space-mono-nerd wlogout kitty shfmt ruff luarocks rust-analyzer hyprland-guiutils waybar socat hyprlock brave-bin clang swaync bat wl-clipboard syncthing python-debugpy ghostty awww kitty tokei gemini-cli hypridle tlp"
  222. ensure_history_file_exists "$MAIN_PKGS" "main packages" "pacman"
  223. AUR_PKGS="simple-mtpfs redshift dashbinsh cspell-lsp doasedit nodejs-cspell nvim-lazy google-java-format lexend-fonts-git"
  224. ensure_pkgs_installed "$AUR_PKGS" "AUR" "doas -u $username paru"
  225. ensure_global_zsh_installed() {
  226. log_info "Ensuring global zshenv"
  227. if grep -q "export ZDOTDIR=\$HOME/.config/zsh" /etc/zsh/zshenv; then
  228. log_ok "Global zshenv ist already installed"
  229. else
  230. mkdir -vp /etc/zsh
  231. echo "export ZDOTDIR=\$HOME/.config/zsh" >/etc/zsh/zshenv
  232. log_changed "Installed global zshenv"
  233. fi
  234. }
  235. ensure_global_zsh_installed
  236. ensure_history_file_exists
  237. ensure_login_shell_is_zsh
  238. setup_final_doas
  239. cleanup_home() {
  240. log_info "Cleaning up \$HOME"
  241. for f in /home/"$username"/.bash*; do
  242. [ -f "$f" ] && rm "$f"
  243. done
  244. for f in /home/"$username"/.less*; do
  245. [ -f "$f" ] && rm "$f"
  246. done
  247. }
  248. cleanup_home