1. sfProjectDeployTask.class.php
  2. /** * Deploys a project to another server. * * @package symfony * @subpackage task * @author Fabien Potencier * @version SVN: $Id: sfProjectDeployTask.class.php 23922 2009-11-14 14:58:38Z fabien $ */
  3. class sfProjectDeployTask extends sfBaseTask
  4. {
  5. protected
  6. $outputBuffer = '',
  7. $errorBuffer = '';
  8. /**
  9. * @see sfTask
  10. */
  11. protected function configure()
  12. {
  13. $this->addArguments(array(
  14. new sfCommandArgument('server', sfCommandArgument::REQUIRED, 'The server name'),
  15. ));
  16. $this->addOptions(array(
  17. new sfCommandOption('go', null, sfCommandOption::PARAMETER_NONE, 'Do the deployment'),
  18. new sfCommandOption('rsync-dir', null, sfCommandOption::PARAMETER_REQUIRED, 'The directory where to look for rsync*.txt files', 'config'),
  19. new sfCommandOption('rsync-options', null, sfCommandOption::PARAMETER_OPTIONAL, 'To options to pass to the rsync executable', '-azC --force --delete --progress'),
  20. ));
  21. $this->namespace = 'project';
  22. $this->name = 'deploy';
  23. $this->briefDescription = 'Deploys a project to another server';
  24. $this->detailedDescription = <<<EOF
  25. The [project:deploy|INFO] task deploys a project on a server:
  26. [./symfony project:deploy production|INFO]
  27. The server must be configured in [config/properties.ini|COMMENT]:
  28. [[production]
  29. host=www.example.com
  30. port=22
  31. user=fabien
  32. dir=/var/www/sfblog/
  33. type=rsync|INFO]
  34. To automate the deployment, the task uses rsync over SSH.
  35. You must configure SSH access with a key or configure the password
  36. in [config/properties.ini|COMMENT].
  37. By default, the task is in dry-mode. To do a real deployment, you
  38. must pass the [--go|COMMENT] option:
  39. [./symfony project:deploy --go production|INFO]
  40. Files and directories configured in [config/rsync_exclude.txt|COMMENT] are
  41. not deployed:
  42. [.svn
  43. /web/uploads/*
  44. /cache/*
  45. /log/*|INFO]
  46. You can also create a [rsync.txt|COMMENT] and [rsync_include.txt|COMMENT] files.
  47. If you need to customize the [rsync*.txt|COMMENT] files based on the server,
  48. you can pass a [rsync-dir|COMMENT] option:
  49. [./symfony project:deploy --go --rsync-dir=config/production production|INFO]
  50. Last, you can specify the options passed to the rsync executable, using the
  51. [rsync-options|INFO] option (defaults are [-azC --force --delete --progress|INFO]):
  52. [./symfony project:deploy --go --rsync-options=-avz|INFO]
  53. EOF;
  54. }
  55. /**
  56. * @see sfTask
  57. */
  58. protected function execute($arguments = array(), $options = array())
  59. {
  60. $env = $arguments['server'];
  61. $ini = sfConfig::get('sf_config_dir').'/properties.ini';
  62. if (!file_exists($ini))
  63. {
  64. throw new sfCommandException('You must create a config/properties.ini file');
  65. }
  66. $properties = parse_ini_file($ini, true);
  67. if (!isset($properties[$env]))
  68. {
  69. throw new sfCommandException(sprintf('You must define the configuration for server "%s" in config/properties.ini', $env));
  70. }
  71. $properties = $properties[$env];
  72. if (!isset($properties['host']))
  73. {
  74. throw new sfCommandException('You must define a "host" entry.');
  75. }
  76. if (!isset($properties['dir']))
  77. {
  78. throw new sfCommandException('You must define a "dir" entry.');
  79. }
  80. $host = $properties['host'];
  81. $dir = $properties['dir'];
  82. $user = isset($properties['user']) ? $properties['user'].'@' : '';
  83. if (substr($dir, -1) != '/')
  84. {
  85. $dir .= '/';
  86. }
  87. $ssh = 'ssh';
  88. if (isset($properties['port']))
  89. {
  90. $port = $properties['port'];
  91. $ssh = '"ssh -p'.$port.'"';
  92. }
  93. if (isset($properties['parameters']))
  94. {
  95. $parameters = $properties['parameters'];
  96. }
  97. else
  98. {
  99. $parameters = $options['rsync-options'];
  100. if (file_exists($options['rsync-dir'].'/rsync_exclude.txt'))
  101. {
  102. $parameters .= sprintf(' --exclude-from=%s/rsync_exclude.txt', $options['rsync-dir']);
  103. }
  104. if (file_exists($options['rsync-dir'].'/rsync_include.txt'))
  105. {
  106. $parameters .= sprintf(' --include-from=%s/rsync_include.txt', $options['rsync-dir']);
  107. }
  108. if (file_exists($options['rsync-dir'].'/rsync.txt'))
  109. {
  110. $parameters .= sprintf(' --files-from=%s/rsync.txt', $options['rsync-dir']);
  111. }
  112. }
  113. $dryRun = $options['go'] ? '' : '--dry-run';
  114. $command = "rsync $dryRun $parameters -e $ssh ./ $user$host:$dir";
  115. $this->getFilesystem()->execute($command, $options['trace'] ? array($this, 'logOutput') : null, array($this, 'logErrors'));
  116. $this->clearBuffers();
  117. }
  118. public function logOutput($output)
  119. {
  120. if (false !== $pos = strpos($output, "\n"))
  121. {
  122. $this->outputBuffer .= substr($output, 0, $pos);
  123. $this->log($this->outputBuffer);
  124. $this->outputBuffer = substr($output, $pos + 1);
  125. }
  126. else
  127. {
  128. $this->outputBuffer .= $output;
  129. }
  130. }
  131. public function logErrors($output)
  132. {
  133. if (false !== $pos = strpos($output, "\n"))
  134. {
  135. $this->errorBuffer .= substr($output, 0, $pos);
  136. $this->log($this->formatter->format($this->errorBuffer, 'ERROR'));
  137. $this->errorBuffer = substr($output, $pos + 1);
  138. }
  139. else
  140. {
  141. $this->errorBuffer .= $output;
  142. }
  143. }
  144. protected function clearBuffers()
  145. {
  146. if ($this->outputBuffer)
  147. {
  148. $this->log($this->outputBuffer);
  149. $this->outputBuffer = '';
  150. }
  151. if ($this->errorBuffer)
  152. {
  153. $this->log($this->formatter->format($this->errorBuffer, 'ERROR'));
  154. $this->errorBuffer = '';
  155. }
  156. }
  157. }

Debug toolbar