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.

158 lines
5.2KB

  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_remove(self, name: str) -> None:
  64. self.run(['pkg', 'repo', 'remove', self.catalog_path_arg, name])
  65. def repo_import(self, sdist: Path) -> None:
  66. self.run(['repo', self.repo_dir_arg, 'import', sdist])
  67. def pkg_import(self, filepath: Pathish) -> None:
  68. self.run(['pkg', 'import', filepath, self.repo_dir_arg])
  69. def build(self,
  70. *,
  71. root: Path,
  72. toolchain: Optional[Path] = None,
  73. build_root: Optional[Path] = None,
  74. jobs: Optional[int] = None) -> None:
  75. """
  76. Run 'dds build' with the given arguments.
  77. :param toolchain: The toolchain to use for the build.
  78. :param root: The root project directory.
  79. :param build_root: The root directory where the output will be written.
  80. :param jobs: The number of jobs to use. Default is CPU-count + 2
  81. """
  82. toolchain = toolchain or tc_mod.get_default_audit_toolchain()
  83. jobs = jobs or multiprocessing.cpu_count() + 2
  84. self.run([
  85. 'build',
  86. f'--toolchain={toolchain}',
  87. self.repo_dir_arg,
  88. self.catalog_path_arg,
  89. f'--jobs={jobs}',
  90. f'{self.project_dir_flag}={root}',
  91. f'--out={build_root}',
  92. ])
  93. def compile_file(self,
  94. paths: Iterable[Pathish],
  95. *,
  96. toolchain: Optional[Pathish] = None,
  97. project_dir: Pathish,
  98. out: Optional[Pathish] = None) -> None:
  99. """
  100. Run 'dds compile-file' for the given paths.
  101. """
  102. toolchain = toolchain or tc_mod.get_default_audit_toolchain()
  103. self.run([
  104. 'compile-file',
  105. paths,
  106. f'--toolchain={toolchain}',
  107. f'{self.project_dir_flag}={project_dir}',
  108. f'--out={out}',
  109. ])
  110. def build_deps(self, args: proc.CommandLine, *, toolchain: Optional[Path] = None) -> None:
  111. toolchain = toolchain or tc_mod.get_default_audit_toolchain()
  112. self.run([
  113. 'build-deps',
  114. f'--toolchain={toolchain}',
  115. self.catalog_path_arg,
  116. self.repo_dir_arg,
  117. args,
  118. ])
  119. class NewDDSWrapper(DDSWrapper):
  120. """
  121. Wraps the new 'dds' executable with some convenience APIs
  122. """
  123. @property
  124. def repo_dir_arg(self) -> str:
  125. return f'--pkg-cache-dir={self.repo_dir}'
  126. @property
  127. def catalog_path_arg(self) -> str:
  128. return f'--pkg-db-path={self.pkg_db_path}'
  129. @property
  130. def project_dir_flag(self) -> str:
  131. return '--project'