BuildSettingsCommand.php 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139
  1. <?php
  2. declare(strict_types = 1);
  3. namespace Fgm\Drupal\Composer;
  4. use Symfony\Component\Console\Input\InputArgument;
  5. use Symfony\Component\Console\Input\InputDefinition;
  6. use Symfony\Component\Console\Input\InputInterface;
  7. use Symfony\Component\Console\Output\OutputInterface;
  8. use Symfony\Component\Yaml\Exception\ParseException;
  9. use Symfony\Component\Yaml\Yaml;
  10. use Twig\Environment;
  11. use Twig\Extension\DebugExtension;
  12. use Twig\Loader\FilesystemLoader;
  13. use Twig\TemplateWrapper;
  14. class BuildSettingsCommand extends BaseBuilderCommand
  15. {
  16. /**
  17. * @var string
  18. */
  19. protected $eventName;
  20. /**
  21. * {@inheritDoc}
  22. */
  23. public function configure()
  24. {
  25. parent::configure();
  26. $this->eventName = $this->getName();
  27. $this
  28. ->setName('build:settings')
  29. ->setDescription('Step 4: build the *.settings.local.php files.')
  30. ->setDefinition(
  31. new InputDefinition([
  32. new InputArgument(static::ARG_FILE, InputArgument::OPTIONAL),
  33. ])
  34. )
  35. ->setHelp(
  36. <<<EOT
  37. The build:settings command combines shared and per-environment parameters and passes
  38. them to the settings.local.php.twig template to build the settings/(build|run).settings.local.php files.
  39. EOT
  40. );
  41. }
  42. /**
  43. * {@inheritDoc}
  44. */
  45. public function execute(InputInterface $input, OutputInterface $output)
  46. {
  47. [$templateName, $err] = $this->validateTemplateName($input, $output);
  48. if ($err) {
  49. return 1;
  50. };
  51. $settingsPath = $this->getSettingsPath();
  52. $templatePath = "${settingsPath}/${templateName}";
  53. $realTemplatePath = realpath($templatePath);
  54. if (empty($realTemplatePath)) {
  55. $output->writeln(sprintf("Could not load template %s: no such file", $templateName));
  56. return 2;
  57. }
  58. $paramsPath = "${settingsPath}/merged.params.local.yml";
  59. $realParamsPath = realpath($paramsPath);
  60. if (empty($realParamsPath)) {
  61. $output->writeln(sprintf("Could not load parameters %s: no such file", $paramsPath));
  62. return 3;
  63. }
  64. $yaml = new Yaml();
  65. try {
  66. $params = $yaml->parseFile($realParamsPath);
  67. } catch (ParseException $e) {
  68. $output->writeln(sprintf("Could not parse %s: %s", $realParamsPath, $e->getMessage()));
  69. return 4;
  70. }
  71. $loader = new FilesystemLoader($settingsPath, $settingsPath);
  72. $twig = new Environment($loader, [
  73. 'auto_reload' => true,
  74. 'cache' => false,
  75. 'debug' => true,
  76. 'strict_variables' => true,
  77. ]);
  78. $twig->addExtension(new DebugExtension());
  79. $wrapper = $twig->load($templateName);
  80. foreach ($params['sites'] as $name => $siteParams) {
  81. foreach (['build', 'run'] as $stage) {
  82. $stageSettings = NestedArray::mergeDeepArray([
  83. $siteParams['settings']['both'] ?? [],
  84. $siteParams['settings'][$stage] ?? []
  85. ], true);
  86. $stageParams = $siteParams;
  87. $stageParams['settings'] = $stageSettings;
  88. $context = [
  89. 'instance' => $params['instance'],
  90. 'name' => $name,
  91. 'stage' => $stage,
  92. 'site' => $stageParams,
  93. ];
  94. $error = $this->render($wrapper, $context, $output);
  95. if ($error) {
  96. $output->writeln(sprintf("Failed rendering %s settings for site %s", $stage, $name));
  97. return 5;
  98. }
  99. }
  100. }
  101. }
  102. protected function render(TemplateWrapper $wrapper, array $context, OutputInterface $output): int
  103. {
  104. $settingsPath = "web/sites/${context['name']}/${context['stage']}.settings.local.php";
  105. if (file_exists($settingsPath)) {
  106. $ok = unlink($settingsPath);
  107. if (!$ok) {
  108. $output->writeln(sprintf(
  109. "Could not remove old %s file",
  110. $settingsPath
  111. ));
  112. return 1;
  113. }
  114. }
  115. $rendered = $wrapper->render($context);
  116. $ok = file_put_contents($settingsPath, $rendered, LOCK_EX);
  117. if (!$ok) {
  118. $output->writeln(sprintf('Could not write new %s file', $settingsPath));
  119. return 2;
  120. }
  121. return 0;
  122. }
  123. }