diff --git a/.editorconfig b/.editorconfig
new file mode 100644
index 0000000..aa9a047
--- /dev/null
+++ b/.editorconfig
@@ -0,0 +1,15 @@
+# This file is for unifying the coding style for different editors and IDEs
+# editorconfig.org
+
+# PHP PSR-2 Coding Standards
+# http://www.php-fig.org/psr/psr-2/
+
+root = true
+
+[*.php]
+charset = utf-8
+end_of_line = lf
+insert_final_newline = true
+trim_trailing_whitespace = true
+indent_style = space
+indent_size = 4
diff --git a/src/RecipeInstaller.php b/src/RecipeInstaller.php
index b1fb84f..c171908 100644
--- a/src/RecipeInstaller.php
+++ b/src/RecipeInstaller.php
@@ -9,6 +9,11 @@ use Composer\IO\IOInterface;
use Composer\Package\PackageInterface;
use Composer\Repository\InstalledRepositoryInterface;
use Composer\Util\Filesystem;
+use FilesystemIterator;
+use Iterator;
+use RecursiveDirectoryIterator;
+use RecursiveIteratorIterator;
+use RegexIterator;
class RecipeInstaller extends LibraryInstaller {
public function __construct(
@@ -25,19 +30,80 @@ class RecipeInstaller extends LibraryInstaller {
{
parent::install($repo, $package);
- // Install recipe skeleton
- var_dump("Package info:\n");
- var_dump($package);
- var_dump($this->getInstallPath($package));
- var_dump($package->getExtra());
-
- var_dump("Repo info:\n");
- var_dump($repo);
- if(file_exists('composer.json')) {
- var_dump(file_get_contents('composer.json'));
+ // Copy project files to root
+ $destinationPath = getcwd();
+ $name = $package->getName();
+ $extra = $package->getExtra();
+ if (isset($extra['project-files'])) {
+ $this->installProjectFiles($name, $this->getInstallPath($package), $destinationPath, $extra['project-files']);
}
+ }
- var_dump("Installer info:\n");
- var_dump($this);
+ /**
+ * Install project files in the specified directory
+ *
+ * @param string $recipe Recipe name
+ * @param string $sourceRoot Base of source files (no trailing slash)
+ * @param string $destinationRoot Base of destination directory (no trailing slash)
+ * @param array $filePatterns List of file patterns in wildcard format (e.g. `code/My*.php`)
+ */
+ public function installProjectFiles($recipe, $sourceRoot, $destinationRoot, $filePatterns)
+ {
+ $fileIterator = $this->getFileIterator($sourceRoot, $filePatterns);
+ foreach($fileIterator as $path => $info) {
+ $relativePath = substr($path, strlen($sourceRoot));
+ $destination = $destinationRoot . $relativePath;
+
+ // Only copy non-existent files
+ if (file_exists($destination)) {
+ continue;
+ }
+ $this->io->write("Installing recipe $recipe file $relativePath");
+ $this->filesystem->ensureDirectoryExists(dirname($destination));
+ file_put_contents($destination, file_get_contents($path));
+ }
+ }
+
+ /**
+ * Get iterator of matching source files to copy
+ *
+ * @param string $sourceRoot Root directory of sources (no trailing slash)
+ * @param array $patterns List of wildcard patterns to match
+ * @return Iterator File iterator, where key is path and value is file info object
+ */
+ public function getFileIterator($sourceRoot, $patterns) {
+ // Build regexp pattern
+ $expressions = [];
+ foreach($patterns as $pattern) {
+ $expressions[] = $this->globToRegexp($pattern);
+ }
+ $regExp = '#' . $this->globToRegexp($sourceRoot . '/').'(('.implode(')|(', $expressions).'))#';
+
+ // Build directory iterator
+ $directoryIterator = new RecursiveDirectoryIterator(
+ $sourceRoot,
+ FilesystemIterator::SKIP_DOTS
+ | FilesystemIterator::UNIX_PATHS
+ | FilesystemIterator::KEY_AS_PATHNAME
+ | FilesystemIterator::CURRENT_AS_FILEINFO
+ );
+
+ // Return filtered iterator
+ $iterator = new RecursiveIteratorIterator($directoryIterator);
+ return new RegexIterator($iterator, $regExp);
+ }
+
+ /**
+ * Convert glob pattern to regexp
+ *
+ * @param string $glob
+ * @return string
+ */
+ protected function globToRegexp($glob) {
+ $sourceParts = explode('*', $glob);
+ $regexParts = array_map(function($part) {
+ return preg_quote($part, '#');
+ }, $sourceParts);
+ return implode('(.+)', $regexParts);
}
}