diff --git a/.gitignore b/.gitignore index 13d30627ee..088d077e44 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,9 @@ /build -/cache /shims /version /versions /sources +/cache +/libexec/*.dylib +/src/Makefile +/src/*.o diff --git a/.travis.yml b/.travis.yml index 62059e3b92..fdb3e762c9 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,6 +1,6 @@ -install: git clone --depth 1 https://github.com/sstephenson/bats.git -script: script/test +install: git clone https://github.com/sstephenson/bats.git +script: PATH="./bats/bin:$PATH" test/run && ( cd plugins/python-build bats ${CI:+--tap} test ) language: c -notifications: - email: - on_success: never +env: + - PYENV_NATIVE_EXT= + - PYENV_NATIVE_EXT=1 diff --git a/libexec/pyenv b/libexec/pyenv index e294f638ac..3cf004e61d 100755 --- a/libexec/pyenv +++ b/libexec/pyenv @@ -12,6 +12,16 @@ if [ -n "$PYENV_DEBUG" ]; then set -x fi +if enable -f "${0%/*}"/../libexec/pyenv-realpath.dylib realpath 2>/dev/null; then + abs_dirname() { + local path="$(realpath "$1")" + echo "${path%/*}" + } +else + if [ -n "$PYENV_NATIVE_EXT" ]; then + echo "pyenv: failed to load \`realpath' builtin" >&2 + exit 1 + fi READLINK=$(type -p greadlink readlink | head -1) if [ -z "$READLINK" ]; then echo "pyenv: cannot find readlink - are you missing GNU coreutils?" >&2 @@ -37,6 +47,7 @@ abs_dirname() { pwd cd "$cwd" } +fi if [ -z "${PYENV_ROOT}" ]; then PYENV_ROOT="${HOME}/.pyenv" @@ -62,15 +73,20 @@ shopt -s nullglob bin_path="$(abs_dirname "$0")" for plugin_bin in "${PYENV_ROOT}/plugins/"*/bin; do - bin_path="${bin_path}:${plugin_bin}" + PATH="${plugin_bin}:${PATH}" done export PATH="${bin_path}:${PATH}" -hook_path="${PYENV_HOOK_PATH}:${PYENV_ROOT}/pyenv.d:/usr/local/etc/pyenv.d:/etc/pyenv.d:/usr/lib/pyenv/hooks" +PYENV_HOOK_PATH="${PYENV_HOOK_PATH}:${PYENV_ROOT}/pyenv.d" +if [ "${bin_path%/*}" != "$PYENV_ROOT" ]; then + # Add pyenv's own `pyenv.d` unless pyenv was cloned to PYENV_ROOT + PYENV_HOOK_PATH="${PYENV_HOOK_PATH}:${bin_path%/*}/pyenv.d" +fi +PYENV_HOOK_PATH="${PYENV_HOOK_PATH}:/usr/local/etc/pyenv.d:/etc/pyenv.d:/usr/lib/pyenv/hooks" for plugin_hook in "${PYENV_ROOT}/plugins/"*/etc/pyenv.d; do - hook_path="${hook_path}:${plugin_hook}" + PYENV_HOOK_PATH="${PYENV_HOOK_PATH}:${plugin_hook}" done -export PYENV_HOOK_PATH="$hook_path" +export PYENV_HOOK_PATH shopt -u nullglob diff --git a/libexec/pyenv-exec b/libexec/pyenv-exec index 728e8f69b9..dcdce7145d 100755 --- a/libexec/pyenv-exec +++ b/libexec/pyenv-exec @@ -18,7 +18,7 @@ set -e # Provide pyenv completions if [ "$1" = "--complete" ]; then - exec pyenv shims --short + exec pyenv-shims --short fi PYENV_VERSION="$(pyenv-version-name)" diff --git a/libexec/pyenv-hooks b/libexec/pyenv-hooks index bd6572aef1..fc4b2c0633 100755 --- a/libexec/pyenv-hooks +++ b/libexec/pyenv-hooks @@ -19,6 +19,11 @@ if [ -z "$PYENV_COMMAND" ]; then exit 1 fi +if ! enable -f "${BASH_SOURCE%/*}"/pyenv-realpath.dylib realpath 2>/dev/null; then + if [ -n "$PYENV_NATIVE_EXT" ]; then + echo "pyenv: failed to load \`realpath' builtin" >&2 + exit 1 + fi READLINK=$(type -p greadlink readlink | head -1) if [ -z "$READLINK" ]; then echo "pyenv: cannot find readlink - are you missing GNU coreutils?" >&2 @@ -42,13 +47,14 @@ realpath() { echo "$(pwd)/$name" cd "$cwd" } +fi IFS=: hook_paths=($PYENV_HOOK_PATH) shopt -s nullglob for path in "${hook_paths[@]}"; do for script in "$path/$PYENV_COMMAND"/*.bash; do - echo $(realpath $script) + realpath "$script" done done shopt -u nullglob diff --git a/libexec/pyenv-init b/libexec/pyenv-init index c99ba4450d..a8712085de 100755 --- a/libexec/pyenv-init +++ b/libexec/pyenv-init @@ -28,31 +28,7 @@ if [ -z "$shell" ]; then shell="$(basename "${shell:-$SHELL}")" fi -READLINK=$(type -p greadlink readlink | head -1) -if [ -z "$READLINK" ]; then - echo "pyenv: cannot find readlink - are you missing GNU coreutils?" >&2 - exit 1 -fi - -resolve_link() { - $READLINK "$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" -} - -root="$(abs_dirname "$0")/.." +root="${0%/*}/.." if [ -z "$print" ]; then case "$shell" in @@ -92,22 +68,13 @@ fi mkdir -p "${PYENV_ROOT}/"{shims,versions} -if [[ ":${PATH}:" != *:"${PYENV_ROOT}/shims":* ]]; then - case "$shell" in - fish ) - echo "setenv PATH '${PYENV_ROOT}/shims' \$PATH" - ;; - * ) - echo 'export PATH="'${PYENV_ROOT}'/shims:${PATH}"' - ;; - esac -fi - case "$shell" in fish ) + echo "setenv PATH '${PYENV_ROOT}/shims' \$PATH" echo "setenv PYENV_SHELL $shell" ;; * ) + echo 'export PATH="'${PYENV_ROOT}'/shims:${PATH}"' echo "export PYENV_SHELL=$shell" ;; esac diff --git a/libexec/pyenv-rehash b/libexec/pyenv-rehash index 5b758ae5d9..c266b1bf21 100755 --- a/libexec/pyenv-rehash +++ b/libexec/pyenv-rehash @@ -70,49 +70,47 @@ SH # of the first shim in the shims directory, assume pyenv has been # upgraded and the existing shims need to be removed. remove_outdated_shims() { - for shim in *; do + local shim + for shim in "$SHIM_PATH"/*; do if ! diff "$PROTOTYPE_SHIM_PATH" "$shim" >/dev/null 2>&1; then - for shim in *; do rm -f "$shim"; done + rm -f "$SHIM_PATH"/* fi break done } +# List basenames of executables for every Python version +list_executable_names() { + local file + for file in "$PYENV_ROOT"/versions/*/bin/*; do + echo "${file##*/}" + 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=("$@") - - for file in "${shims[@]}"; do - local shim="${file##*/}" + local file shim + for file; do + shim="${file##*/}" register_shim "$shim" done } -# 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="" +registered_shims=" " -# We will keep track of shims registered for installation with the -# 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. +# Registers the name of a shim to be generated. register_shim() { - local shim="$@" - registered_shims["${#registered_shims[@]}"]="$shim" - registered_shims_index="$registered_shims_index/$shim/" + registered_shims="${registered_shims}${1} " } -# To install all the registered shims, we iterate over the -# `registered_shims` array and create a link if one does not already -# exist. +# Install all the shims registered via `make_shims` or `register_shim` directly. install_registered_shims() { - local shim - for shim in "${registered_shims[@]}"; do - [ -e "$shim" ] || ln -f "$PROTOTYPE_SHIM_PATH" "$shim" + local shim file + for shim in $registered_shims; do + file="${SHIM_PATH}/${shim}" + [ -e "$file" ] || ln -f "$PROTOTYPE_SHIM_PATH" "$file" done } @@ -122,26 +120,21 @@ install_registered_shims() { # removed. remove_stale_shims() { local shim - for shim in *; do - if [[ "$registered_shims_index" != *"/$shim/"* ]]; then + for shim in "$SHIM_PATH"/*; do + if [[ "$registered_shims" != *" ${shim##*/} "* ]]; then rm -f "$shim" fi done } - -# Change to the shims directory. -cd "$SHIM_PATH" shopt -s nullglob # Create the prototype shim, then register shims for all known # executables. create_prototype_shim remove_outdated_shims -make_shims ../versions/*/bin/* +make_shims $(list_executable_names | sort -u) -# Restore the previous working directory. -cd "$OLDPWD" # Allow plugins to register shims. OLDIFS="$IFS" @@ -152,8 +145,5 @@ for script in "${scripts[@]}"; do source "$script" done -# Change back to the shims directory to install the registered shims -# and remove stale shims. -cd "$SHIM_PATH" install_registered_shims remove_stale_shims diff --git a/libexec/pyenv-whence b/libexec/pyenv-whence index 101c5e2761..d551e567e7 100755 --- a/libexec/pyenv-whence +++ b/libexec/pyenv-whence @@ -8,7 +8,7 @@ set -e # Provide pyenv completions if [ "$1" = "--complete" ]; then echo --path - exec pyenv shims --short + exec pyenv-shims --short fi if [ "$1" = "--path" ]; then diff --git a/libexec/pyenv-which b/libexec/pyenv-which index 65dad24134..675c70fe0c 100755 --- a/libexec/pyenv-which +++ b/libexec/pyenv-which @@ -12,7 +12,7 @@ set -e # Provide pyenv completions if [ "$1" = "--complete" ]; then - exec pyenv shims --short + exec pyenv-shims --short fi remove_from_path() { diff --git a/script/test b/script/test deleted file mode 100755 index 2764644d56..0000000000 --- a/script/test +++ /dev/null @@ -1,20 +0,0 @@ -#!/usr/bin/env bash -set -e - -[ -d ./bats/bin ] && export PATH="$(pwd)"/bats/bin:"$PATH" - -STATUS=0 -bats -t test && ( cd plugins/python-build && bats -t test ) || STATUS="$?" - -#if [ "$TRAVIS_PULL_REQUEST" != "false" ] && [ -z "$TRAVIS_COMMIT_RANGE" ]; then -# first_sha="$(curl -fsSL https://github.com/${TRAVIS_REPO_SLUG}/pull/${TRAVIS_PULL_REQUEST}.patch | head -1 | awk '{print $2}')" -# export TRAVIS_COMMIT_RANGE="${first_sha}^..${TRAVIS_COMMIT}" -#fi - -#if [ "$TRAVIS_SECURE_ENV_VARS" = "true" ]; then -# ./script/mirror update "$TRAVIS_COMMIT_RANGE" -#elif [ "$TRAVIS_PULL_REQUEST" != "false" ]; then -# ./script/mirror verify "$TRAVIS_COMMIT_RANGE" -#fi - -exit "$STATUS" diff --git a/src/Makefile.in b/src/Makefile.in new file mode 100644 index 0000000000..4c203e729a --- /dev/null +++ b/src/Makefile.in @@ -0,0 +1,25 @@ +CC = @CC@ + +CFLAGS = @CFLAGS@ +LOCAL_CFLAGS = @LOCAL_CFLAGS@ +DEFS = @DEFS@ +LOCAL_DEFS = @LOCAL_DEFS@ + +CCFLAGS = $(DEFS) $(LOCAL_DEFS) $(LOCAL_CFLAGS) $(CFLAGS) + +SHOBJ_CC = @SHOBJ_CC@ +SHOBJ_CFLAGS = @SHOBJ_CFLAGS@ +SHOBJ_LD = @SHOBJ_LD@ +SHOBJ_LDFLAGS = @SHOBJ_LDFLAGS@ +SHOBJ_XLDFLAGS = @SHOBJ_XLDFLAGS@ +SHOBJ_LIBS = @SHOBJ_LIBS@ +SHOBJ_STATUS = @SHOBJ_STATUS@ + +.c.o: + $(SHOBJ_CC) $(SHOBJ_CFLAGS) $(CCFLAGS) -c -o $@ $< + +../libexec/pyenv-realpath.dylib: realpath.o + $(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ realpath.o $(SHOBJ_LIBS) + +clean: + rm -f *.o ../libexec/*.dylib diff --git a/src/bash.h b/src/bash.h new file mode 100644 index 0000000000..1b29fd05ca --- /dev/null +++ b/src/bash.h @@ -0,0 +1,31 @@ +#ifndef __BASH_H__ +#define __BASH_H__ + +#define EXECUTION_SUCCESS 0 +#define EXECUTION_FAILURE 1 +#define EX_USAGE 258 + +#define BUILTIN_ENABLED 1 + +typedef struct word_desc { + char *word; + int flags; +} WORD_DESC; + +typedef struct word_list { + struct word_list *next; + WORD_DESC *word; +} WORD_LIST; + +typedef int sh_builtin_func_t(WORD_LIST *); + +struct builtin { + char *name; + sh_builtin_func_t *function; + int flags; + char * const *long_doc; + const char *short_doc; + char *unused; +}; + +#endif diff --git a/src/configure b/src/configure new file mode 100755 index 0000000000..dc29eb79bc --- /dev/null +++ b/src/configure @@ -0,0 +1,46 @@ +#!/usr/bin/env bash +set -e + +src_dir="${0%/*}" + +if [ -z "$CC" ]; then + if type -p gcc >/dev/null; then + CC=gcc + else + echo "warning: gcc not found; using CC=cc" >&2 + CC=cc + fi +fi + +if ! type -p "$CC" >/dev/null; then + echo "aborted: compiler not found: $CC" >&2 + exit 1 +fi + +case "$(uname -s)" in +Darwin* ) + host_os="darwin$(uname -r)" + ;; +OpenBSD* ) + host_os="openbsd$(uname -r)" + ;; +* ) + host_os="linux-gnu" +esac + +eval "$("$src_dir"/shobj-conf -C "$CC" -o "$host_os")" + +sed " + s,@CC@,${CC}, + s,@CFLAGS@,${CFLAGS}, + s,@LOCAL_CFLAGS@,${LOCAL_CFLAGS}, + s,@DEFS@,${DEFS}, + s,@LOCAL_DEFS@,${LOCAL_DEFS}, + s,@SHOBJ_CC@,${SHOBJ_CC}, + s,@SHOBJ_CFLAGS@,${SHOBJ_CFLAGS}, + s,@SHOBJ_LD@,${SHOBJ_LD}, + s,@SHOBJ_LDFLAGS@,${SHOBJ_LDFLAGS//,/\,}, + s,@SHOBJ_XLDFLAGS@,${SHOBJ_XLDFLAGS//,/\,}, + s,@SHOBJ_LIBS@,${SHOBJ_LIBS}, + s,@SHOBJ_STATUS@,${SHOBJ_STATUS}, +" "$src_dir"/Makefile.in > "$src_dir"/Makefile diff --git a/src/realpath.c b/src/realpath.c new file mode 100644 index 0000000000..6c0c9f3c12 --- /dev/null +++ b/src/realpath.c @@ -0,0 +1,43 @@ +#include "bash.h" +#include +#include + +int realpath_builtin(list) +WORD_LIST *list; +{ + int es; + char *realbuf, *p; + + if (list == 0) { + // builtin_usage(); + return (EX_USAGE); + } + + for (es = EXECUTION_SUCCESS; list; list = list->next) { + p = list->word->word; + realbuf = realpath(p, NULL); + if (realbuf == NULL) { + es = EXECUTION_FAILURE; + // builtin_error("%s: cannot resolve: %s", p, strerror(errno)); + } else { + printf("%s\n", realbuf); + free(realbuf); + } + } + return es; +} + +char *realpath_doc[] = { + "Display each PATHNAME argument, resolving symbolic links. The exit status", + "is 0 if each PATHNAME was resolved; non-zero otherwise.", + (char *)NULL +}; + +struct builtin realpath_struct = { + "realpath", + realpath_builtin, + BUILTIN_ENABLED, + realpath_doc, + "realpath pathname [pathname...]", + 0 +}; diff --git a/src/shobj-conf b/src/shobj-conf new file mode 100755 index 0000000000..593867eeb7 --- /dev/null +++ b/src/shobj-conf @@ -0,0 +1,558 @@ +#! /bin/sh +# +# shobj-conf -- output a series of variable assignments to be substituted +# into a Makefile by configure which specify system-dependent +# information for creating shared objects that may be loaded +# into bash with `enable -f' +# +# usage: shobj-conf [-C compiler] -c host_cpu -o host_os -v host_vendor +# +# Chet Ramey +# chet@po.cwru.edu + +# Copyright (C) 1996-2002 Free Software Foundation, Inc. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2, or (at your option) +# any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA. + +# +# defaults +# +SHOBJ_STATUS=supported +SHLIB_STATUS=supported + +SHOBJ_CC=cc +SHOBJ_CFLAGS= +SHOBJ_LD= +SHOBJ_LDFLAGS= +SHOBJ_XLDFLAGS= +SHOBJ_LIBS= + +SHLIB_XLDFLAGS= +SHLIB_LIBS= + +SHLIB_DOT='.' +SHLIB_LIBPREF='lib' +SHLIB_LIBSUFF='so' + +SHLIB_LIBVERSION='$(SHLIB_LIBSUFF)' +SHLIB_DLLVERSION='$(SHLIB_MAJOR)' + +PROGNAME=`basename $0` +USAGE="$PROGNAME [-C compiler] -c host_cpu -o host_os -v host_vendor" + +while [ $# -gt 0 ]; do + case "$1" in + -C) shift; SHOBJ_CC="$1"; shift ;; + -c) shift; host_cpu="$1"; shift ;; + -o) shift; host_os="$1"; shift ;; + -v) shift; host_vendor="$1"; shift ;; + *) echo "$USAGE" >&2 ; exit 2;; + esac +done + +case "${host_os}-${SHOBJ_CC}" in +sunos4*-*gcc*) + SHOBJ_CFLAGS=-fpic + SHOBJ_LD=/usr/bin/ld + SHOBJ_LDFLAGS='-assert pure-text' + + SHLIB_LIBVERSION='$(SHLIB_LIBSUFF).$(SHLIB_MAJOR)$(SHLIB_MINOR)' + ;; + +sunos4*) + SHOBJ_CFLAGS=-pic + SHOBJ_LD=/usr/bin/ld + SHOBJ_LDFLAGS='-assert pure-text' + + SHLIB_LIBVERSION='$(SHLIB_LIBSUFF).$(SHLIB_MAJOR)$(SHLIB_MINOR)' + ;; + +sunos5*-*gcc*|solaris2*-*gcc*) + SHOBJ_CFLAGS=-fpic + SHOBJ_LD='${CC}' + ld_used=`gcc -print-prog-name=ld` + if ${ld_used} -V 2>&1 | grep GNU >/dev/null 2>&1; then + # This line works for the GNU ld + SHOBJ_LDFLAGS='-shared -Wl,-h,$@' + else + # This line works for the Solaris linker in /usr/ccs/bin/ld + SHOBJ_LDFLAGS='-shared -Wl,-i -Wl,-h,$@' + fi + +# SHLIB_XLDFLAGS='-R $(libdir)' + SHLIB_LIBVERSION='$(SHLIB_LIBSUFF).$(SHLIB_MAJOR)' + ;; + +sunos5*|solaris2*) + SHOBJ_CFLAGS='-K pic' + SHOBJ_LD=/usr/ccs/bin/ld + SHOBJ_LDFLAGS='-G -dy -z text -i -h $@' + +# SHLIB_XLDFLAGS='-R $(libdir)' + SHLIB_LIBVERSION='$(SHLIB_LIBSUFF).$(SHLIB_MAJOR)' + ;; + +# All versions of Linux or the semi-mythical GNU Hurd. +linux*-*|gnu*-*|k*bsd*-gnu-*) + SHOBJ_CFLAGS=-fPIC + SHOBJ_LD='${CC}' + SHOBJ_LDFLAGS='-shared -Wl,-soname,$@' + + SHLIB_XLDFLAGS='-Wl,-rpath,$(libdir) -Wl,-soname,`basename $@ $(SHLIB_MINOR)`' + SHLIB_LIBVERSION='$(SHLIB_LIBSUFF).$(SHLIB_MAJOR)$(SHLIB_MINOR)' + ;; + +freebsd2* | netbsd*) + SHOBJ_CFLAGS=-fpic + SHOBJ_LD=ld + SHOBJ_LDFLAGS='-x -Bshareable' + + SHLIB_XLDFLAGS='-R$(libdir)' + SHLIB_LIBVERSION='$(SHLIB_LIBSUFF).$(SHLIB_MAJOR)$(SHLIB_MINOR)' + ;; + +# FreeBSD-3.x ELF +freebsd[3-9]*|freebsdelf[3-9]*|freebsdaout[3-9]*|dragonfly*) + SHOBJ_CFLAGS=-fpic + SHOBJ_LD='${CC}' + + if [ -x /usr/bin/objformat ] && [ "`/usr/bin/objformat`" = "elf" ]; then + SHOBJ_LDFLAGS='-shared -Wl,-soname,$@' + + SHLIB_XLDFLAGS='-Wl,-rpath,$(libdir)' + SHLIB_LIBVERSION='$(SHLIB_LIBSUFF).$(SHLIB_MAJOR)' + else + SHOBJ_LDFLAGS='-shared' + + SHLIB_XLDFLAGS='-R$(libdir)' + SHLIB_LIBVERSION='$(SHLIB_LIBSUFF).$(SHLIB_MAJOR)$(SHLIB_MINOR)' + fi + ;; + +# Darwin/MacOS X +darwin1*) + SHOBJ_STATUS=supported + SHLIB_STATUS=supported + + SHOBJ_CFLAGS='' + SHLIB_LIBSUFF='dylib' + + SHOBJ_LD='${CC}' + SHOBJ_LDFLAGS='-dynamiclib' + ;; + +darwin8*) + SHOBJ_STATUS=supported + SHLIB_STATUS=supported + + SHOBJ_CFLAGS='-fno-common' + + SHOBJ_LD='MACOSX_DEPLOYMENT_TARGET=10.3 ${CC}' + + SHLIB_LIBVERSION='$(SHLIB_MAJOR)$(SHLIB_MINOR).$(SHLIB_LIBSUFF)' + SHLIB_LIBSUFF='dylib' + + SHOBJ_LDFLAGS='-undefined dynamic_lookup' + SHLIB_XLDFLAGS='-dynamiclib -arch_only `/usr/bin/arch` -install_name $(libdir)/$@ -current_version $(SHLIB_MAJOR)$(SHLIB_MINOR) -compatibility_version $(SHLIB_MAJOR) -v' + + SHLIB_LIBS='-lncurses' # see if -lcurses works on MacOS X 10.1 + ;; + +darwin*|macosx*) + SHOBJ_STATUS=unsupported + SHLIB_STATUS=supported + + SHOBJ_CFLAGS='-fno-common' + + SHOBJ_LD='${CC}' + + SHLIB_LIBVERSION='$(SHLIB_MAJOR)$(SHLIB_MINOR).$(SHLIB_LIBSUFF)' + SHLIB_LIBSUFF='dylib' + + case "${host_os}" in + darwin[78]*) SHOBJ_LDFLAGS='' + SHLIB_XLDFLAGS='-dynamiclib -arch_only `/usr/bin/arch` -install_name $(libdir)/$@ -current_version $(SHLIB_MAJOR)$(SHLIB_MINOR) -compatibility_version $(SHLIB_MAJOR) -v' + ;; + *) SHOBJ_LDFLAGS='-dynamic' + SHLIB_XLDFLAGS='-arch_only `/usr/bin/arch` -install_name $(libdir)/$@ -current_version $(SHLIB_MAJOR)$(SHLIB_MINOR) -compatibility_version $(SHLIB_MAJOR) -v' + ;; + esac + + SHLIB_LIBS='-lncurses' # see if -lcurses works on MacOS X 10.1 + ;; + +openbsd*) + SHOBJ_CFLAGS=-fPIC + SHOBJ_LD='${CC}' + SHOBJ_LDFLAGS='-shared' + + SHLIB_XLDFLAGS='-R$(libdir)' + SHLIB_LIBVERSION='$(SHLIB_LIBSUFF).$(SHLIB_MAJOR)$(SHLIB_MINOR)' + ;; + +bsdi2*) + SHOBJ_CC=shlicc2 + SHOBJ_CFLAGS= + SHOBJ_LD=ld + SHOBJ_LDFLAGS=-r + SHOBJ_LIBS=-lc_s.2.1.0 + + # BSD/OS 2.x and 3.x `shared libraries' are too much of a pain in + # the ass -- they require changing {/usr/lib,etc}/shlib.map on + # each system, and the library creation process is byzantine + SHLIB_STATUS=unsupported + ;; + +bsdi3*) + SHOBJ_CC=shlicc2 + SHOBJ_CFLAGS= + SHOBJ_LD=ld + SHOBJ_LDFLAGS=-r + SHOBJ_LIBS=-lc_s.3.0.0 + + # BSD/OS 2.x and 3.x `shared libraries' are too much of a pain in + # the ass -- they require changing {/usr/lib,etc}/shlib.map on + # each system, and the library creation process is byzantine + SHLIB_STATUS=unsupported + ;; + +bsdi4*) + # BSD/OS 4.x now supports ELF and SunOS-style dynamically-linked + # shared libraries. gcc 2.x is the standard compiler, and the + # `normal' gcc options should work as they do in Linux. + + SHOBJ_CFLAGS=-fPIC + SHOBJ_LD='${CC}' + SHOBJ_LDFLAGS='-shared -Wl,-soname,$@' + + SHLIB_XLDFLAGS='-Wl,-soname,`basename $@ $(SHLIB_MINOR)`' + SHLIB_LIBVERSION='$(SHLIB_LIBSUFF).$(SHLIB_MAJOR)$(SHLIB_MINOR)' + ;; + +osf*-*gcc*) + # Fix to use gcc linker driver from bfischer@TechFak.Uni-Bielefeld.DE + SHOBJ_LD='${CC}' + SHOBJ_LDFLAGS='-shared -Wl,-soname,$@' + + SHLIB_XLDFLAGS='-rpath $(libdir)' + SHLIB_LIBVERSION='$(SHLIB_LIBSUFF).$(SHLIB_MAJOR)' + ;; + +osf*) + SHOBJ_LD=ld + SHOBJ_LDFLAGS='-shared -soname $@ -expect_unresolved "*"' + + SHLIB_XLDFLAGS='-rpath $(libdir)' + SHLIB_LIBVERSION='$(SHLIB_LIBSUFF).$(SHLIB_MAJOR)' + ;; + +aix4.[2-9]*-*gcc*) # lightly tested by jik@cisco.com + SHOBJ_CFLAGS=-fpic + SHOBJ_LD='ld' + SHOBJ_LDFLAGS='-bdynamic -bnoentry -bexpall' + SHOBJ_XLDFLAGS='-G' + + SHLIB_XLDFLAGS='-bM:SRE' + SHLIB_LIBS='-lcurses -lc' + SHLIB_LIBVERSION='$(SHLIB_LIBSUFF).$(SHLIB_MAJOR)' + ;; + +aix4.[2-9]*) + SHOBJ_CFLAGS=-K + SHOBJ_LD='ld' + SHOBJ_LDFLAGS='-bdynamic -bnoentry -bexpall' + SHOBJ_XLDFLAGS='-G' + + SHLIB_XLDFLAGS='-bM:SRE' + SHLIB_LIBS='-lcurses -lc' + SHLIB_LIBVERSION='$(SHLIB_LIBSUFF).$(SHLIB_MAJOR)' + ;; + +# +# THE FOLLOWING ARE UNTESTED -- and some may not support the dlopen interface +# +irix[56]*-*gcc*) + SHOBJ_CFLAGS='-fpic' + SHOBJ_LD='${CC}' + SHOBJ_LDFLAGS='-shared -Wl,-soname,$@' + + SHLIB_XLDFLAGS='-Wl,-rpath,$(libdir)' + SHLIB_LIBVERSION='$(SHLIB_LIBSUFF).$(SHLIB_MAJOR)' + ;; + +irix[56]*) + SHOBJ_CFLAGS='-K PIC' + SHOBJ_LD=ld +# SHOBJ_LDFLAGS='-call_shared -hidden_symbol -no_unresolved -soname $@' +# Change from David Kaelbling . If you have problems, +# remove the `-no_unresolved' + SHOBJ_LDFLAGS='-shared -no_unresolved -soname $@' + + SHLIB_XLDFLAGS='-rpath $(libdir)' + SHLIB_LIBVERSION='$(SHLIB_LIBSUFF).$(SHLIB_MAJOR)' + ;; + +hpux9*-*gcc*) + # must use gcc; the bundled cc cannot compile PIC code + SHOBJ_CFLAGS='-fpic' + SHOBJ_LD='${CC}' + SHOBJ_LDFLAGS='-shared -Wl,-b -Wl,+s' + + SHLIB_XLDFLAGS='-Wl,+b,$(libdir)' + SHLIB_LIBSUFF='sl' + SHLIB_LIBVERSION='$(SHLIB_LIBSUFF).$(SHLIB_MAJOR)' + ;; + +hpux9*) + SHOBJ_STATUS=unsupported + SHLIB_STATUS=unsupported + + # If you are using the HP ANSI C compiler, you can uncomment and use + # this code (I have not tested it) +# SHOBJ_STATUS=supported +# SHLIB_STATUS=supported +# +# SHOBJ_CFLAGS='+z' +# SHOBJ_LD='ld' +# SHOBJ_LDFLAGS='-b +s' +# +# SHLIB_XLDFLAGS='+b $(libdir)' +# SHLIB_LIBSUFF='sl' +# SHLIB_LIBVERSION='$(SHLIB_LIBSUFF).$(SHLIB_MAJOR)' + + ;; + +hpux10*-*gcc*) + # must use gcc; the bundled cc cannot compile PIC code + SHOBJ_CFLAGS='-fpic' + SHOBJ_LD='${CC}' + # if you have problems linking here, moving the `-Wl,+h,$@' from + # SHLIB_XLDFLAGS to SHOBJ_LDFLAGS has been reported to work + SHOBJ_LDFLAGS='-shared -Wl,-b -Wl,+s' + + SHLIB_XLDFLAGS='-Wl,+h,$@ -Wl,+b,$(libdir)' + SHLIB_LIBSUFF='sl' + SHLIB_LIBVERSION='$(SHLIB_LIBSUFF).$(SHLIB_MAJOR)' + ;; + +hpux10*) + SHOBJ_STATUS=unsupported + SHLIB_STATUS=unsupported + + # If you are using the HP ANSI C compiler, you can uncomment and use + # this code (I have not tested it) +# SHOBJ_STATUS=supported +# SHLIB_STATUS=supported +# +# SHOBJ_CFLAGS='+z' +# SHOBJ_LD='ld' +# SHOBJ_LDFLAGS='-b +s +h $@' +# +# SHLIB_XLDFLAGS='+b $(libdir)' +# SHLIB_LIBSUFF='sl' +# SHLIB_LIBVERSION='$(SHLIB_LIBSUFF).$(SHLIB_MAJOR)' + + ;; + +hpux11*-*gcc*) + # must use gcc; the bundled cc cannot compile PIC code + SHOBJ_CFLAGS='-fpic' + SHOBJ_LD='${CC}' +# SHOBJ_LDFLAGS='-shared -Wl,-b -Wl,-B,symbolic -Wl,+s -Wl,+std -Wl,+h,$@' + SHOBJ_LDFLAGS='-shared -fpic -Wl,-b -Wl,+s -Wl,+h,$@' + + SHLIB_XLDFLAGS='-Wl,+b,$(libdir)' + SHLIB_LIBSUFF='sl' + SHLIB_LIBVERSION='$(SHLIB_LIBSUFF).$(SHLIB_MAJOR)' + ;; + +hpux11*) + SHOBJ_STATUS=unsupported + SHLIB_STATUS=unsupported + + # If you are using the HP ANSI C compiler, you can uncomment and use + # this code (I have not tested it) +# SHOBJ_STATUS=supported +# SHLIB_STATUS=supported +# +# SHOBJ_CFLAGS='+z' +# SHOBJ_LD='ld' +# SHOBJ_LDFLAGS='-b +s +h $@' +# +# SHLIB_XLDFLAGS='+b $(libdir)' +# SHLIB_LIBSUFF='sl' +# SHLIB_LIBVERSION='$(SHLIB_LIBSUFF).$(SHLIB_MAJOR)' + + ;; + +sysv4*-*gcc*) + SHOBJ_CFLAGS=-shared + SHOBJ_LDFLAGS='-shared -h $@' + SHOBJ_LD='${CC}' + + SHLIB_LIBVERSION='$(SHLIB_LIBSUFF).$(SHLIB_MAJOR)' + ;; + +sysv4*) + SHOBJ_CFLAGS='-K PIC' + SHOBJ_LD=ld + SHOBJ_LDFLAGS='-dy -z text -G -h $@' + + SHLIB_LIBVERSION='$(SHLIB_LIBSUFF).$(SHLIB_MAJOR)' + ;; + +sco3.2v5*-*gcc*) + SHOBJ_CFLAGS='-fpic' # DEFAULTS TO ELF + SHOBJ_LD='${CC}' + SHOBJ_LDFLAGS='-shared' + + SHLIB_LIBVERSION='$(SHLIB_LIBSUFF).$(SHLIB_MAJOR)' + ;; + +sco3.2v5*) + SHOBJ_CFLAGS='-K pic -b elf' + SHOBJ_LD=ld + SHOBJ_LDFLAGS='-G -b elf -dy -z text -h $@' + + SHLIB_LIBVERSION='$(SHLIB_LIBSUFF).$(SHLIB_MAJOR)' + ;; + +sysv5uw7*-*gcc*) + SHOBJ_CFLAGS='-fpic' + SHOBJ_LD='${CC}' + SHOBJ_LDFLAGS='-shared' + + SHLIB_LIBVERSION='$(SHLIB_LIBSUFF).$(SHLIB_MAJOR)' + ;; + +sysv5uw7*) + SHOBJ_CFLAGS='-K PIC' + SHOBJ_LD=ld + SHOBJ_LDFLAGS='-G -dy -z text -h $@' + + SHLIB_LIBVERSION='$(SHLIB_LIBSUFF).$(SHLIB_MAJOR)' + ;; + +sysv5UnixWare*-*gcc*) + SHOBJ_CFLAGS=-fpic + SHOBJ_LD='${CC}' + SHOBJ_LDFLAGS='-shared' + + SHLIB_LIBVERSION='$(SHLIB_LIBSUFF).$(SHLIB_MAJOR)' + ;; + +sysv5UnixWare*) + SHOBJ_CFLAGS='-K PIC' + SHOBJ_LD=ld + SHOBJ_LDFLAGS='-G -dy -z text -h $@' + + SHLIB_LIBVERSION='$(SHLIB_LIBSUFF).$(SHLIB_MAJOR)' + ;; + +sysv5OpenUNIX*-*gcc*) + SHOBJ_CFLAGS=-fpic + SHOBJ_LD='${CC}' + SHOBJ_LDFLAGS='-shared' + + SHLIB_LIBVERSION='$(SHLIB_LIBSUFF).$(SHLIB_MAJOR)' + ;; + +sysv5OpenUNIX*) + SHOBJ_CFLAGS='-K PIC' + SHOBJ_LD=ld + SHOBJ_LDFLAGS='-G -dy -z text -h $@' + + SHLIB_LIBVERSION='$(SHLIB_LIBSUFF).$(SHLIB_MAJOR)' + ;; + +dgux*-*gcc*) + SHOBJ_CFLAGS=-fpic + SHOBJ_LD='${CC}' + SHOBJ_LDFLAGS='-shared' + + SHLIB_LIBVERSION='$(SHLIB_LIBSUFF).$(SHLIB_MAJOR)' + ;; + +dgux*) + SHOBJ_CFLAGS='-K pic' + SHOBJ_LD=ld + SHOBJ_LDFLAGS='-G -dy -h $@' + + SHLIB_LIBVERSION='$(SHLIB_LIBSUFF).$(SHLIB_MAJOR)' + ;; + +msdos*) + SHOBJ_STATUS=unsupported + SHLIB_STATUS=unsupported + ;; + +cygwin*) + SHOBJ_LD='$(CC)' + SHOBJ_LDFLAGS='-shared -Wl,--enable-auto-import -Wl,--enable-auto-image-base -Wl,--export-all -Wl,--out-implib=$(@).a' + SHLIB_LIBPREF='cyg' + SHLIB_LIBSUFF='dll' + SHLIB_LIBVERSION='$(SHLIB_DLLVERSION).$(SHLIB_LIBSUFF)' + SHLIB_LIBS='$(TERMCAP_LIB)' + + SHLIB_DOT= + # For official cygwin releases, DLLVERSION will be defined in the + # environment of configure, and will be incremented any time the API + # changes in a non-backwards compatible manner. Otherwise, it is just + # SHLIB_MAJOR. + if [ -n "$DLLVERSION" ] ; then + SHLIB_DLLVERSION="$DLLVERSION" + fi + ;; + +# +# Rely on correct gcc configuration for everything else +# +*-*gcc*) + SHOBJ_CFLAGS=-fpic + SHOBJ_LD='${CC}' + SHOBJ_LDFLAGS='-shared' + + SHLIB_LIBVERSION='$(SHLIB_LIBSUFF).$(SHLIB_MAJOR)' + ;; + +*) + SHOBJ_STATUS=unsupported + SHLIB_STATUS=unsupported + ;; + +esac + +echo SHOBJ_CC=\'"$SHOBJ_CC"\' +echo SHOBJ_CFLAGS=\'"$SHOBJ_CFLAGS"\' +echo SHOBJ_LD=\'"$SHOBJ_LD"\' +echo SHOBJ_LDFLAGS=\'"$SHOBJ_LDFLAGS"\' +echo SHOBJ_XLDFLAGS=\'"$SHOBJ_XLDFLAGS"\' +echo SHOBJ_LIBS=\'"$SHOBJ_LIBS"\' + +echo SHLIB_XLDFLAGS=\'"$SHLIB_XLDFLAGS"\' +echo SHLIB_LIBS=\'"$SHLIB_LIBS"\' + +echo SHLIB_DOT=\'"$SHLIB_DOT"\' + +echo SHLIB_LIBPREF=\'"$SHLIB_LIBPREF"\' +echo SHLIB_LIBSUFF=\'"$SHLIB_LIBSUFF"\' + +echo SHLIB_LIBVERSION=\'"$SHLIB_LIBVERSION"\' +echo SHLIB_DLLVERSION=\'"$SHLIB_DLLVERSION"\' + +echo SHOBJ_STATUS=\'"$SHOBJ_STATUS"\' +echo SHLIB_STATUS=\'"$SHLIB_STATUS"\' + +exit 0 diff --git a/test/init.bats b/test/init.bats index f5e60c0382..713dad5805 100644 --- a/test/init.bats +++ b/test/init.bats @@ -21,7 +21,7 @@ load test_helper root="$(cd $BATS_TEST_DIRNAME/.. && pwd)" run pyenv-init - bash assert_success - assert_line "source '${root}/libexec/../completions/pyenv.bash'" + assert_line "source '${root}/test/../libexec/../completions/pyenv.bash'" } @test "detect parent shell" { @@ -35,7 +35,7 @@ load test_helper root="$(cd $BATS_TEST_DIRNAME/.. && pwd)" run pyenv-init - fish assert_success - assert_line ". '${root}/libexec/../completions/pyenv.fish'" + assert_line ". '${root}/test/../libexec/../completions/pyenv.fish'" } @test "fish instructions" { @@ -68,7 +68,7 @@ load test_helper export PATH="${PYENV_ROOT}/shims:$PATH" run pyenv-init - bash assert_success - refute_line 'export PATH="'${PYENV_ROOT}'/shims:${PATH}"' + assert_line 0 'export PATH="'${PYENV_ROOT}'/shims:${PATH}"' } @test "doesn't add shims to PATH more than once (fish)" { @@ -77,3 +77,20 @@ load test_helper assert_success refute_line 'setenv PATH "'${PYENV_ROOT}'/shims" $PATH ;' } + +@test "outputs sh-compatible syntax" { + run pyenv-init - bash + assert_success + assert_line ' case "$command" in' + + run pyenv-init - zsh + assert_success + assert_line ' case "$command" in' +} + +@test "outputs fish-specific syntax (fish)" { + run pyenv-init - fish + assert_success + assert_line ' switch "$command"' + refute_line ' case "$command" in' +} diff --git a/test/libexec/pyenv-echo b/test/libexec/pyenv-echo index 0a802df4b5..ee32210438 100755 --- a/test/libexec/pyenv-echo +++ b/test/libexec/pyenv-echo @@ -1,2 +1,9 @@ #!/usr/bin/env bash -eval "echo \$$1" +# Usage: pyenv echo [-F] VAR + +if [[ $1 == -F* ]]; then + sep="${1:2}" + echo "${!2}" | tr "${sep:-:}" $'\n' +else + echo "${!1}" +fi diff --git a/test/pyenv.bats b/test/pyenv.bats index 6e07825fa0..0966bfe88d 100644 --- a/test/pyenv.bats +++ b/test/pyenv.bats @@ -45,3 +45,31 @@ load test_helper assert_failure assert_output "pyenv: cannot change working directory to \`$dir'" } + +@test "adds its own libexec to PATH" { + run pyenv echo "PATH" + assert_success "${BATS_TEST_DIRNAME%/*}/libexec:$PATH" +} + +@test "adds plugin bin dirs to PATH" { + mkdir -p "$PYENV_ROOT"/plugins/python-build/bin + mkdir -p "$PYENV_ROOT"/plugins/pyenv-each/bin + run pyenv echo -F: "PATH" + assert_success + assert_line 0 "${BATS_TEST_DIRNAME%/*}/libexec" + assert_line 1 "${PYENV_ROOT}/plugins/python-build/bin" + assert_line 2 "${PYENV_ROOT}/plugins/pyenv-each/bin" +} + +@test "PYENV_HOOK_PATH preserves value from environment" { + PYENV_HOOK_PATH=/my/hook/path:/other/hooks run pyenv echo -F: "PYENV_HOOK_PATH" + assert_success + assert_line 0 "/my/hook/path" + assert_line 1 "/other/hooks" + assert_line 2 "${PYENV_ROOT}/pyenv.d" +} + +@test "PYENV_HOOK_PATH includes pyenv built-in plugins" { + run pyenv echo "PYENV_HOOK_PATH" + assert_success ":${PYENV_ROOT}/pyenv.d:${BATS_TEST_DIRNAME%/*}/pyenv.d:/usr/local/etc/pyenv.d:/etc/pyenv.d:/usr/lib/pyenv/hooks" +} diff --git a/test/run b/test/run new file mode 100755 index 0000000000..01cd60918f --- /dev/null +++ b/test/run @@ -0,0 +1,9 @@ +#!/usr/bin/env bash +set -e + +if [ -n "$PYENV_NATIVE_EXT" ]; then + src/configure + make -C src +fi + +exec bats ${CI:+--tap} test diff --git a/test/test_helper.bash b/test/test_helper.bash index 9bd8082d97..6e5015c652 100644 --- a/test/test_helper.bash +++ b/test/test_helper.bash @@ -1,7 +1,15 @@ unset PYENV_VERSION unset PYENV_DIR -PYENV_TEST_DIR="${BATS_TMPDIR}/pyenv" +if enable -f "${BATS_TEST_DIRNAME}"/../libexec/pyenv-realpath.dylib realpath 2>/dev/null; then + PYENV_TEST_DIR="$(realpath "$BATS_TMPDIR")/pyenv" +else + if [ -n "$PYENV_NATIVE_EXT" ]; then + echo "pyenv: failed to load \`realpath' builtin" >&2 + exit 1 + fi + PYENV_TEST_DIR="${BATS_TMPDIR}/pyenv" +fi # guard against executing this block twice due to bats internals if [ "$PYENV_ROOT" != "${PYENV_TEST_DIR}/root" ]; then