PageRenderTime 60ms CodeModel.GetById 8ms RepoModel.GetById 1ms app.codeStats 0ms

/src/Sismo/Builder.php

http://github.com/fabpot/Sismo
PHP | 147 lines | 106 code | 26 blank | 15 comment | 14 complexity | e1313a3f2de85494c1a226a6524017b9 MD5 | raw file
  1. <?php
  2. /*
  3. * This file is part of the Sismo utility.
  4. *
  5. * (c) Fabien Potencier <fabien@symfony.com>
  6. *
  7. * This source file is subject to the MIT license that is bundled
  8. * with this source code in the file LICENSE.
  9. */
  10. namespace Sismo;
  11. use Symfony\Component\Process\Process;
  12. // @codeCoverageIgnoreStart
  13. /**
  14. * Builds commits.
  15. *
  16. * @author Fabien Potencier <fabien@symfony.com>
  17. */
  18. class Builder
  19. {
  20. private $project;
  21. private $baseBuildDir;
  22. private $buildDir;
  23. private $callback;
  24. private $gitPath;
  25. private $gitCmds;
  26. public function __construct($buildDir, $gitPath, array $gitCmds)
  27. {
  28. $this->baseBuildDir = $buildDir;
  29. $this->gitPath = $gitPath;
  30. $this->gitCmds = array_replace(array(
  31. 'clone' => 'clone --progress --recursive %repo% %dir% --branch %localbranch%',
  32. 'fetch' => 'fetch origin',
  33. 'prepare' => 'submodule update --init --recursive',
  34. 'checkout' => 'checkout -q -f %branch%',
  35. 'reset' => 'reset --hard %revision%',
  36. 'show' => 'show -s --pretty=format:%format% %revision%',
  37. ), $gitCmds);
  38. }
  39. public function init(Project $project, $callback = null)
  40. {
  41. $process = new Process(sprintf('%s --version', $this->gitPath));
  42. if ($process->run() > 0) {
  43. throw new \RuntimeException(sprintf('The git binary cannot be found (%s).', $this->gitPath));
  44. }
  45. $this->project = $project;
  46. $this->callback = $callback;
  47. $this->buildDir = $this->baseBuildDir.'/'.$this->getBuildDir($project);
  48. }
  49. public function build()
  50. {
  51. file_put_contents($this->buildDir.'/sismo-run-tests.sh', str_replace(array("\r\n", "\r"), "\n", $this->project->getCommand()));
  52. $process = new Process('sh sismo-run-tests.sh', $this->buildDir);
  53. $process->setTimeout(3600);
  54. $process->run($this->callback);
  55. return $process;
  56. }
  57. public function getBuildDir(Project $project)
  58. {
  59. return substr(md5($project->getRepository().$project->getBranch()), 0, 6);
  60. }
  61. public function prepare($revision, $sync)
  62. {
  63. if (!file_exists($this->buildDir)) {
  64. mkdir($this->buildDir, 0777, true);
  65. }
  66. if (!file_exists($this->buildDir.'/.git')) {
  67. $this->execute($this->getGitCommand('clone'), sprintf('Unable to clone repository for project "%s".', $this->project));
  68. }
  69. if ($sync) {
  70. $this->execute($this->gitPath.' '.$this->gitCmds['fetch'], sprintf('Unable to fetch repository for project "%s".', $this->project));
  71. }
  72. $this->execute($this->getGitCommand('checkout'), sprintf('Unable to checkout branch "%s" for project "%s".', $this->project->getBranch(), $this->project));
  73. if ($sync) {
  74. $this->execute($this->gitPath.' '.$this->gitCmds['prepare'], sprintf('Unable to update submodules for project "%s".', $this->project));
  75. }
  76. if (null === $revision || 'HEAD' === $revision) {
  77. $revision = null;
  78. if (file_exists($file = $this->buildDir.'/.git/HEAD')) {
  79. $revision = trim(file_get_contents($file));
  80. if (0 === strpos($revision, 'ref: ')) {
  81. if (file_exists($file = $this->buildDir.'/.git/'.substr($revision, 5))) {
  82. $revision = trim(file_get_contents($file));
  83. } else {
  84. $revision = null;
  85. }
  86. }
  87. }
  88. if (null === $revision) {
  89. throw new BuildException(sprintf('Unable to get HEAD for branch "%s" for project "%s".', $this->project->getBranch(), $this->project));
  90. }
  91. }
  92. $this->execute($this->getGitCommand('reset', array('%revision%' => escapeshellarg($revision))), sprintf('Revision "%s" for project "%s" does not exist.', $revision, $this->project));
  93. $process = $this->execute($this->getGitCommand('show', array('%revision%' => escapeshellarg($revision))), sprintf('Unable to get logs for project "%s".', $this->project));
  94. return explode("\n", trim($process->getOutput()), 4);
  95. }
  96. protected function getGitCommand($command, array $replace = array())
  97. {
  98. $replace = array_merge(array(
  99. '%repo%' => escapeshellarg($this->project->getRepository()),
  100. '%dir%' => escapeshellarg($this->buildDir),
  101. '%branch%' => escapeshellarg('origin/'.$this->project->getBranch()),
  102. '%localbranch%' => escapeshellarg($this->project->getBranch()),
  103. '%format%' => '"%H%n%an%n%ci%n%s%n"',
  104. ), $replace);
  105. return strtr($this->gitPath.' '.$this->gitCmds[$command], $replace);
  106. }
  107. private function execute($command, $message)
  108. {
  109. if (null !== $this->callback) {
  110. call_user_func($this->callback, 'out', sprintf("Running \"%s\"\n", $command));
  111. }
  112. $process = new Process($command, $this->buildDir);
  113. $process->setTimeout(3600);
  114. $process->run($this->callback);
  115. if (!$process->isSuccessful()) {
  116. throw new BuildException($message);
  117. }
  118. return $process;
  119. }
  120. }
  121. // @codeCoverageIgnoreEnd