|
|
@@ -0,0 +1,90 @@
|
|
|
+#! /usr/bin/env python3
|
|
|
+"""
|
|
|
+Create symlinks to homebrewed python-installations that can be used alongside
|
|
|
+pyenv.
|
|
|
+
|
|
|
+After running this script, you can use e.g. homebrew's python@3.12 via
|
|
|
+```
|
|
|
+pyenv shell 3.12
|
|
|
+```
|
|
|
+- You can still install pyenv versions
|
|
|
+- you can still create virtualenvironments based on the homebrew versions
|
|
|
+"""
|
|
|
+
|
|
|
+import subprocess
|
|
|
+from pathlib import Path
|
|
|
+from dataclasses import dataclass
|
|
|
+import logging
|
|
|
+
|
|
|
+
|
|
|
+@dataclass
|
|
|
+class Binary:
|
|
|
+ executable: str
|
|
|
+ links: list[str]
|
|
|
+
|
|
|
+
|
|
|
+BINARIES_TO_LINK = [
|
|
|
+ Binary(executable="python{version}", links=["python3", "python"]),
|
|
|
+ Binary(executable="pip{version}", links=["pip3", "pip"]),
|
|
|
+ Binary(executable="idle{version}", links=["idle3", "idle"]),
|
|
|
+ Binary(executable="pydoc{version}", links=["pydoc3", "pydoc"]),
|
|
|
+ Binary(executable="wheel{version}", links=["wheel3", "wheel"]),
|
|
|
+ Binary(
|
|
|
+ executable="python{version}-config",
|
|
|
+ links=["python3-config", "python-config"],
|
|
|
+ ),
|
|
|
+]
|
|
|
+DIRS_TO_LINK = ["include", "lib", "share"]
|
|
|
+
|
|
|
+installed_brew_packages = subprocess.getoutput("brew list").split()
|
|
|
+brew_prefix = Path(subprocess.getoutput("brew --prefix")) / "opt"
|
|
|
+
|
|
|
+installed_versions = [p for p in installed_brew_packages if "python@" in p]
|
|
|
+
|
|
|
+logging.info(f"Will link following installed versions: {installed_versions}")
|
|
|
+
|
|
|
+homedir = Path.home()
|
|
|
+pyenv_dir = Path(subprocess.getoutput("pyenv root")) / "versions"
|
|
|
+logging.info(f"Will add all necessary links to {pyenv_dir}")
|
|
|
+
|
|
|
+for pyversion in installed_versions:
|
|
|
+ logging.info(f"Check dir for {pyversion}")
|
|
|
+ _, version = pyversion.split("@")
|
|
|
+ (pyenv_dir / version).mkdir(exist_ok=True)
|
|
|
+ for binary in BINARIES_TO_LINK:
|
|
|
+ (pyenv_dir / version / "bin").mkdir(exist_ok=True)
|
|
|
+ target = (
|
|
|
+ brew_prefix / pyversion / "bin" / binary.executable.format(version=version)
|
|
|
+ )
|
|
|
+ source = pyenv_dir / version / "bin" / binary.executable.format(version=version)
|
|
|
+ if source.is_file():
|
|
|
+ if source.resolve() != target.resolve():
|
|
|
+ logging.warning(
|
|
|
+ f"{source} is different from {target}, skipping {pyversion}"
|
|
|
+ )
|
|
|
+ continue
|
|
|
+
|
|
|
+ source.symlink_to(target)
|
|
|
+ for link in binary.links:
|
|
|
+ source = pyenv_dir / version / "bin" / link
|
|
|
+ target = brew_prefix / pyversion / "libexec/bin" / link
|
|
|
+ if source.is_symlink():
|
|
|
+ logging.warning(f"Link {target} -> {source} already exists. Skipping.")
|
|
|
+ continue
|
|
|
+ source.symlink_to(target)
|
|
|
+
|
|
|
+ for dir_ in DIRS_TO_LINK:
|
|
|
+ target = brew_prefix / pyversion / dir_
|
|
|
+ source = pyenv_dir / version / dir_
|
|
|
+ if source.is_dir():
|
|
|
+ if source.resolve() != target.resolve():
|
|
|
+ logging.warning(
|
|
|
+ f"{source} is a proper directory, skipping. "
|
|
|
+ f"Linking for {pyversion} might be broken now."
|
|
|
+ )
|
|
|
+ continue
|
|
|
+ if not source.is_symlink():
|
|
|
+ source.symlink_to(target, target_is_directory=True)
|
|
|
+
|
|
|
+logging.info("Rehashing pyenv")
|
|
|
+subprocess.call(["pyenv", "rehash"])
|