diff --git a/src/Symfony/Installer/DemoCommand.php b/src/Symfony/Installer/DemoCommand.php index ffe1ff7..16970fb 100644 --- a/src/Symfony/Installer/DemoCommand.php +++ b/src/Symfony/Installer/DemoCommand.php @@ -75,6 +75,7 @@ protected function execute(InputInterface $input, OutputInterface $output) ->download() ->extract() ->cleanUp() + ->updateComposerJson() ->createGitIgnore() ->checkSymfonyRequirements() ->displayInstallationResult() diff --git a/src/Symfony/Installer/DownloadCommand.php b/src/Symfony/Installer/DownloadCommand.php index 5d9b28e..aa8ef17 100644 --- a/src/Symfony/Installer/DownloadCommand.php +++ b/src/Symfony/Installer/DownloadCommand.php @@ -325,6 +325,33 @@ protected function checkSymfonyRequirements() return $this; } + /** + * Updates the composer.json file to provide better values for some of the + * default configuration values. + * + * @return $this + */ + protected function updateComposerJson() + { + $composerConfig = $this->getProjectComposerConfig(); + + if (isset($composerConfig['config']['platform']['php'])) { + unset($composerConfig['config']['platform']['php']); + + if (empty($composerConfig['config']['platform'])) { + unset($composerConfig['config']['platform']); + } + + if (empty($composerConfig['config'])) { + unset($composerConfig['config']); + } + } + + $this->saveProjectComposerConfig($composerConfig); + + return $this; + } + /** * Creates the appropriate .gitignore file for a Symfony project if it doesn't exist. * @@ -544,6 +571,107 @@ protected function getUrlContents($url) return $client->get($url)->getBody()->getContents(); } + /** + * It returns the project's Composer config as a PHP array. + * + * @return $this|array + */ + protected function getProjectComposerConfig() + { + $composerJsonFilepath = $this->projectDir.'/composer.json'; + + if (!is_writable($composerJsonFilepath)) { + if ($this->output->isVerbose()) { + $this->output->writeln(sprintf( + " [WARNING] Project's Composer config cannot be updated because\n". + " the %s file is not writable.\n", + $composerJsonFilepath + )); + } + + return $this; + } + + return json_decode(file_get_contents($composerJsonFilepath), true); + } + + /** + * It saves the given PHP array as the project's Composer config. In addition + * to JSON-serializing the contents, it synchronizes the composer.lock file to + * avoid out-of-sync Composer errors. + * + * @param array $config + */ + protected function saveProjectComposerConfig(array $config) + { + $composerJsonFilepath = $this->projectDir.'/composer.json'; + $this->fs->dumpFile($composerJsonFilepath, json_encode($config, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES)."\n"); + + $this->syncComposerLockFile(); + } + + /** + * Updates the hash values stored in composer.lock to avoid out-of-sync + * problems when the composer.json file contents are changed. + */ + private function syncComposerLockFile() + { + $composerJsonFileContents = file_get_contents($this->projectDir.'/composer.json'); + $composerLockFileContents = json_decode(file_get_contents($this->projectDir.'/composer.lock'), true); + + if (array_key_exists('hash', $composerLockFileContents)) { + $composerLockFileContents['hash'] = md5($composerJsonFileContents); + } + + if (array_key_exists('content-hash', $composerLockFileContents)) { + $composerLockFileContents['content-hash'] = $this->getComposerContentHash($composerJsonFileContents); + } + + $this->fs->dumpFile($this->projectDir.'/composer.lock', json_encode($composerLockFileContents, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES)."\n"); + } + + /** + * Returns the md5 hash of the sorted content of the composer file. + * + * @see https://github.com/composer/composer/blob/master/src/Composer/Package/Locker.php (getContentHash() method) + * + * @param string $composerJsonFileContents The contents of the composer.json file. + * + * @return string The hash of the composer file content. + */ + private function getComposerContentHash($composerJsonFileContents) + { + $composerConfig = json_decode($composerJsonFileContents, true); + + $relevantKeys = array( + 'name', + 'version', + 'require', + 'require-dev', + 'conflict', + 'replace', + 'provide', + 'minimum-stability', + 'prefer-stable', + 'repositories', + 'extra', + ); + + $relevantComposerConfig = array(); + + foreach (array_intersect($relevantKeys, array_keys($composerConfig)) as $key) { + $relevantComposerConfig[$key] = $composerConfig[$key]; + } + + if (isset($composerConfig['config']['platform'])) { + $relevantComposerConfig['config']['platform'] = $composerConfig['config']['platform']; + } + + ksort($relevantComposerConfig); + + return md5(json_encode($relevantComposerConfig)); + } + /** * Enables the signal handler. * diff --git a/src/Symfony/Installer/NewCommand.php b/src/Symfony/Installer/NewCommand.php index 41f477a..048c4aa 100644 --- a/src/Symfony/Installer/NewCommand.php +++ b/src/Symfony/Installer/NewCommand.php @@ -337,48 +337,22 @@ protected function updateParameters() */ protected function updateComposerJson() { - $filename = $this->projectDir.'/composer.json'; + parent::updateComposerJson(); - if (!is_writable($filename)) { - if ($this->output->isVerbose()) { - $this->output->writeln(sprintf( - " [WARNING] Project name cannot be configured because\n". - " the %s file is not writable.\n", - $filename - )); - } - - return $this; - } - - $contents = json_decode(file_get_contents($filename), true); + $composerConfig = $this->getProjectComposerConfig(); - $contents['name'] = $this->generateComposerProjectName(); - $contents['license'] = 'proprietary'; + $composerConfig['name'] = $this->generateComposerProjectName(); + $composerConfig['license'] = 'proprietary'; - if (isset($contents['description'])) { - unset($contents['description']); + if (isset($composerConfig['description'])) { + unset($composerConfig['description']); } - if (isset($contents['config']['platform']['php'])) { - unset($contents['config']['platform']['php']); - - if (empty($contents['config']['platform'])) { - unset($contents['config']['platform']); - } - - if (empty($contents['config'])) { - unset($contents['config']); - } - } - - if (isset($contents['extra']['branch-alias'])) { - unset($contents['extra']['branch-alias']); + if (isset($composerConfig['extra']['branch-alias'])) { + unset($composerConfig['extra']['branch-alias']); } - file_put_contents($filename, json_encode($contents, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES)."\n"); - - $this->syncComposerLockFile(); + $this->saveProjectComposerConfig($composerConfig); return $this; } @@ -441,66 +415,4 @@ protected function getRemoteFileUrl() { return 'http://symfony.com/download?v=Symfony_Standard_Vendors_'.$this->version; } - - /** - * Updates the hash values stored in composer.lock to avoid out-of-sync - * problems when the composer.json file contents are changed. - */ - private function syncComposerLockFile() - { - $composerJsonFileContents = file_get_contents($this->projectDir.'/composer.json'); - $composerLockFileContents = json_decode(file_get_contents($this->projectDir.'/composer.lock'), true); - - if (array_key_exists('hash', $composerLockFileContents)) { - $composerLockFileContents['hash'] = md5($composerJsonFileContents); - } - - if (array_key_exists('content-hash', $composerLockFileContents)) { - $composerLockFileContents['content-hash'] = $this->getComposerContentHash($composerJsonFileContents); - } - - file_put_contents($this->projectDir.'/composer.lock', json_encode($composerLockFileContents, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES)."\n"); - } - - /** - * Returns the md5 hash of the sorted content of the composer file. - * - * @see https://github.com/composer/composer/blob/master/src/Composer/Package/Locker.php (getContentHash() method) - * - * @param string $composerJsonFileContents The contents of the composer.json file. - * - * @return string The hash of the composer file content. - */ - private function getComposerContentHash($composerJsonFileContents) - { - $content = json_decode($composerJsonFileContents, true); - - $relevantKeys = array( - 'name', - 'version', - 'require', - 'require-dev', - 'conflict', - 'replace', - 'provide', - 'minimum-stability', - 'prefer-stable', - 'repositories', - 'extra', - ); - - $relevantContent = array(); - - foreach (array_intersect($relevantKeys, array_keys($content)) as $key) { - $relevantContent[$key] = $content[$key]; - } - - if (isset($content['config']['platform'])) { - $relevantContent['config']['platform'] = $content['config']['platform']; - } - - ksort($relevantContent); - - return md5(json_encode($relevantContent)); - } } diff --git a/tests/Symfony/Installer/Tests/IntegrationTest.php b/tests/Symfony/Installer/Tests/IntegrationTest.php index fb300d3..4dd252d 100644 --- a/tests/Symfony/Installer/Tests/IntegrationTest.php +++ b/tests/Symfony/Installer/Tests/IntegrationTest.php @@ -50,6 +50,10 @@ public function testDemoApplicationInstallation() $output = $this->runCommand('php app/console --version', $projectDir); $this->assertRegExp('/Symfony version 2\.\d+\.\d+(-DEV)? - app\/dev\/debug/', $output); + + $composerConfig = json_decode(file_get_contents($projectDir.'/composer.json'), true); + + $this->assertArrayNotHasKey('platform', $composerConfig['config'], 'The composer.json file does not define any platform configuration.'); } /** @@ -75,6 +79,13 @@ public function testSymfonyInstallation($versionToInstall, $messageRegexp, $vers } $this->assertRegExp($versionRegexp, $output); + + $composerConfig = json_decode(file_get_contents($projectDir.'/composer.json'), true); + $this->assertArrayNotHasKey( + isset($composerConfig['config']) ? 'platform' : 'config', + isset($composerConfig['config']) ? $composerConfig['config'] : $composerConfig, + 'The composer.json file does not define any platform configuration.' + ); } public function testSymfonyInstallationInCurrentDirectory()