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

/script/lib/PHP_CodeBrowser/CLIController.php

https://bitbucket.org/chamilo/chamilo/
PHP | 464 lines | 253 code | 47 blank | 164 comment | 24 complexity | 340a25063804b95b5a72b705faa676e7 MD5 | raw file
Possible License(s): GPL-2.0, BSD-3-Clause, LGPL-2.1, LGPL-3.0, GPL-3.0, MIT
  1. <?php
  2. /**
  3. * Cli controller
  4. *
  5. * PHP Version 5.3.2
  6. *
  7. * Copyright (c) 2007-2010, Mayflower GmbH
  8. * All rights reserved.
  9. *
  10. * Redistribution and use in source and binary forms, with or without
  11. * modification, are permitted provided that the following conditions
  12. * are met:
  13. *
  14. * * Redistributions of source code must retain the above copyright
  15. * notice, this list of conditions and the following disclaimer.
  16. *
  17. * * Redistributions in binary form must reproduce the above copyright
  18. * notice, this list of conditions and the following disclaimer in
  19. * the documentation and/or other materials provided with the
  20. * distribution.
  21. *
  22. * * Neither the name of Mayflower GmbH nor the names of his
  23. * contributors may be used to endorse or promote products derived
  24. * from this software without specific prior written permission.
  25. *
  26. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  27. * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  28. * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
  29. * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
  30. * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
  31. * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
  32. * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  33. * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
  34. * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  35. * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
  36. * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  37. * POSSIBILITY OF SUCH DAMAGE.
  38. *
  39. * @category PHP_CodeBrowser
  40. * @package PHP_CodeBrowser
  41. * @author Elger Thiele <elger.thiele@mayflower.de>
  42. * @author Simon Kohlmeyer <simon.kohlmeyer@mayflower.de>
  43. * @copyright 2007-2010 Mayflower GmbH
  44. * @license http://www.opensource.org/licenses/bsd-license.php BSD License
  45. * @version SVN: $Id$
  46. * @link http://www.phpunit.de/
  47. * @since File available since 0.1.0
  48. */
  49. if (!defined('PHPCB_ROOT_DIR')) {
  50. define('PHPCB_ROOT_DIR', dirname(__FILE__) . '/');
  51. }
  52. if (!defined('PHPCB_TEMPLATE_DIR')) {
  53. define('PHPCB_TEMPLATE_DIR', dirname(__FILE__) . '/../templates');
  54. }
  55. require_once dirname(__FILE__) . '/Util/Autoloader.php';
  56. require_once 'Console/CommandLine.php';
  57. require_once 'File/Iterator/Factory.php';
  58. require_once 'Log.php';
  59. /**
  60. * CbCLIController
  61. *
  62. * @category PHP_CodeBrowser
  63. * @package PHP_CodeBrowser
  64. * @author Elger Thiele <elger.thiele@mayflower.de>
  65. * @author Michel Hartmann <michel.hartmann@mayflower.de>
  66. * @author Simon Kohlmeyer <simon.kohlmeyer@mayflower.de>
  67. * @copyright 2007-2010 Mayflower GmbH
  68. * @license http://www.opensource.org/licenses/bsd-license.php BSD License
  69. * @version Release: 0.9.1
  70. * @link http://www.phpunit.de/
  71. * @since Class available since 0.1.0
  72. */
  73. class CbCLIController
  74. {
  75. /**
  76. * Path to the Cruise Control input xml file
  77. *
  78. * @var string
  79. */
  80. private $_logDir;
  81. /**
  82. * Path to the code browser html output folder
  83. *
  84. * @var string
  85. */
  86. private $_htmlOutputDir;
  87. /**
  88. * Path to the project source code files
  89. *
  90. * @var string
  91. */
  92. private $_projectSource;
  93. /**
  94. * Array of PCREs. Matching files will not appear in the output.
  95. *
  96. * @var Array
  97. */
  98. private $_excludeExpressions;
  99. /**
  100. * Array of glob patterns. Matching files will not appear in the output.
  101. *
  102. * @var Array
  103. */
  104. private $_excludePatterns;
  105. /**
  106. * The error plugin classes
  107. *
  108. * @var array
  109. */
  110. private $_registeredPlugins;
  111. /**
  112. * The IOHelper used for filesystem interaction.
  113. *
  114. * @var CbIOHelper
  115. */
  116. private $_ioHelper;
  117. /**
  118. * Pear Log object where debug output should go to.
  119. *
  120. * @var Log
  121. */
  122. private $_debugLog;
  123. /**
  124. * The constructor
  125. *
  126. * Standard setters are initialized
  127. *
  128. * @param string $logPath The (path-to) xml log files. Can be null.
  129. * @param Array $projectSource The project sources. Can be null.
  130. * @param string $htmlOutputDir The html output dir, where new files will
  131. * be created
  132. * @param Array $excludeExpressions
  133. * A list of PCREs. Files matching will not
  134. * appear in the output.
  135. * @param Array $excludePatterns A list of glob patterns. Files matching
  136. * will not appear in the output.
  137. * @param CbIOHelper $ioHelper The CbIOHelper object to be used for
  138. * filesystem interaction.
  139. */
  140. public function __construct($logPath, Array $projectSource,
  141. $htmlOutputDir, Array $excludeExpressions,
  142. Array $excludePatterns, $ioHelper, $debugLog)
  143. {
  144. $this->_logDir = $logPath;
  145. $this->_projectSource = $projectSource;
  146. $this->_htmlOutputDir = $htmlOutputDir;
  147. $this->_excludeExpressions = $excludeExpressions;
  148. $this->_excludePatterns = $excludePatterns;
  149. $this->_ioHelper = $ioHelper;
  150. $this->_debugLog = $debugLog;
  151. }
  152. /**
  153. * Setter/adder method for the used plugin classes.
  154. * For each plugin to use, add it to this array
  155. *
  156. * @param mixed $classNames Definition of plugin classes
  157. *
  158. * @return void
  159. */
  160. public function addErrorPlugins($classNames)
  161. {
  162. foreach ((array) $classNames as $className) {
  163. $this->_registeredPlugins[] = $className;
  164. }
  165. }
  166. /**
  167. * Main execute function for PHP_CodeBrowser.
  168. *
  169. * Following steps are resolved:
  170. * 1. Clean-up output directory
  171. * 2. Merge xml log files
  172. * 3. Generate cbXML file via errorlist from plugins
  173. * 4. Save the cbErrorList as XML file
  174. * 5. Generate HTML output from cbXML
  175. * 6. Copy ressources (css, js, images) from template directory to output
  176. *
  177. * @return void
  178. */
  179. public function run()
  180. {
  181. // clear and create output directory
  182. if (is_dir($this->_htmlOutputDir)) {
  183. $this->_ioHelper->deleteDirectory($this->_htmlOutputDir);
  184. } else if (is_file($this->_htmlOutputDir)) {
  185. $this->_ioHelper->deleteFile($this->_htmlOutputDir);
  186. }
  187. $this->_ioHelper->createDirectory($this->_htmlOutputDir);
  188. // init needed classes
  189. $cbViewReview = new CbViewReview(
  190. PHPCB_TEMPLATE_DIR,
  191. $this->_htmlOutputDir,
  192. $this->_ioHelper
  193. );
  194. $sourceHandler = new CbSourceHandler($this->_debugLog);
  195. if (isset($this->_logDir)) {
  196. $cbIssueXml = new CbIssueXml();
  197. // merge xml files
  198. $cbIssueXml->addDirectory($this->_logDir);
  199. // conversion of XML file cc to cb format
  200. foreach ($this->_registeredPlugins as $className) {
  201. $sourceHandler->addPlugin(new $className($cbIssueXml));
  202. }
  203. }
  204. if (isset($this->_projectSource)) {
  205. foreach ($this->_projectSource as $source) {
  206. if (is_dir($source)) {
  207. $sourceHandler->addSourceFiles(
  208. File_Iterator_Factory::getFileIterator(
  209. $source, array('php','js','css', 'html')
  210. )
  211. );
  212. } else {
  213. $sourceHandler->addSourceFile($source);
  214. }
  215. }
  216. }
  217. array_walk(
  218. $this->_excludeExpressions,
  219. array($sourceHandler, 'excludeMatchingPCRE')
  220. );
  221. array_walk(
  222. $this->_excludePatterns,
  223. array($sourceHandler, 'excludeMatchingPattern')
  224. );
  225. $files = $sourceHandler->getFiles();
  226. if (!$files) {
  227. $cbViewReview->copyNoErrorsIndex();
  228. } else {
  229. // Get the path prefix all files have in common
  230. $commonPathPrefix = $sourceHandler->getCommonPathPrefix();
  231. foreach ($files as $file) {
  232. $cbViewReview->generate(
  233. $file->getIssues(),
  234. $file->name(),
  235. $commonPathPrefix
  236. );
  237. }
  238. // Copy needed ressources (eg js libraries) to output directory
  239. $cbViewReview->copyRessourceFolders();
  240. $cbViewReview->generateIndex($files);
  241. }
  242. }
  243. /**
  244. * Main method called by script
  245. *
  246. * @return void
  247. */
  248. public static function main()
  249. {
  250. // register autoloader
  251. spl_autoload_register(array(new CbAutoloader(), 'autoload'));
  252. $parser = self::createCommandLineParser();
  253. try {
  254. $opts = $parser->parse()->options;
  255. } catch (Exception $e) {
  256. $parser->displayError($e->getMessage());
  257. }
  258. $errors = self::errorsForOpts($opts);
  259. if ($errors) {
  260. foreach ($errors as $e) {
  261. error_log("[Error] $e\n");
  262. }
  263. exit(1);
  264. }
  265. // init new CLIController
  266. $controller = new CbCLIController(
  267. $opts['log'],
  268. isset($opts['source']) ? $opts['source'] : array(),
  269. $opts['output'],
  270. isset($opts['excludePCRE']) ? $opts['excludePCRE'] : array(),
  271. isset($opts['excludePattern']) ? $opts['excludePattern'] : array(),
  272. new CbIOHelper(),
  273. $opts['debugExcludes']
  274. ? Log::factory('console', '', 'PHPCB')
  275. : Log::factory('null')
  276. );
  277. $controller->addErrorPlugins(
  278. array(
  279. 'CbErrorCheckstyle',
  280. 'CbErrorPMD',
  281. 'CbErrorCPD',
  282. 'CbErrorPadawan',
  283. 'CbErrorCoverage',
  284. 'CbErrorCRAP'
  285. )
  286. );
  287. try {
  288. $controller->run();
  289. } catch (Exception $e) {
  290. error_log(
  291. <<<HERE
  292. [Error] {$e->getMessage()}
  293. {$e->getTraceAsString()}
  294. HERE
  295. );
  296. }
  297. }
  298. /**
  299. * Checks the given options array for errors.
  300. *
  301. * @param Array Options as returned by Console_CommandLine->parse()
  302. *
  303. * @return Array of String Errormessages.
  304. */
  305. private static function errorsForOpts($opts)
  306. {
  307. $errors = array();
  308. if (!isset($opts['log'])) {
  309. if (!isset($opts['source'])) {
  310. $errors[] = 'Missing log or source argument.';
  311. }
  312. } else if (!file_exists($opts['log'])) {
  313. $errors[] = 'Log directory does not exist.';
  314. } else if (!is_dir($opts['log'])) {
  315. $errors[] = 'Log argument must be a directory, a file was given.';
  316. }
  317. if (!isset($opts['output'])) {
  318. $errors[] = 'Missing output argument.';
  319. } else if (file_exists($opts['output']) && !is_dir($opts['output'])) {
  320. $errors[] = 'Ouput argument must be a directory, a file was given.';
  321. }
  322. if (isset($opts['source'])) {
  323. foreach ($opts['source'] as $s) {
  324. if (!file_exists($s)) {
  325. $errors[] = "Source '$s' does not exist";
  326. }
  327. }
  328. }
  329. return $errors;
  330. }
  331. /**
  332. * Creates a Console_CommandLine object to parse options.
  333. *
  334. * @return Console_CommandLine
  335. */
  336. private static function createCommandLineParser()
  337. {
  338. $parser = new Console_CommandLine(
  339. array(
  340. 'description' => 'A Code browser for PHP files with syntax '
  341. . 'highlighting and colored error-sections '
  342. . 'found by quality assurance tools like '
  343. . 'PHPUnit or PHP_CodeSniffer.',
  344. 'version' => (strpos('0.9.1', '@') === false)
  345. ? '0.9.1'
  346. : 'from Git'
  347. )
  348. );
  349. $parser->addOption(
  350. 'log',
  351. array(
  352. 'description' => 'The path to the xml log files, e.g. generated'
  353. . ' from PHPUnit. Either this or --source '
  354. . 'must be given',
  355. 'short_name' => '-l',
  356. 'long_name' => '--log'
  357. )
  358. );
  359. $parser->addOption(
  360. 'output',
  361. array(
  362. 'description' => 'Path to the output folder where generated '
  363. . 'files should be stored.',
  364. 'short_name' => '-o',
  365. 'long_name' => '--output'
  366. )
  367. );
  368. $parser->addOption(
  369. 'source',
  370. array(
  371. 'description' => 'Path to the project source code. Can either '
  372. . 'be a directory or a single file. Parse '
  373. . 'complete source directory if set, else '
  374. . 'only files found in logs. Either this or'
  375. . ' --log must be given. Can be given '
  376. . 'multiple times',
  377. 'short_name' => '-s',
  378. 'long_name' => '--source',
  379. 'action' => 'StoreArray'
  380. )
  381. );
  382. $parser->addOption(
  383. 'excludePattern',
  384. array(
  385. 'description' => 'Excludes all files matching the given glob '
  386. . 'pattern. This is done after pulling the '
  387. . 'files in the source dir in if one is '
  388. . 'given. Can be given multiple times. Note'
  389. . ' that the match is run against '
  390. . 'absolute filenames.',
  391. 'short_name' => '-e',
  392. 'long_name' => '--exclude',
  393. 'action' => 'StoreArray'
  394. )
  395. );
  396. $parser->addOption(
  397. 'excludePCRE',
  398. array(
  399. 'description' => 'Works like -e but takes PCRE instead of '
  400. . 'glob patterns.',
  401. 'short_name' => '-E',
  402. 'long_name' => '--excludePCRE',
  403. 'action' => 'StoreArray'
  404. )
  405. );
  406. $parser->addOption(
  407. 'debugExcludes',
  408. array(
  409. 'description' => 'Print which files are excluded by which '
  410. . 'expressions and patterns.',
  411. 'long_name' => '--debugExcludes',
  412. 'action' => 'StoreTrue'
  413. )
  414. );
  415. return $parser;
  416. }
  417. }