diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..e2f4d54 --- /dev/null +++ b/LICENSE @@ -0,0 +1,20 @@ +Copyright (c) 2013 Gildas Cuisinier + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/README.md b/README.md index e69de29..b3fc3d3 100644 --- a/README.md +++ b/README.md @@ -0,0 +1,121 @@ +# Master your Java Environnement with jenv + +jenv is for Java, + +## How It Works + + +## Command Reference + +Like `git`, the `jenv` command delegates to subcommands based on its +first argument. The most common subcommands are: + +### jenv local + +Sets a local application-specific Java version by writing the version +name to a `.java-version` file in the current directory. This version +overrides the global version, and can be overridden itself by setting +the `JENV_VERSION` environment variable or with the `jenv shell` +command. + + $ jenv local 1.9.3-p327 + +When run without a version number, `jenv local` reports the currently +configured local version. You can also unset the local version: + + $ jenv local --unset + +Previous versions of jenv stored local version specifications in a +file named `.jenv-version`. For backwards compatibility, jenv will +read a local version specified in an `.jenv-version` file, but a +`.java-version` file in the same directory will take precedence. + +### jenv global + +Sets the global version of Java to be used in all shells by writing +the version name to the `~/.jenv/version` file. This version can be +overridden by an application-specific `.java-version` file, or by +setting the `JENV_VERSION` environment variable. + + $ jenv global oracle-1.6 + +The special version name `system` tells jenv to use the system Java +(detected by searching your `$PATH`). + +When run without a version number, `jenv global` reports the +currently configured global version. + +### jenv shell + +Sets a shell-specific Java version by setting the `JENV_VERSION` +environment variable in your shell. This version overrides +application-specific versions and the global version. + + $ jenv shell jJava-1.7.1 + +When run without a version number, `jenv shell` reports the current +value of `JENV_VERSION`. You can also unset the shell version: + + $ jenv shell --unset + +Note that you'll need jenv's shell integration enabled (step 3 of +the installation instructions) in order to use this command. If you +prefer not to use shell integration, you may simply set the +`JENV_VERSION` variable yourself: + + $ export JENV_VERSION=oracle-1.6 + +### jenv versions + +Lists all Java versions known to jenv, and shows an asterisk next to +the currently active version. + + $ jenv versions + oracle-1.6 + * oracle-1.7 (set by /Users/hikage/.jenv/version) + +### jenv version + +Displays the currently active Java version, along with information on +how it was set. + + $ jenv version + oracle-1.6 (set by /tmp/test/.java-version) + +### jenv rehash + +Installs shims for all Java executables known to jenv (i.e., +`~/.jenv/versions/*/bin/*`). Run this command after you install a new +version of Java. + + $ jenv rehash + +### jenv which + +Displays the full path to the executable that jenv will invoke when +you run the given command. + + $ jenv which java + /Users/sam/.jenv/versions/oracle-1.6/bin/java + +### jenv whence + +Lists all Java versions with the given command installed. + + $ jenv whence java + oracle-1.6 + oracle-1.7 + +## Development + +The jenv source code is [hosted on +GitHub](https://github.com/hikage/jenv). It's clean, modular, +and easy to understand, even if you're not a shell hacker. + +It is based on [rbenv](https://github.com/hikage/jenv). + +Please feel free to submit pull requests and file bugs on the [issue +tracker](https://github.com/hikage/jenv/issues). + +### Version History + diff --git a/bin/jenv b/bin/jenv deleted file mode 120000 index b938806..0000000 --- a/bin/jenv +++ /dev/null @@ -1 +0,0 @@ -../libexec/jenv \ No newline at end of file diff --git a/bin/jenv b/bin/jenv new file mode 100755 index 0000000..1803f73 --- /dev/null +++ b/bin/jenv @@ -0,0 +1,87 @@ +#!/usr/bin/env bash +set -e + +if [ "$1" = "--debug" ]; then + export JENV_DEBUG=1 + shift +fi + +if [ -n "$JENV_DEBUG" ]; then + export PS4='+ [${BASH_SOURCE##*/}:${LINENO}] ' + set -x +fi + +resolve_link() { + $(type -p greadlink readlink | head -1) "$1" +} + +abs_dirname() { + local cwd="$(pwd)" + local path="$1" + + while [ -n "$path" ]; do + cd "${path%/*}" + local name="${path##*/}" + path="$(resolve_link "$name" || true)" + done + + pwd + cd "$cwd" +} + +if [ -z "${JENV_ROOT}" ]; then + JENV_ROOT="${HOME}/.jenv" +else + JENV_ROOT="${JENV_ROOT%/}" +fi +export JENV_ROOT + +if [ -z "${JENV_DIR}" ]; then + JENV_DIR="$(pwd)" +else + cd "$JENV_DIR" 2>/dev/null || { + echo "jenv: cannot change working directory to \`$JENV_DIR'" + exit 1 + } >&2 + JENV_DIR="$(pwd)" + cd "$OLDPWD" +fi +export JENV_DIR + + +shopt -s nullglob + +bin_path="$(abs_dirname "$0")" +for plugin_bin in "${JENV_ROOT}/plugins/"*/bin; do + bin_path="${bin_path}:${plugin_bin}" +done +export PATH="${bin_path}:${PATH}" + +hook_path="${JENV_HOOK_PATH}:${JENV_ROOT}/jenv.d:/usr/local/etc/jenv.d:/etc/jenv.d:/usr/lib/jenv/hooks" +for plugin_hook in "${JENV_ROOT}/plugins/"*/etc/jenv.d; do + hook_path="${hook_path}:${plugin_hook}" +done +export JENV_HOOK_PATH="$hook_path" + +shopt -u nullglob + + +command="$1" +case "$command" in +"" | "-h" | "--help" ) + echo -e "$(jenv---version)\n$(jenv-help)" >&2 + ;; +"-v" ) + exec jenv---version + ;; +* ) + command_path="$(command -v "jenv-$command" || true)" + if [ -z "$command_path" ]; then + echo "jenv: no such command \`$command'" >&2 + exit 1 + fi + + shift 1 + exec "$command_path" "$@" + ;; +esac diff --git a/bin/ruby-local-exec b/bin/ruby-local-exec new file mode 100755 index 0000000..d01dd18 --- /dev/null +++ b/bin/ruby-local-exec @@ -0,0 +1,23 @@ +#!/usr/bin/env bash +# +# `ruby-local-exec` is a drop-in replacement for the standard Ruby +# shebang line: +# +# #!/usr/bin/env ruby-local-exec +# +# Use it for scripts inside a project with an `.jenv-version` +# file. When you run the scripts, they'll use the project-specified +# Ruby version, regardless of what directory they're run from. Useful +# for e.g. running project tasks in cron scripts without needing to +# `cd` into the project first. + +set -e +export JENV_DIR="${1%/*}" + +[ -n "$JENV_SILENCE_WARNINGS" ] || { + echo "jenv: \`ruby-local-exec' is deprecated and will be removed in the next release." + echo " To upgrade: https://github.com/sstephenson/jenv/wiki/ruby-local-exec" + echo +} >&2 + +exec ruby "$@" diff --git a/completions/jenv.bash b/completions/jenv.bash index b91677b..639b80c 100644 --- a/completions/jenv.bash +++ b/completions/jenv.bash @@ -5,8 +5,10 @@ _jenv() { if [ "$COMP_CWORD" -eq 1 ]; then COMPREPLY=( $(compgen -W "$(jenv commands)" -- "$word") ) else - local command="${COMP_WORDS[1]}" - local completions="$(jenv completions "$command")" + local words=("${COMP_WORDS[@]}") + unset words[0] + unset words[$COMP_CWORD] + local completions=$(jenv completions "${words[@]}") COMPREPLY=( $(compgen -W "$completions" -- "$word") ) fi } diff --git a/completions/jenv.zsh b/completions/jenv.zsh index ede3e10..5e69efb 100644 --- a/completions/jenv.zsh +++ b/completions/jenv.zsh @@ -5,14 +5,13 @@ fi compctl -K _jenv jenv _jenv() { - local word words completions + local words completions read -cA words - word="${words[2]}" if [ "${#words}" -eq 2 ]; then completions="$(jenv commands)" else - completions="$(jenv completions "${word}")" + completions="$(jenv completions ${words[2,-1]})" fi reply=("${(ps:\n:)completions}") diff --git a/libexec/jenv---version b/libexec/jenv---version new file mode 100755 index 0000000..b9b8e30 --- /dev/null +++ b/libexec/jenv---version @@ -0,0 +1,21 @@ +#!/usr/bin/env bash +# Summary: Display the version of jenv +# +# Displays the version number of this jenv release, including the +# current revision from git, if available. +# +# The format of the git revision is: +# -- +# where `num_commits` is the number of commits since `version` was +# tagged. + +set -e +[ -n "$JENV_DEBUG" ] && set -x + +version="0.1.0" + +cd "$JENV_ROOT" +git_revision="$(git describe --tags HEAD 2>/dev/null || true)" +git_revision="${git_revision#v}" + +echo "jenv ${git_revision:-$version}" diff --git a/libexec/jenv-add b/libexec/jenv-add index 3dc1040..bd3c497 100755 --- a/libexec/jenv-add +++ b/libexec/jenv-add @@ -20,7 +20,8 @@ echo $JENV_JAVAPATH if [ -f "$JENV_JAVAPATH/bin/java" ]; then - ln -s "$JENV_JAVAPATH" "${JENV_ROOT}/versions/$JENV_VERSION" + ln -s "$JENV_JAVAPATH" "${JENV_ROOT}/versions/$JENV_VERSION" + $(jenv-rehash) else echo "$JENV_JAVAPATH is not a valid path to java installation" fi diff --git a/libexec/jenv-commands b/libexec/jenv-commands index 6ebd301..4a8fd9c 100755 --- a/libexec/jenv-commands +++ b/libexec/jenv-commands @@ -1,4 +1,7 @@ #!/usr/bin/env bash +# Summary: List all available jenv commands +# Usage: jenv commands [--sh|--no-sh] + set -e [ -n "$JENV_DEBUG" ] && set -x diff --git a/libexec/jenv-completions b/libexec/jenv-completions index 0c8f2da..804a8f9 100755 --- a/libexec/jenv-completions +++ b/libexec/jenv-completions @@ -1,10 +1,12 @@ #!/usr/bin/env bash +# Usage: jenv completions [arg1 arg2...] + set -e [ -n "$JENV_DEBUG" ] && set -x COMMAND="$1" if [ -z "$COMMAND" ]; then - echo "usage: jenv completions COMMAND [arg1 arg2...]" >&2 + jenv-help --usage completions >&2 exit 1 fi diff --git a/libexec/jenv-exec b/libexec/jenv-exec index 7c65406..703a234 100755 --- a/libexec/jenv-exec +++ b/libexec/jenv-exec @@ -1,4 +1,18 @@ #!/usr/bin/env bash +# +# Summary: Run an executable with the selected Ruby version +# +# Usage: jenv exec [arg1 arg2...] +# +# Runs an executable by first preparing PATH so that the selected Ruby +# version's `bin' directory is at the front. +# +# For example, if the currently selected Ruby version is 1.9.3-p327: +# jenv exec bundle install +# +# is equivalent to: +# PATH="$JENV_ROOT/versions/1.9.3-p327/bin:$PATH" bundle install + set -e [ -n "$JENV_DEBUG" ] && set -x @@ -6,25 +20,24 @@ set -e if [ "$1" = "--complete" ]; then exec jenv shims --short fi - -export JAVA_HOME="${JENV_ROOT}/versions/$(jenv-version-name)" +export JENV_VERSION="$(jenv-version-name)" JENV_COMMAND="$1" + if [ -z "$JENV_COMMAND" ]; then - echo "usage: jenv exec COMMAND [arg1 arg2...]" >&2 + jenv-help --usage exec >&2 exit 1 fi JENV_COMMAND_PATH="$(jenv-which "$JENV_COMMAND")" JENV_BIN_PATH="${JENV_COMMAND_PATH%/*}" - - -#for script in $(jenv-hooks exec); do -# source "$script" -#done +for script in $(jenv-hooks exec); do + source "$script" +done shift 1 -export PATH="${JENV_BIN_PATH}:${PATH}" -echo $PATH +if [ "$JENV_VERSION" != "system" ]; then + export PATH="${JENV_BIN_PATH}:${PATH}" +fi exec -a "$JENV_COMMAND" "$JENV_COMMAND_PATH" "$@" diff --git a/libexec/jenv-global b/libexec/jenv-global index 19b34d2..8194216 100755 --- a/libexec/jenv-global +++ b/libexec/jenv-global @@ -1,4 +1,17 @@ #!/usr/bin/env bash +# +# Summary: Set or show the global Ruby version +# +# Usage: jenv global +# +# Sets the global Ruby version. You can override the global version at +# any time by setting a directory-specific version with `jenv local' +# or by setting the `JENV_VERSION' environment variable. +# +# should be a string matching a Ruby version known to jenv. +# The special version string `system' will use your default system Ruby. +# Run `jenv versions' for a list of available Ruby versions. + set -e [ -n "$JENV_DEBUG" ] && set -x diff --git a/libexec/jenv-help b/libexec/jenv-help index e696646..a2c558f 100755 --- a/libexec/jenv-help +++ b/libexec/jenv-help @@ -1,88 +1,162 @@ #!/usr/bin/env bash +# +# Summary: Display help for a command +# +# Usage: jenv help [--usage] COMMAND +# +# Parses and displays help contents from a command's source file. +# +# A command is considered documented if it starts with a comment block +# that has a `Summary:' or `Usage:' section. Usage instructions can +# span multiple lines as long as subsequent lines are indented. +# The remainder of the comment block is displayed as extended +# documentation. + set -e [ -n "$JENV_DEBUG" ] && set -x -print_set_version() { - echo " should be a string matching a Ruby version known by jenv." +command_path() { + local command="$1" + command -v jenv-"$command" || command -v jenv-sh-"$command" || true +} + +extract_initial_comment_block() { + sed -ne " + /^#/ !{ + q + } + + s/^#$/# / + + /^# / { + s/^# // + p + } + " +} + +collect_documentation() { + awk ' + /^Summary:/ { + summary = substr($0, 10) + next + } + + /^Usage:/ { + reading_usage = 1 + usage = usage "\n" $0 + next + } - local versions="$(jenv-versions --bare)" - if [ -z "$versions" ]; then - echo "There are currently no Ruby versions installed for jenv." + /^( *$| )/ && reading_usage { + usage = usage "\n" $0 + next + } + + { + reading_usage = 0 + help = help "\n" $0 + } + + function escape(str) { + gsub(/[`\\$"]/, "\\\\&", str) + return str + } + + function trim(str) { + sub(/^\n*/, "", str) + sub(/\n*$/, "", str) + return str + } + + END { + if (usage || summary) { + print "summary=\"" escape(summary) "\"" + print "usage=\"" escape(trim(usage)) "\"" + print "help=\"" escape(trim(help)) "\"" + } + } + ' +} + +documentation_for() { + local filename="$(command_path "$1")" + if [ -n "$filename" ]; then + extract_initial_comment_block < "$filename" | collect_documentation + fi +} + +print_summary() { + local command="$1" + local summary usage help + eval "$(documentation_for "$command")" + + if [ -n "$summary" ]; then + printf " %-9s %s\n" "$command" "$summary" + fi +} + +print_summaries() { + for command; do + print_summary "$command" + done +} + +print_help() { + local command="$1" + local summary usage help + eval "$(documentation_for "$command")" + [ -n "$help" ] || help="$summary" + + if [ -n "$usage" -o -n "$summary" ]; then + if [ -n "$usage" ]; then + echo "$usage" + else + echo "Usage: jenv ${command}" + fi + if [ -n "$help" ]; then + echo + echo "$help" + echo + fi else - echo "The currently installed Ruby versions are:" - echo "$versions" | sed 's/^/ /' + echo "Sorry, this command isn't documented yet." >&2 + return 1 fi +} - echo - echo "The special version string 'system' will use your default system Ruby." +print_usage() { + local command="$1" + local summary usage help + eval "$(documentation_for "$command")" + [ -z "$usage" ] || echo "$usage" } -case "$1" in -"") echo "usage: jenv [] - -Some useful jenv commands are: - commands List all jenv commands - rehash Rehash jenv shims (run this after installing binaries) - global Set or show the global Ruby version - local Set or show the local directory-specific Ruby version - shell Set or show the shell-specific Ruby version - version Show the current Ruby version - versions List all Ruby versions known by jenv - which Show the full path for the given Ruby command - whence List all Ruby versions with the given command - -See 'jenv help ' for information on a specific command. -For full documentation, see: https://github.com/sstephenson/jenv#readme" -;; -global) echo "usage: jenv global - -Sets the global Ruby version. You can override the global version at -any time by setting a directory-specific version with \`jenv local' -or by setting the JENV_VERSION environment variable. - -$(print_set_version)" -;; -local) echo "usage: jenv local - jenv local --unset - -Sets the local directory-specific Ruby version by writing the version -name to a file named '.jenv-version'. - -When you run a Ruby command, jenv will look for an '.jenv-version' -file in the current directory and each parent directory. If no such -file is found in the tree, jenv will use the global Ruby version -specified with \`jenv global', or the version specified in the -JENV_VERSION environment variable. - -$(print_set_version)" -;; -shell) echo "usage: jenv shell - jenv shell --unset - -Sets a shell-specific Ruby version by setting the 'JENV_VERSION' -environment variable in your shell. This version overrides both -project-specific versions and the global version. - -$(print_set_version)" -;; -which) echo "usage: jenv which - -Displays the full path to the binary that jenv will execute when you -run the given command." -;; -whence) echo "usage: jenv whence - -Lists all Ruby versions with the given command installed." -;; -*) - command_path="$(command -v "jenv-$1" || true)" - if [ -n "$command_path" ]; then - echo "Sorry, the \`$1' command isn't documented yet." - echo - echo "You can view the command's source here:" - echo "$command_path" - echo +unset usage +if [ "$1" = "--usage" ]; then + usage="1" + shift +fi + +if [ -z "$1" ] || [ "$1" == "jenv" ]; then + echo "Usage: jenv []" + [ -z "$usage" ] || exit + echo + echo "Some useful jenv commands are:" + print_summaries commands local global shell install uninstall rehash version versions which whence + echo + echo "See \`jenv help ' for information on a specific command." + echo "For full documentation, see: https://github.com/sstephenson/jenv#readme" +else + command="$1" + if [ -n "$(command_path "$command")" ]; then + if [ -n "$usage" ]; then + print_usage "$command" + else + print_help "$command" + fi else - echo "jenv: no such command \`$1'" + echo "jenv: no such command \`$command'" >&2 + exit 1 fi -esac +fi diff --git a/libexec/jenv-hooks b/libexec/jenv-hooks index 90c4659..a72a90f 100755 --- a/libexec/jenv-hooks +++ b/libexec/jenv-hooks @@ -1,4 +1,7 @@ #!/usr/bin/env bash +# Summary: List hook scripts for a given jenv command +# Usage: jenv hooks + set -e [ -n "$JENV_DEBUG" ] && set -x @@ -12,7 +15,7 @@ fi JENV_COMMAND="$1" if [ -z "$JENV_COMMAND" ]; then - echo "usage: jenv hooks COMMAND" >&2 + jenv-help --usage hooks >&2 exit 1 fi @@ -36,7 +39,7 @@ realpath() { } shopt -s nullglob -for path in ${JENV_HOOK_PATH//:/$'\n'}; do +for path in ${JENV_HOOK_PATH//:/$'\n'}; do for script in $path/"$JENV_COMMAND"/*.bash; do echo $(realpath $script) done diff --git a/libexec/jenv-init b/libexec/jenv-init index 253f605..7c560bd 100755 --- a/libexec/jenv-init +++ b/libexec/jenv-init @@ -1,18 +1,24 @@ #!/usr/bin/env bash +# Summary: Configure the shell environment for jenv +# Usage: eval "$(jenv init - [--no-rehash] [])" + set -e [ -n "$JENV_DEBUG" ] && set -x print="" -if [ "$1" = "-" ]; then - print=1 - shift -fi - no_rehash="" -if [ "$1" = "--no-rehash" ]; then - no_rehash=1 - shift -fi +for args in "$@" +do + if [ "$args" = "-" ]; then + print=1 + shift + fi + + if [ "$args" = "--no-rehash" ]; then + no_rehash=1 + shift + fi +done shell="$1" if [ -z "$shell" ]; then @@ -79,10 +85,11 @@ if [ -z "$no_rehash" ]; then echo 'jenv rehash 2>/dev/null' fi -commands=(`jenv commands --sh`) +commands=(`jenv-commands --sh`) IFS="|" cat < +# jenv local --unset +# +# Sets the local application-specific Ruby version by writing the +# version name to a file named `.java-version'. +# +# When you run a Ruby command, jenv will look for a `.java-version' +# file in the current directory and each parent directory. If no such +# file is found in the tree, jenv will use the global Ruby version +# specified with `jenv global'. A version specified with the +# `JENV_VERSION' environment variable takes precedence over local +# and global versions. +# +# For backwards compatibility, jenv will also read version +# specifications from `.jenv-version' files, but a `.java-version' +# file in the same directory takes precedence. +# +# should be a string matching a Ruby version known to jenv. +# The special version string `system' will use your default system Ruby. +# Run `jenv versions' for a list of available Ruby versions. + set -e [ -n "$JENV_DEBUG" ] && set -x @@ -10,14 +34,20 @@ if [ "$1" = "--complete" ]; then fi JENV_VERSION="$1" -JENV_VERSION_FILE=".jenv-version" if [ "$JENV_VERSION" = "--unset" ]; then - rm -f "$JENV_VERSION_FILE" + rm -f .java-version .jenv-version elif [ -n "$JENV_VERSION" ]; then - jenv-version-file-write "$JENV_VERSION_FILE" "$JENV_VERSION" + if [ "$(JENV_VERSION= jenv-version-origin)" -ef .jenv-version ]; then + rm -f .jenv-version + { echo "jenv: removed existing \`.jenv-version' file and migrated" + echo " local version specification to \`.java-version' file" + } >&2 + fi + jenv-version-file-write .java-version "$JENV_VERSION" else - jenv-version-file-read "$JENV_VERSION_FILE" || + jenv-version-file-read .java-version || + jenv-version-file-read .jenv-version || { echo "jenv: no local version configured for this directory" exit 1 } >&2 diff --git a/libexec/jenv-prefix b/libexec/jenv-prefix index 90726ae..8ffc27f 100755 --- a/libexec/jenv-prefix +++ b/libexec/jenv-prefix @@ -1,4 +1,11 @@ #!/usr/bin/env bash +# Summary: Display prefix for a Ruby version +# Usage: jenv prefix [] +# +# Displays the directory where a Ruby version is installed. If no +# version is given, `jenv prefix' displays the location of the +# currently selected version. + set -e [ -n "$JENV_DEBUG" ] && set -x @@ -16,7 +23,8 @@ fi if [ "$JENV_VERSION" = "system" ]; then RUBY_PATH="$(jenv-which ruby)" - echo "${RUBY_PATH%/*}" + RUBY_PATH="${RUBY_PATH%/*}" + echo "${RUBY_PATH%/bin}" exit fi diff --git a/libexec/jenv-rehash b/libexec/jenv-rehash index 3634e62..d43b2a1 100755 --- a/libexec/jenv-rehash +++ b/libexec/jenv-rehash @@ -1,4 +1,6 @@ #!/usr/bin/env bash +# Summary: Rehash jenv shims (run this after installing executables) + set -e [ -n "$JENV_DEBUG" ] && set -x @@ -30,25 +32,53 @@ remove_prototype_shim() { # The prototype shim file is a script that re-execs itself, passing # its filename and any arguments to `jenv exec`. This file is -# hard-linked for every binary and then removed. The linking technique -# is fast, uses less disk space than unique files, and also serves as -# a locking mechanism. +# hard-linked for every executable and then removed. The linking +# technique is fast, uses less disk space than unique files, and also +# serves as a locking mechanism. create_prototype_shim() { cat > "$PROTOTYPE_SHIM_PATH" </dev/null 2>&1; then + for shim in *; do rm -f "$shim"; done + fi + break + done +} + # The basename of each argument passed to `make_shims` will be # registered for installation as a shim. In this way, plugins may call # `make_shims` with a glob to register many shims at once. make_shims() { - local shims="$@" - + local shims="$@" for file in $shims; do local shim="${file##*/}" @@ -56,58 +86,27 @@ make_shims() { done } -# Create an empty array for the list of registered shims. +# Create an empty array for the list of registered shims and an empty +# string to use as a search index. registered_shims=() +registered_shims_index="" # We will keep track of shims registered for installation with the -# global `reigstered_shims` array and with a global variable for each -# shim. The array will let us iterate over all registered shims. The -# global variables will let us quickly check whether a shim with the -# given name has been registered or not. +# global `registered_shims` array and with a global search index +# string. The array will let us iterate over all registered shims. The +# index string will let us quickly check whether a shim with the given +# name has been registered or not. register_shim() { local shim="$@" - local var="$(shim_variable_name "$shim")" - - if [ -z "${!var}" ]; then - registered_shims[${#registered_shims[*]}]="$shim" - eval "${var}=1" - fi -} - -# To compute the global variable name for a given shim we must first -# escape any non-alphanumeric characters. If the shim name is -# alphanumeric (including a hyphen or underscore) we can take a -# shorter path. Otherwise, we must iterate over each character and -# escape the non-alphanumeric ones using `printf`. -shim_variable_name() { - local shim="$1" - local result="_shim_" - - if [[ ! "$shim" =~ [^[:alnum:]_-] ]]; then - shim="${shim//_/_5f}" - shim="${shim//-/_2d}" - result+="$shim" - else - local length="${#shim}" - local char i - - for ((i=0; i +# jenv shell --unset +# +# Sets a shell-specific Ruby version by setting the `JENV_VERSION' +# environment variable in your shell. This version overrides local +# application-specific versions and the global version. +# +# should be a string matching a Ruby version known to jenv. +# The special version string `system' will use your default system Ruby. +# Run `jenv versions' for a list of available Ruby versions. + set -e [ -n "$JENV_DEBUG" ] && set -x @@ -23,10 +37,13 @@ fi if [ "$version" = "--unset" ]; then echo "unset JENV_VERSION" - exit 1 + exit fi # Make sure the specified version is installed. -jenv-prefix "$version" >/dev/null - -echo "export JENV_VERSION=\"${version}\"" +if jenv-prefix "$version" >/dev/null; then + echo "export JENV_VERSION=\"${version}\"" +else + echo "return 1" + exit 1 +fi diff --git a/libexec/jenv-shims b/libexec/jenv-shims index 8887104..6bb4277 100755 --- a/libexec/jenv-shims +++ b/libexec/jenv-shims @@ -1,4 +1,7 @@ #!/usr/bin/env bash +# Summary: List existing jenv shims +# Usage: jenv shims [--short] + set -e [ -n "$JENV_DEBUG" ] && set -x diff --git a/libexec/jenv-version b/libexec/jenv-version index deb7627..bc749d2 100755 --- a/libexec/jenv-version +++ b/libexec/jenv-version @@ -1,4 +1,10 @@ #!/usr/bin/env bash +# Summary: Show the current Ruby version and its origin +# +# Shows the currently selected Ruby version and how it was +# selected. To obtain only the version string, use `jenv +# version-name'. + set -e [ -n "$JENV_DEBUG" ] && set -x diff --git a/libexec/jenv-version-file b/libexec/jenv-version-file index 2328593..c39b17e 100755 --- a/libexec/jenv-version-file +++ b/libexec/jenv-version-file @@ -1,15 +1,24 @@ #!/usr/bin/env bash +# Summary: Detect the file that sets the current jenv version set -e [ -n "$JENV_DEBUG" ] && set -x -root="$JENV_DIR" -while [ -n "$root" ]; do - if [ -e "${root}/.jenv-version" ]; then - echo "${root}/.jenv-version" - exit - fi - root="${root%/*}" -done +find_local_version_file() { + local root="$1" + while [ -n "$root" ]; do + if [ -e "${root}/.java-version" ]; then + echo "${root}/.java-version" + exit + elif [ -e "${root}/.jenv-version" ]; then + echo "${root}/.jenv-version" + exit + fi + root="${root%/*}" + done +} + +find_local_version_file "$JENV_DIR" +[ "$JENV_DIR" = "$PWD" ] || find_local_version_file "$PWD" global_version_file="${JENV_ROOT}/version" diff --git a/libexec/jenv-version-file-read b/libexec/jenv-version-file-read index 13c55e0..59b5e5d 100755 --- a/libexec/jenv-version-file-read +++ b/libexec/jenv-version-file-read @@ -1,12 +1,13 @@ #!/usr/bin/env bash +# Usage: jenv version-file-read set -e [ -n "$JENV_DEBUG" ] && set -x VERSION_FILE="$1" if [ -e "$VERSION_FILE" ]; then - # Read and print the first non-whitespace word from the specified - # version file. + # Read the first non-whitespace word from the specified version file. + # Be careful not to load it whole in case there's something crazy in it. version="" while read -a words; do word="${words[0]}" diff --git a/libexec/jenv-version-file-write b/libexec/jenv-version-file-write index 62bfe48..8b4765d 100755 --- a/libexec/jenv-version-file-write +++ b/libexec/jenv-version-file-write @@ -1,4 +1,6 @@ #!/usr/bin/env bash +# Usage: jenv version-file-write + set -e [ -n "$JENV_DEBUG" ] && set -x @@ -6,7 +8,7 @@ JENV_VERSION_FILE="$1" JENV_VERSION="$2" if [ -z "$JENV_VERSION" ] || [ -z "$JENV_VERSION_FILE" ]; then - echo "usage: jenv write-version-file FILENAME VERSION" >&2 + jenv-help --usage version-file-write >&2 exit 1 fi diff --git a/libexec/jenv-version-name b/libexec/jenv-version-name index 2ce8b96..17c83be 100755 --- a/libexec/jenv-version-name +++ b/libexec/jenv-version-name @@ -1,4 +1,5 @@ #!/usr/bin/env bash +# Summary: Show the current Ruby version set -e [ -n "$JENV_DEBUG" ] && set -x @@ -12,10 +13,18 @@ if [ -z "$JENV_VERSION" ] || [ "$JENV_VERSION" = "system" ]; then exit fi -JENV_VERSION_PATH="${JENV_ROOT}/versions/${JENV_VERSION}" +version_exists() { + local version="$1" + [ -d "${JENV_ROOT}/versions/${version}" ] +} -if [ -d "$JENV_VERSION_PATH" ]; then +if version_exists "$JENV_VERSION"; then echo "$JENV_VERSION" +elif version_exists "${JENV_VERSION#ruby-}"; then + { echo "warning: ignoring extraneous \`ruby-' prefix in version \`${JENV_VERSION}'" + echo " (set by $(jenv-version-origin))" + } >&2 + echo "${JENV_VERSION#ruby-}" else echo "jenv: version \`$JENV_VERSION' is not installed" >&2 exit 1 diff --git a/libexec/jenv-version-origin b/libexec/jenv-version-origin index 6c1c1a0..2334e53 100755 --- a/libexec/jenv-version-origin +++ b/libexec/jenv-version-origin @@ -1,4 +1,5 @@ #!/usr/bin/env bash +# Summary: Explain how the current Ruby version is set set -e [ -n "$JENV_DEBUG" ] && set -x diff --git a/libexec/jenv-versions b/libexec/jenv-versions index f71020b..940b470 100755 --- a/libexec/jenv-versions +++ b/libexec/jenv-versions @@ -1,27 +1,39 @@ #!/usr/bin/env bash +# Summary: List all Ruby versions available to jenv +# Usage: jenv versions [--bare] +# +# Lists all Ruby versions found in `$JENV_ROOT/versions/*'. + set -e [ -n "$JENV_DEBUG" ] && set -x -JENV_VERSION_NAME="$(jenv-version-name)" - if [ "$1" = "--bare" ]; then hit_prefix="" miss_prefix="" - print_version="$JENV_VERSION_NAME" + current_version="" + include_system="" else hit_prefix="* " miss_prefix=" " - print_version="$(jenv-version)" + current_version="$(jenv-version-name || true)" + include_system="1" +fi + +print_version() { + if [ "$1" == "$current_version" ]; then + echo "${hit_prefix}$(jenv-version 2>/dev/null)" + else + echo "${miss_prefix}$1" + fi +} + +# Include "system" in the non-bare output, if it exists +if [ -n "$include_system" ] && JENV_VERSION=system jenv-which ruby >/dev/null 2>&1; then + print_version system fi for path in "${JENV_ROOT}/versions/"*; do if [ -d "$path" ]; then - version="${path##*/}" - - if [ "$version" == "$JENV_VERSION_NAME" ]; then - echo "${hit_prefix}${print_version}" - else - echo "${miss_prefix}${version}" - fi + print_version "${path##*/}" fi done diff --git a/libexec/jenv-whence b/libexec/jenv-whence index a5cb4e2..e2acd31 100755 --- a/libexec/jenv-whence +++ b/libexec/jenv-whence @@ -1,4 +1,7 @@ #!/usr/bin/env bash +# Summary: List all Ruby versions that contain the given executable +# Usage: jenv whence [--path] + set -e [ -n "$JENV_DEBUG" ] && set -x @@ -27,7 +30,7 @@ whence() { JENV_COMMAND="$1" if [ -z "$JENV_COMMAND" ]; then - echo "usage: jenv whence [--path] COMMAND" >&2 + jenv-help --usage whence >&2 exit 1 fi diff --git a/libexec/jenv-which b/libexec/jenv-which index aa86c0b..882d973 100755 --- a/libexec/jenv-which +++ b/libexec/jenv-which @@ -1,4 +1,12 @@ #!/usr/bin/env bash +# +# Summary: Display the full path to an executable +# +# Usage: jenv which +# +# Displays the full path to the executable that jenv will invoke when +# you run the given command. + set -e [ -n "$JENV_DEBUG" ] && set -x @@ -27,7 +35,10 @@ remove_from_path() { return fi - for path in ${PATH//:/$'\n'}; do + local paths + IFS=: paths=($PATH) + + for path in "${paths[@]}"; do path="$(expand_path "$path" || true)" if [ -n "$path" ] && [ "$path" != "$path_to_remove" ]; then result="${result}${path}:" @@ -41,24 +52,15 @@ JENV_VERSION="$(jenv-version-name)" JENV_COMMAND="$1" if [ -z "$JENV_COMMAND" ]; then - echo "usage: jenv which COMMAND" >&2 + jenv-help --usage which >&2 exit 1 fi if [ "$JENV_VERSION" = "system" ]; then PATH="$(remove_from_path "${JENV_ROOT}/shims")" - JENV_COMMAND_PATH="$(command -v "$JENV_COMMAND")" + JENV_COMMAND_PATH="$(command -v "$JENV_COMMAND" || true)" else - JENV_COMMAND_PATH="${JENV_ROOT}/versions/${JENV_VERSION}/bin/${JENV_COMMAND}" - - if [ -x "$JENV_COMMAND_PATH" ]; then - echo - else - PATH="$(remove_from_path "${JENV_ROOT}/shims")" - JENV_COMMAND_PATH="$(command -v "$JENV_COMMAND")" - fi - - + JENV_COMMAND_PATH="${JENV_ROOT}/versions/${JENV_VERSION}/bin/${JENV_COMMAND}" fi for script in $(jenv-hooks which); do