sync.py 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164
  1. from __future__ import annotations
  2. import configparser
  3. import os
  4. import subprocess
  5. from devenv import constants
  6. from devenv.lib import venv # type: ignore
  7. from devenv.lib import colima, config, limactl, proc, volta
  8. # TODO: need to replace this with a nicer process executor in devenv.lib
  9. def run_procs(
  10. repo: str,
  11. reporoot: str,
  12. venv_path: str,
  13. _procs: tuple[tuple[str, tuple[str, ...]], ...],
  14. ) -> bool:
  15. procs: list[tuple[str, tuple[str, ...], subprocess.Popen[bytes]]] = []
  16. for name, cmd in _procs:
  17. print(f"⏳ {name}")
  18. if constants.DEBUG:
  19. proc.xtrace(cmd)
  20. procs.append(
  21. (
  22. name,
  23. cmd,
  24. subprocess.Popen(
  25. cmd,
  26. stdout=subprocess.PIPE,
  27. stderr=subprocess.STDOUT,
  28. env={
  29. **constants.user_environ,
  30. **proc.base_env,
  31. "VIRTUAL_ENV": venv_path,
  32. "VOLTA_HOME": constants.VOLTA_HOME,
  33. "PATH": f"{venv_path}/bin:{proc.base_path}",
  34. },
  35. cwd=reporoot,
  36. ),
  37. )
  38. )
  39. all_good = True
  40. for name, final_cmd, p in procs:
  41. out, _ = p.communicate()
  42. if p.returncode != 0:
  43. all_good = False
  44. out_str = "" if out is None else out.decode()
  45. print(
  46. f"""
  47. ❌ {name}
  48. failed command (code p.returncode):
  49. {proc.quote(final_cmd)}
  50. Output:
  51. {out_str}
  52. """
  53. )
  54. else:
  55. print(f"✅ {name}")
  56. return all_good
  57. def main(context: dict[str, str]) -> int:
  58. repo = context["repo"]
  59. reporoot = context["reporoot"]
  60. venv_dir, python_version, requirements, editable_paths, bins = venv.get(reporoot, repo)
  61. url, sha256 = config.get_python(reporoot, python_version)
  62. print(f"ensuring {repo} venv at {venv_dir}...")
  63. venv.ensure(venv_dir, python_version, url, sha256)
  64. # This is for engineers with existing dev environments transitioning over.
  65. # Bootstrap will set devenv-managed volta up but they won't be running
  66. # devenv bootstrap, just installing devenv then running devenv sync.
  67. # make install-js-dev will fail since our run_procs expects devenv-managed
  68. # volta.
  69. volta.install()
  70. if constants.DARWIN:
  71. repo_config = configparser.ConfigParser()
  72. repo_config.read(f"{reporoot}/devenv/config.ini")
  73. # we don't officially support colima on linux yet
  74. if constants.CI:
  75. # colima 0.6.8 doesn't work with macos-13,
  76. # but integration coverage is still handy
  77. colima.install(
  78. "v0.6.2",
  79. "https://github.com/abiosoft/colima/releases/download/v0.6.2/colima-Darwin-x86_64",
  80. "43ef3fc80a8347d51b8ec1706f9caf8863bd8727a6f7532caf1ccd20497d8485",
  81. )
  82. else:
  83. colima.install(
  84. repo_config["colima"]["version"],
  85. repo_config["colima"][constants.SYSTEM_MACHINE],
  86. repo_config["colima"][f"{constants.SYSTEM_MACHINE}_sha256"],
  87. )
  88. # TODO: move limactl version into per-repo config
  89. limactl.install()
  90. if not run_procs(
  91. repo,
  92. reporoot,
  93. venv_dir,
  94. (
  95. ("javascript dependencies", ("make", "install-js-dev")),
  96. ("python dependencies", ("make", "install-py-dev")),
  97. ),
  98. ):
  99. return 1
  100. if not run_procs(
  101. repo,
  102. reporoot,
  103. venv_dir,
  104. (
  105. (
  106. "git and precommit",
  107. # this can't be done in paralell with python dependencies
  108. # as multiple pips cannot act on the same venv
  109. ("make", "setup-git"),
  110. ),
  111. ),
  112. ):
  113. return 1
  114. if not os.path.exists(f"{constants.home}/.sentry/config.yml") or not os.path.exists(
  115. f"{constants.home}/.sentry/sentry.conf.py"
  116. ):
  117. proc.run((f"{venv_dir}/bin/sentry", "init", "--dev"))
  118. # TODO: check healthchecks for redis and postgres to short circuit this
  119. proc.run(
  120. (
  121. f"{venv_dir}/bin/{repo}",
  122. "devservices",
  123. "up",
  124. "redis",
  125. "postgres",
  126. ),
  127. exit=True,
  128. )
  129. if run_procs(
  130. repo,
  131. reporoot,
  132. venv_dir,
  133. (
  134. (
  135. "python migrations",
  136. (f"{venv_dir}/bin/{repo}", "upgrade", "--noinput"),
  137. ),
  138. ),
  139. ):
  140. return 0
  141. return 1