#!/usr/bin/env python3 from __future__ import annotations import argparse import configparser import os.path import stat import sys import sysconfig def main() -> int: parser = argparse.ArgumentParser() parser.add_argument("--path", default=".") args = parser.parse_args() # simulate `pip install -e .` -- but bypass setuptools def r(p: str) -> str: return os.path.relpath(p, ".") # must be in a virtualenv assert not sys.flags.no_site, sys.flags.no_site site_dir = sysconfig.get_path("purelib") bin_dir = sysconfig.get_path("scripts") assert "/.venv/" in site_dir, site_dir cfg = configparser.RawConfigParser() cfg.read(os.path.join(args.path, "setup.cfg")) package_name = cfg["metadata"]["name"] package_dir = cfg["options"].get("package_dir", "").strip() if package_dir not in {"", "=src"}: raise SystemExit(f"unsupported package_dir={package_dir!r}") project_root = os.path.abspath(args.path) if package_dir == "=src": source_root = os.path.join(project_root, "src") project_root_relative = "../" else: source_root = project_root project_root_relative = "." # egg-link indicates that the software is installed egg_link = os.path.join(site_dir, f"{package_name}.egg-link") print(f"writing {r(egg_link)}...") with open(egg_link, "w") as f: f.write(f"{source_root}\n{project_root_relative}") # easy-install.pth is how code gets imported easy_install_pth = os.path.join(site_dir, "easy-install.pth") print(f"adding {r(source_root)} to {r(easy_install_pth)}...") try: with open(easy_install_pth) as f: easy_install_paths = f.read().splitlines() except OSError: easy_install_paths = [] if source_root not in easy_install_paths: easy_install_paths.append(source_root) with open(easy_install_pth, "w") as f: f.write("\n".join(easy_install_paths) + "\n") # 0. create bin scripts for anything in `console_scripts` console_scripts = cfg["options.entry_points"]["console_scripts"].strip() for line in console_scripts.splitlines(): entry, rest = line.split(" = ") mod, attr = rest.split(":") binary = os.path.join(bin_dir, entry) print(f"writing {r(binary)}...") with open(binary, "w") as f: f.write( f"#!{sys.executable}\n" f"from {mod} import {attr}\n" f'if __name__ == "__main__":\n' f" raise SystemExit({attr}())\n" ) mode = os.stat(binary).st_mode mode |= stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH os.chmod(binary, mode) # 0. write out the `sentry.egg-info` directory in `src/` egg_info_dir = os.path.join(source_root, f"{package_name}.egg-info") print(f"creating {r(egg_info_dir)}...") os.makedirs(egg_info_dir, exist_ok=True) entry_points_txt = os.path.join(egg_info_dir, "entry_points.txt") print(f"writing {r(entry_points_txt)}...") ep_cfg = configparser.RawConfigParser() for section, eps in cfg["options.entry_points"].items(): ep_cfg.add_section(section) for ep in eps.strip().splitlines(): k, v = ep.split(" = ") ep_cfg[section][k] = v with open(entry_points_txt, "w") as f: ep_cfg.write(f) pkg_info = os.path.join(egg_info_dir, "PKG-INFO") print(f"writing {r(pkg_info)}...") with open(pkg_info, "w") as f: f.write( f"Metadata-Version: 2.1\n" f"Name: {package_name}\n" f"Version: {cfg['metadata']['version']}\n" ) return 0 if __name__ == "__main__": raise SystemExit(main())