norisa.sh 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338
  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, cargo
  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 cargo"
  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. "/home/$username/.local/"
  158. )
  159. mkdir -vp "${needed_dirs[@]}"
  160. chown -v "$username:users" "${needed_dirs[@]}"
  161. }
  162. ensure_sudo_is_symlinked_to_doas() {
  163. log_info "Ensure sudo is symlinked to doas"
  164. if [ ! -f /usr/bin/sudo ]; then
  165. ln -s /usr/bin/doas /usr/bin/sudo
  166. log_changed "sudo was symlinked to doas"
  167. else
  168. log_ok "sudo is already symlinked to doas"
  169. fi
  170. }
  171. ensure_needed_dirs_created
  172. setup_temporary_doas
  173. ensure_user_is_part_of_needed_groups
  174. ensure_sudo_is_symlinked_to_doas
  175. # add xdg-repo
  176. # if ! grep -q "^\s*\[xdg-repo\]\s*$" /etc/pacman.conf; then
  177. # echo -e "\e[0;30;34mAdding Noah's xdg-repo ...\e[0m"
  178. # pacman-key --recv-keys 7FA7BB604F2A4346 --keyserver keyserver.ubuntu.com
  179. # pacman-key --lsign-key 7FA7BB604F2A4346
  180. # echo "[xdg-repo]
  181. # Server = https://git.noahvogt.com/noah/\$repo/raw/master/\$arch" >> /etc/pacman.conf
  182. # fi
  183. # Add chaotic-aur (x86_64 only)
  184. if [ "$ARCH" = "x86_64" ]; then
  185. if ! grep -q "^\s*\[chaotic-aur\]\s*$" /etc/pacman.conf; then
  186. echo -e "\e[0;30;34mAdding the chaotic aur repo ...\e[0m"
  187. pacman-key --recv-key 3056513887B78AEB --keyserver keyserver.ubuntu.com
  188. pacman-key --lsign-key 3056513887B78AEB
  189. pacman -U --noconfirm 'https://cdn-mirror.chaotic.cx/chaotic-aur/chaotic-keyring.pkg.tar.zst'
  190. pacman -U --noconfirm 'https://cdn-mirror.chaotic.cx/chaotic-aur/chaotic-mirrorlist.pkg.tar.zst'
  191. echo "[chaotic-aur]
  192. Include = /etc/pacman.d/chaotic-mirrorlist" >>/etc/pacman.conf
  193. fi
  194. fi
  195. # Install AUR Helper (paru as paru-bin is out-of-date)
  196. ensure_paru_installed() {
  197. log_info "Ensuring paru is installed"
  198. if ! command -v paru >/dev/null 2>&1; then
  199. if [ "$ARCH" = "x86_64" ] && pacman -Si paru >/dev/null 2>&1; then
  200. pacman -S --noconfirm paru
  201. else
  202. log_info "Building paru from source..."
  203. temp_dir=$(mktemp -d)
  204. chown "$username:users" "$temp_dir"
  205. doas -u "$username" bash -c "cd $temp_dir && git clone https://aur.archlinux.org/paru.git && cd paru && makepkg --noconfirm"
  206. pacman -U --noconfirm "$temp_dir"/paru/*.pkg.tar.* || pkg_install_error_exit
  207. fi
  208. log_changed "Installed AUR helper (paru)"
  209. else
  210. log_ok "AUR helper (paru) is already installed"
  211. fi
  212. }
  213. ensure_paru_installed
  214. ensure_dotfiles_are_fetched() {
  215. log_info "Ensuring dotfiles are fetched"
  216. if [ ! -d /home/"$username"/.local/src/dotfiles ]; then
  217. echo -e "\e[0;30;34mFetching dotfiles ...\e[0m"
  218. cd_into /home/"$username"/.local/src
  219. while true; do
  220. git clone https://git.noahvogt.com/noah/dotfiles.git && break
  221. done
  222. log_changed "dotfiles were fetched successfully"
  223. else
  224. log_ok "dotfiles were already fetched"
  225. fi
  226. }
  227. apply_dotfiles() {
  228. log_info "Applying dotfiles"
  229. cd_into /home/"$username"/.local/src/dotfiles
  230. doas -u "$username" /home/"$username"/.local/src/dotfiles/apply-dotfiles
  231. }
  232. # Architecture-specific packages
  233. ARCH=$(uname -m)
  234. if [ "$ARCH" = "x86_64" ]; then
  235. ARCH_PKGS="xf86-video-vesa xf86-video-fbdev xf86-video-amdgpu xf86-video-intel xf86-video-nouveau ungoogled-chromium-bin obs-studio brave-bin ghostty ttf-material-symbols-variable-git nomacs wlogout unifetch shellcheck yt-dlp"
  236. ARCH_AUR_PKGS="simple-mtpfs google-java-format code2prompt-bin"
  237. else
  238. # Asahi/ARM specific or generic alternatives
  239. ARCH_PKGS="chromium"
  240. ARCH_AUR_PKGS="unifetch shellcheck-bin yt-dlp-git logseq-desktop-bin code2prompt"
  241. # TODO: fix manual install of wlogout
  242. fi
  243. # TODO: add element-desktop back
  244. MAIN_PKGS="xorg-server neovim ranger xournalpp ffmpeg sxiv arandr man-db brightnessctl unzip python mupdf-gl mediainfo highlight pipewire pipewire-pulse pipewire-alsa pipewire-audio wireplumber pulsemixer pamixer ttf-linux-libertine calcurse xclip noto-fonts-emoji imagemagick gimp xorg-setxkbmap wavemon dash htop wireless_tools alsa-utils acpi zip libreoffice-fresh nm-connection-editor dunst libnotify dosfstools mpv xorg-xinput cpupower zsh zsh-syntax-highlighting newsboat pcmanfm openbsd-netcat powertop mupdf-tools stow zsh-autosuggestions 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 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 yad hyprland python-poetry python-build python-pillow ttf-space-mono-nerd kitty shfmt ruff luarocks rust-analyzer hyprland-guiutils waybar socat hyprlock clang swaync bat wl-clipboard syncthing python-debugpy awww kitty tokei gemini-cli hypridle tlp texlive-basic texlive-bibtexextra texlive-binextra texlive-context texlive-fontsextra texlive-fontsrecommended texlive-fontutils texlive-formatsextra texlive-games texlive-humanities texlive-latex texlive-latexextra texlive-latexrecommended texlive-luatex texlive-mathscience texlive-metapost texlive-music texlive-pictures texlive-plaingeneric texlive-pstricks texlive-publishers texlive-xetex libva-utils blueman woff2-font-awesome bind qt5-wayland qt6-wayland pre-commit python-pandas pyright python-beautifulsoup4 tree-sitter-cli jupyterlab $ARCH_PKGS"
  245. ensure_pkgs_installed "$MAIN_PKGS" "main packages" "pacman"
  246. ensure_dotfiles_are_fetched
  247. apply_dotfiles
  248. AUR_PKGS="redshift dashbinsh cspell-lsp doasedit nodejs-cspell nvim-lazy lexend-fonts-git xwaylandvideobridge $ARCH_AUR_PKGS"
  249. ensure_pkgs_installed "$AUR_PKGS" "AUR" "doas -u $username paru"
  250. ensure_global_zsh_installed() {
  251. log_info "Ensuring global zshenv"
  252. if grep -q "export ZDOTDIR=\$HOME/.config/zsh" /etc/zsh/zshenv; then
  253. log_ok "Global zshenv ist already installed"
  254. else
  255. mkdir -vp /etc/zsh
  256. echo "export ZDOTDIR=\$HOME/.config/zsh" >/etc/zsh/zshenv
  257. log_changed "Installed global zshenv"
  258. fi
  259. }
  260. ensure_bluetooth_service_enabled() {
  261. log_info "Ensuring Bluetooth service is enabled"
  262. if ! systemctl is-enabled bluetooth.service >/dev/null 2>&1; then
  263. systemctl enable bluetooth.service
  264. log_changed "Enabled bluetooth.service system-wide"
  265. else
  266. log_ok "Bluetooth service is already enabled"
  267. fi
  268. }
  269. cleanup_home() {
  270. log_info "Cleaning up \$HOME"
  271. for f in /home/"$username"/.bash*; do
  272. [ -f "$f" ] && rm "$f"
  273. done
  274. for f in /home/"$username"/.less*; do
  275. [ -f "$f" ] && rm "$f"
  276. done
  277. }
  278. ensure_dns_priority_in_nsswitch() {
  279. log_info "Ensuring DNS priority in /etc/nsswitch.conf"
  280. if grep -q "hosts:.*dns.*resolve" /etc/nsswitch.conf; then
  281. log_ok "DNS priority is already correct in nsswitch.conf"
  282. else
  283. cp /etc/nsswitch.conf /etc/nsswitch.conf.bak
  284. sed -i 's/^hosts:.*/hosts: mymachines files dns resolve [!UNAVAIL=return] myhostname/' /etc/nsswitch.conf || error_exit "Failed to set new config options on /etc/nsswitch.conf"
  285. log_changed "Updated hosts config in nsswitch.conf"
  286. fi
  287. }
  288. ensure_global_zsh_installed
  289. ensure_history_file_exists
  290. ensure_login_shell_is_zsh
  291. setup_final_doas
  292. ensure_bluetooth_service_enabled
  293. ensure_dns_priority_in_nsswitch
  294. cleanup_home