aboutsummaryrefslogtreecommitdiff
path: root/gbpm.sh
diff options
context:
space:
mode:
Diffstat (limited to 'gbpm.sh')
-rwxr-xr-xgbpm.sh176
1 files changed, 176 insertions, 0 deletions
diff --git a/gbpm.sh b/gbpm.sh
new file mode 100755
index 0000000..50ff7a2
--- /dev/null
+++ b/gbpm.sh
@@ -0,0 +1,176 @@
+#!/usr/bin/env bash
+#
+# Copyright 2014 David Vazgenovich Shakaryan
+# Distributed under the terms of the MIT License.
+#
+# gbpm
+# https://git.potato.am/gbpm.git/
+# Manage multiple Python/Ruby/etc. installations with no black magic.
+#
+# Output must be executed: gbpm() { . <(/path/to/gbpm.sh "${@}"); }
+
+GBPM_VERSION='0.4'
+
+: ${GBPM_OPTS_PATH:="${HOME}/.pythons"}
+
+_echo() {
+ echo "echo '${@//\'/\'\\\'\'}'"
+}
+
+_export() {
+ echo "export PATH='${PATH//\'/\'\\\'\'}'"
+ echo 'hash -r'
+}
+
+_warn() {
+ echo "echo 'gbpm: ${@//\'/\'\\\'\'}' >&2"
+}
+
+_die() {
+ [[ -n "${@}" ]] && _warn "${@}"
+
+ echo 'false'
+ exit 1
+}
+
+_populate_dirs() {
+ [[ -d "${GBPM_OPTS_PATH}" ]] \
+ || _die "directory ${GBPM_OPTS_PATH} does not exist"
+
+ mapfile -td $'\0' dirs < <(shopt -s nullglob;
+ printf '%s\0' "${GBPM_OPTS_PATH}"/* | sort -zV)
+
+ [[ -n "${dirs}" ]] || _die "directory ${GBPM_OPTS_PATH} is empty"
+}
+
+_populate_selected() {
+ local dir dirs
+
+ mapfile -td : dirs < <(printf %s "${PATH}")
+
+ selected=()
+ for dir in "${dirs[@]}"; do
+ if [[ "${dir}" == "${GBPM_OPTS_PATH}/"* ]]; then
+ dir="${dir%/bin}"
+ selected+=("${dir##*/}")
+ fi
+ done
+
+ [[ "${#selected[@]}" -ne 0 ]] || return 1
+ [[ "${#selected[@]}" -eq 1 ]] \
+ || _warn 'warning: multiple managed paths found in PATH'
+}
+
+_clear() {
+ local dir dirs cdirs
+
+ mapfile -td : dirs < <(printf %s "${PATH}")
+
+ for dir in "${dirs[@]}"; do
+ if [[ "${dir}" == "${GBPM_OPTS_PATH}/"* ]]; then
+ _echo "removing ${dir} from PATH"
+ else
+ cdirs+=("${dir}")
+ fi
+ done
+
+ [[ "${#cdirs[@]}" -ne "${#dirs[@]}" ]] || return 1
+
+ PATH="$(IFS=':'; echo "${cdirs[*]}")"
+}
+
+_add() {
+ _echo "adding ${1}/bin to PATH"
+
+ PATH="${1}/bin:${PATH}"
+}
+
+cmd_ls() {
+ local dir dirs selected str
+
+ _populate_dirs
+ _populate_selected
+
+ for dir in "${dirs[@]}"; do
+ str=" ${dir##*/}"
+
+ [[ "${dir##*/}" == "${selected}" ]] && str="${str/ /*}"
+
+ _echo "${str}"
+ done
+}
+
+cmd_get() {
+ local dir selected
+
+ _populate_selected || _die 'no managed path found in PATH'
+
+ for dir in "${selected[@]}"; do
+ _echo "${dir}"
+ done
+}
+
+cmd_set() {
+ [[ -n "${1}" ]] || _die 'set command requires an argument'
+
+ local dir dirs match match_start
+
+ _populate_dirs
+
+ for dir in "${dirs[@]}"; do
+ [[ "${dir##*/}" == *"${1}"* ]] || continue
+
+ match="${dir}"
+
+ # match from start of version is preferred. we assume the
+ # version is at the beginning of the directory name or
+ # immediately following a hyphen. this avoids unintuitive
+ # behaviour like `2.1' matching `3.2.1' over `2.1.0'.
+ if [[ "${dir##*/}" == "${1}"* ||
+ "${dir##*/}" == *-"${1}"* ]]; then
+ match_start="${dir}"
+ fi
+ done
+
+ [[ -n "${match}" ]] || _die 'no matching version found'
+ [[ -n "${match_start}" ]] && match="${match_start}"
+
+ _clear
+ _add "${match}"
+ _export
+}
+
+cmd_clear() {
+ _clear || _die 'no managed path found in PATH'
+ _export
+}
+
+cmd_version() {
+ _echo "gbpm ${GBPM_VERSION}"
+}
+
+cmd_help() {
+ _echo 'Usage: gbpm <command> [args]'
+ _echo
+ _echo 'Commands:'
+ _echo ' ls List all available versions'
+ _echo ' get Display currently selected version'
+ _echo ' set Select specified version'
+ _echo ' clear Unselect any selected versions'
+ _echo ' version Display gbpm version'
+}
+
+case "${1}" in
+ 'ls')
+ cmd_ls ;;
+ 'get')
+ cmd_get ;;
+ 'set')
+ cmd_set "${2}" ;;
+ 'clear')
+ cmd_clear ;;
+ 'version')
+ cmd_version ;;
+ *)
+ cmd_help ;;
+esac