diff --git a/src/Exception/InvalidConfigException.php b/src/Exception/InvalidConfigException.php new file mode 100644 index 000000000..49874cc0e --- /dev/null +++ b/src/Exception/InvalidConfigException.php @@ -0,0 +1,8 @@ +fs->remove($link); } diff --git a/src/Local/LocalBuild.php b/src/Local/LocalBuild.php index 1718dd42e..7e90461d7 100644 --- a/src/Local/LocalBuild.php +++ b/src/Local/LocalBuild.php @@ -1,6 +1,7 @@ parse(file_get_contents($appRoot . '/.platform.app.yaml')); + try { + $parser = new Parser(); + $config = (array) $parser->parse(file_get_contents($appRoot . '/.platform.app.yaml')); + } + catch (ParseException $e) { + throw new InvalidConfigException( + "Parse error in file '$appRoot/.platform.app.yaml'. \n" . $e->getMessage() + ); + } + } + + return $this->normalizeConfig($config); + } + + /** + * Normalize an application's configuration. + * + * @param array $config + * + * @return array + */ + public function normalizeConfig(array $config) + { + if (isset($config['toolstack'])) { + $this->deprecationWarning('2015.7'); + if (!strpos($config['toolstack'], ':')) { + throw new InvalidConfigException("Invalid value for 'toolstack'"); + } + list($config['type'], $config['build']['flavor']) = explode(':', $config['toolstack'], 2); } return $config; } + /** + * Show a warning about deprecated configuration. + * + * @param string $version + * @param string $file + */ + public function deprecationWarning($version, $file = '.platform.app.yaml') + { + $this->output->writeln("The format of your $file configuration file is deprecated."); + $this->output->writeln(sprintf("See how to upgrade at: https://docs.platform.sh/reference/upgrade/#changes-in-%s", $version)); + $this->output->writeln(""); + } + /** * Get the toolstack for a particular application. * @@ -180,9 +222,22 @@ public function getAppConfig($appRoot) public function getToolstack($appRoot, array $appConfig = array()) { $toolstackChoice = false; - if (isset($appConfig['toolstack'])) { - $toolstackChoice = $appConfig['toolstack']; + + // For now, we reconstruct a toolstack string based on the 'type' and + // 'build.flavor' config keys. + if (isset($appConfig['type'])) { + $toolstackChoice = sprintf( + '%s:%s', + $appConfig['type'], + !empty($appConfig['build']['flavor']) ? $appConfig['build']['flavor'] : 'default' + ); + + // Alias php:default to php:composer. + if ($toolstackChoice === 'php:default') { + $toolstackChoice = 'php:composer'; + } } + foreach (self::getToolstacks() as $toolstack) { $key = $toolstack->getKey(); if ((!$toolstackChoice && $toolstack->detect($appRoot)) @@ -319,8 +374,15 @@ protected function buildApp($appRoot, $sourceDir, $destination, array $appConfig $this->fsHelper->extractArchive($archive, $buildDir); } else { $message = "Building application $appIdentifier"; - if ($key = $toolstack->getKey()) { - $message .= " using the toolstack $key"; + $info = array(); + if (isset($appConfig['type'])) { + $info[] = 'runtime type: ' . $appConfig['type']; + } + if (!empty($treeId)) { + $info[] = "tree: " . substr($treeId, 0, 7); + } + if (!empty($info)) { + $message .= ' (' . implode(', ', $info) . ')'; } $this->output->writeln($message); diff --git a/src/Local/Toolstack/Composer.php b/src/Local/Toolstack/Composer.php index 4540bc64e..8667b25db 100644 --- a/src/Local/Toolstack/Composer.php +++ b/src/Local/Toolstack/Composer.php @@ -4,6 +4,10 @@ class Composer extends ToolstackBase { + public function getKey() + { + return 'php:composer'; + } public function detect($appRoot) { diff --git a/src/Local/Toolstack/ToolstackBase.php b/src/Local/Toolstack/ToolstackBase.php index 3b55fe5ab..ea7eed0ce 100644 --- a/src/Local/Toolstack/ToolstackBase.php +++ b/src/Local/Toolstack/ToolstackBase.php @@ -107,6 +107,9 @@ protected function processSpecialDestinations() if (!$matched) { continue; } + if ($relDestination === '{webroot}' && $this->buildInPlace) { + continue; + } // On Platform these replacements would be a bit different. $absDestination = str_replace(array('{webroot}', '{approot}'), array($this->getWebRoot(), $this->buildDir), $relDestination); @@ -117,17 +120,21 @@ protected function processSpecialDestinations() if (in_array($relSource, $this->ignoredFiles)) { continue; } + $destination = $absDestination; + // Do not overwrite directories with files. + if (!is_dir($source) && is_dir($destination)) { + $destination = $destination . '/' . basename($source); + } + // Ignore if source and destination are the same. + if ($destination === $source) { + continue; + } if ($this->copy) { $this->output->writeln("Copying $relSource to $relDestination"); } else { $this->output->writeln("Symlinking $relSource to $relDestination"); } - $destination = $absDestination; - // Do not overwrite directories with files. - if (!is_dir($source) && is_dir($destination)) { - $destination = $destination . '/' . basename($source); - } // Delete existing files, emitting a warning. if (file_exists($destination)) { $this->output->writeln( diff --git a/tests/Local/Toolstack/ComposerTest.php b/tests/Local/Toolstack/ComposerTest.php index 2e8d4e96f..e740edd8d 100644 --- a/tests/Local/Toolstack/ComposerTest.php +++ b/tests/Local/Toolstack/ComposerTest.php @@ -26,4 +26,12 @@ public function testBuildFakeSymfony() { $this->assertBuildSucceeds('tests/data/apps/fake-symfony'); } + + /** + * Test the deprecated config file format still works. + */ + public function testBuildDeprecatedConfig() + { + $this->assertBuildSucceeds('tests/data/apps/deprecated-config'); + } } diff --git a/tests/data/apps/deprecated-config/.platform.app.yaml b/tests/data/apps/deprecated-config/.platform.app.yaml new file mode 100644 index 000000000..6f0986971 --- /dev/null +++ b/tests/data/apps/deprecated-config/.platform.app.yaml @@ -0,0 +1,2 @@ +name: deprecated-config +toolstack: php:symfony diff --git a/tests/data/apps/drupal/project-yaml/.platform.app.yaml b/tests/data/apps/drupal/project-yaml/.platform.app.yaml index 5838d4806..bbf5203ff 100644 --- a/tests/data/apps/drupal/project-yaml/.platform.app.yaml +++ b/tests/data/apps/drupal/project-yaml/.platform.app.yaml @@ -1 +1,3 @@ -toolstack: "php:drupal" +type: php +build: + flavor: drupal diff --git a/tests/data/apps/drupal/project/.platform.app.yaml b/tests/data/apps/drupal/project/.platform.app.yaml index e70640625..c2eb729b8 100644 --- a/tests/data/apps/drupal/project/.platform.app.yaml +++ b/tests/data/apps/drupal/project/.platform.app.yaml @@ -1,4 +1,6 @@ -toolstack: "php:drupal" +type: php +build: + flavor: drupal # Test build hook hooks: diff --git a/tests/data/apps/fake-symfony/.platform.app.yaml b/tests/data/apps/fake-symfony/.platform.app.yaml index 862c680a4..cfa869d6a 100644 --- a/tests/data/apps/fake-symfony/.platform.app.yaml +++ b/tests/data/apps/fake-symfony/.platform.app.yaml @@ -2,4 +2,6 @@ # composer.json file. name: fake-symfony -toolstack: "php:symfony" +type: php +build: + flavor: symfony diff --git a/tests/data/repositories/multiple/drupal/.platform.app.yaml b/tests/data/repositories/multiple/drupal/.platform.app.yaml index d9aab9aaa..07d0f82cf 100644 --- a/tests/data/repositories/multiple/drupal/.platform.app.yaml +++ b/tests/data/repositories/multiple/drupal/.platform.app.yaml @@ -1,3 +1,4 @@ name: drupal - -toolstack: "php:drupal" +type: php +build: + flavor: drupal