freeze_requirements.py 2.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101
  1. from __future__ import annotations
  2. import argparse
  3. from concurrent.futures import Future, ThreadPoolExecutor
  4. from os.path import abspath
  5. from subprocess import CalledProcessError, run
  6. from typing import Sequence
  7. from tools.lib import gitroot
  8. def worker(args: tuple[str, ...]) -> None:
  9. # pip-compile doesn't let you customize the header, so we write
  10. # one ourselves. However, pip-compile needs -o DEST otherwise
  11. # it will bump >= pins even if they're satisfied. So, we need to
  12. # unfortunately rewrite the whole file.
  13. dest = args[-1]
  14. try:
  15. run(args, check=True, capture_output=True)
  16. except CalledProcessError as e:
  17. raise e
  18. with open(dest, "rb+") as f:
  19. content = f.read()
  20. f.seek(0, 0)
  21. f.write(
  22. b"""# DO NOT MODIFY. This file was generated with `make freeze-requirements`.
  23. """
  24. + content
  25. )
  26. def check_futures(futures: list[Future[None]]) -> int:
  27. rc = 0
  28. for future in futures:
  29. try:
  30. future.result()
  31. except CalledProcessError as e:
  32. rc = 1
  33. print(
  34. f"""`{e.cmd}` returned code {e.returncode}
  35. stdout:
  36. {e.stdout.decode()}
  37. stderr:
  38. {e.stderr.decode()}
  39. """
  40. )
  41. return rc
  42. def main(argv: Sequence[str] | None = None) -> int:
  43. parser = argparse.ArgumentParser()
  44. parser.parse_args(argv)
  45. base_path = abspath(gitroot())
  46. base_cmd = (
  47. "pip-compile",
  48. "--allow-unsafe",
  49. "--no-annotate",
  50. "--no-header",
  51. "--quiet",
  52. "--strip-extras",
  53. "--index-url=https://pypi.devinfra.sentry.io/simple",
  54. )
  55. executor = ThreadPoolExecutor(max_workers=2)
  56. futures = [
  57. executor.submit(
  58. worker,
  59. (
  60. *base_cmd,
  61. f"{base_path}/requirements-base.txt",
  62. f"{base_path}/requirements-getsentry.txt",
  63. "-o",
  64. f"{base_path}/requirements-frozen.txt",
  65. ),
  66. ),
  67. executor.submit(
  68. worker,
  69. (
  70. *base_cmd,
  71. f"{base_path}/requirements-base.txt",
  72. f"{base_path}/requirements-getsentry.txt",
  73. f"{base_path}/requirements-dev.txt",
  74. "-o",
  75. f"{base_path}/requirements-dev-frozen.txt",
  76. ),
  77. ),
  78. ]
  79. rc = check_futures(futures)
  80. executor.shutdown()
  81. return rc
  82. if __name__ == "__main__":
  83. raise SystemExit(main())