Du kannst nicht mehr als 25 Themen auswählen Themen müssen entweder mit einem Buchstaben oder einer Ziffer beginnen. Sie können Bindestriche („-“) enthalten und bis zu 35 Zeichen lang sein.

174 Zeilen
4.2 KiB

  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. acquire_lock() {
  10. # Ensure only one instance of pyenv-rehash is running at a time by
  11. # setting the shell's `noclobber` option and attempting to write to
  12. # the prototype shim file. If the file already exists, print a warning
  13. # to stderr and exit with a non-zero status.
  14. local ret
  15. set -o noclobber
  16. echo > "$PROTOTYPE_SHIM_PATH" 2>| /dev/null || ret=1
  17. set +o noclobber
  18. [ -z "${ret}" ]
  19. }
  20. # If we were able to obtain a lock, register a trap to clean up the
  21. # prototype shim when the process exits.
  22. trap release_lock EXIT
  23. remove_prototype_shim() {
  24. rm -f "$PROTOTYPE_SHIM_PATH"
  25. }
  26. release_lock() {
  27. remove_prototype_shim
  28. }
  29. if [ ! -w "$SHIM_PATH" ]; then
  30. echo "pyenv: cannot rehash: $SHIM_PATH isn't writable"
  31. exit 1
  32. fi
  33. unset acquired
  34. for (( i=1; i<="${PYENV_REHASH_TIMEOUT:-60}"; i++ )); do
  35. if acquire_lock 2>/dev/null; then
  36. acquired=1
  37. break
  38. else
  39. # POSIX sleep(1) doesn't provides time precision of subsecond
  40. sleep 1
  41. fi
  42. done
  43. if [ -z "${acquired}" ]; then
  44. echo "pyenv: cannot rehash: $PROTOTYPE_SHIM_PATH exists"
  45. exit 1
  46. fi
  47. # The prototype shim file is a script that re-execs itself, passing
  48. # its filename and any arguments to `pyenv exec`. This file is
  49. # hard-linked for every executable and then removed. The linking
  50. # technique is fast, uses less disk space than unique files, and also
  51. # serves as a locking mechanism.
  52. create_prototype_shim() {
  53. cat > "$PROTOTYPE_SHIM_PATH" <<SH
  54. #!/usr/bin/env bash
  55. set -e
  56. [ -n "\$PYENV_DEBUG" ] && set -x
  57. program="\${0##*/}"
  58. if [[ "\$program" = "python"* ]]; then
  59. for arg; do
  60. case "\$arg" in
  61. -c* | -- ) break ;;
  62. */* )
  63. if [ -f "\$arg" ]; then
  64. export PYENV_FILE_ARG="\$arg"
  65. break
  66. fi
  67. ;;
  68. esac
  69. done
  70. fi
  71. export PYENV_ROOT="$PYENV_ROOT"
  72. exec "$(command -v pyenv)" exec "\$program" "\$@"
  73. SH
  74. chmod +x "$PROTOTYPE_SHIM_PATH"
  75. }
  76. # If the contents of the prototype shim file differ from the contents
  77. # of the first shim in the shims directory, assume pyenv has been
  78. # upgraded and the existing shims need to be removed.
  79. remove_outdated_shims() {
  80. local shim
  81. for shim in "$SHIM_PATH"/*; do
  82. if ! diff "$PROTOTYPE_SHIM_PATH" "$shim" >/dev/null 2>&1; then
  83. rm -f "$SHIM_PATH"/*
  84. fi
  85. break
  86. done
  87. }
  88. # List basenames of executables for every Python version
  89. list_executable_names() {
  90. local version file
  91. pyenv-versions --bare --skip-aliases | \
  92. while read -r version; do
  93. for file in "${PYENV_ROOT}/versions/${version}/bin/"*; do
  94. echo "${file##*/}"
  95. done
  96. done
  97. }
  98. # The basename of each argument passed to `make_shims` will be
  99. # registered for installation as a shim. In this way, plugins may call
  100. # `make_shims` with a glob to register many shims at once.
  101. make_shims() {
  102. local file shim
  103. for file; do
  104. shim="${file##*/}"
  105. register_shim "$shim"
  106. done
  107. }
  108. registered_shims=" "
  109. # Registers the name of a shim to be generated.
  110. register_shim() {
  111. registered_shims="${registered_shims}${1} "
  112. }
  113. # Install all the shims registered via `make_shims` or `register_shim` directly.
  114. install_registered_shims() {
  115. local shim file
  116. for shim in $registered_shims; do
  117. file="${SHIM_PATH}/${shim}"
  118. [ -e "$file" ] || cp "$PROTOTYPE_SHIM_PATH" "$file"
  119. done
  120. }
  121. # Once the registered shims have been installed, we make a second pass
  122. # over the contents of the shims directory. Any file that is present
  123. # in the directory but has not been registered as a shim should be
  124. # removed.
  125. remove_stale_shims() {
  126. local shim
  127. for shim in "$SHIM_PATH"/*; do
  128. if [[ "$registered_shims" != *" ${shim##*/} "* ]]; then
  129. rm -f "$shim"
  130. fi
  131. done
  132. }
  133. shopt -s nullglob
  134. # Create the prototype shim, then register shims for all known
  135. # executables.
  136. create_prototype_shim
  137. remove_outdated_shims
  138. # shellcheck disable=SC2046
  139. make_shims $(list_executable_names | sort -u)
  140. # Allow plugins to register shims.
  141. OLDIFS="$IFS"
  142. IFS=$'\n' scripts=(`pyenv-hooks rehash`)
  143. IFS="$OLDIFS"
  144. for script in "${scripts[@]}"; do
  145. source "$script"
  146. done
  147. install_registered_shims
  148. remove_stale_shims