PageRenderTime 50ms CodeModel.GetById 21ms RepoModel.GetById 0ms app.codeStats 0ms

/app/vendors/fbollon/commands.php

http://fredistrano.googlecode.com/
PHP | 545 lines | 396 code | 79 blank | 70 comment | 100 complexity | b2837d3bc66d39a664416095f549abc7 MD5 | raw file
Possible License(s): LGPL-2.1
  1. <?php
  2. /* SVN FILE: $Id: commands.php 374 2009-10-12 21:49:11Z fbollon $ */
  3. /**
  4. * Wrap all used shell commands in a static PHP function
  5. *
  6. * PHP 5
  7. *
  8. * Licensed under The MIT License
  9. * Redistributions of files must retain the above copyright notice.
  10. *
  11. * @filesource
  12. * @link http://code.google.com/p/fredistrano
  13. * @package app
  14. * @subpackage app.vendors.fbollon
  15. * @version $Revision: 374 $
  16. * @modifiedby $Author: fbollon $
  17. * @lastmodified $Date: 2009-10-12 23:49:11 +0200 (Mon, 12 Oct 2009) $
  18. * @license http://www.opensource.org/licenses/mit-license.php The MIT License
  19. */
  20. /**
  21. * Wrap all used shell commands in a static PHP function
  22. *
  23. * @package app
  24. * @subpackage app.vendors.fbollon
  25. */
  26. class Utils {
  27. public static function computeDirMode( $fileMode, $options = array() ) {
  28. $fileMode = str_split($fileMode);
  29. $dirMode = '';
  30. for ($i=0; $i < 3; $i++) {
  31. if ($fileMode[$i] > 7) {
  32. $fileMode[$i] = 7;
  33. } elseif (!in_array($fileMode[$i], array(0,7))) {
  34. $fileMode[$i]++;
  35. }
  36. $dirMode .= $fileMode[$i];
  37. }
  38. return $dirMode;
  39. }// computeDirMode
  40. public static function getSvnRevisionFromOutput($output, $options = array() ) {
  41. preg_match('/ ([0-9]+)\.$/', $output, $matches);
  42. if (isset($matches[1])) {
  43. return $matches[1];
  44. } else {
  45. return false;
  46. }
  47. }// getRevisionFromOutput
  48. /**
  49. * Convert if necessary a path to a cygwin/linux format
  50. * @param string $path Path to be converted
  51. * @return string Converted path
  52. */
  53. public static function formatPath($path) {
  54. $pathForRsync = $path;
  55. if ( F_OS == 'WIN') {
  56. $pattern = '/^([A-Za-z]):/';
  57. preg_match($pattern, $path, $matches, PREG_OFFSET_CAPTURE);
  58. if (!empty ($matches[1][0])) {
  59. $windowsLetter = strtolower($matches[1][0]);
  60. $pathForRsync = strtr( Configure::read('Cygwin.rootDir') . $windowsLetter . substr($path, 2), "\\", "/");
  61. }
  62. }
  63. return $pathForRsync;
  64. }// formatPath
  65. }// FileSystemCommand
  66. class Action {
  67. public function initAction($name=null, $comment=null, $type=null, $options = array() ) {
  68. if ( isset($options['stepLog']) && get_class($options['stepLog']) == 'StepLog' ) {
  69. $actionLog = $options['stepLog']->addNewAction($name, $comment , $type);
  70. } else if ( isset($options['actionLog']) && get_class($options['actionLog']) == 'ActionLog' ) {
  71. $actionLog = $options['actionLog'];
  72. } else {
  73. $actionLog = new ActionLog($name, $comment , $type);
  74. }
  75. return $actionLog;
  76. }// initAction
  77. }// Action
  78. class PhpAction extends Action {
  79. // Create files list and directories list for chmod step
  80. public function createFilesListToChmod($output=null, $projectTmpDir=null, $target=null, $options = array()) {
  81. $actionLog = self::initAction('createFilesListToChmod', 'files_to_chmod.txt and dir_to_chmod.txt', 'PhpAction', $options);
  82. if (empty($output) || empty($projectTmpDir) || empty($target)) {
  83. $actionLog->error( sprintf(__('Missing working data', true)) );
  84. }
  85. $list = array_reverse(explode("\n", $output));
  86. $size = count($list);
  87. if ($size > 0) {
  88. $files_to_chmod = $projectTmpDir."files_to_chmod.txt";
  89. $dir_to_chmod = $projectTmpDir."dir_to_chmod.txt";
  90. $handle_f = fopen($files_to_chmod, "w");
  91. $handle_d = fopen($dir_to_chmod, "w");
  92. for ($i = 4; $i < $size ; $i++) {
  93. if (empty($list[$i]) || strpos($list[$i],'deleting ') !== false) {
  94. break;
  95. }
  96. if (is_file($target . $list[$i])) {
  97. $tmp_str = $list[$i];
  98. fwrite($handle_f, $target.str_replace(".".Configure::read('FileSystem.renameExt').".", ".", $list[$i]) . "\n");
  99. } else if (is_dir($target . $list[$i])){
  100. fwrite($handle_d, $target.$list[$i] . "\n");
  101. }
  102. }
  103. fclose($handle_f);
  104. fclose($handle_d);
  105. }
  106. // End action
  107. $actionLog->end();
  108. return $actionLog;
  109. }// createFilesListToChmod
  110. public static function loadConfig(& $config, $projectName = null, $options = array()) {
  111. $actionLog = self::initAction('loadConfig', null, 'PhpAction', $options);
  112. if (empty($projectName)) {
  113. $actionLog->error(__('Invalid project',true));
  114. }
  115. // Check new path
  116. $path = F_DEPLOYTMPDIR.$projectName.DS.'tmpDir'.DS.'.fredistrano'.DS.'deploy.php';
  117. if ( !file_exists( $path ) ) {
  118. $path = F_DEPLOYTMPDIR.$projectName.DS.'tmpDir'.DS.'deploy.php';
  119. if (!file_exists( $path )) {
  120. $actionLog->error( sprintf(__('Unable to find deploy.php', true)) );
  121. }
  122. }
  123. include_once($path);
  124. $config = new DEPLOY_CONFIG();
  125. // End action
  126. $actionLog->end();
  127. return $actionLog;
  128. }// loadConfig
  129. }// PhpAction
  130. class ShellAction extends Action {
  131. public static function changePermissions( $path=null, $mode=array(), $options = array() ) {
  132. $actionLog = self::initAction('resetPermission', null, 'ShellAction', $options);
  133. if (!is_array($mode)) {
  134. $mode = array(
  135. 'file' => $mode,
  136. 'dir' => Utils::computeDirMode($mode)
  137. );
  138. }
  139. // Check
  140. if ( is_null($path) || empty($mode) ) {
  141. $actionLog->error(sprintf(__('Forbidden NULL value for input parameter [%s;%s]',true),$path,$mode));
  142. }
  143. if (!file_exists($path)) {
  144. $actionLog->error(sprintf(__('Path [%s] not found',true),$path));
  145. }
  146. $path = Utils::formatPath($path);
  147. if (isset($mode['file'])) {
  148. // Change file mode
  149. $desc = sprintf(__('Reseting permissions files on %s',true),$path);
  150. $actionLog->description = $desc;
  151. $command = "find ".$path." -type f -exec chmod ".$mode['file']." {} \;";
  152. ShellAction::executeCommand( $command,
  153. array(
  154. 'directory' => $path,
  155. 'actionLog' => $actionLog
  156. )
  157. );
  158. }
  159. if (isset($mode['dir'])) {
  160. // Change directory mode
  161. $desc = sprintf(__('Resetting directories permissions on %s',true),$path);
  162. $actionLog->description = $desc;
  163. $command = "find ".$path." -type d -exec chmod ".$mode['dir']." {} \;";
  164. ShellAction::executeCommand( $command,
  165. array(
  166. 'directory' => $path,
  167. 'actionLog' => $actionLog
  168. )
  169. );
  170. }
  171. // Terminate action
  172. $actionLog->end();
  173. return $actionLog;
  174. }// changePermissions
  175. public static function createDirectory( $path=null, $mode=null, $options = array() ) {
  176. $comment = sprintf(__('Creating %s with mode %s',true),$path,$mode);
  177. $actionLog = self::initAction('createDirectory', $comment, 'ShellAction', $options);
  178. // Check
  179. if ( is_null($path) || is_null($mode) ) {
  180. $actionLog->error(sprintf(__('Forbidden NULL value for input parameter [%s;%s]',true),$path,$mode));
  181. } else if (is_dir($path)) {
  182. $actionLog->error(sprintf(__('Directory %s already exists',true),$path));
  183. }
  184. // Execute
  185. // $path = Utils::formatPath($path);
  186. if (!@mkdir($path, octdec( $mode ), TRUE)) {
  187. $actionLog->error( sprintf(__('Unable to create directory %s', true), $path) );
  188. }
  189. // Terminate action
  190. $actionLog->end();
  191. return $actionLog;
  192. }// createDirectory
  193. public static function executeCommand( $command = null, $options = array() ){
  194. $defaultOptions = array(
  195. 'comment' => null,
  196. 'directory' => null,
  197. 'commandForLog' => null
  198. );
  199. $options = array_merge($defaultOptions, $options);
  200. // Log management
  201. $actionLog = self::initAction('executeCommand', $options['comment'], 'ShellAction', $options);
  202. if ( !isset($options['actionLog']) || get_class($options['actionLog']) != 'ActionLog' ) {
  203. // Terminate log if passed in params
  204. $terminate = false;
  205. } else {
  206. $terminate = true;
  207. }
  208. // Check
  209. if ( is_null($command) ) {
  210. $actionLog->error(sprintf(__('Forbidden NULL value for input parameter [%s]',true),$command));
  211. }
  212. // Prepare command
  213. if ( F_OS == 'WIN' ) {
  214. if (!is_null($options['directory'])) {
  215. $cd = 'cd '.Utils::formatPath( $options['directory'] ).'; ';
  216. } else {
  217. $cd = '';
  218. }
  219. $prefix = "bash.exe --login -c \"".$cd;
  220. $suffix = "\"";
  221. } else {
  222. if (!is_null($options['directory'])) {
  223. chdir($options['directory']);
  224. }
  225. $prefix = "";
  226. $suffix = "";
  227. }
  228. // Execute command
  229. $output = utf8_encode(shell_exec($prefix.$command.$suffix));
  230. if (!is_null($options['commandForLog'])) {
  231. $commandForLog = $options['commandForLog'];
  232. }else{
  233. $commandForLog = $prefix.$command.$suffix;
  234. }
  235. $actionLog->saveCommand($commandForLog, $output);
  236. // End action
  237. if ($terminate) {
  238. $actionLog->end($output);
  239. }
  240. return $actionLog;
  241. }// executeCommand
  242. public static function remove( $path, $recursive = false , $options = array() ) {
  243. $comment = sprintf(__('Deleting content under %s (recursivity=%d)',true), $path, $recursive);
  244. $actionLog = self::initAction('remove', $comment, 'ShellAction', $options);
  245. // Check
  246. if (!is_dir($path)) {
  247. $actionLog->error( sprintf(__('Nothing to delete since no temporary files have been found', true)) );
  248. }
  249. // Execute command
  250. $path = Utils::formatPath($path);
  251. $recStr = $recursive?'r':'';
  252. $command = "rm -f".$recStr." ".$path;
  253. ShellAction::executeCommand( $command, array('actionLog' => $actionLog) );
  254. // End action
  255. $actionLog->end();
  256. return $actionLog;
  257. }// remove
  258. public static function runScript( $type, $projectTmpDir, $scriptPath, $options ) {
  259. $comment = sprintf(__('Executing script %s',true), $scriptPath);
  260. $actionLog = self::initAction('runScript', $comment, 'ShellAction', $options);
  261. if (!isset($scriptPath) || !$scriptPath) {
  262. $actionLog->error( sprintf(__('Script not found', true)) );
  263. }
  264. // Run script
  265. if ($options['run'.ucfirst($type).'Script']) {
  266. if (!file_exists($scriptPath) && file_exists($projectTmpDir.'tmpDir'.DS.'.fredistrano'.DS.$scriptPath)) {
  267. $scriptPath = $projectTmpDir.'tmpDir'.DS.'.fredistrano'.DS.$scriptPath;
  268. } else if (!file_exists($scriptPath)){
  269. $actionLog->error( __('Script not found', true) );
  270. }
  271. $formatedScriptPath = Utils::formatPath($scriptPath);
  272. if (!is_executable($scriptPath)) {
  273. $log = ShellAction::executeCommand( "chmod u+x $formatedScriptPath",
  274. array(
  275. 'comment' => __('Execution privileges to script',true),
  276. 'actionLog' => $actionLog
  277. )
  278. );
  279. }
  280. ShellAction::executeCommand( $formatedScriptPath,
  281. array(
  282. 'comment' => sprintf(__('%s script',true), $type),
  283. 'actionLog' => $actionLog
  284. )
  285. );
  286. }
  287. // End action
  288. $actionLog->end();
  289. return $actionLog;
  290. }// runScript
  291. public static function synchronizeContent( $source = null, $target = null, $options = array ()) {
  292. $comment = sprintf(__('Synchronizing %s with %s',true),$source,$target);
  293. $actionLog = self::initAction('synchronizeContent', $comment, 'ShellAction', $options);
  294. // Setting up Rsync options
  295. if ($options['simulation'] === true) {
  296. // Simulation mode
  297. $option = 'rtvn';
  298. } else {
  299. // Live mode
  300. $option = 'rtv';
  301. }
  302. $optionalOptions = Configure::read('Rsync.optionalOptions');
  303. if (!empty($optionalOptions)) {
  304. $option .= $optionalOptions;
  305. }
  306. // Execute command
  307. $excludeFileName = Utils::formatPath( $options['exclude'] );
  308. $source = Utils::formatPath( $source );
  309. $target = Utils::formatPath( $target );
  310. $command = "rsync -$option --delete --exclude-from=$excludeFileName $source $target 2>&1";
  311. ShellAction::executeCommand( $command, array('actionLog' => $actionLog));
  312. // End action
  313. $actionLog->end();
  314. return $actionLog;
  315. }// synchronizeContent
  316. }//
  317. class SvnAction extends Action {
  318. public static function checkout( $svnUrl = null, $path = null, $targetDir = null, $options = array() ) {
  319. $actionLog = self::initAction('checkout',$svnUrl,'SvnAction',$options);
  320. $configDirectory = '';
  321. // Check
  322. if ( is_null($svnUrl) || is_null($path) || is_null($targetDir)) {
  323. $actionLog->error(sprintf(__('Forbidden NULL value for input parameter [%s;%s;%s]',true),$svnUrl,$path,$targetDir));
  324. } else if (!is_dir($path)) {
  325. $actionLog->error(sprintf(__('Directory %s not found',true),$path));
  326. } else if (is_dir($path.DS.$targetDir)) {
  327. $actionLog->error(sprintf(__('Delete target %s directory first',true), $path.DS.$targetDir));
  328. }
  329. // Define step options
  330. $default_options = array(
  331. 'revision' => null,
  332. 'user_svn' => null,
  333. 'password_svn' => null,
  334. 'configDirectory' => null,
  335. 'parseResponse' => false
  336. );
  337. $options = array_merge($default_options, $options);
  338. // Execute command
  339. $path = Utils::formatPath($path);
  340. $revision = !is_null($options['revision'])?' -r' . $options['revision']:'';
  341. $authentication = '';
  342. if (!is_null($options['user_svn'])) {
  343. $authentication .= '--username '.$options['user_svn'];
  344. if (!empty($options['password_svn'])) {
  345. $authentication .= ' --password '.$options['password_svn'];
  346. }
  347. }
  348. if (!is_null($options['configDirectory'])) {
  349. $configDirectory = '--config-dir '.Utils::formatPath( $options['configDirectory'] );
  350. }
  351. $command = "svn checkout --non-interactive $configDirectory $revision $authentication $svnUrl $targetDir 2>&1";
  352. $commandForLog = "svn checkout --non-interactive $configDirectory $revision XXXX $svnUrl $targetDir 2>&1";
  353. ShellAction::executeCommand( $command,
  354. array(
  355. 'directory' => $path,
  356. 'actionLog' => $actionLog,
  357. 'commandForLog' => $commandForLog
  358. )
  359. );
  360. // Parse output
  361. if ( !(strpos( $actionLog->getResult() , 'PROPFIND request failed on' ) === false) && $options['parseResponse'] ) {
  362. $actionLog->error(__('An error has been detected in the SVN output',true));
  363. }
  364. // End action
  365. $actionLog->end();
  366. return $actionLog;
  367. }// checkout
  368. public static function export( $svnUrl = null, $path = null, $targetDir = null, $options = array() ) {
  369. $actionLog = self::initAction('export',$svnUrl,'SvnAction',$options);
  370. $configDirectory = '';
  371. if ( is_null($svnUrl) || is_null($path) || is_null($targetDir)) {
  372. $actionLog->error(sprintf(__('Forbidden NULL value for input parameter [%s;%s;%s]',true),$svnUrl,$path,$targetDir));
  373. } else if (!is_dir($path)) {
  374. $actionLog->error(sprintf(__('Directory %s not found',true),$path));
  375. } else if (is_dir($path.DS.$targetDir)) {
  376. $actionLog->error(sprintf(__('Delete target %s directory first',true), $path.DS.$targetDir));
  377. }
  378. // Define step options
  379. $default_options = array(
  380. 'revision' => null,
  381. 'user_svn' => null,
  382. 'password_svn' => null,
  383. 'configDirectory' => null,
  384. 'parseResponse' => false
  385. );
  386. $options = array_merge($default_options, $options);
  387. // Execute command
  388. $path = Utils::formatPath($path);
  389. $revision = !is_null($options['revision'])?' -r' . $options['revision']:'';
  390. $authentication = '';
  391. if (!is_null($options['user_svn'])) {
  392. $authentication .= '--username '.$options['user_svn'];
  393. if (!empty($options['password_svn'])) {
  394. $authentication .= ' --password '.$options['password_svn'];
  395. }
  396. }
  397. if (!is_null($options['configDirectory'])) {
  398. $configDirectory = '--config-dir '.Utils::formatPath( $options['configDirectory'] );
  399. }
  400. $command = "svn export --non-interactive $configDirectory $revision $authentication $svnUrl $targetDir 2>&1";
  401. $commandForLog = "svn export --non-interactive $configDirectory $revision XXXX $svnUrl $targetDir 2>&1";
  402. ShellAction::executeCommand( $command,
  403. array(
  404. 'directory' => $path,
  405. 'actionLog' => $actionLog,
  406. 'commandForLog' => $commandForLog
  407. )
  408. );
  409. // Parse output
  410. if ( !(strpos( $actionLog->getResult() , 'PROPFIND request failed on' ) === false) && $options['parseResponse'] ) {
  411. $actionLog->error(__('An error has been detected in the SVN output',true));
  412. }
  413. // End action
  414. $actionLog->end();
  415. return $actionLog;
  416. }// export
  417. public static function update( $projectDir, $options = array() ) {
  418. $actionLog = self::initAction('update',$projectDir,'SvnAction',$options);
  419. $configDirectory = '';
  420. if ( is_null($projectDir) ) {
  421. $actionLog->error(sprintf(__('Forbidden NULL value for input parameter [%s]',true),$projectDir));
  422. } else if (!is_dir($projectDir) ) {
  423. $actionLog->error(sprintf(__('Directory %s not found',true), $projectDir));
  424. } else if ( !is_dir($projectDir.DS.'.svn') ) {
  425. $actionLog->error(sprintf(__('Specified directory %s is not a working copy',true), $projectDir.DS.'.svn'));
  426. } else if ( !is_writeable($projectDir) ) {
  427. $actionLog->error(sprintf(__('Specified directory %s is not writeable',true), $projectDir));
  428. }
  429. // Define step options
  430. $default_options = array(
  431. 'revision' => null,
  432. 'configDirectory' => null,
  433. 'parseResponse' => false
  434. );
  435. $options = array_merge($default_options, $options);
  436. // Execute command
  437. $projectDir = Utils::formatPath($projectDir);
  438. $revision = ($options['revision']!=null)?' -r' . $options['revision']:'';
  439. $authentication = '';
  440. if (!is_null($options['user_svn'])) {
  441. $authentication .= '--username '.$options['user_svn'];
  442. if (!empty($options['password_svn'])) {
  443. $authentication .= ' --password '.$options['password_svn'];
  444. }
  445. }
  446. if (!is_null($options['configDirectory'])) {
  447. $configDirectory = '--config-dir '.Utils::formatPath( $options['configDirectory'] );
  448. }
  449. $command = "svn update --non-interactive $configDirectory $revision $authentication 2>&1";
  450. $commandForLog = "svn update --non-interactive $configDirectory $revision XXXX 2>&1";
  451. ShellAction::executeCommand( $command, array(
  452. 'directory' => $projectDir,
  453. 'actionLog' => $actionLog,
  454. 'commandForLog' => $commandForLog
  455. )
  456. );
  457. // Parse response
  458. if ( !(strpos( $actionLog->getResult() , 'PROPFIND request failed on' ) === false) && $options['parseResponse'] ) {
  459. $actionLog->error(__('An error has been detected in the SVN output',true));
  460. }
  461. // End action
  462. $actionLog->end();
  463. return $actionLog;
  464. }// update
  465. }// SvnAction
  466. ?>