Forráskód Böngészése

Merge remote-tracking branch 'nfx/artefact-repo-type'

Jordi Boggiano 12 éve
szülő
commit
e50173ff93

+ 34 - 0
doc/05-repositories.md

@@ -485,6 +485,40 @@ Check [the satis GitHub repository](https://github.com/composer/satis) and
 the [Satis article](articles/handling-private-packages-with-satis.md) for more
 information.
 
+### Artifact
+
+There are some cases, when there is no ability to have one of the previously
+mentioned repository types online, even the VCS one. Typical example could be
+cross-organisation library exchange through built artifacts. Of course, most
+of the times they are private. To simplify maintenance, one can simply specify
+repository of type `artifact` with a folder containing ZIP archives of those
+private packages:
+
+    {
+        "repositories": [
+            {
+                "type": "artifact",
+                "url": "path/to/directory/with/zips/"
+            }
+        ],
+        "require": {
+            "private-vendor-one/core": "15.6.2",
+            "private-vendor-two/connectivity": "*",
+            "acme-corp/parser": "10.3.5"
+        }
+    }
+
+Each zip artifact is just a ZIP archive with `composer.json` in root folder:
+
+    $ tar -tf acme-corp-parser-10.3.5.zip
+    composer.json
+    ...
+
+If there is two archives with different versions of a package, they would be
+imported both. If archive with newer version would be put to artifact folder and
+`update` command would be triggered, that version would replace previous, at it
+ logically seems.
+
 ## Disabling Packagist
 
 You can disable the default Packagist repository by adding this to your

+ 1 - 0
src/Composer/Factory.php

@@ -287,6 +287,7 @@ class Factory
         $rm->setRepositoryClass('git', 'Composer\Repository\VcsRepository');
         $rm->setRepositoryClass('svn', 'Composer\Repository\VcsRepository');
         $rm->setRepositoryClass('hg', 'Composer\Repository\VcsRepository');
+        $rm->setRepositoryClass('artifact', 'Composer\Repository\ArtifactRepository');
 
         return $rm;
     }

+ 109 - 0
src/Composer/Repository/ArtifactRepository.php

@@ -0,0 +1,109 @@
+<?php
+
+/*
+ * This file is part of Composer.
+ *
+ * (c) Nils Adermann <naderman@naderman.de>
+ *     Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Composer\Repository;
+
+use Composer\IO\IOInterface;
+use Composer\Json\JsonFile;
+use Composer\Package\Loader\ArrayLoader;
+
+/**
+ * @author Serge Smertin <serg.smertin@gmail.com>
+ */
+class ArtifactRepository extends ArrayRepository
+{
+    /** @var LoaderInterface */
+    protected $loader;
+
+    protected $lookup;
+
+    public function __construct(array $repoConfig, IOInterface $io)
+    {
+        $this->loader = new ArrayLoader();
+        $this->lookup = $repoConfig['url'];
+        $this->io = $io;
+    }
+
+    protected function initialize()
+    {
+        parent::initialize();
+
+        if (!extension_loaded('zip')) {
+            $msg = 'In order to use <comment>artifact</comment> repository, ' .
+                'you need to have <comment>zip</comment> extension enabled';
+            $this->io->write($msg);
+            return;
+        }
+
+        $this->scanDirectory($this->lookup);
+    }
+
+    private function scanDirectory($path)
+    {
+        $io = $this->io;
+        foreach (new \RecursiveDirectoryIterator($path) as $file) {
+            /* @var $file \SplFileInfo */
+            if (!$file->isFile()) {
+                continue;
+            }
+
+            $package = $this->getComposerInformation($file);
+            if (!$package) {
+                if ($io->isVerbose()) {
+                    $msg = "File <comment>{$file->getBasename()}</comment> doesn't seem to hold a package";
+                    $io->write($msg);
+                }
+                continue;
+            }
+
+            if ($io->isVerbose()) {
+                $template = 'Found package <info>%s</info> (<comment>%s</comment>) in file <info>%s</info>';
+                $msg = sprintf($template, $package->getName(), $package->getPrettyVersion(), $file->getBasename());
+                $io->write($msg);
+            }
+
+            $this->addPackage($package);
+        }
+    }
+
+    private function getComposerInformation(\SplFileInfo $file)
+    {
+        $zip = new \ZipArchive();
+        $zip->open($file->getPathname());
+
+        if (0 == $zip->numFiles) {
+            return false;
+        }
+
+        $foundFileIndex = $zip->locateName('composer.json', \ZipArchive::FL_NODIR);
+        if (false === $foundFileIndex) {
+            return false;
+        }
+
+        $configurationFileName = $zip->getNameIndex($foundFileIndex);
+
+        $composerFile = "zip://{$file->getPathname()}#$configurationFileName";
+        $json = file_get_contents($composerFile);
+
+        $package = JsonFile::parseJson($json, $composerFile);
+        $package['dist'] = array(
+            'type' => 'zip',
+            'url' => $file->getRealPath(),
+            'reference' => $file->getBasename(),
+            'shasum' => sha1_file($file->getRealPath())
+        );
+
+        $package = $this->loader->load($package);
+
+        return $package;
+    }
+}

+ 42 - 0
tests/Composer/Test/Repository/ArtifactRepositoryTest.php

@@ -0,0 +1,42 @@
+<?php
+
+/*
+ * This file is part of Composer.
+ *
+ * (c) Nils Adermann <naderman@naderman.de>
+ *     Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Composer\Repository;
+
+use Composer\Test\TestCase;
+use Composer\IO\NullIO;
+use Composer\Config;
+use Composer\Package\BasePackage;
+
+class ArtifactRepositoryTest extends TestCase
+{
+    public function testExtractsConfigsFromZipArchives()
+    {
+        $expectedPackages = array(
+            'vendor0/package0-0.0.1',
+            'composer/composer-1.0.0-alpha6',
+            'vendor1/package2-4.3.2',
+        );
+
+        $coordinates = array('type' => 'artifact', 'url' => __DIR__ . '/Fixtures/artifacts');
+        $repo = new ArtifactRepository($coordinates, new NullIO(), new Config());
+
+        $foundPackages = array_map(function(BasePackage $package) {
+            return "{$package->getPrettyName()}-{$package->getPrettyVersion()}";
+        }, $repo->getPackages());
+
+        sort($expectedPackages);
+        sort($foundPackages);
+
+        $this->assertSame($expectedPackages, $foundPackages);
+    }
+}

BIN
tests/Composer/Test/Repository/Fixtures/artifacts/composer-1.0.0-alpha6.zip


BIN
tests/Composer/Test/Repository/Fixtures/artifacts/not-an-artifact.zip


BIN
tests/Composer/Test/Repository/Fixtures/artifacts/package0.zip


BIN
tests/Composer/Test/Repository/Fixtures/artifacts/package2.zip