diff --git a/src/Composer/Command/ConfigCommand.php b/src/Composer/Command/ConfigCommand.php index c98fdda21..b6e1205d4 100644 --- a/src/Composer/Command/ConfigCommand.php +++ b/src/Composer/Command/ConfigCommand.php @@ -75,6 +75,7 @@ class ConfigCommand extends BaseCommand new InputOption('absolute', null, InputOption::VALUE_NONE, 'Returns absolute paths when fetching *-dir config values instead of relative'), new InputOption('json', 'j', InputOption::VALUE_NONE, 'JSON decode the setting value, to be used with extra.* keys'), new InputOption('merge', 'm', InputOption::VALUE_NONE, 'Merge the setting value with the current value, to be used with extra.* keys in combination with --json'), + new InputOption('append', null, InputOption::VALUE_NONE, 'When adding a repository, append it (lowest priority) to the existing ones instead of prepending it (highest priority)'), new InputArgument('setting-key', null, 'Setting key'), new InputArgument('setting-value', InputArgument::IS_ARRAY, 'Setting value'), )) @@ -596,7 +597,7 @@ EOT $this->configSource->addRepository($matches[1], array( 'type' => $values[0], 'url' => $values[1], - )); + ), $input->getOption('append')); return 0; } @@ -605,13 +606,13 @@ EOT $value = strtolower($values[0]); if (true === $booleanValidator($value)) { if (false === $booleanNormalizer($value)) { - $this->configSource->addRepository($matches[1], false); + $this->configSource->addRepository($matches[1], false, $input->getOption('append')); return 0; } } else { $value = JsonFile::parseJson($values[0]); - $this->configSource->addRepository($matches[1], $value); + $this->configSource->addRepository($matches[1], $value, $input->getOption('append')); return 0; } diff --git a/src/Composer/Command/CreateProjectCommand.php b/src/Composer/Command/CreateProjectCommand.php index 70569522d..497b71680 100644 --- a/src/Composer/Command/CreateProjectCommand.php +++ b/src/Composer/Command/CreateProjectCommand.php @@ -199,7 +199,7 @@ EOT ) { $configSource->addRepository('packagist.org', false); } else { - $configSource->addRepository($name, $repoConfig); + $configSource->addRepository($name, $repoConfig, false); } $composer = Factory::create($io, null, $disablePlugins); diff --git a/src/Composer/Config/ConfigSourceInterface.php b/src/Composer/Config/ConfigSourceInterface.php index 0bd4faaa0..030123cc4 100644 --- a/src/Composer/Config/ConfigSourceInterface.php +++ b/src/Composer/Config/ConfigSourceInterface.php @@ -26,7 +26,7 @@ interface ConfigSourceInterface * @param string $name Name * @param array|false $config Configuration */ - public function addRepository($name, $config); + public function addRepository($name, $config/* , $append = true */); /** * Remove a repository diff --git a/src/Composer/Config/JsonConfigSource.php b/src/Composer/Config/JsonConfigSource.php index e03e0f274..36b0bc972 100644 --- a/src/Composer/Config/JsonConfigSource.php +++ b/src/Composer/Config/JsonConfigSource.php @@ -57,9 +57,9 @@ class JsonConfigSource implements ConfigSourceInterface /** * {@inheritdoc} */ - public function addRepository($name, $config) + public function addRepository($name, $config, $append = true) { - $this->manipulateJson('addRepository', $name, $config, function (&$config, $repo, $repoConfig) { + $this->manipulateJson('addRepository', $name, $config, $append, function (&$config, $repo, $repoConfig) use ($append) { // if converting from an array format to hashmap format, and there is a {"packagist.org":false} repo, we have // to convert it to "packagist.org": false key on the hashmap otherwise it fails schema validation if (isset($config['repositories'])) { @@ -75,7 +75,11 @@ class JsonConfigSource implements ConfigSourceInterface } } - $config['repositories'][$repo] = $repoConfig; + if ($append) { + $config['repositories'][$repo] = $repoConfig; + } else { + $config['repositories'] = array($repo => $repoConfig) + $config['repositories']; + } }); } diff --git a/src/Composer/Json/JsonManipulator.php b/src/Composer/Json/JsonManipulator.php index ae9c95ce5..b2b1be872 100644 --- a/src/Composer/Json/JsonManipulator.php +++ b/src/Composer/Json/JsonManipulator.php @@ -145,9 +145,9 @@ class JsonManipulator }); } - public function addRepository($name, $config) + public function addRepository($name, $config, $append = true) { - return $this->addSubNode('repositories', $name, $config); + return $this->addSubNode('repositories', $name, $config, $append); } public function removeRepository($name) @@ -199,7 +199,7 @@ class JsonManipulator return $this->removeMainKey($name); } - public function addSubNode($mainNode, $name, $value) + public function addSubNode($mainNode, $name, $value, $append = true) { $decoded = JsonFile::parseJson($this->contents); @@ -258,7 +258,7 @@ class JsonManipulator return $matches['start'] . $that->format($value, 1) . $matches['end']; }, $children); } else { - $this->pregMatch('#^{ \s*? (?P\S+.*?)? (?P\s*) }$#sx', $children, $match); + $this->pregMatch('#^{ (?P\s*?) (?P\S+.*?)? (?P\s*) }$#sx', $children, $match); $whitespace = ''; if (!empty($match['trailingspace'])) { @@ -271,11 +271,24 @@ class JsonManipulator } // child missing but non empty children - $children = preg_replace( - '#'.$whitespace.'}$#', - addcslashes(',' . $this->newline . $this->indent . $this->indent . JsonFile::encode($name).': '.$this->format($value, 1) . $whitespace . '}', '\\$'), - $children - ); + if ($append) { + $children = preg_replace( + '#'.$whitespace.'}$#', + addcslashes(',' . $this->newline . $this->indent . $this->indent . JsonFile::encode($name).': '.$this->format($value, 1) . $whitespace . '}', '\\$'), + $children + ); + } else { + $whitespace = ''; + if (!empty($match['leadingspace'])) { + $whitespace = $match['leadingspace']; + } + + $children = preg_replace( + '#^{'.$whitespace.'#', + addcslashes('{' . $whitespace . JsonFile::encode($name).': '.$this->format($value, 1) . ',' . $this->newline . $this->indent . $this->indent, '\\$'), + $children + ); + } } else { if ($subName !== null) { $value = array($subName => $value); diff --git a/tests/Composer/Test/Json/JsonManipulatorTest.php b/tests/Composer/Test/Json/JsonManipulatorTest.php index 9a0274740..118eb91c7 100644 --- a/tests/Composer/Test/Json/JsonManipulatorTest.php +++ b/tests/Composer/Test/Json/JsonManipulatorTest.php @@ -1935,7 +1935,7 @@ class JsonManipulatorTest extends TestCase ", $manipulator->getContents()); } - public function testAddRepositoryCanAdd() + public function testAddRepositoryCanAppend() { $manipulator = new JsonManipulator('{ "repositories": { @@ -1946,7 +1946,7 @@ class JsonManipulatorTest extends TestCase } }'); - $this->assertTrue($manipulator->addRepository('bar', array('type' => 'composer'))); + $this->assertTrue($manipulator->addRepository('bar', array('type' => 'composer'), true)); $this->assertEquals('{ "repositories": { "foo": { @@ -1961,6 +1961,32 @@ class JsonManipulatorTest extends TestCase ', $manipulator->getContents()); } + public function testAddRepositoryCanPrepend() + { + $manipulator = new JsonManipulator('{ + "repositories": { + "foo": { + "type": "vcs", + "url": "lala" + } + } +}'); + + $this->assertTrue($manipulator->addRepository('bar', array('type' => 'composer'), false)); + $this->assertEquals('{ + "repositories": { + "bar": { + "type": "composer" + }, + "foo": { + "type": "vcs", + "url": "lala" + } + } +} +', $manipulator->getContents()); + } + public function testAddRepositoryCanOverrideDeepRepos() { $manipulator = new JsonManipulator('{