diff --git a/src/Composer/Command/InstallCommand.php b/src/Composer/Command/InstallCommand.php index 426c1fb9e..6b6120bb8 100644 --- a/src/Composer/Command/InstallCommand.php +++ b/src/Composer/Command/InstallCommand.php @@ -113,10 +113,10 @@ EOT } foreach ($aliases as $alias) { foreach ($repoManager->findPackages($alias['package'], $alias['version']) as $package) { - $package->getRepository()->addPackage(new AliasPackage($package, $alias['alias'])); + $package->getRepository()->addPackage(new AliasPackage($package, $alias['alias_normalized'], $alias['alias'])); } foreach ($repoManager->getLocalRepository()->findPackages($alias['package'], $alias['version']) as $package) { - $repoManager->getLocalRepository()->addPackage(new AliasPackage($package, $alias['alias'])); + $repoManager->getLocalRepository()->addPackage(new AliasPackage($package, $alias['alias_normalized'], $alias['alias'])); $repoManager->getLocalRepository()->removePackage($package); } } diff --git a/src/Composer/Factory.php b/src/Composer/Factory.php index e27976a4b..a9ed4722a 100644 --- a/src/Composer/Factory.php +++ b/src/Composer/Factory.php @@ -130,7 +130,7 @@ class Factory protected function addLocalRepository(RepositoryManager $rm, $vendorDir) { - $rm->setLocalRepository(new Repository\FilesystemRepository(new JsonFile($vendorDir.'/.composer/installed.json'))); + $rm->setLocalRepository(new Repository\InstalledFilesystemRepository(new JsonFile($vendorDir.'/.composer/installed.json'))); } protected function addPackagistRepository(RepositoryManager $rm) diff --git a/src/Composer/Installer/InstallationManager.php b/src/Composer/Installer/InstallationManager.php index 6500e6b00..68355f72c 100644 --- a/src/Composer/Installer/InstallationManager.php +++ b/src/Composer/Installer/InstallationManager.php @@ -127,6 +127,7 @@ class InstallationManager $package = $operation->getPackage(); if ($package instanceof AliasPackage) { $package = $package->getAliasOf(); + $package->setInstalledAsAlias(true); } $installer = $this->getInstaller($package->getType()); $installer->install($package); @@ -146,6 +147,7 @@ class InstallationManager $target = $operation->getTargetPackage(); if ($target instanceof AliasPackage) { $target = $target->getAliasOf(); + $target->setInstalledAsAlias(true); } $initialType = $initial->getType(); diff --git a/src/Composer/Package/AliasPackage.php b/src/Composer/Package/AliasPackage.php index 02c0a9510..b302868ee 100644 --- a/src/Composer/Package/AliasPackage.php +++ b/src/Composer/Package/AliasPackage.php @@ -23,6 +23,7 @@ use Composer\Repository\PlatformRepository; class AliasPackage extends BasePackage { protected $version; + protected $prettyVersion; protected $dev; protected $aliasOf; @@ -38,12 +39,14 @@ class AliasPackage extends BasePackage * * @param PackageInterface $aliasOf The package this package is an alias of * @param string $version The version the alias must report + * @param string $prettyVersion The alias's non-normalized version */ - public function __construct($aliasOf, $version) + public function __construct($aliasOf, $version, $prettyVersion) { parent::__construct($aliasOf->getName()); $this->version = $version; + $this->prettyVersion = $prettyVersion; $this->aliasOf = $aliasOf; $this->dev = 'dev-' === substr($version, 0, 4) || '-dev' === substr($version, -4); @@ -78,7 +81,7 @@ class AliasPackage extends BasePackage */ public function getPrettyVersion() { - return $this->version; + return $this->prettyVersion; } /** @@ -92,7 +95,7 @@ class AliasPackage extends BasePackage /** * {@inheritDoc} */ - function getRequires() + public function getRequires() { return $this->requires; } @@ -100,7 +103,7 @@ class AliasPackage extends BasePackage /** * {@inheritDoc} */ - function getConflicts() + public function getConflicts() { return $this->conflicts; } @@ -108,7 +111,7 @@ class AliasPackage extends BasePackage /** * {@inheritDoc} */ - function getProvides() + public function getProvides() { return $this->provides; } @@ -116,7 +119,7 @@ class AliasPackage extends BasePackage /** * {@inheritDoc} */ - function getReplaces() + public function getReplaces() { return $this->replaces; } @@ -124,7 +127,7 @@ class AliasPackage extends BasePackage /** * {@inheritDoc} */ - function getRecommends() + public function getRecommends() { return $this->recommends; } @@ -132,11 +135,27 @@ class AliasPackage extends BasePackage /** * {@inheritDoc} */ - function getSuggests() + public function getSuggests() { return $this->suggests; } + /** + * {@inheritDoc} + */ + public function getAlias() + { + return ''; + } + + /** + * {@inheritDoc} + */ + public function getPrettyAlias() + { + return ''; + } + /*************************************** * Wrappers around the aliased package * ***************************************/ @@ -173,6 +192,10 @@ class AliasPackage extends BasePackage { return $this->aliasOf->getSourceReference(); } + public function setSourceReference($reference) + { + return $this->aliasOf->setSourceReference($reference); + } public function getDistType() { return $this->aliasOf->getDistType(); diff --git a/src/Composer/Package/Dumper/ArrayDumper.php b/src/Composer/Package/Dumper/ArrayDumper.php index f372929b1..188d55c5c 100644 --- a/src/Composer/Package/Dumper/ArrayDumper.php +++ b/src/Composer/Package/Dumper/ArrayDumper.php @@ -42,6 +42,7 @@ class ArrayDumper $data['name'] = $package->getPrettyName(); $data['version'] = $package->getPrettyVersion(); $data['version_normalized'] = $package->getVersion(); + if ($package->getTargetDir()) { $data['target-dir'] = $package->getTargetDir(); } diff --git a/src/Composer/Package/Loader/ArrayLoader.php b/src/Composer/Package/Loader/ArrayLoader.php index 98733372b..001fa2e25 100644 --- a/src/Composer/Package/Loader/ArrayLoader.php +++ b/src/Composer/Package/Loader/ArrayLoader.php @@ -134,6 +134,30 @@ class ArrayLoader $package->setDistSha1Checksum(isset($config['dist']['shasum']) ? $config['dist']['shasum'] : null); } + // check for a branch alias (dev-master => 1.0.x-dev for example) if this is a named branch + if ('dev-' === substr($package->getPrettyVersion(), 0, 4) && isset($config['extra']['branch-alias']) && is_array($config['extra']['branch-alias'])) { + foreach ($config['extra']['branch-alias'] as $sourceBranch => $targetBranch) { + // ensure it is an alias to a -dev package + if ('-dev' !== substr($targetBranch, -4)) { + continue; + } + // normalize without -dev and ensure it's a numeric branch that is parseable + $validatedTargetBranch = $this->versionParser->normalizeBranch(substr($targetBranch, 0, -4)); + if ('-dev' !== substr($validatedTargetBranch, -4)) { + continue; + } + + // ensure that it is the current branch aliasing itself + if (strtolower($package->getPrettyVersion()) !== strtolower($sourceBranch)) { + continue; + } + + $package->setAlias($validatedTargetBranch); + $package->setPrettyAlias($targetBranch); + break; + } + } + foreach (Package\BasePackage::$supportedLinkTypes as $type => $description) { if (isset($config[$type])) { $method = 'set'.ucfirst($description); diff --git a/src/Composer/Package/Loader/RootPackageLoader.php b/src/Composer/Package/Loader/RootPackageLoader.php index a6865f01e..77b2599fb 100644 --- a/src/Composer/Package/Loader/RootPackageLoader.php +++ b/src/Composer/Package/Loader/RootPackageLoader.php @@ -50,7 +50,8 @@ class RootPackageLoader extends ArrayLoader $aliases[] = array( 'package' => strtolower($reqName), 'version' => $this->versionParser->normalize($match[1]), - 'alias' => $this->versionParser->normalize($match[2]), + 'alias' => $match[2], + 'alias_normalized' => $this->versionParser->normalize($match[2]), ); } } diff --git a/src/Composer/Package/Locker.php b/src/Composer/Package/Locker.php index 205372481..b4df22f21 100644 --- a/src/Composer/Package/Locker.php +++ b/src/Composer/Package/Locker.php @@ -14,6 +14,7 @@ namespace Composer\Package; use Composer\Json\JsonFile; use Composer\Repository\RepositoryManager; +use Composer\Package\AliasPackage; /** * Reads/writes project lockfile (composer.lock). @@ -72,10 +73,14 @@ class Locker $lockList = $this->getLockData(); $packages = array(); foreach ($lockList['packages'] as $info) { - $package = $this->repositoryManager->getLocalRepository()->findPackage($info['package'], $info['version']); + $resolvedVersion = !empty($info['alias']) ? $info['alias'] : $info['version']; + $package = $this->repositoryManager->getLocalRepository()->findPackage($info['package'], $resolvedVersion); if (!$package) { $package = $this->repositoryManager->findPackage($info['package'], $info['version']); + if ($package && !empty($info['alias'])) { + $package = new AliasPackage($package, $info['alias'], $info['alias']); + } } if (!$package) { @@ -134,6 +139,9 @@ class Locker if ($package->isDev()) { $spec['source-reference'] = $package->getSourceReference(); } + if ($package->getAlias() && $package->isInstalledAsAlias()) { + $spec['alias'] = $package->getAlias(); + } $lock['packages'][] = $spec; } diff --git a/src/Composer/Package/MemoryPackage.php b/src/Composer/Package/MemoryPackage.php index a2a711027..e266f754c 100644 --- a/src/Composer/Package/MemoryPackage.php +++ b/src/Composer/Package/MemoryPackage.php @@ -42,6 +42,9 @@ class MemoryPackage extends BasePackage protected $binaries = array(); protected $scripts = array(); protected $aliases = array(); + protected $alias; + protected $prettyAlias; + protected $installedAsAlias; protected $dev; protected $requires = array(); @@ -173,6 +176,56 @@ class MemoryPackage extends BasePackage return $this->aliases; } + /** + * @param string $alias + */ + public function setAlias($alias) + { + $this->alias = $alias; + } + + /** + * {@inheritDoc} + */ + public function getAlias() + { + return $this->alias; + } + + /** + * @param string $prettyAlias + */ + public function setPrettyAlias($prettyAlias) + { + $this->prettyAlias = $prettyAlias; + } + + /** + * {@inheritDoc} + */ + public function getPrettyAlias() + { + return $this->prettyAlias; + } + + /** + * Enabled if the package is installed from its alias package + * + * @param string $installedAsAlias + */ + public function setInstalledAsAlias($installedAsAlias) + { + $this->installedAsAlias = $installedAsAlias; + } + + /** + * @return string + */ + public function isInstalledAsAlias() + { + return $this->installedAsAlias; + } + /** * {@inheritDoc} */ diff --git a/src/Composer/Package/PackageInterface.php b/src/Composer/Package/PackageInterface.php index cf68cc02d..97997f093 100644 --- a/src/Composer/Package/PackageInterface.php +++ b/src/Composer/Package/PackageInterface.php @@ -316,6 +316,20 @@ interface PackageInterface */ function getAuthors(); + /** + * Returns a version this package should be aliased to + * + * @return string + */ + function getAlias(); + + /** + * Returns a non-normalized version this package should be aliased to + * + * @return string + */ + function getPrettyAlias(); + /** * Returns package unique name, constructed from name and version. * diff --git a/src/Composer/Repository/ArrayRepository.php b/src/Composer/Repository/ArrayRepository.php index a46bfd20d..515f89ea9 100644 --- a/src/Composer/Repository/ArrayRepository.php +++ b/src/Composer/Repository/ArrayRepository.php @@ -12,6 +12,7 @@ namespace Composer\Repository; +use Composer\Package\AliasPackage; use Composer\Package\PackageInterface; use Composer\Package\Version\VersionParser; @@ -94,6 +95,16 @@ class ArrayRepository implements RepositoryInterface } $package->setRepository($this); $this->packages[] = $package; + + // create alias package on the fly if needed (installed repos manage aliases themselves) + if ($package->getAlias() && !$this instanceof InstalledRepositoryInterface) { + $this->addPackage($this->createAliasPackage($package)); + } + } + + protected function createAliasPackage(PackageInterface $package) + { + return new AliasPackage($package, $package->getAlias(), $package->getPrettyAlias()); } /** diff --git a/src/Composer/Repository/FilesystemRepository.php b/src/Composer/Repository/FilesystemRepository.php index 73fc37305..e17134b42 100644 --- a/src/Composer/Repository/FilesystemRepository.php +++ b/src/Composer/Repository/FilesystemRepository.php @@ -54,8 +54,17 @@ class FilesystemRepository extends ArrayRepository implements WritableRepository } $loader = new ArrayLoader(); - foreach ($packages as $package) { - $this->addPackage($loader->load($package)); + foreach ($packages as $packageData) { + $package = $loader->load($packageData); + + // package was installed as alias, so we only add the alias + if ($this instanceof InstalledRepositoryInterface && !empty($packageData['installed-as-alias'])) { + $package->setInstalledAsAlias(true); + $this->addPackage($this->createAliasPackage($package)); + } else { + // only add regular package - if it's not an installed repo the alias will be created on the fly + $this->addPackage($package); + } } } @@ -67,7 +76,11 @@ class FilesystemRepository extends ArrayRepository implements WritableRepository $packages = array(); $dumper = new ArrayDumper(); foreach ($this->getPackages() as $package) { - $packages[] = $dumper->dump($package); + $data = $dumper->dump($package); + if ($this instanceof InstalledRepositoryInterface && $package->isInstalledAsAlias()) { + $data['installed-as-alias'] = true; + } + $packages[] = $data; } $this->file->write($packages); diff --git a/src/Composer/Repository/InstalledFilesystemRepository.php b/src/Composer/Repository/InstalledFilesystemRepository.php new file mode 100644 index 000000000..7bb70d666 --- /dev/null +++ b/src/Composer/Repository/InstalledFilesystemRepository.php @@ -0,0 +1,27 @@ + + * Jordi Boggiano + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Composer\Repository; + +use Composer\Json\JsonFile; +use Composer\Package\PackageInterface; +use Composer\Package\Loader\ArrayLoader; +use Composer\Package\Dumper\ArrayDumper; + +/** + * Installed filesystem repository. + * + * @author Jordi Boggiano + */ +class InstalledFilesystemRepository extends FilesystemRepository implements InstalledRepositoryInterface +{ +} diff --git a/src/Composer/Repository/InstalledRepositoryInterface.php b/src/Composer/Repository/InstalledRepositoryInterface.php new file mode 100644 index 000000000..de71d23c6 --- /dev/null +++ b/src/Composer/Repository/InstalledRepositoryInterface.php @@ -0,0 +1,26 @@ + + * Jordi Boggiano + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Composer\Repository; + +use Composer\Package\PackageInterface; + +/** + * Installable repository interface. + * + * Just used to tag installed repositories so the base classes can act differently on Alias packages + * + * @author Jordi Boggiano + */ +interface InstalledRepositoryInterface +{ +} diff --git a/src/Composer/Repository/VcsRepository.php b/src/Composer/Repository/VcsRepository.php index 2c4175fa0..afdc12bcb 100644 --- a/src/Composer/Repository/VcsRepository.php +++ b/src/Composer/Repository/VcsRepository.php @@ -4,6 +4,8 @@ namespace Composer\Repository; use Composer\Repository\Vcs\VcsDriverInterface; use Composer\Package\Version\VersionParser; +use Composer\Package\PackageInterface; +use Composer\Package\AliasPackage; use Composer\Package\Loader\ArrayLoader; use Composer\IO\IOInterface; @@ -16,6 +18,7 @@ class VcsRepository extends ArrayRepository protected $packageName; protected $debug; protected $io; + protected $versionParser; public function __construct(array $config, IOInterface $io, array $drivers = null) { @@ -67,7 +70,7 @@ class VcsRepository extends ArrayRepository throw new \InvalidArgumentException('No driver found to handle VCS repository '.$this->url); } - $versionParser = new VersionParser; + $this->versionParser = new VersionParser; $loader = new ArrayLoader(); if ($driver->hasComposerFile($driver->getRootIdentifier())) { @@ -83,7 +86,7 @@ class VcsRepository extends ArrayRepository $this->io->overwrite($msg, false); } - $parsedTag = $this->validateTag($versionParser, $tag); + $parsedTag = $this->validateTag($tag); if ($parsedTag && $driver->hasComposerFile($identifier)) { try { $data = $driver->getComposerInformation($identifier); @@ -96,7 +99,7 @@ class VcsRepository extends ArrayRepository // manually versioned package if (isset($data['version'])) { - $data['version_normalized'] = $versionParser->normalize($data['version']); + $data['version_normalized'] = $this->versionParser->normalize($data['version']); } else { // auto-versionned package, read value from tag $data['version'] = $tag; @@ -135,7 +138,7 @@ class VcsRepository extends ArrayRepository $this->io->overwrite($msg, false); } - $parsedBranch = $this->validateBranch($versionParser, $branch); + $parsedBranch = $this->validateBranch($branch); if ($driver->hasComposerFile($identifier)) { $data = $driver->getComposerInformation($identifier); @@ -185,20 +188,20 @@ class VcsRepository extends ArrayRepository return $data; } - private function validateBranch($versionParser, $branch) + private function validateBranch($branch) { try { - return $versionParser->normalizeBranch($branch); + return $this->versionParser->normalizeBranch($branch); } catch (\Exception $e) { } return false; } - private function validateTag($versionParser, $version) + private function validateTag($version) { try { - return $versionParser->normalize($version); + return $this->versionParser->normalize($version); } catch (\Exception $e) { }