diff --git a/TODO b/TODO deleted file mode 100644 index c078859..0000000 --- a/TODO +++ /dev/null @@ -1,22 +0,0 @@ -ask user to set $LOCATION in .config/zsh/configs/host-setup -ask user to run arandr and save config script in .config/X11/xsession.d/40display-setup - -run fc-cache to get fonts from dotfiles - -these files need to be created -.config -.config/X11/xinitrc.d/40display-setup -.config/X11/xinitrc.d/99host-setup -.config/zsh/configs/host-setup -.local/share/ -.local/share/gnupg/ -.local/share/virtualenv/ -.local/src/ - -rework progs.csv - -look into necessary polkit/sudoers changes (power management, networkmanager stuff) -https://wiki.archlinux.org/title/NetworkManager#Set_up_PolicyKit_permissions - -enable dbus: `ln -s /etc/sv/dbus /var/service/` -enable elogind `ln -s /etc/sv/elogind /var/service` diff --git a/bootstrap.sh b/bootstrap.sh index d22c6b0..530af38 100755 --- a/bootstrap.sh +++ b/bootstrap.sh @@ -1,261 +1,245 @@ #!/bin/sh +DOTS_REPO="https://git.snaile.de/luca/dotfiles" +DOTS_BRANCH="main" +STOW_DIR=".local/share/stow" +DOTS_PACKAGE="dots" -dotsrepo="https://github.com/ssnailed/dotfiles" -dotsbranch="main" +USER_GROUPS="wheel" # Comma separated list +SCRIPT_DIR="$(dirname "$(readlink -f "$0")")" + +BOLD="$(tput bold)" +RED="$(tput setaf 1)" +GREEN="$(tput setaf 2)" +YELLOW="$(tput setaf 3)" +BLUE="$(tput setaf 4)" +RESET="$(tput sgr0)" error() { - # Log to stderr and exit with failure. - printf "%s\n" "$1" >&2 + printf "%b\n" "${RED}${BOLD}${1}${RESET}" >&2 exit 1 } -welcome() { - dialog \ - --title "Welcome!" \ - --msgbox \ - "Welcome!\\n\\nThis script will automatically install a fully-featured Linux desktop with DWM and my dotfiles." \ - 10 60 +prompt() { + message=$1 + tty=$2 + printf "%b" "${BLUE}${message}${RESET}" >"$tty" + # shellcheck disable=SC3037,SC2046 + read -r x + echo "$x" + unset x } -getlogin() { - # Prompts user for new username an password. - name=$( - dialog \ - --inputbox "First, please enter a name for the user account." \ - 10 60 3>&1 1>&2 2>&3 3>&1 - ) || exit 1 - while ! echo "$name" | grep -q "^[a-z_][a-z0-9_-]*$"; do - name=$( - dialog \ - --nocancel \ - --inputbox "Username not valid. Give a username beginning with a letter, with only lowercase letters, - or _." \ - 10 60 3>&1 1>&2 2>&3 3>&1 - ) - done - pass1=$( - dialog \ - --nocancel \ - --passwordbox "Enter a password for that user." \ - 10 60 3>&1 1>&2 2>&3 3>&1 - ) - pass2=$( - dialog \ - --nocancel \ - --passwordbox \ - "Retype password." \ - 10 60 3>&1 1>&2 2>&3 3>&1 - ) - while ! [ "$pass1" = "$pass2" ]; do - unset pass2 - pass1=$( - dialog \ - --nocancel \ - --passwordbox "Passwords do not match.\\n\\nEnter password again." \ - 10 60 3>&1 1>&2 2>&3 3>&1 - ) - pass2=$( - dialog \ - --nocancel \ - --passwordbox "Retype password." \ - 10 60 3>&1 1>&2 2>&3 3>&1 - ) - done +emphasize() { + printf "%b\n" "${GREEN}${BOLD}${1}${RESET}" } -usercheck() { - if id -u "$name" >/dev/null 2>&1; then - dialog \ - --title "WARNING" \ - --yes-button "Continue" \ - --no-button "Cancel" \ - --yesno "\`$name\` already exists on this system.\\n\\nThis script will overwrite any conflicting dotfiles and change this user's password to the one you just gave." 14 70 - fi +info() { + printf "%b\n" "${1}" } -sanitycheck() { - while IFS=, read -r tag program comment; do - case "$tag" in - # "G") ;; - "C") ;; - "X") ;; - *) error "Incorrect installation tag for $program in progs.csv" ;; - esac - done < progs.csv +warn() { + printf "%b\n" "${YELLOW}${BOLD}${1}${RESET}" } -rootcheck() { - return "$(id -u)" -} +_loop_wrapper() { + unset n + unset total + file=$1 + message=$2 + command=$3 -preinstall() { - dialog \ - --title "Confirmation" \ - --yes-button "Start Installation" \ - --no-button "Cancel" \ - --yesno "The rest of the installation is automated." \ - 13 60 || clear && exit 1 - dialog \ - --title "XBPS Updates" \ - --infobox "Updating XBPS Packages." \ - 10 60 - xbps-install -Syu >/dev/null 2>&1 -} + skip_regex="^(#.*)?$" + total=$(grep -cvP "$skip_regex" "$file") -addlogin() { - # Adds user `$name` with password $pass1. - dialog \ - --infobox "Adding user \"$name\"..." \ - 7 50 - useradd -m -g wheel -s /bin/zsh "$name" >/dev/null 2>&1 || - usermod -a -G wheel "$name" && - mkdir -p /home/"$name" && - chown "$name":wheel /home/"$name" - export HOME="/home/$name" - export repodir="$HOME/.local/src" - export dotsdir="$HOME/.local/share/stow/dots" - mkdir -p "$repodir" - chown -R "$name":wheel "$(dirname "$repodir")" - echo "$name:$pass1" | chpasswd - unset pass1 pass2 -} - -installxbps() { - dialog \ - --title "XBPS Installation" \ - --infobox "Installing \`$1\` ($n of $total). $1 $2" \ - 9 70 - xbps-install -Sy "$1" >/dev/null 2>&1 -} - -# installgitmake() { -# progname="${1##*/}" -# progname="${progname%.git}" -# dir="$repodir/$progname" -# dialog \ -# --title "Git Installation" \ -# --infobox "Installing \`$progname\` ($n of $total) via \`git\` and \`make\`. $(basename "$1") $2" \ -# 8 70 -# sudo -u "$name" git -C "$repodir" clone --depth 1 --single-branch \ -# --no-tags -q "$1" "$dir" || -# { -# cd "$dir" || return 1 -# sudo -u "$name" git pull --force origin main -# } -# cd "$dir" || exit 1 -# make >/dev/null 2>&1 -# make install >/dev/null 2>&1 -# cd /tmp || return 1 -# } - -installpip() { - dialog \ - --title "Pip Installation" \ - --infobox "Installing the Python package \`$1\` ($n of $total). $1 $2" 9 70 - [ -x "$(command -v "pip")" ] || installpkg python-pip >/dev/null 2>&1 - yes | pip install "$1" -} - -initnvim() { - dialog \ - --title "Installation" \ - --infobox "Bootstrapping neovim" \ - 8 70 - nvim --headless +qa -} - -installationloop() { - total=$(wc -l /etc/sudoers.d/bootstrap-temp - sed -i "s/-j2/-j$(nproc)/;/^#MAKEFLAGS/s/^#//" /etc/makepkg.conf +setup() { + tput sc + info "Synchronizing XBPS index..." + xbps-install -Syu >/dev/null 2>&1 || error "Failed to synchronize XBPS index!" + tput rc + tput el + + info "Installing ntp..." + xbps-install -y ntp >/dev/null 2>&1 + tput rc + tput el + + info "Synchronizing time..." + ntpdate "pool.ntp.org" >/dev/null 2>&1 || warn "Failed to synchronize time!" + tput rc + tput el + + info "Done!" } -synctime() { - dialog \ - --title "Installation" \ - --infobox "Synchronizing system time to ensure successful and secure installation of software..." \ - 8 70 - ntpdate "0.us.pool.ntp.org" >/dev/null 2>&1 +install_packages() { + failed_packages="" + #shellcheck disable=SC2016 + _loop_wrapper "$1" \ + 'Installing ${x}' \ + 'xbps-install -y "$x" >/dev/null 2>&1 || failed_packages="${failed_packages} ${x}"' + if [ -n "$failed_packages" ]; then + tput rc + tput el + warn "Failed to install:${failed_packages}" + else + info "Done!" + fi + command -v git 1>/dev/null 2>&1 || error "git isn't installed even though it should be!" + command -v stow 1>/dev/null 2>&1 || error "stow isn't installed even though it should be!" +} + +install_files() { + ( + cd "${SCRIPT_DIR}/files" || exit 1 + find . -type f -exec install -Dm 644 "{}" "/{}" \; + ) + info "Done!" +} + +create_user() { + tput sc + + failed=false + while ! echo "$username" | grep -q "[a-z_][a-z0-9_-]*$"; do + $failed && warn "Invalid username, try again!" + username=$(prompt "Input Username: " "$(tty)") + failed=true + tput rc + tput el + done + + if id -u "$username" >/dev/null 2>&1; then + warn "User \"$username\" already exists! Skipping user creation!" + else + info "Creating user \"$username\" with the following groups: \"$USER_GROUPS\"..." + useradd -m -G "$USER_GROUPS" "$username" + failed=false + while [ -z "$pass1" ] || [ "$pass1" != "$pass2" ]; do + $failed && warn "Passwords do not match or are empty, try again!" + tput rc + tput el + pass1=$(prompt "Input Password: " "$(tty)") + tput rc + tput el + pass2=$(prompt "Repeat Password: " "$(tty)") + tput rc + tput el + failed=true + done + echo "$username:$pass1" | chpasswd + fi + + user_home=$(getent passwd "$username" | cut -d ':' -f 6) + [ -z "$username" ] && + error "\$username variable is empty, this script is bugged!" + [ -z "$user_home" ] && + error "\$user_home variable is empty, this script is bugged!" + sudo -u "$username" [ -w "$user_home" ] || error "$username can't write to '$user_home'!" + + info "Done!" +} + +create_directories() { + #shellcheck disable=SC2016 + _loop_wrapper "$1" \ + 'Creating directory ${x}' \ + "mkdir -p $user_home/\${x}" + info "Done!" +} + +install_dotfiles() { + tput sc + info "Cloning dotfiles..." + mkdir -p "${user_home}/${STOW_DIR}" + if [ ! -d "${user_home}/${STOW_DIR}/${DOTS_PACKAGE}/.git" ]; then + if ! git -C "${user_home}/${STOW_DIR}" clone -q --recurse-submodules -b "$DOTS_BRANCH" "$DOTS_REPO" "$DOTS_PACKAGE"; then + tput rc + tput el + warn "Failed to clone dotfiles" + return 1 + fi + fi + tput rc + tput el + info "Symlinking dotfiles..." + if ! stow -d "$user_home/$STOW_DIR" -t "$user_home" "$DOTS_PACKAGE" 1>/dev/null 2>&1; then + tput rc + tput el + warn "Failed to symlink dotfiles" + return 2 + fi + tput rc + tput el + info "Done!" +} + +enable_services() { + tput sc + info "Installing user service service..." + target="/etc/sv/runsvdir-${username}/run" + mkdir -p "$(dirname "$target")" + sed "s//$username/" "${SCRIPT_DIR}/userservice.sh" >"$target" + [ ! -L "/var/service/$(basename "$target")" ] && + ln -s "$target" "/var/service/" + chmod 755 "$target" + tput rc + tput el + #shellcheck disable=SC2016 + _loop_wrapper "$1" \ + 'Enabling ${x} service' \ + '[ ! -L /var/service/${x} ] && ln -s "/etc/sv/${x}" "/var/service/"' + info "Done!" } finalize() { - dialog \ - --title "Installation" \ - --infobox "Cleaning up..." \ - 8 70 - mkdir -p "$HOME/.local/share/virtualenv" - mkdir -p "$HOME/.local/share/gnupg" + gid=$(getent passwd "$username" | cut -d ':' -f 4) + groupname=$(getent group "$gid" | cut -d ':' -f 1) + chown "$username:$groupname" "$user_home" + info "Done!" } -goodbye() { - dialog \ - --title "All done!" \ - --msgbox "Unless this script has bugs (contact me at luca@snaile.de) the installation is finished\\n\\n\ -To run the new graphical environment, log out and log back in as your new user, then run the command \"startgraphical\" to start the graphical environment (it will start automatically in tty1)." \ - 13 80 -} +### CONTROL FLOW BEGINS HERE ### -### EXECUTION STARTS HERE ### +check_root -sanitycheck +emphasize "-- Preparing Installation --" +setup -rootcheck || error "Make sure this script is running as root. (Was run as user \`$(id -un $?)\`)" +emphasize "-- Installing Packages --" +install_packages "${SCRIPT_DIR}/packages.txt" -welcome || error "User exited." +emphasize "-- Copying Files --" +install_files -getlogin || error "User exited." +emphasize "-- Creating User Account --" +create_user -usercheck || error "User exited." +emphasize "-- Creating Standard Home Directories --" +create_directories "${SCRIPT_DIR}/directories.txt" -preinstall || error "User exited." +emphasize "-- Installing Dotfiles --" +install_dotfiles -addlogin || error "Error adding username and/or password." - -initbootstrap - -synctime - -installationloop - -pulldots - -initnvim +emphasize "-- Enabling Services --" +enable_services "${SCRIPT_DIR}/services.txt" +emphasize "-- Finalizing Installation --" finalize -goodbye +emphasize "-- Installation Complete --" diff --git a/directories.txt b/directories.txt new file mode 100644 index 0000000..639a097 --- /dev/null +++ b/directories.txt @@ -0,0 +1,12 @@ +.cache +.config/zsh/configs +.config/X11/xinitrc.d +.local/state +.local/share/applications +.local/share/gnupg +.local/bin/cron +Desktop +Documents +Downloads +Pictures/Screenshots +Videos diff --git a/files/etc/X11/xorg.conf.d/50-mouseaccel.conf b/files/etc/X11/xorg.conf.d/50-mouseaccel.conf new file mode 100644 index 0000000..045e0e9 --- /dev/null +++ b/files/etc/X11/xorg.conf.d/50-mouseaccel.conf @@ -0,0 +1,7 @@ +Section "InputClass" + Identifier "My Mouse" + Driver "libinput" + MatchIsPointer "yes" + Option "AccelProfile" "flat" + Option "AccelSpeed" "0" +EndSection diff --git a/files/etc/zsh/zshenv b/files/etc/zsh/zshenv new file mode 100644 index 0000000..6ffade8 --- /dev/null +++ b/files/etc/zsh/zshenv @@ -0,0 +1,2 @@ +[ -z "$XDG_CONFIG_HOME" ] && export XDG_CONFIG_HOME="$HOME/.config/" +[ -d "$XDG_CONFIG_HOME/zsh" ] && export ZDOTDIR="$XDG_CONFIG_HOME/zsh/" diff --git a/requirements b/packages.txt similarity index 59% rename from requirements rename to packages.txt index d963c1f..fd73e83 100644 --- a/requirements +++ b/packages.txt @@ -1,14 +1,12 @@ --- asmara installed -- git neovim -base-devel -firefox stow zsh xorg noto-fonts-ttf +noto-fonts-ttf-extra noto-fonts-emoji -sxiv +nsxiv xwallpaper ffmpeg man-db @@ -28,7 +26,7 @@ xsecurelock lf psmisc wget -xcompmgr +picom xss-lock playerctl ntp @@ -43,9 +41,20 @@ lazygit elogind pamixer xdg-utils -ffmpeg-thumbnailer +gpgme +virtualenvwrapper +atool +rsync +lm_sensors +dwm-custom +pinentry-dmenu-custom +dmenu-custom +st-custom +dwmblocks-custom +ffmpegthumbnailer +pnpm +shellcheck +shfmt htop-vim - --- needed -- -npm -brave +NetworkManager +bind-utils diff --git a/progs.csv b/progs.csv deleted file mode 100644 index b18e27e..0000000 --- a/progs.csv +++ /dev/null @@ -1,57 +0,0 @@ -,xorg-server,"is the graphical server. This first one may take a while as it pulls many other dependencies first on clean installs." -,xorg-xwininfo,"allows querying information about windows." -,xorg-xinit,"starts the graphical server." -,xorg-xprop,"is a tool for detecting window properties." -,xorg-xbacklight,"enables changing screen brightness levels." -,arandr,"allows the user to customize monitor arrangements." -,dosfstools,"allows your computer to access dos-like filesystems." -,libnotify,"allows desktop notifications." -,dunst,"provides the system notification daemon." -,exfat-utils,"allows management of FAT drives." -,picom,"allows for some eyecandy effects and vsync." -,sxiv,"is an image viewer." -,xwallpaper,"sets the wallpaper." -,ffmpeg,"can record and splice video and audio on the command line." -,ffmpegthumbnailer,"creates thumbnail previews of video files." -,gnome-keyring,"serves as the system keyring." -,neovim,"is a lua based vim, a text editor." -,mpv,"the one true video player." -,man-db,"lets you read man pages of programs." -,newsboat,"is a terminal RSS client." -,noto-fonts,"is an expansive font package." -,noto-fonts-emoji,"is an emoji font." -,wireplumber,"is the audio system." -,pipewire-pulse,"gives pipewire compatibility with PulseAudio programs." -,pulsemixer,"is an audio controller." -,maim,"can take quick screenshots at your request." -,unclutter,"hides an inactive mouse." -,unzip,"unzips zips." -,lynx,"is a terminal browser also used in LARBS for generating in-terminal previews of websites, emails and HTML files." -,xcape,"allows keyboard remapping of escape/capslock." -,xclip,"allows for copying and pasting from the command line." -,xdotool,"provides window action utilities on the command line." -,yt-dlp,"can download any YouTube video (or playlist or channel) when given the link." -,zathura,"is a pdf viewer with vim-like bindings." -,zathura-pdf-mupdf,"allows mupdf pdf compatibility in zathura." -,poppler,"manipulates .pdfs and gives .pdf previews and other .pdf functions." -,mediainfo,"shows audio and video information and is used in the file browser." -,atool,"manages and gives information about archives." -,7z,"manages and gives information about archives." -,fzf,"is a fuzzy finder tool used for easy selection and location of files." -,bat,"can highlight code output and display files and is used to generate previews in the file browser." -,socat,"is a utility which establishes two byte streams and transfers data between them." -,moreutils,"is a collection of useful unix tools." -,mpd,"is a lightweight music daemon." -,mpc,"provides a terminal interface for mpd." -,ncmpcpp,"provides an ncurses interface for mpc." -,neofetch,"comes preinstalled on this system because you were gonna install it anyways." -,pinentry,"allows prompts for SSH keys." -,transmission-cli,"is a torrenting client." -,breeze-icons,"provides some fallback icons." -,hicolor-icon-theme,"provides some fallback icons." -,xsecurelock,"is a screen locker." -,lf,"is a terminal file manager" -,simple-mtpfs,"enables the mounting of cell phones." - -A,task-spooler,"queues commands or files for download." -A,htop-vim,"is a graphical and colorful system monitor." diff --git a/services.txt b/services.txt new file mode 100644 index 0000000..3a1b18c --- /dev/null +++ b/services.txt @@ -0,0 +1,4 @@ +dhcpcd +dbus +NetworkManager +elogind diff --git a/userservice.sh b/userservice.sh new file mode 100644 index 0000000..c50199a --- /dev/null +++ b/userservice.sh @@ -0,0 +1,9 @@ +#!/bin/sh + +export USER="" +export HOME="/home/" + +groups="$(id -Gn "$USER" | tr ' ' ':')" +svdir="$HOME/.local/sv/" + +exec chpst -u "$USER:$groups" runsvdir "$svdir"