Skip to content

Commit

Permalink
✨ dependency files
Browse files Browse the repository at this point in the history
  • Loading branch information
juftin committed Mar 21, 2024
1 parent f0d3fe1 commit c1ba30c
Show file tree
Hide file tree
Showing 8 changed files with 500 additions and 17 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
cache/
mac/Brewfile.lock.json
20 changes: 20 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -94,8 +94,28 @@ https://github.com/juftin/dotfiles/assets/49741340/569d7e27-114b-4378-9157-f7f9e
ln -s ~/.dotfiles/bootstrap/pyenv ~/.pyenv
ln -s ~/.dotfiles/git/.gitconfig ~/.gitconfig
ln -s ~/.dotfiles/git/.gitignore ~/.gitignore
ls -s ~/.dotfiles/bin/aptfile /usr/local/bin/aptfile
```
## Dependencies
### MacOS
Dependencies for macOS can be installed using [Homebrew](https://brew.sh/)'s `bundle` command.
```shell
brew bundle --file=~/.dotfiles/Brewfile
```
### Debian
Dependencies for Debian can be installed using `apt` and the `aptfile` command,
which is installed alongside the dotfiles:
```shell
aptfile ~/.dotfiles/debian/Aptfile
```
## Customization
Customizing this repo for yourself requires editing a few key
Expand Down
296 changes: 296 additions & 0 deletions bin/aptfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,296 @@
#!/usr/bin/env bash

# https://github.com/seatgeek/bash-aptfile/blob/master/bin/aptfile

set -eo pipefail

[[ $TRACE ]] && set -x && export TRACE=$TRACE

version() {
local VERSION="dev-master"
if [[ -f /var/lib/aptfile/VERSION ]]; then
VERSION=$(cat /var/lib/aptfile/VERSION)
fi
echo "aptfile $VERSION"
}

usage() {
version
echo "Usage: aptfile <aptfile>"
}

help() {
usage
echo
echo " <aptfile> is the path to a bash file with apt instructions."
echo
echo " -h, --help Display this help message"
echo " -v, --version Display the version number"
echo
echo " For more information, see https://github.com/seatgeek/bash-aptfile"
echo
}

resolve_link() {
$(type -p greadlink readlink | head -1) "$1"
}

abs_dirname() {
local cwd
local path="$1"
cwd="$(pwd)"

while [ -n "$path" ]; do
cd "${path%/*}"
local name="${path##*/}"
path="$(resolve_link "$name" || true)"
done

pwd
cd "$cwd"
}

expand_path() {
{
cd "$(dirname "$1")" 2>/dev/null
local dirname="$PWD"
cd "$OLDPWD"
echo "$dirname/$(basename "$1")"
} || echo "$1"
}

options=()
arguments=()
for arg in "$@"; do
if [ "${arg:0:1}" = "-" ]; then
if [ "${arg:1:1}" = "-" ]; then
options[${#options[*]}]="${arg:2}"
else
index=1
while option="${arg:index:1}"; do
[ -n "$option" ] || break
options[${#options[*]}]="$option"
let index+=1
done
fi
else
arguments[${#arguments[*]}]="$arg"
fi
done

for option in "${options[@]}"; do
case "$option" in
"h" | "help")
help
exit 0
;;
"v" | "version")
version
exit 0
;;
*)
usage >&2
exit 1
;;
esac
done

if [ "${#arguments[@]}" -eq 0 ]; then
APTFILE_PATH=$(expand_path "aptfile")
if [[ ! -f $APTFILE_PATH ]]; then
usage >&2
exit 1
fi
set -- "aptfile" "$@"
fi

export APTFILE_COLOR_OFF="\033[0m" # unsets color to term fg color
export APTFILE_RED="\033[0;31m" # red
export APTFILE_GREEN="\033[0;32m" # green
export APTFILE_YELLOW="\033[0;33m" # yellow
export APTFILE_MAGENTA="\033[0;35m" # magenta
export APTFILE_CYAN="\033[0;36m" # cyan

logfile=$(basename "$0")
TMP_APTFILE_LOGFILE=$(mktemp "/tmp/${logfile}.XXXXXX") || {
log_fail "${APTFILE_RED}WARNING: Cannot create temp file using mktemp in /tmp dir ${APTFILE_COLOR_OFF}\n"
}
export TMP_APTFILE_LOGFILE="$TMP_APTFILE_LOGFILE"
trap 'rm -rf "$TMP_APTFILE_LOGFILE" > /dev/null' INT TERM EXIT

log_fail() {
[[ $TRACE ]] && set -x
echo -e "${APTFILE_RED}$*${APTFILE_COLOR_OFF}" 1>&2
[[ -f $TMP_APTFILE_LOGFILE ]] && echo -e "verbose logs:\n" 1>&2 && sed -e 's/^/ /' "$TMP_APTFILE_LOGFILE"
exit 1
}

log_info() {
[[ $TRACE ]] && set -x
echo -e "$@"
}

update() {
[[ $TRACE ]] && set -x
log_info "Running update"
apt-get update >"$TMP_APTFILE_LOGFILE" 2>&1
[[ $? -eq 0 ]] || log_fail "Failed to run update"
}

package() {
[[ $TRACE ]] && set -x
[[ -z $1 ]] && log_fail "Please specify a package to install"
local pkg="$1"
dpkg --force-confnew -s "$pkg" >"$TMP_APTFILE_LOGFILE" 2>&1 && log_info "${APTFILE_CYAN}[OK]${APTFILE_COLOR_OFF} package $pkg" && return 0
apt-get -o Dpkg::Options::="--force-confdef" -o Dpkg::Options::="--force-confnew" -qq -y install "$pkg"
[[ $? -eq 0 ]] || log_fail "${APTFILE_RED}[FAIL]${APTFILE_COLOR_OFF} package $pkg"
log_info "${APTFILE_GREEN}[NEW]${APTFILE_COLOR_OFF} package $pkg"
}

package_from_url() {
[[ $TRACE ]] && set -x
[[ -z $2 ]] && log_fail "Please specify a name and a download url to install the package from"
local name=$1
local url=$2
if type curl >/dev/null 2>&1; then
local dl_cmd="curl"
local dl_options="-so"
elif type wget >/dev/null 2>&1; then
local dl_cmd="wget"
local dl_options="-qO"
else
log_fail "Neither curl nor wget found. Unable to download $url"
fi
dpkg --force-confnew -s "$name" >"$TMP_APTFILE_LOGFILE" 2>&1 && log_info "${APTFILE_CYAN}[OK]${APTFILE_COLOR_OFF} package $name" && return 0
tempdir=$(mktemp -d)
$dl_cmd $dl_options $tempdir/${name}.deb $url &&
apt-get -o Dpkg::Options::="--force-confdef" -o Dpkg::Options::="--force-confnew" -qq -y install "$tempdir/${name}.deb"
if [[ $? -ne 0 ]]; then
rm -r $tempdir
log_fail "${APTFILE_RED}[FAIL]${APTFILE_COLOR_OFF} package $name"
fi
rm -r $tempdir
log_info "${APTFILE_GREEN}[NEW]${APTFILE_COLOR_OFF} package $name"
}

packagelist() {
[[ $TRACE ]] && set -x
[[ -z $1 ]] && log_fail "Please specify at least one package to install"
local input_packages=$@
local install_packages=()
for pkg in $input_packages; do
dpkg --force-confnew -s "$pkg" >"$TMP_APTFILE_LOGFILE" 2>&1 && log_info "${APTFILE_CYAN}[OK]${APTFILE_COLOR_OFF} package $pkg" && continue
install_packages+=($pkg)
done
if [[ ${#install_packages[@]} -gt 0 ]]; then
apt-get -o Dpkg::Options::="--force-confdef" -o Dpkg::Options::="--force-confnew" -qq -y install ${install_packages[@]}
[[ $? -eq 0 ]] || log_fail "${APTFILE_RED}[FAIL]${APTFILE_COLOR_OFF} packages ${install_packages[@]}"
log_info "${APTFILE_GREEN}[NEW]${APTFILE_COLOR_OFF} packages ${install_packages[@]}"
fi
}

ppa() {
[[ $TRACE ]] && set -x
[[ -z $1 ]] && log_fail "Please specify a repository to setup"
local repo="$1"
if [[ -d /etc/apt/sources.list.d/ ]]; then
grep ^ /etc/apt/sources.list /etc/apt/sources.list.d/* | grep -q "$repo" && log_info "${APTFILE_CYAN}[OK]${APTFILE_COLOR_OFF} ppa $repo" && return 0
fi
repository "ppa:$1"
}

repository() {
[[ $TRACE ]] && set -x
[[ -z $1 ]] && log_fail "Please specify a repository to setup"
local repo="$1"
if [[ -d /etc/apt/sources.list.d/ ]]; then
grep ^ /etc/apt/sources.list /etc/apt/sources.list.d/* | grep -Fq "$repo" && log_info "${APTFILE_CYAN}[OK]${APTFILE_COLOR_OFF} repository $repo" && return 0
fi
add-apt-repository -y "$repo" >"$TMP_APTFILE_LOGFILE" 2>&1
[[ $? -eq 0 ]] || log_fail "${APTFILE_RED}[FAIL]${APTFILE_COLOR_OFF} repository $pkg"
update
log_info "${APTFILE_GREEN}[NEW]${APTFILE_COLOR_OFF} repository $repo"
}

repository_file() {
[[ $TRACE ]] && set -x
[[ -z $2 ]] && log_fail "Please specify a filename and sourceline to setup"
local repofile="$1"
local repo="$2"
# sourceline is not a complete repo configuration, needs modifying
# i.e. not sourceline="deb http://domain.invalid/debian buster main extra"
if [[ $repo != "deb "* ]]; then
releasename=$(lsb_release -sc)
if [[ $repo == *" "* ]]; then
# Components given in sourceline, adding suite
# i.e. sourceline="http://domain.invalid/debian main"
repo="deb ${repo/ / $releasename }"
else
# only URL given, adding suite and component
# i.e. sourceline="http://domain.invalid/debian"
repo="deb ${repo} $releasename main"
fi
fi

if [[ $repofile != *.list ]]; then
# Adding extension to enable parsing file
repofile=${repofile}.list
fi
# Adding path
repofile="/etc/apt/sources.list.d/$repofile"

[[ -d "/etc/apt/sources.list.d" ]] || mkdir -p /etc/apt/sources.list.d

grep ^ /etc/apt/sources.list /etc/apt/sources.list.d/* | grep -Fq "$repo" && log_info "${APTFILE_CYAN}[OK]${APTFILE_COLOR_OFF} repository $repo" && return 0

echo "Writing '$repo' to file '$repofile'" >"$TMP_APTFILE_LOGFILE"
echo "$repo" >"$repofile" 2>>"$TMP_APTFILE_LOGFILE"
[[ $? -eq 0 ]] || log_fail "${APTFILE_RED}[FAIL]${APTFILE_COLOR_OFF} repository $pkg"
update
log_info "${APTFILE_GREEN}[NEW]${APTFILE_COLOR_OFF} repository $repo"
}

debconf_selection() {
[[ $TRACE ]] && set -x
[[ -z $1 ]] && log_fail "Please specify a debconf line"
echo "$1" | debconf-set-selections
[[ $? -eq 0 ]] || log_fail "${APTFILE_RED}[FAIL]${APTFILE_COLOR_OFF} debconf: $1"
log_info "${APTFILE_CYAN}[OK]${APTFILE_COLOR_OFF} set debconf line: $1"
}

if [ -z "$TMPDIR" ]; then
APTFILE_TMPDIR="/tmp"
else
APTFILE_TMPDIR="${TMPDIR%/}"
fi

APTFILE_INPUT=$(expand_path "$1")
APTFILE_TMPNAME="$APTFILE_TMPDIR/aptfile.$$"
APTFILE_OUTPUT="${APTFILE_TMPNAME}.out"

aptfile_preprocess_source() {
tail -n +2 "$1" >"$APTFILE_OUTPUT"
trap "aptfile_cleanup_preprocessed_source" err exit
trap "aptfile_cleanup_preprocessed_source; exit 1" int
}

aptfile_cleanup_preprocessed_source() {
rm -f "$APTFILE_TMPNAME"
rm -f "$APTFILE_OUTPUT"
}

aptfile_preprocess_source "$APTFILE_INPUT"

export -f update
export -f package
export -f package_from_url
export -f packagelist
export -f ppa
export -f repository
export -f repository_file
export -f debconf_selection
export -f log_fail
export -f log_info

chmod +x "$APTFILE_OUTPUT"
exec "$APTFILE_OUTPUT"
48 changes: 39 additions & 9 deletions bootstrap/bootstrap.sh
Original file line number Diff line number Diff line change
Expand Up @@ -265,31 +265,61 @@ function symlink_item() {
###################### symlinks ##########################
##########################################################

function symlink_dotfiles() {
function symlink_shell() {
symlink_item "${DOTFILES_DIR}/shell/.shell_aliases" "${HOME}/.shell_aliases"
}

function symlink_mac() {
if [[ $(uname) == "Darwin" ]]; then
symlink_item "${DOTFILES_DIR}/shell/.mac_aliases" "${HOME}/.mac_aliases"
fi
}

function symlink_zsh() {
# OhMyZsh
symlink_item "${DOTFILES_DIR}/bootstrap/oh-my-zsh" "${HOME}/.oh-my-zsh"
# OhMyZsh Custom Plugins
symlink_item "${DOTFILES_DIR}/bootstrap/powerlevel10k" "${HOME}/.oh-my-zsh/custom/themes/powerlevel10k"
symlink_item "${DOTFILES_DIR}/bootstrap/fast-syntax-highlighting" "${HOME}/.oh-my-zsh/custom/plugins/fast-syntax-highlighting"
symlink_item "${DOTFILES_DIR}/bootstrap/zsh-autosuggestions" "${HOME}/.oh-my-zsh/custom/plugins/zsh-autosuggestions"
symlink_item "${DOTFILES_DIR}/bootstrap/zsh-completions" "${HOME}/.oh-my-zsh/custom/plugins/zsh-completions"
# OhMyBash
symlink_item "${DOTFILES_DIR}/bootstrap/oh-my-bash" "${HOME}/.oh-my-bash"
# Shell Files
symlink_item "${DOTFILES_DIR}/shell/.zshrc" "${HOME}/.zshrc"
symlink_item "${DOTFILES_DIR}/shell/.zprofile" "${HOME}/.zprofile"
symlink_item "${DOTFILES_DIR}/shell/.p10k.zsh" "${HOME}/.p10k.zsh"
}

function symlink_bash() {
symlink_item "${DOTFILES_DIR}/bootstrap/oh-my-bash" "${HOME}/.oh-my-bash"
symlink_item "${DOTFILES_DIR}/shell/.profile" "${HOME}/.profile"
symlink_item "${DOTFILES_DIR}/shell/.bashrc" "${HOME}/.bashrc"
symlink_item "${DOTFILES_DIR}/shell/.p10k.zsh" "${HOME}/.p10k.zsh"
symlink_item "${DOTFILES_DIR}/shell/.shell_aliases" "${HOME}/.shell_aliases"
symlink_item "${DOTFILES_DIR}/shell/.mac_aliases" "${HOME}/.mac_aliases"
# PyEnv
symlink_item "${DOTFILES_DIR}/bootstrap/pyenv" "${HOME}/.pyenv"
# Git
}

function symlink_git() {
symlink_item "${DOTFILES_DIR}/git/.gitconfig" "${HOME}/.gitconfig"
symlink_item "${DOTFILES_DIR}/git/.gitignore" "${HOME}/.gitignore"
}

function symlink_misc() {
symlink_item "${DOTFILES_DIR}/bootstrap/pyenv" "${HOME}/.pyenv"
}

function symlink_bin() {
if [[ $(uname) == "Linux" ]]; then
symlink_item "${DOTFILES_DIR}/bin/aptfile" "/usr/local/bin/aptfile"
fi
}

function symlink_dotfiles() {
symlink_shell
symlink_mac
symlink_zsh
symlink_bash
symlink_git
symlink_misc
symlink_bin
}

##########################################################
######################## script ##########################
##########################################################
Expand Down
Loading

0 comments on commit c1ba30c

Please sign in to comment.