Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154
  1. import multiprocessing
  2. import shutil
  3. from pathlib import Path
  4. import copy
  5. from typing import Optional, TypeVar, Iterable
  6. from . import paths, proc, toolchain as tc_mod
  7. from dds_ci.util import Pathish
  8. T = TypeVar('T')
  9. class DDSWrapper:
  10. """
  11. Wraps a 'dds' executable with some convenience APIs that invoke various
  12. 'dds' subcommands.
  13. """
  14. def __init__(self,
  15. path: Path,
  16. *,
  17. repo_dir: Optional[Pathish] = None,
  18. pkg_db_path: Optional[Pathish] = None,
  19. default_cwd: Optional[Pathish] = None) -> None:
  20. self.path = path
  21. self.repo_dir = Path(repo_dir or (paths.PREBUILT_DIR / 'ci-repo'))
  22. self.pkg_db_path = Path(pkg_db_path or (self.repo_dir.parent / 'ci-catalog.db'))
  23. self.default_cwd = default_cwd or Path.cwd()
  24. def clone(self: T) -> T:
  25. return copy.deepcopy(self)
  26. @property
  27. def catalog_path_arg(self) -> str:
  28. """The arguments for --catalog"""
  29. return f'--catalog={self.pkg_db_path}'
  30. @property
  31. def repo_dir_arg(self) -> str:
  32. """The arguments for --repo-dir"""
  33. return f'--repo-dir={self.repo_dir}'
  34. @property
  35. def project_dir_flag(self) -> str:
  36. return '--project-dir'
  37. def set_repo_scratch(self, path: Pathish) -> None:
  38. self.repo_dir = Path(path) / 'data'
  39. self.pkg_db_path = Path(path) / 'pkgs.db'
  40. def clean(self, *, build_dir: Optional[Path] = None, repo: bool = True, pkg_db: bool = True) -> None:
  41. """
  42. Clean out prior executable output, including repos, pkg_db, and
  43. the build results at 'build_dir', if given.
  44. """
  45. if build_dir and build_dir.exists():
  46. shutil.rmtree(build_dir)
  47. if repo and self.repo_dir.exists():
  48. shutil.rmtree(self.repo_dir)
  49. if pkg_db and self.pkg_db_path.exists():
  50. self.pkg_db_path.unlink()
  51. def run(self, args: proc.CommandLine, *, cwd: Optional[Pathish] = None) -> None:
  52. """Execute the 'dds' executable with the given arguments"""
  53. proc.check_run([self.path, args], cwd=cwd or self.default_cwd)
  54. def catalog_json_import(self, path: Path) -> None:
  55. """Run 'catalog import' to import the given JSON. Only applicable to older 'dds'"""
  56. self.run(['catalog', 'import', self.catalog_path_arg, f'--json={path}'])
  57. def catalog_get(self, what: str) -> None:
  58. self.run(['catalog', 'get', self.catalog_path_arg, what])
  59. def pkg_get(self, what: str) -> None:
  60. self.run(['pkg', 'get', self.catalog_path_arg, what])
  61. def repo_add(self, url: str) -> None:
  62. self.run(['pkg', 'repo', 'add', self.catalog_path_arg, url])
  63. def repo_import(self, sdist: Path) -> None:
  64. self.run(['repo', self.repo_dir_arg, 'import', sdist])
  65. def pkg_import(self, filepath: Pathish) -> None:
  66. self.run(['pkg', 'import', filepath, self.repo_dir_arg])
  67. def build(self,
  68. *,
  69. root: Path,
  70. toolchain: Optional[Path] = None,
  71. build_root: Optional[Path] = None,
  72. jobs: Optional[int] = None) -> None:
  73. """
  74. Run 'dds build' with the given arguments.
  75. :param toolchain: The toolchain to use for the build.
  76. :param root: The root project directory.
  77. :param build_root: The root directory where the output will be written.
  78. :param jobs: The number of jobs to use. Default is CPU-count + 2
  79. """
  80. toolchain = toolchain or tc_mod.get_default_audit_toolchain()
  81. jobs = jobs or multiprocessing.cpu_count() + 2
  82. self.run([
  83. 'build',
  84. f'--toolchain={toolchain}',
  85. self.repo_dir_arg,
  86. self.catalog_path_arg,
  87. f'--jobs={jobs}',
  88. f'{self.project_dir_flag}={root}',
  89. f'--out={build_root}',
  90. ])
  91. def compile_file(self,
  92. paths: Iterable[Pathish],
  93. *,
  94. toolchain: Optional[Pathish] = None,
  95. project_dir: Pathish,
  96. out: Optional[Pathish] = None) -> None:
  97. """
  98. Run 'dds compile-file' for the given paths.
  99. """
  100. toolchain = toolchain or tc_mod.get_default_audit_toolchain()
  101. self.run([
  102. 'compile-file',
  103. paths,
  104. f'--toolchain={toolchain}',
  105. f'{self.project_dir_flag}={project_dir}',
  106. f'--out={out}',
  107. ])
  108. def build_deps(self, args: proc.CommandLine, *, toolchain: Optional[Path] = None) -> None:
  109. toolchain = toolchain or tc_mod.get_default_audit_toolchain()
  110. self.run([
  111. 'build-deps',
  112. f'--toolchain={toolchain}',
  113. self.catalog_path_arg,
  114. self.repo_dir_arg,
  115. args,
  116. ])
  117. class NewDDSWrapper(DDSWrapper):
  118. """
  119. Wraps the new 'dds' executable with some convenience APIs
  120. """
  121. @property
  122. def repo_dir_arg(self) -> str:
  123. return f'--pkg-cache-dir={self.repo_dir}'
  124. @property
  125. def catalog_path_arg(self) -> str:
  126. return f'--pkg-db-path={self.pkg_db_path}'
  127. @property
  128. def project_dir_flag(self) -> str:
  129. return '--project'