dotfiles/utils/debian.sh

396 lines
8.6 KiB
Bash
Executable file

#!/bin/sh
set -eu
# See `parse_args()` for enabling dry run.
dry_run="no"
is_dry_run() {
test "${dry_run}" = "yes"
}
setup_colors() {
if [ -t 1 ]; then
sgr0="$(printf '\033[0m')"
bold="$(printf '\033[1m')"
red="$(printf '\033[31m')"
green="$(printf '\033[32m')"
yellow="$(printf '\033[33m')"
blue="$(printf '\033[34m')"
else
sgr0=''
bold=''
red=''
green=''
yellow=''
blue=''
fi
}
setup_commands() {
dry=''
is_dry_run && dry="echo "
APT="${dry}apt"
APT_FILE="${dry}apt-file"
CD="${dry}cd"
CHSH="${dry}chsh"
CURL="${dry}curl"
DPKG="${dry}dpkg"
GIT="${dry}git"
GZIP="${dry}gzip"
HELP2MAN="${dry}help2man"
LN="${dry}ln"
MKDIR="${dry}mkdir"
MV="${dry}mv"
PANDOC="${dry}pandoc"
RM="${dry}rm"
RMDIR="${dry}rmdir"
SED="${dry}sed"
STOW="${dry}stow"
SU="${dry}su"
TAR="${dry}tar"
UNZIP="${dry}unzip"
UPDATE_GRUB="${dry}update-grub"
USERADD="${dry}useradd"
USERMOD="${dry}usermod"
}
usage() {
echo "Usage: $(basename "$0") [-h] [-n]"
echo ""
echo " -h print this help and exit."
echo " -n dry run, don't make changes."
}
error() {
printf "${red}ERROR:${sgr0} %s\n" "$1" >&2
exit 1
}
info() {
printf "${green}->${sgr0} %s\n" "$1"
}
title() {
echo "${blue}${bold}=> ${1}${sgr0}"
}
skipped() {
echo "${yellow}SKIPPED:${sgr0} ${1}"
}
apt_install() {
title "Install APT packages"
info "Updating package database"
${APT} update
info "Installing APT packages"
${APT} install -y \
apt-file \
ascii \
build-essential \
ca-certificates \
cmake \
cmake-doc \
curl \
exuberant-ctags \
g++ \
gcc \
git \
git-crypt \
gnupg \
help2man \
htop \
jq \
make \
man-db \
nodejs \
pandoc \
pkg-config \
psmisc \
python3 \
python3-virtualenv \
ripgrep \
rsync \
shellcheck \
sshpass \
stow \
sudo \
tmux \
unzip \
zsh
info "Updating apt-file database"
${APT_FILE} update
}
grub_disable_timeout() {
title "Disable GRUB timeout"
${SED} -i.original -e 's/^GRUB_TIMEOUT=.*/GRUB_TIMEOUT=0/' /etc/default/grub
${UPDATE_GRUB}
}
ensure_usr_local_man_manN() {
title "Make sure we have directories for all man page sections"
for dir in $(seq -f '/usr/local/man/man%.0f' 9); do
${MKDIR} -vp "${dir}"
done
}
user_setup() {
title "Setup user: $1"
if user_exists "$1"; then
info "User $1 exists. Updating..."
user_update "$1"
else
info "Creating user $1"
user_new "$1"
fi
user_allow_sudo_nopasswd "$1"
}
user_exists() {
id -u "$1" >/dev/null 2>&1
}
user_new() {
empty_skel="$(mktemp -d)"
${USERADD} \
-m ` # Create home directory.` \
-k "$empty_skel" ` # Copy files from this directory into the new home.` \
-U ` # Create a groups with the same name as the user.` \
-G staff ` # Other groups the new user will be a member of.` \
-s /bin/zsh ` # The new user's login shell. ` \
"$1" ` # The new user's name.` \
2>&1 ` # Silently.` \
${RMDIR} "$empty_skel"
}
# Add user $1 to the `staff` group...
# ...and change shell to `zsh` and get rid of bash files.
user_update() {
info "Adding $1 to group staff"
${USERMOD} -aG staff "$1"
info "Changing login shell to zsh"
${CHSH} -s /bin/zsh "$1"
info "Removing bash leftover files"
for f in .bash_history .bash_logout .bashrc .profile; do
${RM} -vf "/home/${1}/${f}"
done
}
# Allow `sudo` without password for user $1.
user_allow_sudo_nopasswd() {
info "Enabling sudo without password for ${1}"
contents="$1 ALL=(ALL:ALL) NOPASSWD:ALL"
sudoers_file="/etc/sudoers.d/${1}_nopasswd"
if is_dry_run; then
echo "echo \"$contents\" >$sudoers_file"
else
echo "$contents" >"$sudoers_file"
fi
}
# Deploy dotfiles for user $1 from URL $2.
deploy_dotfiles() {
title "Deploy dotfiles"
dotfiles_dir="/home/$1/.dotfiles"
if [ -d "${dotfiles_dir}" ]; then
skipped "${dotfiles_dir} exists"
else
info "Cloning dotfiles"
${SU} "$1" -c "git clone $2 ${dotfiles_dir}"
(
info "Installing dotfiles"
${CD} "${dotfiles_dir}"
${SU} "$1" -c "./install.sh -y"
)
fi
}
install_broot() (
title "Install broot v${1}"
${MKDIR} broot
${CD} broot
pkg="broot-${1}"
info "Creating directory structure"
for subdir in bin share/man/man1 share/zsh/vendor-completions; do
${MKDIR} -p "${pkg}/${subdir}"
done
info "Downloading release archive"
archive="broot_${1}"
${CURL} -LO "https://github.com/Canop/broot/releases/download/v${1}/broot_${1}.zip"
info "Extracting release archive"
${MKDIR} "${archive}"
${UNZIP} -d "${archive}" "broot_${1}.zip"
info "Packaging executable"
${MV} -v "${archive}/x86_64-linux/broot" "${pkg}/bin/"
info "Packaging man page"
${MV} -v "${archive}/broot.1" "${pkg}/share/man/man1/"
info "Packaging zsh completions"
for completion in _br _broot; do
${MV} -v "${archive}/completion/${completion}" "${pkg}/share/zsh/vendor-completions/"
done
info "Installing package"
${MV} "${pkg}" /usr/local/stow/
${STOW} -v -d /usr/local/stow "${pkg}"
)
install_eza() (
title "Install eza v${1}"
${MKDIR} eza
${CD} eza
pkg="eza-${1}"
info "Creating directory structure"
for subdir in bin share/man/man1 share/man/man5 share/zsh/vendor-completions; do
${MKDIR} -p "${pkg}/${subdir}"
done
info "Packaging executable from release archive"
${CURL} -LO "https://github.com/eza-community/eza/releases/download/v${1}/eza_x86_64-unknown-linux-gnu.tar.gz"
${TAR} -xf eza_x86_64-unknown-linux-gnu.tar.gz
${MV} -v eza "${pkg}/bin/"
info "Cloning repository for man pages and shell completions"
${GIT} clone --branch "v${1}" --depth 1 https://github.com/eza-community/eza.git repo
info "Generating man pages"
for page in eza.1 eza_colors.5 eza_colors-explanation.5; do
${SED} -i -e "s/\$version/v${1}/g" "repo/man/${page}.md"
${PANDOC} \
--standalone \
--from markdown \
--to man \
--output "${pkg}/share/man/man${page##*.}/${page}" \
"repo/man/${page}.md"
${GZIP} -n9 "${pkg}/share/man/man${page##*.}/${page}"
done;
info "Packaging zsh comletions"
${MV} -v "repo/completions/zsh/_eza" "${pkg}/share/zsh/vendor-completions/"
info "Installing package"
${MV} "${pkg}" /usr/local/stow/
${STOW} -v -d /usr/local/stow "${pkg}"
)
install_fd() (
title "Install fd v${1}"
${MKDIR} fd
${CD} fd
pkg="fd-${1}"
info "Downloading release archive"
${CURL} -LO "https://github.com/sharkdp/fd/releases/download/v${1}/fd_${1}_amd64.deb"
info "Extracting release archive"
${DPKG} --extract "fd_${1}_amd64.deb" .
${MV} -v usr "${pkg}"
info "Installing package"
${MV} "${pkg}" /usr/local/stow/
${STOW} -v -d /usr/local/stow "${pkg}"
)
install_git_delta() (
title "Install git-delta v${1}"
${MKDIR} git-delta
${CD} git-delta
pkg="git-delta-${1}"
info "Downloading release archive"
${CURL} -LO "https://github.com/dandavison/delta/releases/download/${1}/git-delta_${1}_amd64.deb"
info "Extracting release archive"
${DPKG} --extract "git-delta_${1}_amd64.deb" .
${MV} -v usr "${pkg}"
info "Creating additional directories"
for subdir in share/man/man1 share/zsh/vendor-completions; do
${MKDIR} -p "${pkg}/${subdir}"
done
info "Cloning repository for shell completions"
${GIT} clone --branch "${1}" --depth 1 https://github.com/dandavison/delta.git repo
info "Packaging zsh completions"
${MV} -v "repo/etc/completion/completion.zsh" "${pkg}/share/zsh/vendor-completions/_delta"
info "Generating man pages"
${HELP2MAN} --no-info --output "git-delta.1" "${pkg}/bin/delta"
${SED} -i -e 's/\x1b\[[0-9;]*[Mm]//g' git-delta.1
${GZIP} -n9 git-delta.1
${MV} -v git-delta.1.gz "${pkg}/share/man/man1/"
info "Installing package"
${MV} "${pkg}" /usr/local/stow/
${STOW} -v -d /usr/local/stow "${pkg}"
)
parse_args() {
while getopts 'hn' opt; do
case "$opt" in
h) # help
usage
exit 0
;;
n) # dry run
dry_run="yes"
;;
*) # invalid argument
usage
exit 1
;;
esac
done
}
require_root() {
[ "$(id -u)" -eq 0 ] || error "This script must be run as root!"
}
user="fernando"
dotfiles_url="https://git.schauenburg.me/fernando/dotfiles.git"
main() {
setup_colors
parse_args "$@"
is_dry_run || require_root
setup_commands
apt_install
install_broot 1.36.1
install_eza 0.18.7
install_fd 9.0.0
install_git_delta 0.17.0
grub_disable_timeout
ensure_usr_local_man_manN
user_setup "$user"
deploy_dotfiles "$user" "$dotfiles_url"
}
main "$@"