You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

165 lines
5.0 KiB

  1. #!/usr/bin/env python3
  2. # -*- coding: utf-8 -*-
  3. import os
  4. import sys
  5. from multiprocessing import cpu_count
  6. from subprocess import check_call
  7. import yaml
  8. from doodbalib import (
  9. ADDONS_YAML,
  10. AUTO_REPOS_YAML,
  11. CORE,
  12. ODOO_DIR,
  13. PRIVATE,
  14. REPOS_YAML,
  15. SRC_DIR,
  16. logger,
  17. )
  18. # if the umask matches the `chmod -R u+rwX,g+rX-w,o= /opt/odoo` command the build is faster as we don't need to fix as
  19. # many permissions after auto aggregation
  20. UMASK = os.environ.get("UMASK") or "0027"
  21. UID = int(os.environ.get("UID") or -1)
  22. GID = int(os.environ.get("GID") or -1)
  23. DEFAULT_REPO_PATTERN = os.environ.get("DEFAULT_REPO_PATTERN")
  24. DEFAULT_REPO_PATTERN_ODOO = os.environ.get("DEFAULT_REPO_PATTERN_ODOO")
  25. log_level = os.environ.get("LOG_LEVEL", "INFO")
  26. def aggregate(config):
  27. """Execute git aggregator to pull git code.
  28. :param str config:
  29. Path where to find the ``repos.yaml`` file.
  30. """
  31. logger.info("Running gitaggregate with %s", config)
  32. def pre_exec_umask():
  33. # Download git code with the specified umask, if set, otherwise use "0027"
  34. os.umask(int(UMASK, 8))
  35. pre_execs = [pre_exec_umask]
  36. def pre_exec():
  37. for _exec in pre_execs:
  38. try:
  39. _exec()
  40. except Exception as e:
  41. logger.error("Error in %s: %s" % (_exec, e))
  42. logger.exception(e)
  43. raise
  44. if ~GID:
  45. def pre_exec_gid():
  46. # execute git with GID
  47. os.setgid(GID)
  48. pre_execs.append(pre_exec_gid)
  49. if ~UID:
  50. def pre_exec_uid():
  51. # execute git with UID
  52. os.setuid(UID)
  53. # set odoo home directory
  54. # (git checks if user has a config in $HOME, and we cannot read /root as odoo user)
  55. os.environ["HOME"] = "/home/odoo"
  56. pre_execs.append(pre_exec_uid)
  57. check_call(
  58. [
  59. "gitaggregate",
  60. "--expand-env",
  61. "--config",
  62. config,
  63. "--log-level",
  64. log_level,
  65. "--jobs",
  66. str(cpu_count() or 1),
  67. "aggregate",
  68. ],
  69. cwd=SRC_DIR,
  70. stderr=sys.stderr,
  71. stdout=sys.stdout,
  72. preexec_fn=pre_exec,
  73. )
  74. def origin_for(
  75. folder,
  76. default_repo_pattern=DEFAULT_REPO_PATTERN,
  77. odoo_repo_pattern=DEFAULT_REPO_PATTERN_ODOO,
  78. ):
  79. """Guess the default git origin for that folder.
  80. :param str folder:
  81. Normally an absolute path to an expected git repo, whose name should
  82. match the git repository where it comes from, using the env-supplied
  83. pattern.
  84. """
  85. base = os.path.basename(folder)
  86. pattern = default_repo_pattern
  87. if base == "odoo":
  88. pattern = odoo_repo_pattern
  89. return pattern.format(base)
  90. def missing_repos_config():
  91. """Find the undefined repositories and return their default configuration.
  92. :return dict:
  93. git-aggregator-ready configuration dict for undefined repositories.
  94. """
  95. defined, expected = set(), {ODOO_DIR}
  96. # Find the repositories defined by hand
  97. try:
  98. with open(REPOS_YAML) as yaml_file:
  99. for doc in yaml.safe_load_all(yaml_file):
  100. for repo in doc:
  101. defined.add(os.path.abspath(os.path.join(SRC_DIR, repo)))
  102. except (IOError, AttributeError):
  103. logger.debug("No repositories defined by hand")
  104. addons_env = {}
  105. # Find the repositories that should be present
  106. try:
  107. with open(ADDONS_YAML) as yaml_file:
  108. for doc in yaml.safe_load_all(yaml_file):
  109. env = dict(os.environ, **doc.get("ENV", {}))
  110. for repo in doc:
  111. if repo in {PRIVATE, "ONLY", "ENV"}:
  112. continue
  113. if repo == CORE:
  114. repo_path = ODOO_DIR
  115. else:
  116. repo_path = os.path.abspath(os.path.join(SRC_DIR, repo))
  117. if not os.path.exists(repo_path) or os.path.isdir(
  118. os.path.join(repo_path, ".git")
  119. ):
  120. expected.add(repo_path)
  121. addons_env[repo_path] = env
  122. except (IOError, AttributeError):
  123. logger.debug("No addons are expected to be present")
  124. # Find the undefined repositories and generate a config for them
  125. missing = expected - defined
  126. config = {}
  127. for repo_path in missing:
  128. env = addons_env.get(repo_path, os.environ)
  129. depth = env["DEPTH_DEFAULT"]
  130. origin_version = "origin %s" % env["ODOO_VERSION"]
  131. config[repo_path] = {
  132. "defaults": {"depth": depth},
  133. "merges": [origin_version],
  134. "remotes": {
  135. "origin": origin_for(
  136. repo_path,
  137. env["DEFAULT_REPO_PATTERN"],
  138. env["DEFAULT_REPO_PATTERN_ODOO"],
  139. )
  140. },
  141. "target": origin_version,
  142. }
  143. logger.debug("Generated missing repos config %r", config)
  144. return config