sync.py 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167
  1. from __future__ import annotations
  2. import configparser
  3. import os
  4. import shlex
  5. import subprocess
  6. from devenv import constants
  7. from devenv.lib import colima, config, limactl, proc, venv, 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": f"{reporoot}/.devenv/bin/volta-home",
  33. "PATH": f"{venv_path}/bin:{reporoot}/.devenv/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. print(
  45. f"""
  46. ❌ {name}
  47. failed command (code p.returncode):
  48. {shlex.join(final_cmd)}
  49. Output:
  50. {out.decode()}
  51. """
  52. )
  53. else:
  54. print(f"✅ {name}")
  55. return all_good
  56. def main(context: dict[str, str]) -> int:
  57. repo = context["repo"]
  58. reporoot = context["reporoot"]
  59. venv_dir, python_version, requirements, editable_paths, bins = venv.get(reporoot, repo)
  60. url, sha256 = config.get_python(reporoot, python_version)
  61. print(f"ensuring {repo} venv at {venv_dir}...")
  62. venv.ensure(venv_dir, python_version, url, sha256)
  63. # TODO: move volta version into per-repo config
  64. try:
  65. volta.install(reporoot)
  66. except TypeError:
  67. # this is needed for devenv <=1.4.0,>1.2.3 to finish syncing and therefore update itself
  68. volta.install()
  69. if constants.DARWIN:
  70. repo_config = configparser.ConfigParser()
  71. repo_config.read(f"{reporoot}/devenv/config.ini")
  72. try:
  73. colima.install(
  74. repo_config["colima"]["version"],
  75. repo_config["colima"][constants.SYSTEM_MACHINE],
  76. repo_config["colima"][f"{constants.SYSTEM_MACHINE}_sha256"],
  77. reporoot,
  78. )
  79. except TypeError:
  80. # this is needed for devenv <=1.4.0,>1.2.3 to finish syncing and therefore update itself
  81. colima.install(
  82. repo_config["colima"]["version"],
  83. repo_config["colima"][constants.SYSTEM_MACHINE],
  84. repo_config["colima"][f"{constants.SYSTEM_MACHINE}_sha256"],
  85. )
  86. # TODO: move limactl version into per-repo config
  87. try:
  88. limactl.install(reporoot)
  89. except TypeError:
  90. # this is needed for devenv <=1.4.0,>1.2.3 to finish syncing and therefore update itself
  91. limactl.install()
  92. if not run_procs(
  93. repo,
  94. reporoot,
  95. venv_dir,
  96. (
  97. ("javascript dependencies", ("make", "install-js-dev")),
  98. ("python dependencies", ("make", "install-py-dev")),
  99. ),
  100. ):
  101. return 1
  102. if not run_procs(
  103. repo,
  104. reporoot,
  105. venv_dir,
  106. (
  107. (
  108. "git and precommit",
  109. # this can't be done in paralell with python dependencies
  110. # as multiple pips cannot act on the same venv
  111. ("make", "setup-git"),
  112. ),
  113. ),
  114. ):
  115. return 1
  116. if not os.path.exists(f"{constants.home}/.sentry/config.yml") or not os.path.exists(
  117. f"{constants.home}/.sentry/sentry.conf.py"
  118. ):
  119. proc.run((f"{venv_dir}/bin/sentry", "init", "--dev"))
  120. # TODO: check healthchecks for redis and postgres to short circuit this
  121. proc.run(
  122. (
  123. f"{venv_dir}/bin/{repo}",
  124. "devservices",
  125. "up",
  126. "redis",
  127. "postgres",
  128. ),
  129. pathprepend=f"{reporoot}/.devenv/bin",
  130. exit=True,
  131. )
  132. if run_procs(
  133. repo,
  134. reporoot,
  135. venv_dir,
  136. (
  137. (
  138. "python migrations",
  139. ("make", "apply-migrations"),
  140. ),
  141. ),
  142. ):
  143. return 0
  144. return 1