You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

159 lines
4.3 KiB

преди 11 години
преди 10 години
преди 11 години
преди 10 години
преди 10 години
преди 10 години
преди 10 години
  1. #!/usr/bin/env bash
  2. # Summary: Rehash pyenv shims (run this after installing executables)
  3. set -e
  4. [ -n "$PYENV_DEBUG" ] && set -x
  5. SHIM_PATH="${PYENV_ROOT}/shims"
  6. PROTOTYPE_SHIM_PATH="${SHIM_PATH}/.pyenv-shim"
  7. # Create the shims directory if it doesn't already exist.
  8. mkdir -p "$SHIM_PATH"
  9. # Ensure only one instance of pyenv-rehash is running at a time by
  10. # setting the shell's `noclobber` option and attempting to write to
  11. # the prototype shim file. If the file already exists, print a warning
  12. # to stderr and exit with a non-zero status.
  13. set -o noclobber
  14. { echo > "$PROTOTYPE_SHIM_PATH"
  15. } 2>/dev/null ||
  16. { if [ -w "$SHIM_PATH" ]; then
  17. echo "pyenv: cannot rehash: $PROTOTYPE_SHIM_PATH exists"
  18. else
  19. echo "pyenv: cannot rehash: $SHIM_PATH isn't writable"
  20. fi
  21. exit 1
  22. } >&2
  23. set +o noclobber
  24. # If we were able to obtain a lock, register a trap to clean up the
  25. # prototype shim when the process exits.
  26. trap remove_prototype_shim EXIT
  27. remove_prototype_shim() {
  28. rm -f "$PROTOTYPE_SHIM_PATH"
  29. }
  30. # The prototype shim file is a script that re-execs itself, passing
  31. # its filename and any arguments to `pyenv exec`. This file is
  32. # hard-linked for every executable and then removed. The linking
  33. # technique is fast, uses less disk space than unique files, and also
  34. # serves as a locking mechanism.
  35. create_prototype_shim() {
  36. cat > "$PROTOTYPE_SHIM_PATH" <<SH
  37. #!/usr/bin/env bash
  38. set -e
  39. [ -n "\$PYENV_DEBUG" ] && set -x
  40. program="\${0##*/}"
  41. if [ "\$program" = "python" ]; then
  42. for arg; do
  43. case "\$arg" in
  44. -c* | -- ) break ;;
  45. */* )
  46. if [ -f "\$arg" ]; then
  47. export PYENV_DIR="\${arg%/*}"
  48. break
  49. fi
  50. ;;
  51. esac
  52. done
  53. fi
  54. export PYENV_ROOT="$PYENV_ROOT"
  55. exec "$(command -v pyenv)" exec "\$program" "\$@"
  56. SH
  57. chmod +x "$PROTOTYPE_SHIM_PATH"
  58. }
  59. # If the contents of the prototype shim file differ from the contents
  60. # of the first shim in the shims directory, assume pyenv has been
  61. # upgraded and the existing shims need to be removed.
  62. remove_outdated_shims() {
  63. for shim in *; do
  64. if ! diff "$PROTOTYPE_SHIM_PATH" "$shim" >/dev/null 2>&1; then
  65. for shim in *; do rm -f "$shim"; done
  66. fi
  67. break
  68. done
  69. }
  70. # The basename of each argument passed to `make_shims` will be
  71. # registered for installation as a shim. In this way, plugins may call
  72. # `make_shims` with a glob to register many shims at once.
  73. make_shims() {
  74. local shims=("$@")
  75. for file in "${shims[@]}"; do
  76. local shim="${file##*/}"
  77. register_shim "$shim"
  78. done
  79. }
  80. # Create an empty array for the list of registered shims and an empty
  81. # string to use as a search index.
  82. registered_shims=()
  83. registered_shims_index=""
  84. # We will keep track of shims registered for installation with the
  85. # global `registered_shims` array and with a global search index
  86. # string. The array will let us iterate over all registered shims. The
  87. # index string will let us quickly check whether a shim with the given
  88. # name has been registered or not.
  89. register_shim() {
  90. local shim="$@"
  91. registered_shims["${#registered_shims[@]}"]="$shim"
  92. registered_shims_index="$registered_shims_index/$shim/"
  93. }
  94. # To install all the registered shims, we iterate over the
  95. # `registered_shims` array and create a link if one does not already
  96. # exist.
  97. install_registered_shims() {
  98. local shim
  99. for shim in "${registered_shims[@]}"; do
  100. [ -e "$shim" ] || ln -f "$PROTOTYPE_SHIM_PATH" "$shim"
  101. done
  102. }
  103. # Once the registered shims have been installed, we make a second pass
  104. # over the contents of the shims directory. Any file that is present
  105. # in the directory but has not been registered as a shim should be
  106. # removed.
  107. remove_stale_shims() {
  108. local shim
  109. for shim in *; do
  110. if [[ "$registered_shims_index" != *"/$shim/"* ]]; then
  111. rm -f "$shim"
  112. fi
  113. done
  114. }
  115. # Change to the shims directory.
  116. cd "$SHIM_PATH"
  117. shopt -s nullglob
  118. # Create the prototype shim, then register shims for all known
  119. # executables.
  120. create_prototype_shim
  121. remove_outdated_shims
  122. make_shims ../versions/*/bin/*
  123. # Restore the previous working directory.
  124. cd "$OLDPWD"
  125. # Allow plugins to register shims.
  126. OLDIFS="$IFS"
  127. IFS=$'\n' scripts=(`pyenv-hooks rehash`)
  128. IFS="$OLDIFS"
  129. for script in "${scripts[@]}"; do
  130. source "$script"
  131. done
  132. # Change back to the shims directory to install the registered shims
  133. # and remove stale shims.
  134. cd "$SHIM_PATH"
  135. install_registered_shims
  136. remove_stale_shims