選択できるのは25トピックまでです。 トピックは、先頭が英数字で、英数字とダッシュ('-')を使用した35文字以内のものにしてください。

235 行
7.2KB

  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;
  11. use Composer\Composer;
  12. use Composer\DependencyResolver\Pool;
  13. use Composer\EventDispatcher\EventSubscriberInterface;
  14. use Composer\Installer\InstallerEvent;
  15. use Composer\Installer\InstallerEvents;
  16. use Composer\IO\IOInterface;
  17. use Composer\Plugin\CommandEvent;
  18. use Composer\Plugin\PluginEvents;
  19. use Composer\Plugin\PluginInterface;
  20. use Composer\Repository\InstalledFilesystemRepository;
  21. use Composer\Repository\RepositoryInterface;
  22. use Composer\Repository\RepositoryManager;
  23. use Fxp\Composer\AssetPlugin\Event\VcsRepositoryEvent;
  24. use Fxp\Composer\AssetPlugin\Repository\VcsPackageFilter;
  25. use Fxp\Composer\AssetPlugin\Repository\Util;
  26. use Fxp\Composer\AssetPlugin\Util\AssetPlugin;
  27. /**
  28. * Composer plugin.
  29. *
  30. * @author François Pluchino <francois.pluchino@gmail.com>
  31. */
  32. class FxpAssetPlugin implements PluginInterface, EventSubscriberInterface
  33. {
  34. /**
  35. * @var Composer
  36. */
  37. protected $composer;
  38. /**
  39. * @var IOInterface
  40. */
  41. protected $io;
  42. /**
  43. * @var RepositoryInterface[]
  44. */
  45. protected $repos = array();
  46. /**
  47. * @var Pool
  48. */
  49. protected $pool;
  50. /**
  51. * @var VcsPackageFilter
  52. */
  53. protected $packageFilter;
  54. /**
  55. * {@inheritdoc}
  56. */
  57. public static function getSubscribedEvents()
  58. {
  59. return array(
  60. AssetEvents::ADD_VCS_REPOSITORIES => array(
  61. array('onAddVcsRepositories', 0),
  62. ),
  63. PluginEvents::COMMAND => array(
  64. array('onPluginCommand', 0),
  65. ),
  66. InstallerEvents::PRE_DEPENDENCIES_SOLVING => array(
  67. array('onPreDependenciesSolving', 0),
  68. ),
  69. );
  70. }
  71. /**
  72. * {@inheritdoc}
  73. */
  74. public function activate(Composer $composer, IOInterface $io)
  75. {
  76. /* @var InstalledFilesystemRepository $installedRepository */
  77. $installedRepository = $composer->getRepositoryManager()->getLocalRepository();
  78. $this->composer = $composer;
  79. $this->io = $io;
  80. $this->packageFilter = new VcsPackageFilter($composer->getPackage(), $composer->getInstallationManager(), $installedRepository);
  81. $extra = $composer->getPackage()->getExtra();
  82. $rm = $composer->getRepositoryManager();
  83. AssetPlugin::addRegistryRepositories($rm, $this->packageFilter, $extra);
  84. AssetPlugin::setVcsTypeRepositories($rm);
  85. if (isset($extra['asset-repositories']) && is_array($extra['asset-repositories'])) {
  86. $this->addRepositories($rm, $extra['asset-repositories']);
  87. }
  88. AssetPlugin::addInstallers($composer, $io);
  89. }
  90. /**
  91. * Adds vcs repositories in manager from asset dependencies with url version.
  92. *
  93. * @param VcsRepositoryEvent $event
  94. */
  95. public function onAddVcsRepositories(VcsRepositoryEvent $event)
  96. {
  97. if (null !== $this->composer) {
  98. $rm = $this->composer->getRepositoryManager();
  99. $this->addRepositories($rm, $event->getRepositories(), $this->pool);
  100. }
  101. }
  102. /**
  103. * Disable the package filter for all command, but for install and update command.
  104. *
  105. * @param CommandEvent $event
  106. */
  107. public function onPluginCommand(CommandEvent $event)
  108. {
  109. if (!in_array($event->getCommandName(), array('install', 'update'))) {
  110. $this->packageFilter->setEnabled(false);
  111. }
  112. }
  113. /**
  114. * Add pool in plugin.
  115. *
  116. * @param InstallerEvent $event
  117. */
  118. public function onPreDependenciesSolving(InstallerEvent $event)
  119. {
  120. $this->pool = $event->getPool();
  121. }
  122. /**
  123. * Adds asset vcs repositories.
  124. *
  125. * @param RepositoryManager $rm
  126. * @param array $repositories
  127. * @param Pool|null $pool
  128. *
  129. * @throws \UnexpectedValueException When config of repository is not an array
  130. * @throws \UnexpectedValueException When the config of repository has not a type defined
  131. * @throws \UnexpectedValueException When the config of repository has an invalid type
  132. */
  133. protected function addRepositories(RepositoryManager $rm, array $repositories, Pool $pool = null)
  134. {
  135. foreach ($repositories as $index => $repo) {
  136. $this->validateRepositories($index, $repo);
  137. if ('package' === $repo['type']) {
  138. $name = $repo['package']['name'];
  139. } else {
  140. $name = is_int($index) ? preg_replace('{^https?://}i', '', $repo['url']) : $index;
  141. $name = isset($repo['name']) ? $repo['name'] : $name;
  142. $repo['vcs-package-filter'] = $this->packageFilter;
  143. }
  144. Util::addRepository($this->io, $rm, $this->repos, $name, $repo, $pool);
  145. }
  146. }
  147. /**
  148. * Validates the config of repositories.
  149. *
  150. * @param int|string $index The index
  151. * @param mixed|array $repo The config repo
  152. *
  153. * @throws \UnexpectedValueException
  154. */
  155. protected function validateRepositories($index, $repo)
  156. {
  157. if (!is_array($repo)) {
  158. throw new \UnexpectedValueException('Repository '.$index.' ('.json_encode($repo).') should be an array, '.gettype($repo).' given');
  159. }
  160. if (!isset($repo['type'])) {
  161. throw new \UnexpectedValueException('Repository '.$index.' ('.json_encode($repo).') must have a type defined');
  162. }
  163. $this->validatePackageRepositories($index, $repo);
  164. $this->validateVcsRepositories($index, $repo);
  165. }
  166. /**
  167. * Validates the config of package repositories.
  168. *
  169. * @param int|string $index The index
  170. * @param mixed|array $repo The config repo
  171. *
  172. * @throws \UnexpectedValueException
  173. */
  174. protected function validatePackageRepositories($index, $repo)
  175. {
  176. if ('package' !== $repo['type']) {
  177. return;
  178. }
  179. if (!isset($repo['package'])) {
  180. throw new \UnexpectedValueException('Repository '.$index.' ('.json_encode($repo).') must have a package definition"');
  181. }
  182. foreach (array('name', 'type', 'version', 'dist') as $key) {
  183. if (!isset($repo['package'][$key])) {
  184. throw new \UnexpectedValueException('Repository '.$index.' ('.json_encode($repo).') must have the "'.$key.'" key in the package definition"');
  185. }
  186. }
  187. }
  188. /**
  189. * Validates the config of vcs repositories.
  190. *
  191. * @param int|string $index The index
  192. * @param mixed|array $repo The config repo
  193. *
  194. * @throws \UnexpectedValueException
  195. */
  196. protected function validateVcsRepositories($index, $repo)
  197. {
  198. if ('package' === $repo['type']) {
  199. return;
  200. }
  201. if (false === strpos($repo['type'], '-')) {
  202. throw new \UnexpectedValueException('Repository '.$index.' ('.json_encode($repo).') must have a type defined in this way: "%asset-type%-%type%"');
  203. }
  204. if (!isset($repo['url'])) {
  205. throw new \UnexpectedValueException('Repository '.$index.' ('.json_encode($repo).') must have a url defined');
  206. }
  207. }
  208. }