diff --git a/src/Module/Config/Step/LoadConfig.php b/src/Module/Config/Step/LoadConfig.php index 93df1a35..3dfa29d1 100644 --- a/src/Module/Config/Step/LoadConfig.php +++ b/src/Module/Config/Step/LoadConfig.php @@ -51,6 +51,18 @@ public function __invoke(Project $project) } $metadata = $this->parseYamlFile($filename); + + if (array_key_exists('import', $metadata)) { + // Extend configuration with extra data files. + $filesToImport = $metadata['import']; + foreach ($filesToImport as $dataFile) { + $metadata = array_replace_recursive( + $metadata, + $this->loadDataFile($dataFile, $project) + ); + } + } + $metadata = $this->validateConfig($metadata); $project->metadata->setMany($metadata); @@ -99,4 +111,26 @@ private function validateConfig($values) return $values; } + + /** + * Load extra data files defined in configuration file. + * + * @param array $dataFile File to load. + * @param string $relativeTo Path from where files will be resolved. + * + * @return array Array - key,value - of loaded data. + */ + private function loadDataFile($dataFile, $project) + { + // Resolve path to this file. + $path = $project->sourceDirectory.DIRECTORY_SEPARATOR.$dataFile; + + // Load this data file. + $loadedData = $this->parseYamlFile($path); + + // Watch this file. + $project->watchlist->watchFile($path); + + return $loadedData; + } } diff --git a/tests/UnitTest/Module/Config/Step/Fixtures/couscous-simple.yml b/tests/UnitTest/Module/Config/Step/Fixtures/couscous-simple.yml new file mode 100644 index 00000000..cbd4495f --- /dev/null +++ b/tests/UnitTest/Module/Config/Step/Fixtures/couscous-simple.yml @@ -0,0 +1,9 @@ + +template: + index: index.md + +include: + - some/dir + - some/other/dir + +title: coucous-simple! diff --git a/tests/UnitTest/Module/Config/Step/Fixtures/couscous-with-import.yml b/tests/UnitTest/Module/Config/Step/Fixtures/couscous-with-import.yml new file mode 100644 index 00000000..4128ee7d --- /dev/null +++ b/tests/UnitTest/Module/Config/Step/Fixtures/couscous-with-import.yml @@ -0,0 +1,12 @@ + +template: + index: index.md + +include: + - some/dir + - some/other/dir + +title: coucous-simple! + +import: + - imported-file1.yml diff --git a/tests/UnitTest/Module/Config/Step/Fixtures/imported-file1.yml b/tests/UnitTest/Module/Config/Step/Fixtures/imported-file1.yml new file mode 100644 index 00000000..45a00a2f --- /dev/null +++ b/tests/UnitTest/Module/Config/Step/Fixtures/imported-file1.yml @@ -0,0 +1,6 @@ +include: + - some/dir + - some/other/dir + - other/dir/imported + +title: overwritten by imported-file1.yml \ No newline at end of file diff --git a/tests/UnitTest/Module/Config/Step/LoadConfigTest.php b/tests/UnitTest/Module/Config/Step/LoadConfigTest.php new file mode 100644 index 00000000..61e0b8fd --- /dev/null +++ b/tests/UnitTest/Module/Config/Step/LoadConfigTest.php @@ -0,0 +1,112 @@ +filesystem = new Filesystem(); + $this->workingDir = $this->getUniqueTmpDirectory(); + } + + protected function tearDown() + { + if ($this->filesystem->exists($this->workingDir)) { + $this->filesystem->remove($this->workingDir); + } + } + + /** + * @test + */ + public function it_should_load_simple_config() + { + // Copy fixtures to working directory. + $this->filesystem->copy($this->getFixturePath('couscous-simple.yml'), $this->workingDir.DIRECTORY_SEPARATOR.LoadConfig::FILENAME); + + // Create a project for working directory. + $project = new Project($this->workingDir, ''); + + // Load config. + $parser = new Parser(); + $step = new LoadConfig($this->filesystem, $parser, new NullLogger()); + $step->__invoke($project); + + $this->assertEquals(['some/dir', 'some/other/dir'], $project->metadata['include']); + $this->assertEquals('coucous-simple!', $project->metadata['title']); + } + + /** + * @test + */ + public function it_should_overwrite_config() + { + // Copy fixtures to working directory. + $this->filesystem->copy($this->getFixturePath('couscous-with-import.yml'), $this->workingDir.DIRECTORY_SEPARATOR.LoadConfig::FILENAME); + $this->filesystem->copy($this->getFixturePath('imported-file1.yml'), $this->workingDir.DIRECTORY_SEPARATOR.'imported-file1.yml'); + + // Create a project for working directory. + $project = new Project($this->workingDir, ''); + + // Load config. + $parser = new Parser(); + $step = new LoadConfig($this->filesystem, $parser, new NullLogger()); + $step->__invoke($project); + + $this->assertEquals(['some/dir', 'some/other/dir', 'other/dir/imported'], $project->metadata['include']); + $this->assertEquals('overwritten by imported-file1.yml', $project->metadata['title']); + } + + /** + * Locate fixtures and return path. + * + * @param string $name + * + * @return string + */ + protected function getFixturePath($name) + { + return __DIR__.'/Fixtures/'.$name; + } + + /** + * Create a unique working directory within temp dir. + * + * Shamelessly borrowed from Composer\TestCase. + * + * @return string + */ + public function getUniqueTmpDirectory() + { + $attempts = 5; + $root = sys_get_temp_dir(); + + do { + $unique = $root.DIRECTORY_SEPARATOR.uniqid('couscous-test-'.rand(1000, 9000)); + + if (!$this->filesystem->exists($unique)) { + // Create and return. + $this->filesystem->mkdir($unique, 0777); + + return realpath($unique); + } + } while (--$attempts); + + throw new \RuntimeException('Failed to create a unique temporary directory.'); + } +}