Du kannst nicht mehr als 25 Themen auswählen Themen müssen entweder mit einem Buchstaben oder einer Ziffer beginnen. Sie können Bindestriche („-“) enthalten und bis zu 35 Zeichen lang sein.

116 Zeilen
3.0KB

  1. import argparse
  2. from pathlib import Path
  3. import subprocess
  4. import os
  5. from typing import Sequence, NamedTuple
  6. import sys
  7. import shutil
  8. class BootstrapPhase(NamedTuple):
  9. ref: str
  10. nix_compiler: str
  11. win_compiler: str
  12. @property
  13. def platform_compiler(self):
  14. if os.name == 'nt':
  15. return self.win_compiler
  16. else:
  17. return self.nix_compiler
  18. BOOTSTRAP_PHASES = [
  19. BootstrapPhase('bootstrap-p1.2', 'g++-8', 'cl.exe'),
  20. BootstrapPhase('bootstrap-p4.2', 'g++-8', 'cl.exe'),
  21. BootstrapPhase('bootstrap-p5.2', 'g++-9', 'cl.exe'),
  22. BootstrapPhase('0.1.0-alpha.3', 'g++-9', 'cl.exe'),
  23. BootstrapPhase('0.1.0-alpha.4', 'g++-9', 'cl.exe'),
  24. ]
  25. HERE = Path(__file__).parent.absolute()
  26. PROJECT_ROOT = HERE.parent
  27. BUILD_DIR = PROJECT_ROOT / '_build'
  28. BOOTSTRAP_BASE_DIR = BUILD_DIR / '_bootstrap'
  29. PREBUILT_DIR = PROJECT_ROOT / '_prebuilt'
  30. EXE_SUFFIX = '.exe' if os.name == 'nt' else ''
  31. def _run_quiet(cmd, **kwargs) -> None:
  32. cmd = [str(s) for s in cmd]
  33. res = subprocess.run(
  34. cmd,
  35. stdout=subprocess.PIPE,
  36. stderr=subprocess.STDOUT,
  37. **kwargs,
  38. )
  39. if res.returncode != 0:
  40. print(f'Subprocess command {cmd} failed '
  41. f'[{res.returncode}]:\n{res.stdout.decode()}')
  42. raise subprocess.CalledProcessError(res.returncode, cmd)
  43. def _clone_bootstrap_phase(ref: str) -> Path:
  44. print(f'Clone revision: {ref}')
  45. bts_dir = BOOTSTRAP_BASE_DIR / ref
  46. if bts_dir.exists():
  47. shutil.rmtree(bts_dir)
  48. _run_quiet([
  49. 'git',
  50. 'clone',
  51. '--depth=1',
  52. f'--branch={ref}',
  53. f'file://{PROJECT_ROOT}',
  54. bts_dir,
  55. ])
  56. return bts_dir
  57. def _build_bootstrap_phase(ph: BootstrapPhase, bts_dir: Path) -> None:
  58. print(f'Build revision: {ph.ref} [This may take a moment]')
  59. env = os.environ.copy()
  60. env['DDS_BOOTSTRAP_PREV_EXE'] = str(PREBUILT_DIR / F'dds{EXE_SUFFIX}')
  61. _run_quiet(
  62. [
  63. sys.executable,
  64. '-u',
  65. str(bts_dir / 'tools/build.py'),
  66. f'--cxx={ph.platform_compiler}',
  67. ],
  68. env=env,
  69. cwd=bts_dir,
  70. )
  71. def _pull_executable(bts_dir: Path) -> Path:
  72. prebuild_dir = (PROJECT_ROOT / '_prebuilt')
  73. prebuild_dir.mkdir(exist_ok=True)
  74. generated = list(bts_dir.glob(f'_build/dds{EXE_SUFFIX}'))
  75. assert len(generated) == 1, repr(generated)
  76. exe, = generated
  77. dest = prebuild_dir / exe.name
  78. if dest.exists():
  79. dest.unlink()
  80. exe.rename(dest)
  81. return dest
  82. def _run_boot_phase(phase: BootstrapPhase) -> Path:
  83. bts_dir = _clone_bootstrap_phase(phase.ref)
  84. _build_bootstrap_phase(phase, bts_dir)
  85. return _pull_executable(bts_dir)
  86. def main() -> int:
  87. for idx, phase in enumerate(BOOTSTRAP_PHASES):
  88. print(f'Bootstrap phase [{idx+1}/{len(BOOTSTRAP_PHASES)}]')
  89. exe = _run_boot_phase(phase)
  90. print(f'A bootstrapped DDS executable has been generated: {exe}')
  91. return 0
  92. if __name__ == "__main__":
  93. sys.exit(main())