PageRenderTime 103ms CodeModel.GetById 28ms RepoModel.GetById 0ms app.codeStats 0ms

/vendor/magento/magento-composer-installer/src/MagentoHackathon/Composer/Magento/Deploystrategy/DeploystrategyAbstract.php

https://gitlab.com/yousafsyed/easternglamor
PHP | 402 lines | 179 code | 42 blank | 181 comment | 15 complexity | cd596d8242492f142235067c2fd6603a MD5 | raw file
  1. <?php
  2. /**
  3. * Composer Magento Installer
  4. */
  5. namespace MagentoHackathon\Composer\Magento\Deploystrategy;
  6. /**
  7. * Abstract deploy strategy
  8. */
  9. abstract class DeploystrategyAbstract
  10. {
  11. /**
  12. * The path mappings to map project's directories to magento's directory structure
  13. *
  14. * @var array
  15. */
  16. protected $mappings = array();
  17. /**
  18. * The current mapping of the deployment iteration
  19. *
  20. * @var array
  21. */
  22. protected $currentMapping = array();
  23. /**
  24. * The List of entries which files should not get deployed
  25. *
  26. * @var array
  27. */
  28. protected $ignoredMappings = array();
  29. /**
  30. * The magento installation's base directory
  31. *
  32. * @var string
  33. */
  34. protected $destDir;
  35. /**
  36. * The module's base directory
  37. *
  38. * @var string
  39. */
  40. protected $sourceDir;
  41. /**
  42. * If set overrides existing files
  43. *
  44. * @var bool
  45. */
  46. protected $isForced = false;
  47. /**
  48. * Constructor
  49. *
  50. * @param string $sourceDir
  51. * @param string $destDir
  52. */
  53. public function __construct($sourceDir, $destDir)
  54. {
  55. $this->destDir = $destDir;
  56. $this->sourceDir = $sourceDir;
  57. }
  58. /**
  59. * Executes the deployment strategy for each mapping
  60. *
  61. * @return \MagentoHackathon\Composer\Magento\Deploystrategy\DeploystrategyAbstract
  62. */
  63. public function deploy()
  64. {
  65. foreach ($this->getMappings() as $data) {
  66. list ($source, $dest) = $data;
  67. $this->setCurrentMapping($data);
  68. $this->create($source, $dest);
  69. }
  70. return $this;
  71. }
  72. /**
  73. * Removes the module's files in the given path from the target dir
  74. *
  75. * @return \MagentoHackathon\Composer\Magento\Deploystrategy\DeploystrategyAbstract
  76. */
  77. public function clean()
  78. {
  79. foreach ($this->getMappings() as $data) {
  80. list ($source, $dest) = $data;
  81. $this->remove($source, $dest);
  82. $this->rmEmptyDirsRecursive(dirname($dest), $this->getDestDir());
  83. }
  84. return $this;
  85. }
  86. /**
  87. * Returns the destination dir of the magento module
  88. *
  89. * @return string
  90. */
  91. protected function getDestDir()
  92. {
  93. return $this->destDir;
  94. }
  95. /**
  96. * Returns the current path of the extension
  97. *
  98. * @return mixed
  99. */
  100. protected function getSourceDir()
  101. {
  102. return $this->sourceDir;
  103. }
  104. /**
  105. * If set overrides existing files
  106. *
  107. * @return bool
  108. */
  109. public function isForced()
  110. {
  111. return $this->isForced;
  112. }
  113. /**
  114. * Setter for isForced property
  115. *
  116. * @param bool $forced
  117. */
  118. public function setIsForced($forced = true)
  119. {
  120. $this->isForced = (bool) $forced;
  121. }
  122. /**
  123. * Returns the path mappings to map project's directories to magento's directory structure
  124. *
  125. * @return array
  126. */
  127. public function getMappings()
  128. {
  129. return $this->mappings;
  130. }
  131. /**
  132. * Sets path mappings to map project's directories to magento's directory structure
  133. *
  134. * @param array $mappings
  135. */
  136. public function setMappings(array $mappings)
  137. {
  138. $this->mappings = $mappings;
  139. }
  140. /**
  141. * Gets the current mapping used on the deployment iteration
  142. *
  143. * @return array
  144. */
  145. public function getCurrentMapping()
  146. {
  147. return $this->currentMapping;
  148. }
  149. /**
  150. * Sets the current mapping used on the deployment iteration
  151. *
  152. * @param array $mapping
  153. */
  154. public function setCurrentMapping($mapping)
  155. {
  156. $this->currentMapping = $mapping;
  157. }
  158. /**
  159. * sets the current ignored mappings
  160. *
  161. * @param $ignoredMappings
  162. */
  163. public function setIgnoredMappings($ignoredMappings)
  164. {
  165. $this->ignoredMappings = $ignoredMappings;
  166. }
  167. /**
  168. * gets the current ignored mappings
  169. *
  170. * @return array
  171. */
  172. public function getIgnoredMappings()
  173. {
  174. return $this->ignoredMappings;
  175. }
  176. /**
  177. * @param string $destination
  178. *
  179. * @return bool
  180. */
  181. protected function isDestinationIgnored($destination)
  182. {
  183. $destination = '/'.$destination;
  184. $destination = str_replace('/./','/', $destination);
  185. $destination = str_replace('//','/', $destination);
  186. foreach($this->ignoredMappings as $ignored){
  187. if( 0 === strpos($ignored,$destination) ){
  188. return true;
  189. }
  190. }
  191. return false;
  192. }
  193. /**
  194. * Add a key value pair to mapping
  195. */
  196. public function addMapping($key, $value)
  197. {
  198. $this->mappings[] = array($key, $value);
  199. }
  200. protected function removeTrailingSlash($path)
  201. {
  202. return rtrim($path, ' \\/');
  203. }
  204. /**
  205. * Normalize mapping parameters using a glob wildcard.
  206. *
  207. * Delegate the creation of the module's files in the given destination.
  208. *
  209. * @param string $source
  210. * @param string $dest
  211. * @throws \ErrorException
  212. * @return bool
  213. */
  214. public function create($source, $dest)
  215. {
  216. if($this->isDestinationIgnored($dest)){
  217. return;
  218. }
  219. $sourcePath = $this->getSourceDir() . '/' . $this->removeTrailingSlash($source);
  220. $destPath = $this->getDestDir() . '/' . $dest;
  221. /* List of possible cases, keep around for now, might come in handy again
  222. Assume app/etc exists, app/etc/a does not exist unless specified differently
  223. dir app/etc/a/ --> link app/etc/a to dir
  224. dir app/etc/a --> link app/etc/a to dir
  225. dir app/etc/ --> link app/etc/dir to dir
  226. dir app/etc --> link app/etc/dir to dir
  227. dir/* app/etc --> for each dir/$file create a target link in app/etc
  228. dir/* app/etc/ --> for each dir/$file create a target link in app/etc
  229. dir/* app/etc/a --> for each dir/$file create a target link in app/etc/a
  230. dir/* app/etc/a/ --> for each dir/$file create a target link in app/etc/a
  231. file app/etc --> link app/etc/file to file
  232. file app/etc/ --> link app/etc/file to file
  233. file app/etc/a --> link app/etc/a to file
  234. file app/etc/a --> if app/etc/a is a file throw exception unless force is set, in that case rm and see above
  235. file app/etc/a/ --> link app/etc/a/file to file regardless if app/etc/a exists or not
  236. */
  237. // Create target directory if it ends with a directory separator
  238. if (! file_exists($destPath) && in_array(substr($destPath, -1), array('/', '\\')) && ! is_dir($sourcePath)) {
  239. mkdir($destPath, 0777, true);
  240. $destPath = $this->removeTrailingSlash($destPath);
  241. }
  242. // If source doesn't exist, check if it's a glob expression, otherwise we have nothing we can do
  243. if (!file_exists($sourcePath)) {
  244. // Handle globing
  245. $matches = glob($sourcePath);
  246. if ($matches) {
  247. foreach ($matches as $match) {
  248. $newDest = substr($destPath . '/' . basename($match), strlen($this->getDestDir()));
  249. $newDest = ltrim($newDest, ' \\/');
  250. $this->create(substr($match, strlen($this->getSourceDir())+1), $newDest);
  251. }
  252. return true;
  253. }
  254. // Source file isn't a valid file or glob
  255. throw new \ErrorException("Source $sourcePath does not exist");
  256. }
  257. return $this->createDelegate($source, $dest);
  258. }
  259. /**
  260. * Remove (unlink) the destination file
  261. *
  262. * @param string $source
  263. * @param string $dest
  264. * @throws \ErrorException
  265. */
  266. public function remove($source, $dest)
  267. {
  268. $sourcePath = $this->getSourceDir() . '/' . $this->removeTrailingSlash($source);
  269. $destPath = $this->getDestDir() . '/' . $dest;
  270. // If source doesn't exist, check if it's a glob expression, otherwise we have nothing we can do
  271. if (!file_exists($sourcePath)) {
  272. // Handle globing
  273. $matches = glob($sourcePath);
  274. if ($matches) {
  275. foreach ($matches as $match) {
  276. $newDest = substr($destPath . '/' . basename($match), strlen($this->getDestDir()));
  277. $newDest = ltrim($newDest, ' \\/');
  278. $this->remove(substr($match, strlen($this->getSourceDir())+1), $newDest);
  279. }
  280. return;
  281. }
  282. // Source file isn't a valid file or glob
  283. throw new \ErrorException("Source $sourcePath does not exist");
  284. }
  285. // MP Avoid removing whole folders in case the modman file is not 100% well-written
  286. // e.g. app/etc/modules/Testmodule.xml app/etc/modules/ installs correctly, but would otherwise delete the whole app/etc/modules folder!
  287. if (basename($sourcePath) !== basename($destPath)) {
  288. $destPath .= '/' . basename($source);
  289. }
  290. self::rmdirRecursive($destPath);
  291. }
  292. /**
  293. * Remove an empty directory branch up to $stopDir, or stop at the first non-empty parent.
  294. *
  295. * @param string $dir
  296. * @param string $stopDir
  297. */
  298. public function rmEmptyDirsRecursive($dir, $stopDir = null)
  299. {
  300. $absoluteDir = $this->getDestDir() . '/' . $dir;
  301. if (is_dir($absoluteDir)) {
  302. $iterator = new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($absoluteDir),
  303. \RecursiveIteratorIterator::CHILD_FIRST);
  304. foreach ($iterator as $item) {
  305. $path = (string) $item;
  306. if (!strcmp($path, '.') || !strcmp($path, '..')) {
  307. continue;
  308. }
  309. // The directory contains something, do not remove
  310. return;
  311. }
  312. // RecursiveIteratorIterator have opened handle on $absoluteDir
  313. // that cause Windows to block the directory and not remove it until
  314. // the iterator will be destroyed.
  315. unset($iterator);
  316. // The specified directory is empty
  317. if (@rmdir($absoluteDir)) {
  318. // If the parent directory doesn't match the $stopDir and it's empty, remove it, too
  319. $parentDir = dirname($dir);
  320. $absoluteParentDir = $this->getDestDir() . '/' . $parentDir;
  321. if (! isset($stopDir) || (realpath($stopDir) !== realpath($absoluteParentDir))) {
  322. // Remove the parent directory if it is empty
  323. $this->rmEmptyDirsRecursive($parentDir);
  324. }
  325. }
  326. }
  327. }
  328. /**
  329. * Recursively removes the specified directory or file
  330. *
  331. * @param $dir
  332. */
  333. public static function rmdirRecursive($dir)
  334. {
  335. $fs = new \Composer\Util\Filesystem();
  336. if(is_dir($dir)){
  337. $result = $fs->removeDirectory($dir);
  338. }else{
  339. @unlink($dir);
  340. }
  341. return;
  342. }
  343. /**
  344. * Create the module's files in the given destination.
  345. *
  346. * NOTE: source and dest have to be passed as relative directories, like they are listed in the mapping
  347. *
  348. * @param string $source
  349. * @param string $dest
  350. * @return bool
  351. */
  352. abstract protected function createDelegate($source, $dest);
  353. }