Ver código fonte

Add --repository flag to init command, and rename --repository-url to --repository in create-project, fixes #4200, closes #4207, closes #2604, fixes #2920

Jordi Boggiano 9 anos atrás
pai
commit
1aec1c1fc8

+ 9 - 2
doc/03-cli.md

@@ -50,6 +50,11 @@ php composer.phar init
   in format `foo/bar:1.0.0`.
 * **--require-dev:** Development requirements, see **--require**.
 * **--stability (-s):** Value for the `minimum-stability` field.
+* **--repository:** Provide one (or more) custom repositories. They will be stored
+  in the generated composer.json, and used for auto-completion when prompting for
+  the list of requires. Every repository can be either an HTTP URL pointing
+  to a `composer` repository or a JSON string which similar to what the
+  [repositories](04-schema.md#repositories) key accepts.
 
 ## install
 
@@ -541,9 +546,11 @@ By default the command checks for the packages on packagist.org.
 
 ### Options
 
-* **--repository-url:** Provide a custom repository to search for the package,
+* **--repository:** Provide a custom repository to search for the package,
   which will be used instead of packagist. Can be either an HTTP URL pointing
-  to a `composer` repository, or a path to a local `packages.json` file.
+  to a `composer` repository, a path to a local `packages.json` file, or a
+  JSON string which similar to what the [repositories](04-schema.md#repositories)
+  key accepts.
 * **--stability (-s):** Minimum stability of package. Defaults to `stable`.
 * **--prefer-source:** Install packages from `source` when available.
 * **--prefer-dist:** Install packages from `dist` when available.

+ 2 - 1
src/Composer/Command/ArchiveCommand.php

@@ -16,6 +16,7 @@ use Composer\Factory;
 use Composer\IO\IOInterface;
 use Composer\Config;
 use Composer\Repository\CompositeRepository;
+use Composer\Repository\RepositoryFactory;
 use Composer\Script\ScriptEvents;
 use Composer\Plugin\CommandEvent;
 use Composer\Plugin\PluginEvents;
@@ -126,7 +127,7 @@ EOT
             $localRepo = $composer->getRepositoryManager()->getLocalRepository();
             $repo = new CompositeRepository(array_merge(array($localRepo), $composer->getRepositoryManager()->getRepositories()));
         } else {
-            $defaultRepos = Factory::createDefaultRepositories($this->getIO());
+            $defaultRepos = RepositoryFactory::default($this->getIO());
             $io->writeError('No composer.json found in the current directory, searching packages from ' . implode(', ', array_keys($defaultRepos)));
             $repo = new CompositeRepository($defaultRepos);
         }

+ 1 - 4
src/Composer/Command/ConfigCommand.php

@@ -447,10 +447,7 @@ EOT
                         return $this->configSource->addRepository($matches[1], false);
                     }
                 } else {
-                    $value = json_decode($values[0], true);
-                    if (JSON_ERROR_NONE !== json_last_error()) {
-                        throw new \InvalidArgumentException(sprintf('%s is not valid JSON.', $values[0]));
-                    }
+                    $value = JsonFile::parseJson($values[0]);
 
                     return $this->configSource->addRepository($matches[1], $value);
                 }

+ 11 - 19
src/Composer/Command/CreateProjectCommand.php

@@ -22,6 +22,7 @@ use Composer\Package\BasePackage;
 use Composer\DependencyResolver\Pool;
 use Composer\DependencyResolver\Operation\InstallOperation;
 use Composer\Package\Version\VersionSelector;
+use Composer\Repository\RepositoryFactory;
 use Composer\Repository\ComposerRepository;
 use Composer\Repository\CompositeRepository;
 use Composer\Repository\FilesystemRepository;
@@ -60,7 +61,8 @@ class CreateProjectCommand extends BaseCommand
                 new InputOption('stability', 's', InputOption::VALUE_REQUIRED, 'Minimum-stability allowed (unless a version is specified).'),
                 new InputOption('prefer-source', null, InputOption::VALUE_NONE, 'Forces installation from package sources when possible, including VCS information.'),
                 new InputOption('prefer-dist', null, InputOption::VALUE_NONE, 'Forces installation from package dist even for dev versions.'),
-                new InputOption('repository-url', null, InputOption::VALUE_REQUIRED, 'Pick a different repository url to look for the package.'),
+                new InputOption('repository', null, InputOption::VALUE_REQUIRED, 'Pick a different repository (as url or json config) to look for the package.'),
+                new InputOption('repository-url', null, InputOption::VALUE_REQUIRED, 'DEPRECATED: Use --repository instead.'),
                 new InputOption('dev', null, InputOption::VALUE_NONE, 'Enables installation of require-dev packages (enabled by default, only present for BC).'),
                 new InputOption('no-dev', null, InputOption::VALUE_NONE, 'Disables installation of require-dev packages.'),
                 new InputOption('no-plugins', null, InputOption::VALUE_NONE, 'Whether to disable plugins.'),
@@ -92,7 +94,7 @@ To setup a developer workable version you should create the project using the so
 controlled code by appending the <info>'--prefer-source'</info> flag.
 
 To install a package from another repository than the default one you
-can pass the <info>'--repository-url=https://myrepository.org'</info> flag.
+can pass the <info>'--repository=https://myrepository.org'</info> flag.
 
 EOT
             )
@@ -125,7 +127,7 @@ EOT
             $preferSource,
             $preferDist,
             !$input->getOption('no-dev'),
-            $input->getOption('repository-url'),
+            $input->getOption('repository') || $input->getOption('repository-url'),
             $input->getOption('no-plugins'),
             $input->getOption('no-scripts'),
             $input->getOption('keep-vcs'),
@@ -135,7 +137,7 @@ EOT
         );
     }
 
-    public function installProject(IOInterface $io, Config $config, InputInterface $input, $packageName, $directory = null, $packageVersion = null, $stability = 'stable', $preferSource = false, $preferDist = false, $installDevPackages = false, $repositoryUrl = null, $disablePlugins = false, $noScripts = false, $keepVcs = false, $noProgress = false, $noInstall = false, $ignorePlatformReqs = false)
+    public function installProject(IOInterface $io, Config $config, InputInterface $input, $packageName, $directory = null, $packageVersion = null, $stability = 'stable', $preferSource = false, $preferDist = false, $installDevPackages = false, $repository = null, $disablePlugins = false, $noScripts = false, $keepVcs = false, $noProgress = false, $noInstall = false, $ignorePlatformReqs = false)
     {
         $oldCwd = getcwd();
 
@@ -143,7 +145,7 @@ EOT
         $io->loadConfiguration($config);
 
         if ($packageName !== null) {
-            $installedFromVcs = $this->installRootPackage($io, $config, $packageName, $directory, $packageVersion, $stability, $preferSource, $preferDist, $installDevPackages, $repositoryUrl, $disablePlugins, $noScripts, $keepVcs, $noProgress);
+            $installedFromVcs = $this->installRootPackage($io, $config, $packageName, $directory, $packageVersion, $stability, $preferSource, $preferDist, $installDevPackages, $repository, $disablePlugins, $noScripts, $keepVcs, $noProgress);
         } else {
             $installedFromVcs = false;
         }
@@ -239,22 +241,12 @@ EOT
         return 0;
     }
 
-    protected function installRootPackage(IOInterface $io, Config $config, $packageName, $directory = null, $packageVersion = null, $stability = 'stable', $preferSource = false, $preferDist = false, $installDevPackages = false, $repositoryUrl = null, $disablePlugins = false, $noScripts = false, $keepVcs = false, $noProgress = false)
+    protected function installRootPackage(IOInterface $io, Config $config, $packageName, $directory = null, $packageVersion = null, $stability = 'stable', $preferSource = false, $preferDist = false, $installDevPackages = false, $repository = null, $disablePlugins = false, $noScripts = false, $keepVcs = false, $noProgress = false)
     {
-        if (null === $repositoryUrl) {
-            $sourceRepo = new CompositeRepository(Factory::createDefaultRepositories($io, $config));
-        } elseif ("json" === pathinfo($repositoryUrl, PATHINFO_EXTENSION) && file_exists($repositoryUrl)) {
-            $json = new JsonFile($repositoryUrl, Factory::createRemoteFilesystem($io, $config));
-            $data = $json->read();
-            if (!empty($data['packages']) || !empty($data['includes']) || !empty($data['provider-includes'])) {
-                $sourceRepo = new ComposerRepository(array('url' => 'file://' . strtr(realpath($repositoryUrl), '\\', '/')), $io, $config);
-            } else {
-                $sourceRepo = new FilesystemRepository($json);
-            }
-        } elseif (0 === strpos($repositoryUrl, 'http')) {
-            $sourceRepo = new ComposerRepository(array('url' => $repositoryUrl), $io, $config);
+        if (null === $repository) {
+            $sourceRepo = new CompositeRepository(RepositoryFactory::default($io, $config));
         } else {
-            throw new \InvalidArgumentException("Invalid repository url given. Has to be a .json file or an http url.");
+            $sourceRepo = RepositoryFactory::fromString($io, $config, $repository, true);
         }
 
         $parser = new VersionParser();

+ 2 - 3
src/Composer/Command/HomeCommand.php

@@ -16,6 +16,7 @@ use Composer\Factory;
 use Composer\Package\CompletePackageInterface;
 use Composer\Repository\RepositoryInterface;
 use Composer\Repository\ArrayRepository;
+use Composer\Repository\RepositoryFactory;
 use Composer\Util\Platform;
 use Composer\Util\ProcessExecutor;
 use Symfony\Component\Console\Input\InputArgument;
@@ -153,8 +154,6 @@ EOT
             );
         }
 
-        $defaultRepos = Factory::createDefaultRepositories($this->getIO());
-
-        return $defaultRepos;
+        return RepositoryFactory::default($this->getIO());
     }
 }

+ 30 - 3
src/Composer/Command/InitCommand.php

@@ -15,6 +15,7 @@ namespace Composer\Command;
 use Composer\DependencyResolver\Pool;
 use Composer\Json\JsonFile;
 use Composer\Factory;
+use Composer\Repository\RepositoryFactory;
 use Composer\Package\BasePackage;
 use Composer\Package\Version\VersionParser;
 use Composer\Package\Version\VersionSelector;
@@ -61,6 +62,7 @@ class InitCommand extends BaseCommand
                 new InputOption('require-dev', null, InputOption::VALUE_IS_ARRAY | InputOption::VALUE_REQUIRED, 'Package to require for development with a version constraint, e.g. foo/bar:1.0.0 or foo/bar=1.0.0 or "foo/bar 1.0.0"'),
                 new InputOption('stability', 's', InputOption::VALUE_REQUIRED, 'Minimum stability (empty or one of: '.implode(', ', array_keys(BasePackage::$stabilities)).')'),
                 new InputOption('license', 'l', InputOption::VALUE_REQUIRED, 'License of package'),
+                new InputOption('repository', null, InputOption::VALUE_REQUIRED | InputOption::VALUE_IS_ARRAY, 'Add custom repositories, either by URL or using JSON arrays'),
             ))
             ->setHelp(<<<EOT
 The <info>init</info> command creates a basic composer.json file
@@ -78,8 +80,9 @@ EOT
      */
     protected function execute(InputInterface $input, OutputInterface $output)
     {
-        $whitelist = array('name', 'description', 'author', 'type', 'homepage', 'require', 'require-dev', 'stability', 'license');
+        $io = $this->getIO();
 
+        $whitelist = array('name', 'description', 'author', 'type', 'homepage', 'require', 'require-dev', 'stability', 'license');
         $options = array_filter(array_intersect_key($input->getOptions(), array_flip($whitelist)));
 
         if (isset($options['author'])) {
@@ -87,6 +90,14 @@ EOT
             unset($options['author']);
         }
 
+        $repositories = $input->getOption('repository');
+        if ($repositories) {
+            $config = Factory::createConfig($io);
+            foreach ($repositories as $repo) {
+                $options['repositories'][] = RepositoryFactory::configFromString($io, $config, $repo);
+            }
+        }
+
         if (isset($options['stability'])) {
             $options['minimum-stability'] = $options['stability'];
             unset($options['stability']);
@@ -106,7 +117,6 @@ EOT
 
         $file = new JsonFile('composer.json');
         $json = $file->encode($options);
-        $io = $this->getIO();
 
         if ($input->isInteractive()) {
             $io->writeError(array('', $json, ''));
@@ -145,6 +155,23 @@ EOT
         $io = $this->getIO();
         $formatter = $this->getHelperSet()->get('formatter');
 
+        // initialize repos if configured
+        $repositories = $input->getOption('repository');
+        if ($repositories) {
+            $config = Factory::createConfig($io);
+            $repos = array(new PlatformRepository);
+            foreach ($repositories as $repo) {
+                $repos[] = RepositoryFactory::fromString($io, $config, $repo);
+            }
+            $repos[] = RepositoryFactory::createRepo($io, $config, array(
+                'type' => 'composer',
+                'url' => 'https://packagist.org',
+            ));
+
+            $this->repos = new CompositeRepository($repos);
+            unset($repos, $config, $repositories);
+        }
+
         $io->writeError(array(
             '',
             $formatter->formatBlock('Welcome to the Composer config generator', 'bg=blue;fg=white', true),
@@ -318,7 +345,7 @@ EOT
         if (!$this->repos) {
             $this->repos = new CompositeRepository(array_merge(
                 array(new PlatformRepository),
-                Factory::createDefaultRepositories($this->getIO())
+                RepositoryFactory::default($this->getIO())
             ));
         }
 

+ 2 - 1
src/Composer/Command/SearchCommand.php

@@ -18,6 +18,7 @@ use Symfony\Component\Console\Input\InputOption;
 use Symfony\Component\Console\Output\OutputInterface;
 use Composer\Repository\CompositeRepository;
 use Composer\Repository\PlatformRepository;
+use Composer\Repository\RepositoryFactory;
 use Composer\Repository\RepositoryInterface;
 use Composer\Factory;
 use Composer\Plugin\CommandEvent;
@@ -62,7 +63,7 @@ EOT
             $installedRepo = new CompositeRepository(array($localRepo, $platformRepo));
             $repos = new CompositeRepository(array_merge(array($installedRepo), $composer->getRepositoryManager()->getRepositories()));
         } else {
-            $defaultRepos = Factory::createDefaultRepositories($io);
+            $defaultRepos = RepositoryFactory::default($io);
             $io->writeError('No composer.json found in the current directory, showing packages from ' . implode(', ', array_keys($defaultRepos)));
             $installedRepo = $platformRepo;
             $repos = new CompositeRepository(array_merge(array($installedRepo), $defaultRepos));

+ 3 - 2
src/Composer/Command/ShowCommand.php

@@ -31,6 +31,7 @@ use Composer\Repository\CompositeRepository;
 use Composer\Repository\ComposerRepository;
 use Composer\Repository\PlatformRepository;
 use Composer\Repository\RepositoryInterface;
+use Composer\Repository\RepositoryFactory;
 use Composer\Spdx\SpdxLicenses;
 
 /**
@@ -106,7 +107,7 @@ EOT
             if ($composer) {
                 $repos = new CompositeRepository($composer->getRepositoryManager()->getRepositories());
             } else {
-                $defaultRepos = Factory::createDefaultRepositories($io);
+                $defaultRepos = RepositoryFactory::default($io);
                 $repos = new CompositeRepository($defaultRepos);
                 $io->writeError('No composer.json found in the current directory, showing available packages from ' . implode(', ', array_keys($defaultRepos)));
             }
@@ -115,7 +116,7 @@ EOT
             $installedRepo = new CompositeRepository(array($localRepo, $platformRepo));
             $repos = new CompositeRepository(array_merge(array($installedRepo), $composer->getRepositoryManager()->getRepositories()));
         } elseif ($input->getOption('all')) {
-            $defaultRepos = Factory::createDefaultRepositories($io);
+            $defaultRepos = RepositoryFactory::default($io);
             $io->writeError('No composer.json found in the current directory, showing available packages from ' . implode(', ', array_keys($defaultRepos)));
             $installedRepo = $platformRepo;
             $repos = new CompositeRepository(array_merge(array($installedRepo), $defaultRepos));

+ 6 - 56
src/Composer/Factory.php

@@ -18,6 +18,7 @@ use Composer\IO\IOInterface;
 use Composer\Package\Archiver;
 use Composer\Package\Version\VersionGuesser;
 use Composer\Repository\RepositoryManager;
+use Composer\Repository\RepositoryFactory;
 use Composer\Repository\WritableRepositoryInterface;
 use Composer\Util\Filesystem;
 use Composer\Util\Platform;
@@ -221,39 +222,12 @@ class Factory
         );
     }
 
+    /**
+     * @deprecated Use Composer\Repository\RepositoryFactory::default instead
+     */
     public static function createDefaultRepositories(IOInterface $io = null, Config $config = null, RepositoryManager $rm = null)
     {
-        $repos = array();
-
-        if (!$config) {
-            $config = static::createConfig($io);
-        }
-        if (!$rm) {
-            if (!$io) {
-                throw new \InvalidArgumentException('This function requires either an IOInterface or a RepositoryManager');
-            }
-            $factory = new static;
-            $rm = $factory->createRepositoryManager($io, $config, null, self::createRemoteFilesystem($io, $config));
-        }
-
-        foreach ($config->getRepositories() as $index => $repo) {
-            if (is_string($repo)) {
-                throw new \UnexpectedValueException('"repositories" should be an array of repository definitions, only a single repository was given');
-            }
-            if (!is_array($repo)) {
-                throw new \UnexpectedValueException('Repository "'.$index.'" ('.json_encode($repo).') should be an array, '.gettype($repo).' given');
-            }
-            if (!isset($repo['type'])) {
-                throw new \UnexpectedValueException('Repository "'.$index.'" ('.json_encode($repo).') must have a type defined');
-            }
-            $name = is_int($index) && isset($repo['url']) ? preg_replace('{^https?://}i', '', $repo['url']) : $index;
-            while (isset($repos[$name])) {
-                $name .= '2';
-            }
-            $repos[$name] = $rm->createRepository($repo['type'], $repo);
-        }
-
-        return $repos;
+        return RepositoryFactory::default($io, $config, $rm);
     }
 
     /**
@@ -336,7 +310,7 @@ class Factory
         $composer->setEventDispatcher($dispatcher);
 
         // initialize repository manager
-        $rm = $this->createRepositoryManager($io, $config, $dispatcher, $rfs);
+        $rm = RepositoryFactory::manager($io, $config, $dispatcher, $rfs);
         $composer->setRepositoryManager($rm);
 
         // load local repository
@@ -399,30 +373,6 @@ class Factory
         return $composer;
     }
 
-    /**
-     * @param  IOInterface                  $io
-     * @param  Config                       $config
-     * @param  EventDispatcher              $eventDispatcher
-     * @return Repository\RepositoryManager
-     */
-    protected function createRepositoryManager(IOInterface $io, Config $config, EventDispatcher $eventDispatcher = null, RemoteFilesystem $rfs = null)
-    {
-        $rm = new RepositoryManager($io, $config, $eventDispatcher, $rfs);
-        $rm->setRepositoryClass('composer', 'Composer\Repository\ComposerRepository');
-        $rm->setRepositoryClass('vcs', 'Composer\Repository\VcsRepository');
-        $rm->setRepositoryClass('package', 'Composer\Repository\PackageRepository');
-        $rm->setRepositoryClass('pear', 'Composer\Repository\PearRepository');
-        $rm->setRepositoryClass('git', 'Composer\Repository\VcsRepository');
-        $rm->setRepositoryClass('gitlab', 'Composer\Repository\VcsRepository');
-        $rm->setRepositoryClass('svn', 'Composer\Repository\VcsRepository');
-        $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;
-    }
-
     /**
      * @param Repository\RepositoryManager $rm
      * @param string                       $vendorDir

+ 2 - 3
src/Composer/IO/IOInterface.php

@@ -155,13 +155,12 @@ interface IOInterface
      * @param string|array $question     The question to ask
      * @param array        $choices      List of choices to pick from
      * @param bool|string  $default      The default answer if the user enters nothing
-     * @param bool|int     $attempts Max number of times to ask before giving up (false by default, which means infinite)
+     * @param bool|int     $attempts     Max number of times to ask before giving up (false by default, which means infinite)
      * @param string       $errorMessage Message which will be shown if invalid value from choice list would be picked
      * @param bool         $multiselect  Select more than one value separated by comma
      *
-     * @return int|string|array The selected value or values (the key of the choices array)
-     *
      * @throws \InvalidArgumentException
+     * @return int|string|array          The selected value or values (the key of the choices array)
      */
     public function select($question, $choices, $default, $attempts = false, $errorMessage = 'Value "%s" is invalid', $multiselect = false);
 

+ 2 - 1
src/Composer/Package/Loader/RootPackageLoader.php

@@ -17,6 +17,7 @@ use Composer\Package\PackageInterface;
 use Composer\Package\AliasPackage;
 use Composer\Config;
 use Composer\Factory;
+use Composer\Repository\RepositoryFactory;
 use Composer\Package\Version\VersionGuesser;
 use Composer\Package\Version\VersionParser;
 use Composer\Repository\RepositoryManager;
@@ -141,7 +142,7 @@ class RootPackageLoader extends ArrayLoader
             $realPackage->setPreferStable((bool) $config['prefer-stable']);
         }
 
-        $repos = Factory::createDefaultRepositories(null, $this->config, $this->manager);
+        $repos = RepositoryFactory::default(null, $this->config, $this->manager);
         foreach ($repos as $repo) {
             $this->manager->addRepository($repo);
         }

+ 148 - 0
src/Composer/Repository/RepositoryFactory.php

@@ -0,0 +1,148 @@
+<?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\Factory;
+use Composer\IO\IOInterface;
+use Composer\Config;
+use Composer\EventDispatcher\EventDispatcher;
+use Composer\Util\RemoteFilesystem;
+use Composer\Json\JsonFile;
+
+/**
+ * @author Jordi Boggiano <j.boggiano@seld.be>
+ */
+class RepositoryFactory
+{
+    /**
+     * @return array
+     */
+    public static function configFromString(IOInterface $io, Config $config, $repository, $allowFilesystem = false)
+    {
+        if ("json" === pathinfo($repository, PATHINFO_EXTENSION)) {
+            $json = new JsonFile($repository, Factory::createRemoteFilesystem($io, $config));
+            $data = $json->read();
+            if (!empty($data['packages']) || !empty($data['includes']) || !empty($data['provider-includes'])) {
+                $repoConfig = array('type' => 'composer', 'url' => 'file://' . strtr(realpath($repository), '\\', '/'));
+            } elseif ($allowFilesystem) {
+                $repoConfig = array('type' => 'filesystem', 'json' => $json);
+            } else {
+                throw new \InvalidArgumentException("Invalid repository URL ($repository) given. This file does not contain a valid composer repository.");
+            }
+        } elseif (0 === strpos($repository, 'http')) {
+            $repoConfig = array('type' => 'composer', 'url' => $repository);
+        } elseif ('{' === substr($repository, 0, 1)) {
+            // assume it is a json object that makes a repo config
+            $repoConfig = JsonFile::parseJson($repository);
+        } else {
+            throw new \InvalidArgumentException("Invalid repository url ($repository) given. Has to be a .json file, an http url or a JSON object.");
+        }
+
+        return $repoConfig;
+    }
+
+    /**
+     * @return RepositoryInterface
+     */
+    public static function fromString(IOInterface $io, Config $config, $repository, $allowFilesystem = false)
+    {
+        $repoConfig = static::configFromString($io, $config, $repository, $allowFilesystem);
+
+        return static::createRepo($io, $config, $repoConfig);
+    }
+
+    /**
+     * @return RepositoryInterface
+     */
+    public static function createRepo($io, $config, array $repoConfig)
+    {
+        $rm = static::manager($io, $config, null, Factory::createRemoteFilesystem($io, $config));
+        $repos = static::createRepos($rm, array($repoConfig));
+
+        return reset($repos);
+    }
+
+    /**
+     * @return RepositoryInterface[]
+     */
+    public static function default(IOInterface $io = null, Config $config = null, RepositoryManager $rm = null)
+    {
+        if (!$config) {
+            $config = Factory::createConfig($io);
+        }
+        if (!$rm) {
+            if (!$io) {
+                throw new \InvalidArgumentException('This function requires either an IOInterface or a RepositoryManager');
+            }
+            $rm = static::manager($io, $config, null, Factory::createRemoteFilesystem($io, $config));
+        }
+
+        return static::createRepos($rm, $config->getRepositories());
+    }
+
+    /**
+     * @param  IOInterface                  $io
+     * @param  Config                       $config
+     * @param  EventDispatcher              $eventDispatcher
+     * @param  RemoteFilesystem             $rfs
+     * @return RepositoryManager
+     */
+    public static function manager(IOInterface $io, Config $config, EventDispatcher $eventDispatcher = null, RemoteFilesystem $rfs = null)
+    {
+        $rm = new RepositoryManager($io, $config, $eventDispatcher, $rfs);
+        $rm->setRepositoryClass('composer', 'Composer\Repository\ComposerRepository');
+        $rm->setRepositoryClass('vcs', 'Composer\Repository\VcsRepository');
+        $rm->setRepositoryClass('package', 'Composer\Repository\PackageRepository');
+        $rm->setRepositoryClass('pear', 'Composer\Repository\PearRepository');
+        $rm->setRepositoryClass('git', 'Composer\Repository\VcsRepository');
+        $rm->setRepositoryClass('gitlab', 'Composer\Repository\VcsRepository');
+        $rm->setRepositoryClass('svn', 'Composer\Repository\VcsRepository');
+        $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;
+    }
+
+    /**
+     * @return RepositoryInterface[]
+     */
+    private static function createRepos(RepositoryManager $rm, array $repoConfigs)
+    {
+        $repos = array();
+
+        foreach ($repoConfigs as $index => $repo) {
+            if (is_string($repo)) {
+                throw new \UnexpectedValueException('"repositories" should be an array of repository definitions, only a single repository was given');
+            }
+            if (!is_array($repo)) {
+                throw new \UnexpectedValueException('Repository "'.$index.'" ('.json_encode($repo).') should be an array, '.gettype($repo).' given');
+            }
+            if (!isset($repo['type'])) {
+                throw new \UnexpectedValueException('Repository "'.$index.'" ('.json_encode($repo).') must have a type defined');
+            }
+            $name = is_int($index) && isset($repo['url']) ? preg_replace('{^https?://}i', '', $repo['url']) : $index;
+            while (isset($repos[$name])) {
+                $name .= '2';
+            }
+            if ($repo['type'] === 'filesystem') {
+                $repos[$name] = new FilesystemRepository($repo['json']);
+            } else {
+                $repos[$name] = $rm->createRepository($repo['type'], $repo);
+            }
+        }
+
+        return $repos;
+    }
+}