From ab5766625df66a33101d96fe8b717a19707e6598 Mon Sep 17 00:00:00 2001 From: David Vazgenovich Shakaryan Date: Fri, 19 Dec 2025 22:40:15 -0800 Subject: genericise --- README | 61 ++++++++++++++-------- gbpm.sh | 176 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ rbpm.sh | 182 ---------------------------------------------------------------- 3 files changed, 215 insertions(+), 204 deletions(-) create mode 100755 gbpm.sh delete mode 100755 rbpm.sh diff --git a/README b/README index dd2be04..6239b75 100644 --- a/README +++ b/README @@ -1,19 +1,19 @@ -rbpm (ruby path mangler) +gbpm ( path mangler) -https://git.potato.am/rbpm.git/ -Manage multiple Ruby installations with no black magic. +https://git.potato.am/gbpm.git/ +Manage multiple Python/Ruby/etc. installations with no black magic. NOTES - rbpm only manages rubies located in the ~/.rubies directory. This - directory can be changed by setting the RUBIES_PATH environment - variable to some other location. rbpm does not display information - about rubies it does not manage, such as any system-wide install. + gbpm only manages installations located in GBPM_OPTS_PATH, shadowing + binaries already reachable from PATH. No information on external + installations is displayed. - rbpm performs a substring match when selecting a ruby. If there are - multiple matches, it gives precedence to matches at the start of the - version. If there are still multiple, the greatest of those is used. + A substring match is performed when selecting an installation, with + tiebreak rules to choose intuitively, the greatest being selected + amongst equally ranked matches. For example, `2.1' will match + `python-2.1.3' over `python-2.1.2' or `python-3.2.1'. DEPENDENCIES @@ -24,21 +24,32 @@ DEPENDENCIES INSTALLING - Save the script to a safe location, then add the following function to - your ~/.bashrc or equivalent file: + The output of this script is a series of commands to be executed, e.g. + via a shell function in `~/.bashrc': - rbpm() { source <(/path/to/rbpm.sh "${@}"); } + pypm() { + . <( + GBPM_OPTS_PATH="${HOME}/.pythons" \ + /path/to/gbpm.sh "${@}") + } + rbpm() { + . <( + GBPM_OPTS_PATH="${HOME}/.rubies" \ + /path/to/gbpm.sh "${@}") + } -INSTALLING RUBIES - The path to the executable should look something like this: +INSTALLING VERSIONS + + With `~/.rubies' as the managed directory, the path to a ruby binary + should look something like: ~/.rubies/ruby-2.1.2/bin/ruby To install Ruby to this directory: - $ wget http://cache.ruby-lang.org/pub/ruby/2.1/ruby-2.1.2.tar.bz2 + $ wget https://cache.ruby-lang.org/pub/ruby/2.1/ruby-2.1.2.tar.bz2 $ tar -xf ruby-2.1.2.tar.bz2 $ cd ruby-2.1.2 $ ./configure --prefix="${HOME}"/.rubies/ruby-2.1.2 @@ -48,7 +59,10 @@ INSTALLING RUBIES USAGE - A sequence of commands showing rbpm in use: + A series of commands showing gbpm in use, through an `rbpm' function: + + $ ruby -v + bash: ruby: command not found $ rbpm ls ruby-1.8.7-p374 @@ -56,7 +70,7 @@ USAGE ruby-2.1.2 $ rbpm set 2.1 - Adding /home/omp/.rubies/ruby-2.1.2/bin to PATH. + adding /home/david/.rubies/ruby-2.1.2/bin to PATH $ rbpm ls ruby-1.8.7-p374 @@ -67,19 +81,22 @@ USAGE ruby 2.1.2p95 (2014-05-08 revision 45877) [x86_64-linux] $ rbpm set 1.9 - Removing /home/omp/.rubies/ruby-2.1.2/bin from PATH. - Adding /home/omp/.rubies/ruby-1.9.3-p547/bin to PATH. + removing /home/david/.rubies/ruby-2.1.2/bin from PATH + adding /home/david/.rubies/ruby-1.9.3-p547/bin to PATH $ ruby -v ruby 1.9.3p547 (2014-05-14 revision 45962) [x86_64-linux] $ rbpm clear - Removing /home/omp/.rubies/ruby-1.9.3-p547/bin from PATH. + removing /home/david/.rubies/ruby-1.9.3-p547/bin from PATH + + $ ruby -v + bash: ruby: command not found To set the version from a .ruby-version file: $ rbpm set $(cat .ruby-version) - Adding /home/omp/.rubies/ruby-1.8.7-p374/bin to PATH. + adding /home/david/.rubies/ruby-1.8.7-p374/bin to PATH AUTHORS 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 [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 diff --git a/rbpm.sh b/rbpm.sh deleted file mode 100755 index 88077ff..0000000 --- a/rbpm.sh +++ /dev/null @@ -1,182 +0,0 @@ -#!/usr/bin/env bash -# -# Copyright 2014 David Vazgenovich Shakaryan -# Distributed under the terms of the MIT License. -# -# rbpm (ruby path mangler) -# https://git.potato.am/rbpm.git/ -# Manage multiple Ruby installations with no black magic. -# -# In order to prevent environment pollution, the output of this script -# is a list of commands which must be sourced. This can be achieved -# through a simple shell function: -# -# rbpm() { source <(/path/to/rbpm.sh "${@}"); } -# -# Placing the above function inside ~/.bashrc (or equivalent) will load -# it upon starting your shell. - -RBPM_VERSION='0.3' - -: ${RUBIES_PATH:="${HOME}/.rubies"} - -_echo() { - echo "echo '${@//\'/\'\\\'\'}'" -} - -_export() { - echo "export PATH='${PATH//\'/\'\\\'\'}'" - echo 'hash -r' -} - -_warn() { - echo "echo 'rbpm: ${@//\'/\'\\\'\'}' 1>&2" -} - -_die() { - [[ -n "${@}" ]] && _warn "${@}" - - echo 'false' - exit 1 -} - -_populate_dirs() { - [[ -d "${RUBIES_PATH}" ]] \ - || _die "directory ${RUBIES_PATH} does not exist" - - mapfile -td $'\0' dirs < <(shopt -s nullglob; - printf '%s\0' "${RUBIES_PATH}"/* | sort -zV) - - [[ -n "${dirs}" ]] || _die "directory ${RUBIES_PATH} is empty" -} - -_populate_selected() { - local dir dirs - - mapfile -td : dirs < <(printf %s "${PATH}") - - for dir in "${dirs[@]}"; do - if [[ "${dir}" == "${RUBIES_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}" == "${RUBIES_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}" -} - -rbpm_ls() { - local dir dirs selected str - - _populate_dirs - _populate_selected - - for dir in "${dirs[@]}"; do - str=" ${dir##*/}" - - [[ "${dir##*/}" == "${selected}" ]] && str="${str/ /*}" - - _echo "${str}" - done -} - -rbpm_get() { - local dir selected - - _populate_selected || _die 'no managed path found in PATH' - - for dir in "${selected[@]}"; do - _echo "${dir}" - done -} - -rbpm_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 `2.2.1' over `2.1.0'. - if [[ "${dir##*/}" == "${1}"* || - "${dir##*/}" == *-"${1}"* ]]; then - match_start="${dir}" - fi - done - - [[ -n "${match}" ]] || _die 'no matching ruby found' - [[ -n "${match_start}" ]] && match="${match_start}" - - _clear - _add "${match}" - _export -} - -rbpm_clear() { - _clear || _die 'no managed path found in PATH' - _export -} - -rbpm_version() { - _echo "rbpm ${RBPM_VERSION}" -} - -rbpm_help() { - _echo 'Usage: rbpm [args]' - _echo - _echo 'Commands:' - _echo ' ls List all available rubies' - _echo ' get Display currently selected ruby' - _echo ' set Select specified ruby' - _echo ' clear Unselect any selected rubies' - _echo ' version Display rbpm version' -} - -case "${1}" in - 'ls') - rbpm_ls ;; - 'get') - rbpm_get ;; - 'set') - rbpm_set "${2}" ;; - 'clear') - rbpm_clear ;; - 'version') - rbpm_version ;; - *) - rbpm_help ;; -esac -- cgit v1.2.3-70-g09d2