/_piecrust/src/PieCrust/Baker/DirectoryBaker.php

https://github.com/hdonnay/site · PHP · 174 lines · 151 code · 11 blank · 12 comment · 21 complexity · dbaee310bfc82de2e095be6fe77a7c3e MD5 · raw file

  1. <?php
  2. namespace PieCrust\Baker;
  3. use \Exception;
  4. use \DirectoryIterator;
  5. use PieCrust\PieCrust;
  6. use PieCrust\PieCrustException;
  7. use PieCrust\Util\PluginLoader;
  8. /**
  9. * A class responsible for baking non-PieCrust content.
  10. */
  11. class DirectoryBaker
  12. {
  13. protected $pieCrust;
  14. protected $rootDirLength;
  15. protected $bakeDir;
  16. protected $parameters;
  17. protected $processorsLoader;
  18. /**
  19. * Gets the PluginLoader for the file processors.
  20. */
  21. public function getProcessorsLoader()
  22. {
  23. if ($this->processorsLoader === null)
  24. {
  25. $processorsToFilter = $this->parameters['processors'];
  26. $this->processorsLoader = new PluginLoader(
  27. 'PieCrust\\Baker\\Processors\\IProcessor',
  28. PieCrust::APP_DIR . '/Baker/Processors',
  29. function ($p1, $p2) { return $p1->getPriority() < $p2->getPriority(); },
  30. $processorsToFilter == '*' ?
  31. null :
  32. function ($p) use ($processorsToFilter) { return in_array($p->getName(), $processorsToFilter); },
  33. 'SimpleFileProcessor.php'
  34. );
  35. foreach ($this->processorsLoader->getPlugins() as $proc)
  36. {
  37. $proc->initialize($this->pieCrust);
  38. }
  39. }
  40. return $this->processorsLoader;
  41. }
  42. /**
  43. * Creates a new instance of DirectoryBaker.
  44. */
  45. public function __construct(PieCrust $pieCrust, $bakeDir, array $parameters = array())
  46. {
  47. $this->pieCrust = $pieCrust;
  48. $this->bakeDir = rtrim(str_replace(array('/', '\\'), DIRECTORY_SEPARATOR, $bakeDir), '/\\') . DIRECTORY_SEPARATOR;
  49. $this->parameters = array_merge(
  50. array(
  51. 'smart' => true,
  52. 'skip_patterns' => array(),
  53. 'processors' => array('copy')
  54. ),
  55. $parameters
  56. );
  57. $rootDir = $this->pieCrust->getRootDir();
  58. $this->rootDirLength = strlen($rootDir);
  59. if (!is_dir($this->bakeDir) or !is_writable($this->bakeDir))
  60. {
  61. throw new PieCrustException('The bake directory is not writable, or does not exist: ' . $this->bakeDir);
  62. }
  63. }
  64. /**
  65. * Bakes the given directory and all its files and sub-directories.
  66. */
  67. public function bake()
  68. {
  69. $this->bakeDirectory($this->pieCrust->getRootDir(), 0);
  70. }
  71. protected function bakeDirectory($currentDir, $level)
  72. {
  73. $it = new DirectoryIterator($currentDir);
  74. foreach ($it as $i)
  75. {
  76. if ($i->isDot())
  77. {
  78. continue;
  79. }
  80. if ($i->getPathname() . DIRECTORY_SEPARATOR == $this->bakeDir)
  81. {
  82. continue;
  83. }
  84. $shouldSkip = false;
  85. foreach ($this->parameters['skip_patterns'] as $p)
  86. {
  87. if (preg_match($p, $i->getFilename()))
  88. {
  89. $shouldSkip = true;
  90. break;
  91. }
  92. }
  93. if ($shouldSkip) continue;
  94. $relative = substr($i->getPathname(), $this->rootDirLength);
  95. if ($i->isDir())
  96. {
  97. $destination = $this->bakeDir . $relative;
  98. if (!is_dir($destination))
  99. {
  100. @mkdir($destination, 0777, true);
  101. }
  102. $this->bakeDirectory($i->getPathname(), $level + 1);
  103. }
  104. else if ($i->isFile())
  105. {
  106. $fileProcessor = null;
  107. foreach ($this->getProcessorsLoader()->getPlugins() as $proc)
  108. {
  109. if ($proc->supportsExtension(pathinfo($i->getFilename(), PATHINFO_EXTENSION)))
  110. {
  111. $fileProcessor = $proc;
  112. break;
  113. }
  114. }
  115. if ($fileProcessor != null)
  116. {
  117. $isUpToDate = false;
  118. $destinationDir = $this->bakeDir . dirname($relative) . DIRECTORY_SEPARATOR;
  119. $outputFilenames = $fileProcessor->getOutputFilenames($i->getFilename());
  120. if (!is_array($outputFilenames))
  121. {
  122. $outputFilenames = array($outputFilenames);
  123. }
  124. if ($this->parameters['smart'])
  125. {
  126. $isUpToDate = true;
  127. foreach ($outputFilenames as $f)
  128. {
  129. $destination = $destinationDir . $f;
  130. if (!is_file($destination) or $i->getMTime() >= filemtime($destination))
  131. {
  132. $isUpToDate = false;
  133. break;
  134. }
  135. }
  136. }
  137. if (!$isUpToDate)
  138. {
  139. $previousErrorHandler = set_error_handler('piecrust_error_handler');
  140. try
  141. {
  142. $start = microtime(true);
  143. $fileProcessor->process($i->getPathname(), $destinationDir);
  144. echo PieCrustBaker::formatTimed($start, $relative) . PHP_EOL;
  145. }
  146. catch (Exception $e)
  147. {
  148. throw new PieCrustException("Error processing '" . $relative . "': " . $e->getMessage());
  149. }
  150. if ($previousErrorHandler)
  151. {
  152. set_error_handler($previousErrorHandler);
  153. }
  154. }
  155. }
  156. else
  157. {
  158. echo "Warning: no processor for " . $relative . PHP_EOL;
  159. }
  160. }
  161. }
  162. }
  163. }