25'ten fazla konu seçemezsiniz Konular bir harf veya rakamla başlamalı, kısa çizgiler ('-') içerebilir ve en fazla 35 karakter uzunluğunda olabilir.

151 satır
4.1 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. # 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. { echo "pyenv: cannot rehash: $PROTOTYPE_SHIM_PATH exists"
  17. exit 1
  18. } >&2
  19. set +o noclobber
  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 remove_prototype_shim EXIT
  23. remove_prototype_shim() {
  24. rm -f "$PROTOTYPE_SHIM_PATH"
  25. }
  26. # The prototype shim file is a script that re-execs itself, passing
  27. # its filename and any arguments to `pyenv exec`. This file is
  28. # hard-linked for every executable and then removed. The linking
  29. # technique is fast, uses less disk space than unique files, and also
  30. # serves as a locking mechanism.
  31. create_prototype_shim() {
  32. cat > "$PROTOTYPE_SHIM_PATH" <<SH
  33. #!/usr/bin/env bash
  34. set -e
  35. [ -n "\$PYENV_DEBUG" ] && set -x
  36. program="\${0##*/}"
  37. if [ "\$program" = "python" ]; then
  38. for arg; do
  39. case "\$arg" in
  40. -c* | -- ) break ;;
  41. */* )
  42. if [ -f "\$arg" ]; then
  43. export PYENV_DIR="\${arg%/*}"
  44. break
  45. fi
  46. ;;
  47. esac
  48. done
  49. fi
  50. export PYENV_ROOT="$PYENV_ROOT"
  51. exec "$(command -v pyenv)" exec "\$program" "\$@"
  52. SH
  53. chmod +x "$PROTOTYPE_SHIM_PATH"
  54. }
  55. # If the contents of the prototype shim file differ from the contents
  56. # of the first shim in the shims directory, assume pyenv has been
  57. # upgraded and the existing shims need to be removed.
  58. remove_outdated_shims() {
  59. for shim in *; do
  60. if ! diff "$PROTOTYPE_SHIM_PATH" "$shim" >/dev/null 2>&1; then
  61. for shim in *; do rm -f "$shim"; done
  62. fi
  63. break
  64. done
  65. }
  66. # The basename of each argument passed to `make_shims` will be
  67. # registered for installation as a shim. In this way, plugins may call
  68. # `make_shims` with a glob to register many shims at once.
  69. make_shims() {
  70. local shims="$@"
  71. for file in $shims; do
  72. local shim="${file##*/}"
  73. register_shim "$shim"
  74. done
  75. }
  76. # Create an empty array for the list of registered shims and an empty
  77. # string to use as a search index.
  78. registered_shims=()
  79. registered_shims_index=""
  80. # We will keep track of shims registered for installation with the
  81. # global `reigstered_shims` array and with a global search index
  82. # string. The array will let us iterate over all registered shims. The
  83. # index string will let us quickly check whether a shim with the given
  84. # name has been registered or not.
  85. register_shim() {
  86. local shim="$@"
  87. registered_shims["${#registered_shims[@]}"]="$shim"
  88. registered_shims_index="$registered_shims_index/$shim/"
  89. }
  90. # To install all the registered shims, we iterate over the
  91. # `registered_shims` array and create a link if one does not already
  92. # exist.
  93. install_registered_shims() {
  94. local shim
  95. for shim in "${registered_shims[@]}"; do
  96. [ -e "$shim" ] || ln -f "$PROTOTYPE_SHIM_PATH" "$shim"
  97. done
  98. }
  99. # Once the registered shims have been installed, we make a second pass
  100. # over the contents of the shims directory. Any file that is present
  101. # in the directory but has not been registered as a shim should be
  102. # removed.
  103. remove_stale_shims() {
  104. local shim
  105. for shim in *; do
  106. if [[ "$registered_shims_index" != *"/$shim/"* ]]; then
  107. rm -f "$shim"
  108. fi
  109. done
  110. }
  111. # Change to the shims directory.
  112. cd "$SHIM_PATH"
  113. shopt -s nullglob
  114. # Create the prototype shim, then register shims for all known
  115. # executables.
  116. create_prototype_shim
  117. remove_outdated_shims
  118. make_shims ../versions/*/bin/*
  119. # Restore the previous working directory.
  120. cd "$OLDPWD"
  121. # Allow plugins to register shims.
  122. for script in $(pyenv-hooks rehash); do
  123. source "$script"
  124. done
  125. # Change back to the shims directory to install the registered shims
  126. # and remove stale shims.
  127. cd "$SHIM_PATH"
  128. install_registered_shims
  129. remove_stale_shims