From c1ba30c8617a0228731f13605e0e0573bf3dec14 Mon Sep 17 00:00:00 2001 From: juftin Date: Thu, 21 Mar 2024 09:16:16 -0600 Subject: [PATCH] =?UTF-8?q?=E2=9C=A8=20dependency=20files?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 1 + README.md | 20 +++ bin/aptfile | 296 +++++++++++++++++++++++++++++++++++++++++ bootstrap/bootstrap.sh | 48 +++++-- debian/Aptfile | 52 ++++++++ mac/Brewfile | 72 ++++++++++ shell/.profile | 14 +- shell/.zprofile | 14 +- 8 files changed, 500 insertions(+), 17 deletions(-) create mode 100755 bin/aptfile create mode 100644 debian/Aptfile create mode 100644 mac/Brewfile diff --git a/.gitignore b/.gitignore index e934adf..36804db 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ cache/ +mac/Brewfile.lock.json diff --git a/README.md b/README.md index c9484aa..0f6b40a 100644 --- a/README.md +++ b/README.md @@ -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 diff --git a/bin/aptfile b/bin/aptfile new file mode 100755 index 0000000..d3ffbe1 --- /dev/null +++ b/bin/aptfile @@ -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 " +} + +help() { + usage + echo + echo " 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" diff --git a/bootstrap/bootstrap.sh b/bootstrap/bootstrap.sh index fd15b8b..7db7351 100755 --- a/bootstrap/bootstrap.sh +++ b/bootstrap/bootstrap.sh @@ -265,7 +265,17 @@ 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 @@ -273,23 +283,43 @@ function symlink_dotfiles() { 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 ########################## ########################################################## diff --git a/debian/Aptfile b/debian/Aptfile new file mode 100644 index 0000000..d6f6fe1 --- /dev/null +++ b/debian/Aptfile @@ -0,0 +1,52 @@ +#!/usr/bin/env aptfile + +update + +########################################################## +########################## CORE ########################## +########################################################## + +package "dialog" +package "apt-utils" +package "software-properties-common" +package "build-essential" +package "git-core" +package "curl" +package "wget" + +########################################################## +####################### UTILITIES ######################## +########################################################## + +package "ffmpeg" +package "fzf" +package "gh" +package "git-lfs" +package "glances" +package "grep" +package "htop" +package "jq" +package "make" +package "neovim" +package "pipx" +package "ripgrep" +package "tree" +package "yq" + +########################################################## +#################### PYTHON + PYENV ###################### +########################################################## + +package "libssl-dev" +package "zlib1g-dev" +package "libbz2-dev" +package "libreadline-dev" +package "libsqlite3-dev" +package "curl" +package "libncursesw5-dev" +package "xz-utils" +package "tk-dev" +package "libxml2-dev" +package "libxmlsec1-dev" +package "libffi-dev" +package "liblzma-dev" diff --git a/mac/Brewfile b/mac/Brewfile new file mode 100644 index 0000000..b531ae8 --- /dev/null +++ b/mac/Brewfile @@ -0,0 +1,72 @@ +########################################################## +######################### TAPS ########################### +########################################################## + +tap "hashicorp/tap" +tap "homebrew/bundle" +tap "homebrew/cask-fonts" +tap "homebrew/services" + +########################################################## +####################### UTILITIES ######################## +########################################################## + +brew "awsume" +brew "curl" +brew "ffmpeg" +brew "fzf" +brew "gh" +brew "git" +brew "git-lfs" +brew "glances" +brew "go" +brew "grep" +brew "helm" +brew "htop" +brew "hugo" +brew "jq" +brew "make" +brew "neovim" +brew "node" +brew "openjdk" +brew "pipx" +brew "ripgrep" +brew "terraform" +brew "terragrunt" +brew "thefuck" +brew "tree" +brew "wget" +brew "yq" + +########################################################## +######################### CASKS ########################## +########################################################## + +cask "caffeine" +cask "codewhisperer" +cask "cyberduck" +cask "docker" +cask "hammerspoon" +cask "iterm2" +cask "lens" +cask "spotify" +cask "syntax-highlight" +cask "vlc" + +########################################################## +######################### FONTS ########################## +########################################################## + +cask "font-fontawesome" +cask "font-meslo-lg-nerd-font" + +########################################################## +#################### PYTHON + PYENV ###################### +########################################################## + +brew "openssl" +brew "readline" +brew "sqlite3" +brew "tcl-tk" +brew "xz" +brew "zlib" diff --git a/shell/.profile b/shell/.profile index f44f846..85c1d3a 100644 --- a/shell/.profile +++ b/shell/.profile @@ -3,6 +3,16 @@ if [[ -f "${HOME}/Library/Application Support/codewhisperer/shell/zshrc.pre.bash builtin source "${HOME}/Library/Application Support/codewhisperer/shell/zshrc.pre.bash" fi +if [[ ! $PATH == *"${HOME}/.local/bin"* && -d "${HOME}/.local/bin" ]]; then + export PATH="$PATH:${HOME}/.local/bin" +fi + +if [[ $(uname -m) == "arm64" && -d /opt/homebrew ]]; then + eval "$(/opt/homebrew/bin/brew shellenv)" +elif [[ $(uname -m) == "x86_64" && -d /usr/local ]]; then + eval "$(/usr/local/bin/brew shellenv)" +fi + if [[ -d ${HOME}/.pyenv && -z ${PYENV_ROOT} ]]; then export PYENV_ROOT="${HOME}/.pyenv" export PATH="${PYENV_ROOT}/bin:${PATH}" @@ -10,10 +20,6 @@ if [[ -d ${HOME}/.pyenv && -z ${PYENV_ROOT} ]]; then alias awsume="source \$(pyenv which awsume)" fi -if [[ ! $PATH == *"${HOME}/.local/bin"* && -d "${HOME}/.local/bin" ]]; then - export PATH="$PATH:${HOME}/.local/bin" -fi - # CodeWhisperer post block. Keep at the bottom of this file. if [[ -f "${HOME}/Library/Application Support/codewhisperer/shell/zshrc.post.bash" ]]; then builtin source "${HOME}/Library/Application Support/codewhisperer/shell/zshrc.post.bash" diff --git a/shell/.zprofile b/shell/.zprofile index 490a35a..67117c5 100644 --- a/shell/.zprofile +++ b/shell/.zprofile @@ -3,6 +3,16 @@ if [[ -f "${HOME}/Library/Application Support/codewhisperer/shell/zshrc.pre.zsh" builtin source "${HOME}/Library/Application Support/codewhisperer/shell/zshrc.pre.zsh" fi +if [[ ! $PATH == *"${HOME}/.local/bin"* && -d "${HOME}/.local/bin" ]]; then + export PATH="$PATH:${HOME}/.local/bin" +fi + +if [[ $(uname -m) == "arm64" && -d /opt/homebrew ]]; then + eval "$(/opt/homebrew/bin/brew shellenv)" +elif [[ $(uname -m) == "x86_64" && -d /usr/local ]]; then + eval "$(/usr/local/bin/brew shellenv)" +fi + if [[ -d ${HOME}/.pyenv && -z ${PYENV_ROOT} ]]; then export PYENV_ROOT="${HOME}/.pyenv" export PATH="${PYENV_ROOT}/bin:${PATH}" @@ -10,10 +20,6 @@ if [[ -d ${HOME}/.pyenv && -z ${PYENV_ROOT} ]]; then alias awsume="source \$(pyenv which awsume)" fi -if [[ ! $PATH == *"${HOME}/.local/bin"* && -d "${HOME}/.local/bin" ]]; then - export PATH="$PATH:${HOME}/.local/bin" -fi - # CodeWhisperer post block. Keep at the bottom of this file. if [[ -f "${HOME}/Library/Application Support/codewhisperer/shell/zshrc.post.zsh" ]]; then builtin source "${HOME}/Library/Application Support/codewhisperer/shell/zshrc.post.zsh"