1
0

brew_pyenv_setup.py 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990
  1. #! /usr/bin/env python3
  2. """
  3. Create symlinks to homebrewed python-installations that can be used alongside
  4. pyenv.
  5. After running this script, you can use e.g. homebrew's python@3.12 via
  6. ```
  7. pyenv shell 3.12
  8. ```
  9. - You can still install pyenv versions
  10. - you can still create virtualenvironments based on the homebrew versions
  11. """
  12. import subprocess
  13. from pathlib import Path
  14. from dataclasses import dataclass
  15. import logging
  16. @dataclass
  17. class Binary:
  18. executable: str
  19. links: list[str]
  20. BINARIES_TO_LINK = [
  21. Binary(executable="python{version}", links=["python3", "python"]),
  22. Binary(executable="pip{version}", links=["pip3", "pip"]),
  23. Binary(executable="idle{version}", links=["idle3", "idle"]),
  24. Binary(executable="pydoc{version}", links=["pydoc3", "pydoc"]),
  25. Binary(executable="wheel{version}", links=["wheel3", "wheel"]),
  26. Binary(
  27. executable="python{version}-config",
  28. links=["python3-config", "python-config"],
  29. ),
  30. ]
  31. DIRS_TO_LINK = ["include", "lib", "share"]
  32. installed_brew_packages = subprocess.getoutput("brew list").split()
  33. brew_prefix = Path(subprocess.getoutput("brew --prefix")) / "opt"
  34. installed_versions = [p for p in installed_brew_packages if "python@" in p]
  35. logging.info(f"Will link following installed versions: {installed_versions}")
  36. homedir = Path.home()
  37. pyenv_dir = Path(subprocess.getoutput("pyenv root")) / "versions"
  38. logging.info(f"Will add all necessary links to {pyenv_dir}")
  39. for pyversion in installed_versions:
  40. logging.info(f"Check dir for {pyversion}")
  41. _, version = pyversion.split("@")
  42. (pyenv_dir / version).mkdir(exist_ok=True)
  43. for binary in BINARIES_TO_LINK:
  44. (pyenv_dir / version / "bin").mkdir(exist_ok=True)
  45. target = (
  46. brew_prefix / pyversion / "bin" / binary.executable.format(version=version)
  47. )
  48. source = pyenv_dir / version / "bin" / binary.executable.format(version=version)
  49. if source.is_file():
  50. if source.resolve() != target.resolve():
  51. logging.warning(
  52. f"{source} is different from {target}, skipping {pyversion}"
  53. )
  54. continue
  55. source.symlink_to(target)
  56. for link in binary.links:
  57. source = pyenv_dir / version / "bin" / link
  58. target = brew_prefix / pyversion / "libexec/bin" / link
  59. if source.is_symlink():
  60. logging.warning(f"Link {target} -> {source} already exists. Skipping.")
  61. continue
  62. source.symlink_to(target)
  63. for dir_ in DIRS_TO_LINK:
  64. target = brew_prefix / pyversion / dir_
  65. source = pyenv_dir / version / dir_
  66. if source.is_dir():
  67. if source.resolve() != target.resolve():
  68. logging.warning(
  69. f"{source} is a proper directory, skipping. "
  70. f"Linking for {pyversion} might be broken now."
  71. )
  72. continue
  73. if not source.is_symlink():
  74. source.symlink_to(target, target_is_directory=True)
  75. logging.info("Rehashing pyenv")
  76. subprocess.call(["pyenv", "rehash"])