From ead68d3d4900d63284e1db3d360cd5c8353c39e5 Mon Sep 17 00:00:00 2001 From: Samuel ROZE Date: Tue, 18 Aug 2015 14:40:48 +0100 Subject: [PATCH] Create the path repository and downloader --- composer.json | 1 + composer.lock | 52 +++++++++- src/Composer/Downloader/PathDownloader.php | 50 ++++++++++ src/Composer/Factory.php | 2 + src/Composer/Repository/PathRepository.php | 105 +++++++++++++++++++++ src/Composer/Util/Filesystem.php | 9 +- 6 files changed, 217 insertions(+), 2 deletions(-) create mode 100644 src/Composer/Downloader/PathDownloader.php create mode 100644 src/Composer/Repository/PathRepository.php diff --git a/composer.json b/composer.json index c53971509..4ba003887 100644 --- a/composer.json +++ b/composer.json @@ -29,6 +29,7 @@ "symfony/console": "~2.5", "symfony/finder": "~2.2", "symfony/process": "~2.1", + "symfony/filesystem": "~2.5", "seld/phar-utils": "~1.0", "seld/cli-prompt": "~1.0" }, diff --git a/composer.lock b/composer.lock index f05689b63..fc7e1ef34 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", "This file is @generated automatically" ], - "hash": "6fbac2ddcd4e9064c84090f6d5514412", + "hash": "3024e89a7e808b8dece156112459a7ea", "packages": [ { "name": "composer/spdx-licenses", @@ -328,6 +328,56 @@ "homepage": "https://symfony.com", "time": "2015-07-26 09:08:40" }, + { + "name": "symfony/filesystem", + "version": "v2.6.11", + "target-dir": "Symfony/Component/Filesystem", + "source": { + "type": "git", + "url": "https://github.com/symfony/Filesystem.git", + "reference": "823c035b1a5c13a4924e324d016eb07e70f94735" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/Filesystem/zipball/823c035b1a5c13a4924e324d016eb07e70f94735", + "reference": "823c035b1a5c13a4924e324d016eb07e70f94735", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "require-dev": { + "symfony/phpunit-bridge": "~2.7" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.6-dev" + } + }, + "autoload": { + "psr-0": { + "Symfony\\Component\\Filesystem\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony Filesystem Component", + "homepage": "https://symfony.com", + "time": "2015-07-08 05:59:48" + }, { "name": "symfony/finder", "version": "v2.6.11", diff --git a/src/Composer/Downloader/PathDownloader.php b/src/Composer/Downloader/PathDownloader.php new file mode 100644 index 000000000..fbdb0aebc --- /dev/null +++ b/src/Composer/Downloader/PathDownloader.php @@ -0,0 +1,50 @@ + + * Jordi Boggiano + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Composer\Downloader; + +use Composer\Package\PackageInterface; +use Symfony\Component\Filesystem\Exception\IOException; +use Symfony\Component\Filesystem\Filesystem; + +/** + * Download a package from a local path. + * + * @author Samuel Roze + * @author Johann Reinke + */ +class PathDownloader extends FileDownloader +{ + /** + * {@inheritdoc} + */ + public function download(PackageInterface $package, $path) + { + $fileSystem = new Filesystem(); + if ($fileSystem->exists($path)) { + $fileSystem->remove($path); + } + + try { + $fileSystem->symlink($package->getDistUrl(), $path); + } catch (IOException $e) { + $fileSystem->mirror($package->getDistUrl(), $path); + } + + $this->io->writeError(sprintf( + ' Downloaded %s (%s) from %s', + $package->getName(), + $package->getFullPrettyVersion(), + $package->getDistUrl() + )); + } +} diff --git a/src/Composer/Factory.php b/src/Composer/Factory.php index 6f9a5da36..4fabbe455 100644 --- a/src/Composer/Factory.php +++ b/src/Composer/Factory.php @@ -331,6 +331,7 @@ class Factory $rm->setRepositoryClass('perforce', 'Composer\Repository\VcsRepository'); $rm->setRepositoryClass('hg', 'Composer\Repository\VcsRepository'); $rm->setRepositoryClass('artifact', 'Composer\Repository\ArtifactRepository'); + $rm->setRepositoryClass('path', 'Composer\Repository\PathRepository'); return $rm; } @@ -403,6 +404,7 @@ class Factory $dm->setDownloader('gzip', new Downloader\GzipDownloader($io, $config, $eventDispatcher, $cache)); $dm->setDownloader('phar', new Downloader\PharDownloader($io, $config, $eventDispatcher, $cache)); $dm->setDownloader('file', new Downloader\FileDownloader($io, $config, $eventDispatcher, $cache)); + $dm->setDownloader('path', new Downloader\PathDownloader($io, $config, $eventDispatcher, $cache)); return $dm; } diff --git a/src/Composer/Repository/PathRepository.php b/src/Composer/Repository/PathRepository.php new file mode 100644 index 000000000..63bd3be01 --- /dev/null +++ b/src/Composer/Repository/PathRepository.php @@ -0,0 +1,105 @@ + + * 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\Loader\ArrayLoader; +use Symfony\Component\Filesystem\Filesystem; + +/** + * This repository allows installing local packages that are not necessarily under their own VCS. + * + * The local packages will be symlinked when possible, else they will be copied. + * + * @code + * "require": { + * "/": "*" + * }, + * "repositories": [ + * { + * "type": "path", + * "url": "../../relative/path/to/package/" + * }, + * { + * "type": "path", + * "url": "/absolute/path/to/package/" + * } + * ] + * @endcode + * + * @author Samuel Roze + * @author Johann Reinke + */ +class PathRepository extends ArrayRepository +{ + /** + * @var Filesystem + */ + private $fileSystem; + + /** + * @var ArrayLoader + */ + private $loader; + + /** + * @var string + */ + private $path; + + /** + * Initializes path repository. + * + * @param array $config package definition + */ + public function __construct(array $config) + { + if (!isset($config['url'])) { + throw new \RuntimeException('You must specify the `url` configuration for the path repository'); + } + + $this->fileSystem = new Filesystem(); + $this->loader = new ArrayLoader(); + $this->path = realpath(rtrim($config['url'], '/')) . '/'; + } + + /** + * Initializes path repository. + * + * This method will basically read the folder and add the found package. + * + */ + protected function initialize() + { + parent::initialize(); + + $composerFilePath = $this->path.'composer.json'; + if (!$this->fileSystem->exists($composerFilePath)) { + throw new \RuntimeException(sprintf('No `composer.json` file found in path repository "%s"', $this->path)); + } + + $json = file_get_contents($composerFilePath); + $package = JsonFile::parseJson($json, $composerFilePath); + $package['dist'] = array( + 'type' => 'folder', + 'url' => $this->path, + ); + + if (!isset($package['version'])) { + $package['version'] = 'dev-master'; + } + + $package = $this->loader->load($package); + $this->addPackage($package); + } +} diff --git a/src/Composer/Util/Filesystem.php b/src/Composer/Util/Filesystem.php index 92e5e0623..c36347fb7 100644 --- a/src/Composer/Util/Filesystem.php +++ b/src/Composer/Util/Filesystem.php @@ -508,7 +508,14 @@ class Filesystem return unlink($path); } - private function isSymlinkedDirectory($directory) + /** + * return true if that directory is a symlink. + * + * @param string $directory + * + * @return bool + */ + public function isSymlinkedDirectory($directory) { if (!is_dir($directory)) { return false;