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.

143 lines
4.9KB

  1. import multiprocessing
  2. import shutil
  3. import os
  4. from pathlib import Path
  5. import copy
  6. from typing import Optional, TypeVar, Iterable
  7. from . import paths, proc, toolchain as tc_mod
  8. from dds_ci.util import Pathish
  9. T = TypeVar('T')
  10. class DDSWrapper:
  11. """
  12. Wraps a 'dds' executable with some convenience APIs that invoke various
  13. 'dds' subcommands.
  14. """
  15. def __init__(self,
  16. path: Path,
  17. *,
  18. repo_dir: Optional[Pathish] = None,
  19. pkg_db_path: Optional[Pathish] = None,
  20. default_cwd: Optional[Pathish] = None) -> None:
  21. self.path = path
  22. self.repo_dir = Path(repo_dir or (paths.PREBUILT_DIR / 'ci-repo'))
  23. self.pkg_db_path = Path(pkg_db_path or (self.repo_dir.parent / 'ci-catalog.db'))
  24. self.default_cwd = default_cwd or Path.cwd()
  25. def clone(self: T) -> T:
  26. return copy.deepcopy(self)
  27. @property
  28. def pkg_db_path_arg(self) -> str:
  29. """The arguments for --catalog"""
  30. return f'--pkg-db-path={self.pkg_db_path}'
  31. @property
  32. def cache_dir_arg(self) -> str:
  33. """The arguments for --repo-dir"""
  34. return f'--pkg-cache-dir={self.repo_dir}'
  35. def set_repo_scratch(self, path: Pathish) -> None:
  36. self.repo_dir = Path(path) / 'data'
  37. self.pkg_db_path = Path(path) / 'pkgs.db'
  38. def clean(self, *, build_dir: Optional[Path] = None, repo: bool = True, pkg_db: bool = True) -> None:
  39. """
  40. Clean out prior executable output, including repos, pkg_db, and
  41. the build results at 'build_dir', if given.
  42. """
  43. if build_dir and build_dir.exists():
  44. shutil.rmtree(build_dir)
  45. if repo and self.repo_dir.exists():
  46. shutil.rmtree(self.repo_dir)
  47. if pkg_db and self.pkg_db_path.exists():
  48. self.pkg_db_path.unlink()
  49. def run(self, args: proc.CommandLine, *, cwd: Optional[Pathish] = None, timeout: Optional[int] = None) -> None:
  50. """Execute the 'dds' executable with the given arguments"""
  51. env = os.environ.copy()
  52. env['DDS_NO_ADD_INITIAL_REPO'] = '1'
  53. proc.check_run([self.path, args], cwd=cwd or self.default_cwd, env=env, timeout=timeout)
  54. def pkg_get(self, what: str) -> None:
  55. self.run(['pkg', 'get', self.pkg_db_path_arg, what])
  56. def repo_add(self, url: str) -> None:
  57. self.run(['pkg', 'repo', 'add', self.pkg_db_path_arg, url])
  58. def repo_remove(self, name: str) -> None:
  59. self.run(['pkg', 'repo', 'remove', self.pkg_db_path_arg, name])
  60. def repo_import(self, sdist: Path) -> None:
  61. self.run(['repo', self.cache_dir_arg, 'import', sdist])
  62. def pkg_import(self, filepath: Pathish) -> None:
  63. self.run(['pkg', 'import', filepath, self.cache_dir_arg])
  64. def build(self,
  65. *,
  66. root: Path,
  67. toolchain: Optional[Path] = None,
  68. build_root: Optional[Path] = None,
  69. jobs: Optional[int] = None,
  70. tweaks_dir: Optional[Path] = None,
  71. more_args: Optional[proc.CommandLine] = None,
  72. timeout: 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. [
  84. 'build',
  85. f'--toolchain={toolchain}',
  86. self.cache_dir_arg,
  87. self.pkg_db_path_arg,
  88. f'--jobs={jobs}',
  89. f'--project={root}',
  90. f'--out={build_root}',
  91. f'--tweaks-dir={tweaks_dir}' if tweaks_dir else (),
  92. more_args or (),
  93. ],
  94. timeout=timeout,
  95. )
  96. def compile_file(self,
  97. paths: Iterable[Pathish],
  98. *,
  99. toolchain: Optional[Pathish] = None,
  100. project_dir: Pathish,
  101. out: Optional[Pathish] = None) -> None:
  102. """
  103. Run 'dds compile-file' for the given paths.
  104. """
  105. toolchain = toolchain or tc_mod.get_default_audit_toolchain()
  106. self.run([
  107. 'compile-file',
  108. self.pkg_db_path_arg,
  109. self.cache_dir_arg,
  110. paths,
  111. f'--toolchain={toolchain}',
  112. f'--project={project_dir}',
  113. f'--out={out}',
  114. ])
  115. def build_deps(self, args: proc.CommandLine, *, toolchain: Optional[Path] = None) -> None:
  116. toolchain = toolchain or tc_mod.get_default_audit_toolchain()
  117. self.run([
  118. 'build-deps',
  119. f'--toolchain={toolchain}',
  120. self.pkg_db_path_arg,
  121. self.cache_dir_arg,
  122. args,
  123. ])