You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

284 lines
7.0KB

  1. <?php
  2. /*
  3. * This file is part of the Fxp Composer Asset Plugin package.
  4. *
  5. * (c) François Pluchino <francois.pluchino@gmail.com>
  6. *
  7. * For the full copyright and license information, please view the LICENSE
  8. * file that was distributed with this source code.
  9. */
  10. namespace Fxp\Composer\AssetPlugin\Package\Loader;
  11. use Composer\Downloader\TransportException;
  12. use Composer\EventDispatcher\EventDispatcher;
  13. use Composer\IO\IOInterface;
  14. use Composer\Package\CompletePackageInterface;
  15. use Composer\Package\Loader\LoaderInterface;
  16. use Composer\Repository\Vcs\VcsDriverInterface;
  17. use Fxp\Composer\AssetPlugin\AssetEvents;
  18. use Fxp\Composer\AssetPlugin\Event\VcsRepositoryEvent;
  19. use Fxp\Composer\AssetPlugin\Package\LazyPackageInterface;
  20. use Fxp\Composer\AssetPlugin\Type\AssetTypeInterface;
  21. /**
  22. * Lazy loader for asset package.
  23. *
  24. * @author François Pluchino <francois.pluchino@gmail.com>
  25. */
  26. class LazyAssetPackageLoader implements LazyLoaderInterface
  27. {
  28. /**
  29. * @var string
  30. */
  31. protected $type;
  32. /**
  33. * @var string
  34. */
  35. protected $identifier;
  36. /**
  37. * @var array
  38. */
  39. protected $packageData;
  40. /**
  41. * @var AssetTypeInterface
  42. */
  43. protected $assetType;
  44. /**
  45. * @var LoaderInterface
  46. */
  47. protected $loader;
  48. /**
  49. * @var VcsDriverInterface
  50. */
  51. protected $driver;
  52. /**
  53. * @var IOInterface
  54. */
  55. protected $io;
  56. /**
  57. * @var EventDispatcher
  58. */
  59. protected $dispatcher;
  60. /**
  61. * @var bool
  62. */
  63. protected $verbose;
  64. /**
  65. * @var array
  66. */
  67. protected $cache;
  68. /**
  69. * Constructor.
  70. *
  71. * @param string $identifier
  72. * @param string $type
  73. * @param array $packageData
  74. */
  75. public function __construct($type, $identifier, array $packageData)
  76. {
  77. $this->identifier = $identifier;
  78. $this->type = $type;
  79. $this->packageData = $packageData;
  80. $this->verbose = false;
  81. $this->cache = array();
  82. }
  83. /**
  84. * Sets the asset type.
  85. *
  86. * @param AssetTypeInterface $assetType
  87. */
  88. public function setAssetType(AssetTypeInterface $assetType)
  89. {
  90. $this->assetType = $assetType;
  91. }
  92. /**
  93. * Sets the laoder.
  94. *
  95. * @param LoaderInterface $loader
  96. */
  97. public function setLoader(LoaderInterface $loader)
  98. {
  99. $this->loader = $loader;
  100. }
  101. /**
  102. * Sets the driver.
  103. *
  104. * @param VcsDriverInterface $driver
  105. */
  106. public function setDriver(VcsDriverInterface $driver)
  107. {
  108. $this->driver = $driver;
  109. }
  110. /**
  111. * Sets the IO.
  112. *
  113. * @param IOInterface $io
  114. */
  115. public function setIO(IOInterface $io)
  116. {
  117. $this->io = $io;
  118. $this->verbose = $io->isVerbose();
  119. }
  120. /**
  121. * Sets the event dispatcher.
  122. *
  123. * @param EventDispatcher $dispatcher
  124. */
  125. public function setEventDispatcher(EventDispatcher $dispatcher)
  126. {
  127. $this->dispatcher = $dispatcher;
  128. }
  129. /**
  130. * {@inheritdoc}
  131. */
  132. public function load(LazyPackageInterface $package)
  133. {
  134. if (isset($this->cache[$package->getUniqueName()])) {
  135. return $this->cache[$package->getUniqueName()];
  136. }
  137. $this->validateConfig();
  138. $filename = $this->assetType->getFilename();
  139. $msg = 'Reading '.$filename.' of <info>'.$package->getName().'</info> (<comment>'.$package->getPrettyVersion().'</comment>)';
  140. if ($this->verbose) {
  141. $this->io->write($msg);
  142. } else {
  143. $this->io->overwrite($msg, false);
  144. }
  145. $realPackage = $this->loadRealPackage($package);
  146. $this->cache[$package->getUniqueName()] = $realPackage;
  147. if (!$this->verbose) {
  148. $this->io->overwrite('', false);
  149. }
  150. return $realPackage;
  151. }
  152. /**
  153. * Validates the class config.
  154. *
  155. * @throws \InvalidArgumentException When the property of this class is not defined
  156. */
  157. protected function validateConfig()
  158. {
  159. foreach (array('assetType', 'loader', 'driver', 'io') as $property) {
  160. if (null === $this->$property) {
  161. throw new \InvalidArgumentException(sprintf('The "%s" property must be defined', $property));
  162. }
  163. }
  164. }
  165. /**
  166. * Loads the real package.
  167. *
  168. * @param LazyPackageInterface $package
  169. *
  170. * @return CompletePackageInterface|false
  171. */
  172. protected function loadRealPackage(LazyPackageInterface $package)
  173. {
  174. $realPackage = false;
  175. try {
  176. $data = $this->driver->getComposerInformation($this->identifier);
  177. $valid = is_array($data);
  178. $data = $this->preProcess($this->driver, $this->validateData($data), $this->identifier);
  179. if ($this->verbose) {
  180. $this->io->write('Importing '.($valid ? '' : 'empty ').$this->type.' '.$data['version'].' ('.$data['version_normalized'].')');
  181. }
  182. /* @var CompletePackageInterface $realPackage */
  183. $realPackage = $this->loader->load($data);
  184. } catch (\Exception $e) {
  185. if ($this->verbose) {
  186. $filename = $this->assetType->getFilename();
  187. $this->io->write('<'.$this->getIoTag().'>Skipped '.$this->type.' '.$package->getPrettyVersion().', '.($e instanceof TransportException ? 'no '.$filename.' file was found' : $e->getMessage()).'</'.$this->getIoTag().'>');
  188. }
  189. }
  190. $this->driver->cleanup();
  191. return $realPackage;
  192. }
  193. /**
  194. * @param array|bool $data
  195. *
  196. * @return array
  197. */
  198. protected function validateData($data)
  199. {
  200. return is_array($data) ? $data : array();
  201. }
  202. /**
  203. * Gets the tag name for IO.
  204. *
  205. * @return string
  206. */
  207. protected function getIoTag()
  208. {
  209. return 'branch' === $this->type ? 'error' : 'warning';
  210. }
  211. /**
  212. * Pre process the data of package before the conversion to Package instance.
  213. *
  214. * @param VcsDriverInterface $driver
  215. * @param array $data
  216. * @param string $identifier
  217. *
  218. * @return array
  219. */
  220. protected function preProcess(VcsDriverInterface $driver, array $data, $identifier)
  221. {
  222. $vcsRepos = array();
  223. $data = array_merge($data, $this->packageData);
  224. $data = $this->assetType->getPackageConverter()->convert($data, $vcsRepos);
  225. $this->dispatchAddVcsEvent($vcsRepos);
  226. if (!isset($data['dist'])) {
  227. $data['dist'] = $driver->getDist($identifier);
  228. }
  229. if (!isset($data['source'])) {
  230. $data['source'] = $driver->getSource($identifier);
  231. }
  232. return (array) $data;
  233. }
  234. /**
  235. * Dispatches the vcs repositories event.
  236. *
  237. * @param array $vcsRepos
  238. */
  239. protected function dispatchAddVcsEvent(array $vcsRepos)
  240. {
  241. if (null !== $this->dispatcher) {
  242. $event = new VcsRepositoryEvent(AssetEvents::ADD_VCS_REPOSITORIES, $vcsRepos);
  243. $this->dispatcher->dispatch($event->getName(), $event);
  244. }
  245. }
  246. }