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.

297 lines
8.6KB

  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\Repository;
  11. use Composer\Config;
  12. use Composer\EventDispatcher\EventDispatcher;
  13. use Composer\IO\IOInterface;
  14. use Composer\Package\AliasPackage;
  15. use Composer\Package\Loader\ArrayLoader;
  16. use Composer\Package\Loader\LoaderInterface;
  17. use Composer\Package\Package;
  18. use Composer\Package\PackageInterface;
  19. use Composer\Repository\Vcs\VcsDriverInterface;
  20. use Composer\Repository\VcsRepository;
  21. use Fxp\Composer\AssetPlugin\Assets;
  22. use Fxp\Composer\AssetPlugin\Converter\SemverConverter;
  23. use Fxp\Composer\AssetPlugin\Package\Loader\LazyAssetPackageLoader;
  24. use Fxp\Composer\AssetPlugin\Package\Version\VersionParser;
  25. use Fxp\Composer\AssetPlugin\Type\AssetTypeInterface;
  26. /**
  27. * Abstract class for Asset VCS repository.
  28. *
  29. * @author François Pluchino <francois.pluchino@gmail.com>
  30. */
  31. abstract class AbstractAssetVcsRepository extends VcsRepository
  32. {
  33. /**
  34. * @var AssetTypeInterface
  35. */
  36. protected $assetType;
  37. /**
  38. * @var VersionParser
  39. */
  40. protected $versionParser;
  41. /**
  42. * @var EventDispatcher
  43. */
  44. protected $dispatcher;
  45. /**
  46. * @var LoaderInterface
  47. */
  48. protected $loader;
  49. /**
  50. * @var string
  51. */
  52. protected $rootPackageVersion;
  53. /**
  54. * @var array|null
  55. */
  56. protected $rootData;
  57. /**
  58. * @var VcsPackageFilter|null
  59. */
  60. protected $filter;
  61. /**
  62. * Constructor.
  63. *
  64. * @param array $repoConfig
  65. * @param IOInterface $io
  66. * @param Config $config
  67. * @param EventDispatcher $dispatcher
  68. * @param array $drivers
  69. */
  70. public function __construct(array $repoConfig, IOInterface $io, Config $config, EventDispatcher $dispatcher = null, array $drivers = null)
  71. {
  72. $drivers = $drivers ?: Assets::getVcsDrivers();
  73. $assetType = substr($repoConfig['type'], 0, strpos($repoConfig['type'], '-'));
  74. $assetType = Assets::createType($assetType);
  75. $repoConfig['asset-type'] = $assetType->getName();
  76. $repoConfig['filename'] = $assetType->getFilename();
  77. $this->assetType = $assetType;
  78. $this->dispatcher = $dispatcher;
  79. $this->filter = isset($repoConfig['vcs-package-filter'])
  80. && $repoConfig['vcs-package-filter'] instanceof VcsPackageFilter
  81. ? $repoConfig['vcs-package-filter']
  82. : null;
  83. parent::__construct($repoConfig, $io, $config, $dispatcher, $drivers);
  84. }
  85. /**
  86. * Gets the package name of this repository.
  87. *
  88. * @return string
  89. */
  90. public function getComposerPackageName()
  91. {
  92. if (null === $this->packages) {
  93. $this->initialize();
  94. }
  95. return $this->assetType->formatComposerName($this->packageName);
  96. }
  97. /**
  98. * Initializes the driver.
  99. *
  100. * @return VcsDriverInterface
  101. *
  102. * @throws \InvalidArgumentException When not driver found.
  103. */
  104. protected function initDriver()
  105. {
  106. $driver = $this->getDriver();
  107. if (!$driver) {
  108. throw new \InvalidArgumentException('No driver found to handle Asset VCS repository '.$this->url);
  109. }
  110. return $driver;
  111. }
  112. /**
  113. * Initializes the version parser and loader.
  114. */
  115. protected function initLoader()
  116. {
  117. $this->versionParser = new VersionParser();
  118. if (!$this->loader) {
  119. $this->loader = new ArrayLoader($this->versionParser);
  120. }
  121. }
  122. /**
  123. * Initializes the root identifier.
  124. *
  125. * @param VcsDriverInterface $driver
  126. */
  127. protected function initRootIdentifier(VcsDriverInterface $driver)
  128. {
  129. try {
  130. if ($driver->hasComposerFile($driver->getRootIdentifier())) {
  131. $data = $driver->getComposerInformation($driver->getRootIdentifier());
  132. $sc = new SemverConverter();
  133. $this->rootPackageVersion = !empty($data['version'])
  134. ? $sc->convertVersion(ltrim($data['version'], '^~'))
  135. : null;
  136. $this->rootData = $data;
  137. if (null === $this->packageName) {
  138. $this->packageName = !empty($data['name']) ? $data['name'] : null;
  139. }
  140. }
  141. } catch (\Exception $e) {
  142. if ($this->verbose) {
  143. $this->io->write('<error>Skipped parsing '.$driver->getRootIdentifier().', '.$e->getMessage().'</error>');
  144. }
  145. }
  146. }
  147. /**
  148. * Creates the package name with the composer prefix and the asset package name,
  149. * or only with the URL.
  150. *
  151. * @return string The package name
  152. */
  153. protected function createPackageName()
  154. {
  155. if (null === $this->packageName) {
  156. return $this->url;
  157. }
  158. return sprintf('%s/%s', $this->assetType->getComposerVendorName(), $this->packageName);
  159. }
  160. /**
  161. * Creates the mock of package config.
  162. *
  163. * @param string $name The package name
  164. * @param string $version The version
  165. *
  166. * @return array The package config
  167. */
  168. protected function createMockOfPackageConfig($name, $version)
  169. {
  170. return array(
  171. 'name' => $name,
  172. 'version' => $version,
  173. 'type' => $this->assetType->getComposerType(),
  174. );
  175. }
  176. /**
  177. * Creates the lazy loader of package.
  178. *
  179. * @param string $type
  180. * @param string $identifier
  181. * @param array $packageData
  182. * @param VcsDriverInterface $driver
  183. *
  184. * @return LazyAssetPackageLoader
  185. */
  186. protected function createLazyLoader($type, $identifier, array $packageData, VcsDriverInterface $driver)
  187. {
  188. $lazyLoader = new LazyAssetPackageLoader($type, $identifier, $packageData);
  189. $lazyLoader->setAssetType($this->assetType);
  190. $lazyLoader->setLoader($this->loader);
  191. $lazyLoader->setDriver(clone $driver);
  192. $lazyLoader->setIO($this->io);
  193. $lazyLoader->setEventDispatcher($this->dispatcher);
  194. return $lazyLoader;
  195. }
  196. /**
  197. * Pre process the data of package before the conversion to Package instance.
  198. *
  199. * @param array $data
  200. *
  201. * @return array
  202. */
  203. protected function preProcessAsset(array $data)
  204. {
  205. $vcsRepos = array();
  206. // keep the name of the main identifier for all packages
  207. $data['name'] = $this->packageName ?: $data['name'];
  208. $data = $this->assetType->getPackageConverter()->convert($data, $vcsRepos);
  209. return (array) $data;
  210. }
  211. /**
  212. * Override the branch alias extra config of the current package.
  213. *
  214. * @param PackageInterface $package The current package
  215. * @param string $aliasNormalized The alias version normalizes
  216. * @param string $branch The branch name
  217. *
  218. * @return PackageInterface
  219. */
  220. protected function overrideBranchAliasConfig(PackageInterface $package, $aliasNormalized, $branch)
  221. {
  222. if ($package instanceof Package && false === strpos('dev-', $aliasNormalized)) {
  223. $extra = $package->getExtra();
  224. $extra['branch-alias'] = array(
  225. 'dev-'.$branch => $this->rootPackageVersion.'-dev',
  226. );
  227. $this->injectExtraConfig($package, $extra);
  228. }
  229. return $package;
  230. }
  231. /**
  232. * Add the alias packages.
  233. *
  234. * @param PackageInterface $package The current package
  235. * @param string $aliasNormalized The alias version normalizes
  236. *
  237. * @return PackageInterface
  238. */
  239. protected function addPackageAliases(PackageInterface $package, $aliasNormalized)
  240. {
  241. $alias = new AliasPackage($package, $aliasNormalized, $this->rootPackageVersion);
  242. $this->addPackage($alias);
  243. if (false === strpos('dev-', $aliasNormalized)) {
  244. $alias = new AliasPackage($package, $aliasNormalized.'-dev', $this->rootPackageVersion);
  245. $this->addPackage($alias);
  246. }
  247. return $package;
  248. }
  249. /**
  250. * Inject the overriding extra config in the current package.
  251. *
  252. * @param PackageInterface $package The package
  253. * @param array $extra The new extra config
  254. */
  255. private function injectExtraConfig(PackageInterface $package, array $extra)
  256. {
  257. $ref = new \ReflectionClass($package);
  258. $met = $ref->getProperty('extra');
  259. $met->setAccessible(true);
  260. $met->setValue($package, $extra);
  261. }
  262. }