DeployPackage.php 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272
  1. <?php
  2. /**
  3. * Copyright © Magento, Inc. All rights reserved.
  4. * See COPYING.txt for license details.
  5. */
  6. namespace Magento\Deploy\Service;
  7. use Magento\Deploy\Package\Package;
  8. use Magento\Deploy\Package\PackageFile;
  9. use Magento\Framework\App\State as AppState;
  10. use Magento\Framework\Locale\ResolverInterface as LocaleResolver;
  11. use Magento\Framework\View\Asset\ContentProcessorException;
  12. use Magento\Deploy\Console\InputValidator;
  13. use Psr\Log\LoggerInterface;
  14. /**
  15. * Deploy package service
  16. */
  17. class DeployPackage
  18. {
  19. /**
  20. * Application state object
  21. *
  22. * Allows to switch between different application areas
  23. *
  24. * @var AppState
  25. */
  26. private $appState;
  27. /**
  28. * Locale resolver interface
  29. *
  30. * Check if given locale code is a valid one
  31. *
  32. * @var LocaleResolver
  33. */
  34. private $localeResolver;
  35. /**
  36. * Service for deploying static files
  37. *
  38. * @var DeployStaticFile
  39. */
  40. private $deployStaticFile;
  41. /**
  42. * Logger interface
  43. *
  44. * @var LoggerInterface
  45. */
  46. private $logger;
  47. /**
  48. * Total count of processed files
  49. *
  50. * @var int
  51. */
  52. private $count = 0;
  53. /**
  54. * Total count of the errors
  55. *
  56. * @var int
  57. */
  58. private $errorsCount = 0;
  59. /**
  60. * DeployPackage constructor
  61. *
  62. * @param AppState $appState
  63. * @param LocaleResolver $localeResolver
  64. * @param DeployStaticFile $deployStaticFile
  65. * @param LoggerInterface $logger
  66. */
  67. public function __construct(
  68. AppState $appState,
  69. LocaleResolver $localeResolver,
  70. DeployStaticFile $deployStaticFile,
  71. LoggerInterface $logger
  72. ) {
  73. $this->appState = $appState;
  74. $this->localeResolver = $localeResolver;
  75. $this->deployStaticFile = $deployStaticFile;
  76. $this->logger = $logger;
  77. }
  78. /**
  79. * Execute package deploy procedure
  80. *
  81. * @param Package $package
  82. * @param array $options
  83. * @param bool $skipLogging
  84. * @return bool true on success
  85. */
  86. public function deploy(Package $package, array $options, $skipLogging = false)
  87. {
  88. $result = $this->appState->emulateAreaCode(
  89. $package->getArea() === Package::BASE_AREA ? 'global' : $package->getArea(),
  90. function () use ($package, $options, $skipLogging) {
  91. // emulate application locale needed for correct file path resolving
  92. $this->localeResolver->setLocale($package->getLocale());
  93. $this->deployEmulated($package, $options, $skipLogging);
  94. }
  95. );
  96. $package->setState(Package::STATE_COMPLETED);
  97. return $result;
  98. }
  99. /**
  100. * @param Package $package
  101. * @param array $options
  102. * @param bool $skipLogging
  103. * @return bool
  104. */
  105. public function deployEmulated(Package $package, array $options, $skipLogging = false)
  106. {
  107. $this->count = 0;
  108. $this->errorsCount = 0;
  109. $this->register($package, null, $skipLogging);
  110. /** @var PackageFile $file */
  111. foreach ($package->getFiles() as $file) {
  112. $fileId = $file->getDeployedFileId();
  113. ++$this->count;
  114. $this->register($package, $file, $skipLogging);
  115. if ($this->checkFileSkip($fileId, $options)) {
  116. continue;
  117. }
  118. try {
  119. $this->processFile($file, $package);
  120. } catch (ContentProcessorException $exception) {
  121. $errorMessage = __('Compilation from source: ')
  122. . $file->getSourcePath()
  123. . PHP_EOL . $exception->getMessage();
  124. $this->errorsCount++;
  125. $this->logger->critical($errorMessage);
  126. } catch (\Exception $exception) {
  127. $this->logger->critical($exception->getTraceAsString());
  128. $this->errorsCount++;
  129. }
  130. }
  131. // execute package post-processors (may adjust content of deployed files, or produce derivative files)
  132. foreach ($package->getPostProcessors() as $processor) {
  133. $processor->process($package, $options);
  134. }
  135. return true;
  136. }
  137. /**
  138. * Apply proper deployment action
  139. *
  140. * File can be created if content is already provided, or copied from parent package or published
  141. *
  142. * @param PackageFile $file
  143. * @param Package $package
  144. * @return void
  145. */
  146. private function processFile(PackageFile $file, Package $package)
  147. {
  148. if ($file->getContent()) {
  149. $this->deployStaticFile->writeFile(
  150. $file->getDeployedFileName(),
  151. $package->getPath(),
  152. $file->getContent()
  153. );
  154. } else {
  155. $parentPackage = $package->getParent();
  156. if ($this->checkIfCanCopy($file, $package, $parentPackage)) {
  157. $this->deployStaticFile->copyFile(
  158. $file->getDeployedFileId(),
  159. $parentPackage->getPath(),
  160. $package->getPath()
  161. );
  162. } else {
  163. $this->deployStaticFile->deployFile(
  164. $file->getFileName(),
  165. [
  166. 'area' => $package->getArea(),
  167. 'theme' => $package->getTheme(),
  168. 'locale' => $package->getLocale(),
  169. 'module' => $file->getModule(),
  170. ]
  171. );
  172. }
  173. }
  174. }
  175. /**
  176. * Check if file can be copied from parent package
  177. *
  178. * @param PackageFile $file
  179. * @param Package $package
  180. * @param Package $parentPackage
  181. * @return bool
  182. */
  183. private function checkIfCanCopy(PackageFile $file, Package $package, Package $parentPackage = null)
  184. {
  185. return $parentPackage
  186. && $file->getOrigPackage() !== $package
  187. && (
  188. $file->getArea() !== $package->getArea()
  189. || $file->getTheme() !== $package->getTheme()
  190. || $file->getLocale() !== $package->getLocale()
  191. )
  192. && $file->getOrigPackage() === $parentPackage
  193. && $this->deployStaticFile->readFile($file->getDeployedFileId(), $parentPackage->getPath());
  194. }
  195. /**
  196. * Check if file can be deployed
  197. *
  198. * @param string $filePath
  199. * @param array $options
  200. * @return boolean
  201. */
  202. private function checkFileSkip($filePath, array $options)
  203. {
  204. if ($filePath !== '.') {
  205. $ext = strtolower(pathinfo($filePath, PATHINFO_EXTENSION));
  206. $basename = pathinfo($filePath, PATHINFO_BASENAME);
  207. if ($ext === 'less' && strpos($basename, '_') === 0) {
  208. return true;
  209. }
  210. $option = isset(InputValidator::$fileExtensionOptionMap[$ext])
  211. ? InputValidator::$fileExtensionOptionMap[$ext]
  212. : null;
  213. return $option ? (isset($options[$option]) ? $options[$option] : false) : false;
  214. }
  215. return false;
  216. }
  217. /**
  218. * Add operation to log and package info files
  219. *
  220. * @param Package $package
  221. * @param PackageFile|null $file
  222. * @param bool $skipLogging
  223. * @return void
  224. */
  225. private function register(Package $package, PackageFile $file = null, $skipLogging = false)
  226. {
  227. $logMessage = '.';
  228. if ($file) {
  229. $logMessage = "Processing file '{$file->getSourcePath()}'";
  230. if ($file->getArea()) {
  231. $logMessage .= " for area '{$file->getArea()}'";
  232. }
  233. if ($file->getTheme()) {
  234. $logMessage .= ", theme '{$file->getTheme()}'";
  235. }
  236. if ($file->getLocale()) {
  237. $logMessage .= ", locale '{$file->getLocale()}'";
  238. }
  239. if ($file->getModule()) {
  240. $logMessage .= "module '{$file->getModule()}'";
  241. }
  242. }
  243. $info = [
  244. 'count' => $this->count,
  245. 'last' => $file ? $file->getSourcePath() : ''
  246. ];
  247. $this->deployStaticFile->writeTmpFile('info.json', $package->getPath(), json_encode($info));
  248. if (!$skipLogging) {
  249. $this->logger->info($logMessage);
  250. }
  251. }
  252. }