From d1b095f98c5f00cb0fbc5ef5ad339dc8bf93c80c Mon Sep 17 00:00:00 2001 From: Buddy Sandidge Date: Tue, 19 Nov 2024 15:47:19 -0800 Subject: [PATCH] Use dynamic dispatch for scripting libs --- dot_config/bash/bashrc.d/completion.sh.tmpl | 5 + dot_config/bash/bashrc.d/functions.sh | 89 +++++++ .../profile/profile.d/functions.sh.tmpl | 220 +++++------------- .../profile/profile.d/hellotech.sh.tmpl | 2 +- dot_config/zsh/zshrc.d/base.zsh.tmpl | 5 + dot_local/bin/executable_install-deno | 2 +- dot_local/bin/executable_install-mockery | 2 +- dot_local/share/buddy/include.bash | 47 ++-- dot_local/share/buddy/include.sh | 36 +++ dot_local/share/buddy/lib/add_date_prefix.sh | 8 + dot_local/share/buddy/lib/assert/command.sh | 9 + dot_local/share/buddy/lib/assert/root_user.sh | 7 + dot_local/share/buddy/lib/bail.sh | 4 + .../share/buddy/lib/file_age_in_seconds.sh | 3 + dot_local/share/buddy/lib/gem_env.sh | 17 ++ dot_local/share/buddy/lib/get_bitrate.sh | 11 + .../share/buddy/lib/github/download_url.sh | 7 + .../share/buddy/lib/github/install_scripts.sh | 16 ++ .../github/install_scripts_latest_releases.sh | 8 + .../share/buddy/lib/github/latest_release.sh | 5 + .../share/buddy/lib/github/release_json.sh | 14 ++ dot_local/share/buddy/lib/github/releases.sh | 14 ++ dot_local/share/buddy/lib/github/tags.sh | 15 ++ dot_local/share/buddy/lib/go_deps.sh | 6 + dot_local/share/buddy/lib/json_to_yaml.sh | 14 ++ dot_local/share/buddy/lib/make_script.sh | 17 ++ dot_local/share/buddy/lib/min_jpg.sh | 13 ++ dot_local/share/buddy/lib/min_png.sh | 13 ++ dot_local/share/buddy/lib/mkdir_if_missing.sh | 8 + dot_local/share/buddy/lib/node/current.sh | 4 + dot_local/share/buddy/lib/node/lts.sh | 4 + dot_local/share/buddy/lib/relative_path.sh | 43 ++++ dot_local/share/buddy/lib/slugify.sh | 12 + dot_local/share/buddy/lib/unlink_if_set.sh | 8 + dot_local/share/buddy/lib/yaml_to_json.sh | 15 ++ 35 files changed, 511 insertions(+), 192 deletions(-) create mode 100644 dot_local/share/buddy/include.sh create mode 100644 dot_local/share/buddy/lib/add_date_prefix.sh create mode 100644 dot_local/share/buddy/lib/assert/command.sh create mode 100644 dot_local/share/buddy/lib/assert/root_user.sh create mode 100644 dot_local/share/buddy/lib/bail.sh create mode 100644 dot_local/share/buddy/lib/file_age_in_seconds.sh create mode 100644 dot_local/share/buddy/lib/gem_env.sh create mode 100644 dot_local/share/buddy/lib/get_bitrate.sh create mode 100644 dot_local/share/buddy/lib/github/download_url.sh create mode 100644 dot_local/share/buddy/lib/github/install_scripts.sh create mode 100644 dot_local/share/buddy/lib/github/install_scripts_latest_releases.sh create mode 100644 dot_local/share/buddy/lib/github/latest_release.sh create mode 100644 dot_local/share/buddy/lib/github/release_json.sh create mode 100644 dot_local/share/buddy/lib/github/releases.sh create mode 100644 dot_local/share/buddy/lib/github/tags.sh create mode 100644 dot_local/share/buddy/lib/go_deps.sh create mode 100644 dot_local/share/buddy/lib/json_to_yaml.sh create mode 100644 dot_local/share/buddy/lib/make_script.sh create mode 100644 dot_local/share/buddy/lib/min_jpg.sh create mode 100644 dot_local/share/buddy/lib/min_png.sh create mode 100644 dot_local/share/buddy/lib/mkdir_if_missing.sh create mode 100644 dot_local/share/buddy/lib/node/current.sh create mode 100644 dot_local/share/buddy/lib/node/lts.sh create mode 100644 dot_local/share/buddy/lib/relative_path.sh create mode 100644 dot_local/share/buddy/lib/slugify.sh create mode 100644 dot_local/share/buddy/lib/unlink_if_set.sh create mode 100644 dot_local/share/buddy/lib/yaml_to_json.sh diff --git a/dot_config/bash/bashrc.d/completion.sh.tmpl b/dot_config/bash/bashrc.d/completion.sh.tmpl index cd4eeae..405314d 100644 --- a/dot_config/bash/bashrc.d/completion.sh.tmpl +++ b/dot_config/bash/bashrc.d/completion.sh.tmpl @@ -54,6 +54,11 @@ source <(trubka --completion-script-bash) source <(rbenv init -) #{{ end -}} +#{{ if stat (joinPath .chezmoi.homeDir ".sdkman/bin/sdkman-init.sh") -}} +export SDKMAN_DIR="$HOME/.sdkman" +source "#{{ .chezmoi.homeDir }}/.sdkman/bin/sdkman-init.sh" +#{{ end -}} + #{{ if and (lookPath "rvm") (stat (joinPath .chezmoi.homeDir ".rvm" "bin") ) -}} if [[ ! "${PATH}" =~ ${HOME}/.rvm/bin ]]; then export PATH="$PATH:$HOME/.rvm/bin" diff --git a/dot_config/bash/bashrc.d/functions.sh b/dot_config/bash/bashrc.d/functions.sh index bad47ee..3284a35 100644 --- a/dot_config/bash/bashrc.d/functions.sh +++ b/dot_config/bash/bashrc.d/functions.sh @@ -1,3 +1,92 @@ +source_env_file() { + if [ -f "${1}" ]; then + return + fi + eval "$( + grep -v '^\s*\#' "${1}" | + grep -v '^\s*$' | + sed 's/^\s*export//g' | + sed 's/^/export /g' + )" +} + +_run_require() ( + import=${1} + shift + set -euo pipefail + source "${XDG_DATA_HOME}/buddy/include.bash" + require "${import}" + "${import//\//_}" "$@" +) + +add_date_prefix() ( + _run_require add_date_prefix "$@" +) + +command_installed() ( + _run_require assert/command "$@" +) + +gem_env () ( + _run_require gem_env "$@" +) + +get_bitrate() ( + _run_require get_bitrate "$@" +) + +get_create_date() ( + date -r "$1" +"%F" +) + +github_install_scripts () ( + _run_require github/install_scripts "$@" +) + +github_install_scripts_latest_releases() ( + _run_require github/install_scripts_latest_releases "$@" +) + +github_latest_release() ( + _run_require github/latest_release "$@" +) + +github_releases() ( + _run_require github/releases "$@" +) + +github_tags() ( + _run_require github/tags "$@" +) + +go_deps() ( + _run_require go_deps "$@" +) + +json_to_yaml() ( + _run_require json_to_yaml "$@" +) + +yaml_to_json() ( + _run_require yaml_to_json "$@" +) + +make_script() ( + _run_require make_script "$@" +) + +min_jpg() ( + _run_require min_jpg "$@" +) + +min_png() ( + _run_require min_png "$@" +) + +slugify() ( + _run_require slugify "$@" +) + function min-jpg { min_jpg "${@}" } diff --git a/dot_config/profile/profile.d/functions.sh.tmpl b/dot_config/profile/profile.d/functions.sh.tmpl index 0487afd..0aa32b2 100644 --- a/dot_config/profile/profile.d/functions.sh.tmpl +++ b/dot_config/profile/profile.d/functions.sh.tmpl @@ -14,196 +14,80 @@ source_env_file() { )" } -make_scripts() ( - for FILE in "$@"; do - make_script "${FILE}" - done +_run_require() ( + import=${1} + shift + fn=$(echo "${import}" | sed 's|/|_|g') + set -eu + . "${XDG_DATA_HOME}/buddy/include.sh" + require "${import}" + ${fn} "$@" ) -go_deps() ( - GO_MOD=${1:-go.mod} - START_AT=$(grep -n '^require ($' "${GO_MOD}" | awk -F : '{print $1}' | head -n 1) - END_AT=$(grep -n '^)$' "${GO_MOD}" | awk -F : '{print $1}' | head -n 1) - awk 'NR>'"${START_AT}"' && NR<'"${END_AT}"' {print $1}' "${GO_MOD}" +add_date_prefix () ( + _run_require add_date_prefix "$@" +) + +command_installed () ( + _run_require assert/command "$@" ) -#{{ if lookPath "gem" -}} -#{{ if lookPath "dasel" -}} -#{{ if lookPath "jq" -}} gem_env () ( - NAME=${1:-} - if [ "$NAME" != '' ]; then - gem_env_json | jq --raw-output '.["'"${NAME}"'"]' - else - gem_env_json - fi + _run_require gem_env "$@" ) -gem_env_json () ( - gem environment \ - | dasel --read yaml --write json \ - | jq '.["RubyGems Environment"] | to_entries | map((.value | keys)[0] as $key | {key: $key, value: .value[$key] }) | from_entries' +get_bitrate () ( + _run_require get_bitrate "$@" ) -#{{- end }} -#{{- end }} -#{{- end }} -make_script() ( - cat <<-EOF > "${1}" - #!/usr/bin/env bash +get_create_date () ( + date -r "$1" +"%F" +) - set -euo pipefail +github_install_scripts () ( + _run_require github/install_scripts "$@" +) - main() ( - echo "todo" - ) +github_install_scripts_latest_releases () ( + _run_require github/install_scripts_latest_releases "$@" +) - main "$@" - EOF - chmod +x "${1}" +github_latest_release () ( + _run_require github/latest_release "$@" ) -add_date_prefix() ( - DIR=$(dirname "$1") - FILE=$(basename "$1") - DATE=$(date -r "$1" +"%F") - if [ ! -f "$1" ]; then - echo "unknown file: $1" - exit 1 - fi - mv "$1" "$DIR/${DATE}_${FILE}" +github_releases () ( + _run_require github/releases "$@" ) -get_bitrate() ( - if [ ! -f "$1" ]; then - echo "[ERROR] unknown file: $1" - exit 1 - fi - command_installed exiftool - exiftool -AudioBitrate "$1" | awk '{print $4}' -) - -json_to_yaml() ( - ARG=${1-} - command_installed bat dasel - if [ -z "${ARG}" ]; then - dasel --read json --write yaml | bat --language yaml - elif [ -f "${ARG}" ]; then - dasel --read json --write yaml --file "${ARG}" | bat --language yaml - else - echo "${ARG}" | dasel --read json --write yaml | bat --language yaml - fi +github_tags () ( + _run_require github/tags "$@" ) -yaml_to_json() ( - ARG=${1-} - command_installed bat dasel - if [ -z "${ARG}" ]; then - dasel --read yaml --write json | bat --language json - elif [ -f "${ARG}" ]; then - dasel --read yaml --write json --file "${ARG}" | bat --language json - else - echo "${ARG}" | dasel --read yaml --write json | bat --language json - fi +go_deps () ( + _run_require go_deps "$@" ) -#{{ if lookPath "rg" -}} -github_install_scripts () ( - rg github.com "${HOME}/.local/bin" \ - | sed 's/:/ /' \ - | sed 's/=/ /g' \ - | awk '{print $3}' \ - | sed 's|https://github.com/||g' \ - | sed 's|/| |g' \ - | awk '{print $1 " " $2}' \ - | sed 's| |/|g' \ - | sort \ - | uniq -) - -github_install_scripts_latest_releases() ( - for REPO in $(github_install_scripts); do - echo "${REPO} $(github_latest_release "${REPO}")" - done -) -#{{- end }} - -github_latest_release() ( - github_tags "$@" | head -n 1 -) - -github_releases() ( - USER=${1} - REPO=${2-} - command_installed curl - if [ -z "${REPO}" ]; then - USER=$(echo "${1}" | sed 's|/| |g' | awk '{print $1}') - REPO=$(echo "${1}" | sed 's|/| |g' | awk '{print $2}') - fi - curl --silent --header "Accept: application/vnd.github.v3+json" \ - "https://api.github.com/repos/${USER}/${REPO}/releases" +json_to_yaml () ( + _run_require json_to_yaml "$@" ) -github_tags() ( - USER=${1} - REPO=${2-} - command_installed curl jq - if [ -z "${REPO}" ]; then - USER=$(echo "${1}" | sed 's|/| |g' | awk '{print $1}') - REPO=$(echo "${1}" | sed 's|/| |g' | awk '{print $2}') - fi - curl --silent --header "Accept: application/vnd.github.v3+json" \ - "https://api.github.com/repos/${USER}/${REPO}/tags" | - jq -r '.[].name' -) - -command_installed() ( - set -ue - for cmd in "${@}"; do - if ! command -v "${cmd}" 1>&2 >/dev/null; then - echo "${cmd} not installed" 1>&2 - exit 1 - fi - done -) - -min_jpg() ( - set -ue - command_installed jpegtran - for FILE in "$@" ; do - PERMISSIONS=$(stat --format '%a' "${FILE}") - OUT_FILE=$(mktemp) - jpegtran -optimize -perfect -outfile "${OUT_FILE}" "${FILE}" - mv "${OUT_FILE}" "${FILE}" - chmod "${PERMISSIONS}" "${FILE}" - done -) - -min_png() ( - set -ue - command_installed pngcrush - for FILE in "$@" ; do - PERMISSIONS=$(stat --format '%a' "${FILE}") - OUT_FILE=$(mktemp) - pngcrush -rem alla -reduce -brute "${FILE}" "${OUT_FILE}" - mv "${OUT_FILE}" "${FILE}" - chmod "${PERMISSIONS}" "${FILE}" - done -) - -get_create_date() ( - date -r "$1" +"%F" +yaml_to_json () ( + _run_require yaml_to_json "$@" ) -#shellcheck disable=SC2120 -slugify() ( - if [ "$#" -ne 0 ]; then - #shellcheck disable=SC2119 - echo "$@" | slugify - else - iconv --to-code ascii//TRANSLIT | - sed -E 's/[^a-zA-Z0-9]+/-/g' | - sed -E 's/^-+\|-+$//g' | - tr '[:upper:]' '[:lower:]' - fi +make_script () ( + _run_require make_script "$@" +) + +min_jpg () ( + _run_require min_jpg "$@" +) + +min_png () ( + _run_require min_png "$@" +) + +slugify () ( + _run_require slugify "$@" ) diff --git a/dot_config/profile/profile.d/hellotech.sh.tmpl b/dot_config/profile/profile.d/hellotech.sh.tmpl index c2448dc..d3d532e 100644 --- a/dot_config/profile/profile.d/hellotech.sh.tmpl +++ b/dot_config/profile/profile.d/hellotech.sh.tmpl @@ -20,7 +20,7 @@ _append_path () { PATH="${PATH}:${1}" } -_append_path "/usr/local/opt/mysql-client/bin" +_append_path /usr/local/opt/mysql-client/bin _append_path "${HOME}/google-cloud-sdk/bin" unset _append_path diff --git a/dot_config/zsh/zshrc.d/base.zsh.tmpl b/dot_config/zsh/zshrc.d/base.zsh.tmpl index 21b0759..fef9568 100644 --- a/dot_config/zsh/zshrc.d/base.zsh.tmpl +++ b/dot_config/zsh/zshrc.d/base.zsh.tmpl @@ -68,6 +68,11 @@ if [ "${RBENV_SHELL}" = "" ]; then fi #{{ end -}} +#{{ if stat (joinPath .chezmoi.homeDir ".sdkman/bin/sdkman-init.sh") -}} +export SDKMAN_DIR="$HOME/.sdkman" +source "#{{ .chezmoi.homeDir }}/.sdkman/bin/sdkman-init.sh" +#{{ end -}} + #{{- if lookPath "rvm" }} if [[ -d "${HOME}/.rvm/bin" ]]; then if [[ ! "${PATH}" =~ "${HOME}/.rvm/bin" ]]; then diff --git a/dot_local/bin/executable_install-deno b/dot_local/bin/executable_install-deno index df78804..9f99116 100755 --- a/dot_local/bin/executable_install-deno +++ b/dot_local/bin/executable_install-deno @@ -16,7 +16,7 @@ function get_os () ( APP=deno -VERSION=${VERSION:-1.45.5} +VERSION=${VERSION:-2.0.6} DEST=${XDG_DATA_HOME}/apps/releases/${APP} URL=https://github.com/denoland/deno/releases/download/v${VERSION}/deno-$(uname -m)-$(get_os).zip diff --git a/dot_local/bin/executable_install-mockery b/dot_local/bin/executable_install-mockery index 548dd1a..315c3da 100755 --- a/dot_local/bin/executable_install-mockery +++ b/dot_local/bin/executable_install-mockery @@ -6,7 +6,7 @@ set -euo pipefail source "${XDG_DATA_HOME}/buddy-up/includes/utils.sh" APP=mockery -VERSION=${VERSION:-2.43.2} +VERSION=${VERSION:-2.46.3} DEST="${XDG_DATA_HOME}/apps/releases/${APP}" URL=https://github.com/vektra/mockery/releases/download/v${VERSION}/mockery_${VERSION}_$(uname)_$(uname -m).tar.gz diff --git a/dot_local/share/buddy/include.bash b/dot_local/share/buddy/include.bash index 4b56248..df71844 100644 --- a/dot_local/share/buddy/include.bash +++ b/dot_local/share/buddy/include.bash @@ -1,26 +1,31 @@ -if [ -v _LOADED_LIBS ]; then - return -fi - _LOADED_LIBS=() include() { - local file - local previous - for file in "${@}"; do - for previous in "${_LOADED_LIBS[@]}"; do - if [[ "${previous}" == "${file}" ]]; then - continue 2 - fi - done + local file + for file in "${@}"; do + if [[ -f "${XDG_DATA_HOME}/buddy/lib/${file}.bash" ]]; then + # shellcheck disable=SC1090 + source "${XDG_DATA_HOME}/buddy/lib/${file}.bash" + elif [[ -f "${XDG_DATA_HOME}/buddy/lib/${file}.sh" ]]; then + # shellcheck disable=SC1090 + source "${XDG_DATA_HOME}/buddy/lib/${file}.sh" + else + >&2 echo "include unknown: ${file}" + exit 1 + fi + done +} - _LOADED_LIBS+=("$file") - if [[ -f "${XDG_DATA_HOME}/buddy/lib/$file.bash" ]]; then - # shellcheck disable=SC1090 - source "${XDG_DATA_HOME}/buddy/lib/${file}.bash" - else - >&2 echo "unknown: ${file}" - exit 1 - fi - done +require() { + local file + local previous + for file in "${@}"; do + for previous in "${_LOADED_LIBS[@]}"; do + if [[ "${previous}" == "${file}" ]]; then + continue 2 + fi + done + _LOADED_LIBS+=("${file}") + include "${file}" + done } diff --git a/dot_local/share/buddy/include.sh b/dot_local/share/buddy/include.sh new file mode 100644 index 0000000..8a9e8c0 --- /dev/null +++ b/dot_local/share/buddy/include.sh @@ -0,0 +1,36 @@ +LOADED_LIBS= + +include() { + local file + for file in "${@}"; do + if [ -f "${XDG_DATA_HOME}/buddy/lib/${file}.sh" ]; then + # shellcheck disable=SC1090 + . "${XDG_DATA_HOME}/buddy/lib/${file}.sh" + else + >&2 echo "include unknown: ${file}" + exit 1 + fi + done +} + +require() { + local file + local previous + for file in "${@}"; do + echo "$LOADED_LIBS" | while read -r previous; do + if [ -z "${previous}" ]; then + continue + elif [ "${previous}" = "${file}" ]; then + continue 2 + fi + done + + if [ -z "${LOADED_LIBS}" ]; then + LOADED_LIBS=${file} + else + LOADED_LIBS="${LOADED_LIBS}\n${file}" + fi + + include "${file}" + done +} diff --git a/dot_local/share/buddy/lib/add_date_prefix.sh b/dot_local/share/buddy/lib/add_date_prefix.sh new file mode 100644 index 0000000..a0e771f --- /dev/null +++ b/dot_local/share/buddy/lib/add_date_prefix.sh @@ -0,0 +1,8 @@ +require bail + +add_date_prefix () ( + if [ ! -f "$1" ]; then + bail "unknown file: $1" + fi + mv "$1" "$(dirname "$1")/$(date -r "$1" +"%F")_$(basename "$1")" +) diff --git a/dot_local/share/buddy/lib/assert/command.sh b/dot_local/share/buddy/lib/assert/command.sh new file mode 100644 index 0000000..e545cda --- /dev/null +++ b/dot_local/share/buddy/lib/assert/command.sh @@ -0,0 +1,9 @@ +require bail + +assert_command() ( + for cmd in "${@}"; do + if ! command -v "${cmd}" 1>&2 >/dev/null; then + bail "command not installed: ${cmd}" + fi + done +) diff --git a/dot_local/share/buddy/lib/assert/root_user.sh b/dot_local/share/buddy/lib/assert/root_user.sh new file mode 100644 index 0000000..5c3f000 --- /dev/null +++ b/dot_local/share/buddy/lib/assert/root_user.sh @@ -0,0 +1,7 @@ +require bail + +must_be_root() ( + if [ "$(id --user)" != 0 ]; then + bail "must run as root" + fi +) diff --git a/dot_local/share/buddy/lib/bail.sh b/dot_local/share/buddy/lib/bail.sh new file mode 100644 index 0000000..26b67a0 --- /dev/null +++ b/dot_local/share/buddy/lib/bail.sh @@ -0,0 +1,4 @@ +bail() ( + echo >&2 "$@" + exit 1 +) diff --git a/dot_local/share/buddy/lib/file_age_in_seconds.sh b/dot_local/share/buddy/lib/file_age_in_seconds.sh new file mode 100644 index 0000000..21bc737 --- /dev/null +++ b/dot_local/share/buddy/lib/file_age_in_seconds.sh @@ -0,0 +1,3 @@ +file_age_in_seconds() ( + echo $(($(date +"%s") - $(stat -c "%Y" "${1}"))) +) diff --git a/dot_local/share/buddy/lib/gem_env.sh b/dot_local/share/buddy/lib/gem_env.sh new file mode 100644 index 0000000..221547e --- /dev/null +++ b/dot_local/share/buddy/lib/gem_env.sh @@ -0,0 +1,17 @@ +require assert/command + +assert_command dasel gem jq + +gem_env() ( + NAME=${1:-} + if [ "${NAME}" ]; then + gem environment | + dasel --read yaml --write json | + jq '.["RubyGems Environment"] | to_entries | map((.value | keys)[0] as $key | {key: $key, value: .value[$key] }) | from_entries' | + jq --raw-output '.["'"${NAME}"'"]' + else + gem environment | + dasel --read yaml --write json | + jq '.["RubyGems Environment"] | to_entries | map((.value | keys)[0] as $key | {key: $key, value: .value[$key] }) | from_entries' + fi +) diff --git a/dot_local/share/buddy/lib/get_bitrate.sh b/dot_local/share/buddy/lib/get_bitrate.sh new file mode 100644 index 0000000..7c2f7b2 --- /dev/null +++ b/dot_local/share/buddy/lib/get_bitrate.sh @@ -0,0 +1,11 @@ +require assert/command +require bail + +assert_command exiftool + +get_bitrate() ( + if [ ! -f "$1" ]; then + bail "unknown file: $1" + fi + exiftool -AudioBitrate "$1" | awk '{print $4}' +) diff --git a/dot_local/share/buddy/lib/github/download_url.sh b/dot_local/share/buddy/lib/github/download_url.sh new file mode 100644 index 0000000..6ffbfb6 --- /dev/null +++ b/dot_local/share/buddy/lib/github/download_url.sh @@ -0,0 +1,7 @@ +github_download_url() ( + USER=$1 + REPO=$2 + TAG=$3 + FILE=$4 + echo "https://github.com/$USER/$REPO/releases/download/v${TAG}/${FILE}" +) diff --git a/dot_local/share/buddy/lib/github/install_scripts.sh b/dot_local/share/buddy/lib/github/install_scripts.sh new file mode 100644 index 0000000..0373ea8 --- /dev/null +++ b/dot_local/share/buddy/lib/github/install_scripts.sh @@ -0,0 +1,16 @@ +require assert/command + +assert_command rg + +github_install_scripts() ( + rg github.com "${HOME}/.local/bin" | + sed 's/:/ /' | + sed 's/=/ /g' | + awk '{print $3}' | + sed 's|https://github.com/||g' | + sed 's|/| |g' | + awk '{print $1 " " $2}' | + sed 's| |/|g' | + sort | + uniq +) diff --git a/dot_local/share/buddy/lib/github/install_scripts_latest_releases.sh b/dot_local/share/buddy/lib/github/install_scripts_latest_releases.sh new file mode 100644 index 0000000..76420dc --- /dev/null +++ b/dot_local/share/buddy/lib/github/install_scripts_latest_releases.sh @@ -0,0 +1,8 @@ +require github/install_scripts +require github/latest_release + +github_install_scripts_latest_releases() ( + for REPO in $(github_install_scripts); do + echo "${REPO} $(github_latest_release "${REPO}")" + done +) diff --git a/dot_local/share/buddy/lib/github/latest_release.sh b/dot_local/share/buddy/lib/github/latest_release.sh new file mode 100644 index 0000000..fa36e0c --- /dev/null +++ b/dot_local/share/buddy/lib/github/latest_release.sh @@ -0,0 +1,5 @@ +require github/tags + +github_latest_release() ( + github_tags "$@" | head -n 1 +) diff --git a/dot_local/share/buddy/lib/github/release_json.sh b/dot_local/share/buddy/lib/github/release_json.sh new file mode 100644 index 0000000..7f13bf3 --- /dev/null +++ b/dot_local/share/buddy/lib/github/release_json.sh @@ -0,0 +1,14 @@ +require file_age_in_seconds +require mkdir_if_missing + +github_release_json() ( + PROJECT=$1 + DAY_IN_SECONDS=$((60 * 60 * 24)) + JSON=${XDG_CACHE_HOME}/apps/meta/${PROJECT}/releases.json + mkdir_if_missing "$(dirname "${JSON}")" + FILE_AGE=$(file_age_in_seconds "${JSON}") + if [[ ! -f ${JSON} || ${FILE_AGE} -gt ${DAY_IN_SECONDS} ]]; then + curl --silent --output "${JSON}" "https://api.github.com/repos/${PROJECT}/releases" + fi + echo "${JSON}" +) diff --git a/dot_local/share/buddy/lib/github/releases.sh b/dot_local/share/buddy/lib/github/releases.sh new file mode 100644 index 0000000..a7b900e --- /dev/null +++ b/dot_local/share/buddy/lib/github/releases.sh @@ -0,0 +1,14 @@ +require assert/command + +assert_command curl + +github_releases() ( + USER=${1} + REPO=${2-} + if [ -z "${REPO}" ]; then + USER=$(echo "${1}" | sed 's|/| |g' | awk '{print $1}') + REPO=$(echo "${1}" | sed 's|/| |g' | awk '{print $2}') + fi + curl --silent --header "Accept: application/vnd.github.v3+json" \ + "https://api.github.com/repos/${USER}/${REPO}/releases" +) diff --git a/dot_local/share/buddy/lib/github/tags.sh b/dot_local/share/buddy/lib/github/tags.sh new file mode 100644 index 0000000..dd58b13 --- /dev/null +++ b/dot_local/share/buddy/lib/github/tags.sh @@ -0,0 +1,15 @@ +require assert/command + +assert_command curl jq + +github_tags() ( + USER=${1} + REPO=${2-} + if [ -z "${REPO}" ]; then + USER=$(echo "${1}" | sed 's|/| |g' | awk '{print $1}') + REPO=$(echo "${1}" | sed 's|/| |g' | awk '{print $2}') + fi + curl --silent --header "Accept: application/vnd.github.v3+json" \ + "https://api.github.com/repos/${USER}/${REPO}/tags" | + jq -r '.[].name' +) diff --git a/dot_local/share/buddy/lib/go_deps.sh b/dot_local/share/buddy/lib/go_deps.sh new file mode 100644 index 0000000..044d3a0 --- /dev/null +++ b/dot_local/share/buddy/lib/go_deps.sh @@ -0,0 +1,6 @@ +go_deps() ( + GO_MOD=${1:-go.mod} + START_AT=$(grep -n '^require ($' "${GO_MOD}" | awk -F : '{print $1}' | head -n 1) + END_AT=$(grep -n '^)$' "${GO_MOD}" | awk -F : '{print $1}' | head -n 1) + awk 'NR>'"${START_AT}"' && NR<'"${END_AT}"' {print $1}' "${GO_MOD}" +) diff --git a/dot_local/share/buddy/lib/json_to_yaml.sh b/dot_local/share/buddy/lib/json_to_yaml.sh new file mode 100644 index 0000000..05bb523 --- /dev/null +++ b/dot_local/share/buddy/lib/json_to_yaml.sh @@ -0,0 +1,14 @@ +require assert/command + +assert_command bat dasel + +json_to_yaml() ( + ARG=${1-} + if [ -z "${ARG}" ]; then + dasel --read json --write yaml | bat --language yaml + elif [ -f "${ARG}" ]; then + dasel --read json --write yaml --file "${ARG}" | bat --language yaml + else + echo "${ARG}" | dasel --read json --write yaml | bat --language yaml + fi +) diff --git a/dot_local/share/buddy/lib/make_script.sh b/dot_local/share/buddy/lib/make_script.sh new file mode 100644 index 0000000..6fcee79 --- /dev/null +++ b/dot_local/share/buddy/lib/make_script.sh @@ -0,0 +1,17 @@ +make_script() ( + for FILE in "$@"; do + cat <"${FILE}" +#!/usr/bin/env bash + +set -euo pipefail + +main() ( + echo "todo" + exit 1 +) + +main "\$@" +EOF + chmod +x "${FILE}" + done +) diff --git a/dot_local/share/buddy/lib/min_jpg.sh b/dot_local/share/buddy/lib/min_jpg.sh new file mode 100644 index 0000000..5ac2adb --- /dev/null +++ b/dot_local/share/buddy/lib/min_jpg.sh @@ -0,0 +1,13 @@ +require assert/command + +assert_command jpegtran + +min_jpg() ( + for FILE in "$@"; do + PERMISSIONS=$(stat --format '%a' "${FILE}") + OUT_FILE=$(mktemp) + jpegtran -optimize -perfect -outfile "${OUT_FILE}" "${FILE}" + mv "${OUT_FILE}" "${FILE}" + chmod "${PERMISSIONS}" "${FILE}" + done +) diff --git a/dot_local/share/buddy/lib/min_png.sh b/dot_local/share/buddy/lib/min_png.sh new file mode 100644 index 0000000..0ea37d8 --- /dev/null +++ b/dot_local/share/buddy/lib/min_png.sh @@ -0,0 +1,13 @@ +require assert/command + +assert_command pngcrush + +min_png() ( + for FILE in "$@"; do + PERMISSIONS=$(stat --format '%a' "${FILE}") + OUT_FILE=$(mktemp) + pngcrush -rem alla -reduce -brute "${FILE}" "${OUT_FILE}" + mv "${OUT_FILE}" "${FILE}" + chmod "${PERMISSIONS}" "${FILE}" + done +) diff --git a/dot_local/share/buddy/lib/mkdir_if_missing.sh b/dot_local/share/buddy/lib/mkdir_if_missing.sh new file mode 100644 index 0000000..d4c95ab --- /dev/null +++ b/dot_local/share/buddy/lib/mkdir_if_missing.sh @@ -0,0 +1,8 @@ +mkdir_if_missing() ( + dir=${1} + sudo=${2-} + if [ ! -d "${dir}" ]; then + # shellcheck disable=SC2086 + $sudo mkdir -p "${dir}" + fi +) diff --git a/dot_local/share/buddy/lib/node/current.sh b/dot_local/share/buddy/lib/node/current.sh new file mode 100644 index 0000000..0bcd23e --- /dev/null +++ b/dot_local/share/buddy/lib/node/current.sh @@ -0,0 +1,4 @@ +node_current() ( + curl --silent https://nodejs.org/dist/index.tab | + cut -f 1,10 | grep '-' | head -n 1 | cut -f 1 +) diff --git a/dot_local/share/buddy/lib/node/lts.sh b/dot_local/share/buddy/lib/node/lts.sh new file mode 100644 index 0000000..8a79bf9 --- /dev/null +++ b/dot_local/share/buddy/lib/node/lts.sh @@ -0,0 +1,4 @@ +node_lts() ( + curl --silent https://nodejs.org/dist/index.tab | + cut -f 1,10 | grep -v '-' | head -n 2 | tail -n 1 | cut -f 1 +) diff --git a/dot_local/share/buddy/lib/relative_path.sh b/dot_local/share/buddy/lib/relative_path.sh new file mode 100644 index 0000000..b671861 --- /dev/null +++ b/dot_local/share/buddy/lib/relative_path.sh @@ -0,0 +1,43 @@ +relative_path() ( + # both $1 and $2 are absolute paths beginning with / + # $1 must be a canonical path; that is none of its directory + # components may be ".", ".." or a symbolic link + # + # returns relative path to $2/$target from $1/$src + src=$1 + target=$2 + + common_part=$src + result= + + while [ "${target#"$common_part"}" = "$target" ]; do + # no match, means that candidate common part is not correct + # go up one level (reduce common part) + common_part=$(dirname "$common_part") + # and record that we went back, with correct / handling + if [ -z "$result" ]; then + result=.. + else + result=../$result + fi + done + + if [ "$common_part" = / ]; then + # special case for root (no common path) + result=$result/ + fi + + # since we now have identified the common part, + # compute the non-common part + forward_part=${target#"$common_part"} + + # and now stick all parts together + if [ -n "$result" ] && [ -n "$forward_part" ]; then + result=$result$forward_part + elif [ -n "$forward_part" ]; then + # extra slash removal + result=${forward_part#?} + fi + + printf '%s' "$result" +) diff --git a/dot_local/share/buddy/lib/slugify.sh b/dot_local/share/buddy/lib/slugify.sh new file mode 100644 index 0000000..bccb27e --- /dev/null +++ b/dot_local/share/buddy/lib/slugify.sh @@ -0,0 +1,12 @@ +#shellcheck disable=SC2120 +slugify() ( + if [ "$#" -ne 0 ]; then + #shellcheck disable=SC2119 + echo "$@" | slugify + else + iconv --to-code ascii//TRANSLIT | + sed -E 's/[^a-zA-Z0-9]+/-/g' | + sed -E 's/^-+\|-+$//g' | + tr '[:upper:]' '[:lower:]' + fi +) diff --git a/dot_local/share/buddy/lib/unlink_if_set.sh b/dot_local/share/buddy/lib/unlink_if_set.sh new file mode 100644 index 0000000..244d4bc --- /dev/null +++ b/dot_local/share/buddy/lib/unlink_if_set.sh @@ -0,0 +1,8 @@ +unlink_if_set() ( + dir=$1 + sudo=${2-} + if [ -L "${dir}" ]; then + # shellcheck disable=SC2086 + ${sudo} unlink "${dir}" + fi +) diff --git a/dot_local/share/buddy/lib/yaml_to_json.sh b/dot_local/share/buddy/lib/yaml_to_json.sh new file mode 100644 index 0000000..b384120 --- /dev/null +++ b/dot_local/share/buddy/lib/yaml_to_json.sh @@ -0,0 +1,15 @@ +require assert/command + +assert_command bat dasel + +yaml_to_json() ( + ARG=${1-} + command_installed bat dasel + if [ -z "${ARG}" ]; then + dasel --read yaml --write json | bat --language json + elif [ -f "${ARG}" ]; then + dasel --read yaml --write json --file "${ARG}" | bat --language json + else + echo "${ARG}" | dasel --read yaml --write json | bat --language json + fi +)