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

main
Jordi Boggiano 8 years ago
parent b6b2635f42
commit 1aec1c1fc8

@ -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.

@ -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);
}

@ -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);
}

@ -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();

@ -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());
}
}

@ -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())
));
}

@ -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));

@ -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));

@ -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

@ -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);

@ -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);
}

@ -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;
}
}
Loading…
Cancel
Save