diff --git a/README.md b/README.md
index 9566e0c..8538a69 100644
--- a/README.md
+++ b/README.md
@@ -133,6 +133,9 @@ Recipe types should follow the following rules:
- The `require` must have `silverstripe/recipe-plugin` as a dependency.
- `extra.project-files` must be declared as a list of wildcard patterns, matching the files in the recipe root
as they should be copied to the root project. The relative paths of these resources are equivalent.
+ - `extra.public-files` must be declared for any files which should be copied to the `public` web folder. If the project
+ in question doesn't have any public folder, these will be copied to root instead. Note that all public files
+ must be committed to the recipe `public` folder.
An example recipe:
@@ -151,9 +154,31 @@ An example recipe:
"project-files": [
"mysite/_config/*.yml",
"mysite/code/MyBlogPage.php"
+ "client/src/*"
+ ],
+ "public-files": [
+ "client/dist/*"
]
},
"prefer-stable": true,
"minimum-stability": "dev"
}
```
+
+The files within this recipe would be organised in the structure:
+
+```
+client/
+ src/
+ blog.scss
+mysite/
+ _config/
+ settings.yml
+ code/
+ MyBlogPage.php
+public/
+ client/
+ dist/
+ blog.css
+composer.json
+```
diff --git a/composer.json b/composer.json
index e969e8e..358607e 100644
--- a/composer.json
+++ b/composer.json
@@ -15,7 +15,10 @@
}
},
"extra": {
- "class": "SilverStripe\\RecipePlugin\\RecipePlugin"
+ "class": "SilverStripe\\RecipePlugin\\RecipePlugin",
+ "branch-alias": {
+ "dev-master": "1.x-dev"
+ }
},
"require": {
"composer-plugin-api": "^1.1"
diff --git a/src/RecipeInstaller.php b/src/RecipeInstaller.php
index e991767..d14b999 100644
--- a/src/RecipeInstaller.php
+++ b/src/RecipeInstaller.php
@@ -27,14 +27,16 @@ public function __construct(IOInterface $io, Composer $composer) {
* @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`)
+ * @param string $registrationKey Registration key for installed files
+ * @param string $name Name of project file type being installed
*/
- protected function installProjectFiles($recipe, $sourceRoot, $destinationRoot, $filePatterns)
+ protected function installProjectFiles($recipe, $sourceRoot, $destinationRoot, $filePatterns, $registrationKey, $name = 'project')
{
// load composer json data
$composerFile = new JsonFile(Factory::getComposerFile(), null, $this->io);
$composerData = $composerFile->read();
- $installedFiles = isset($composerData['extra'][RecipePlugin::PROJECT_FILES_INSTALLED])
- ? $composerData['extra'][RecipePlugin::PROJECT_FILES_INSTALLED]
+ $installedFiles = isset($composerData['extra'][$registrationKey])
+ ? $composerData['extra'][$registrationKey]
: [];
// Load all project files
@@ -46,7 +48,7 @@ protected function installProjectFiles($recipe, $sourceRoot, $destinationRoot, $
// Write header
if (!$any) {
- $this->io->write("Installing project files for recipe {$recipe}:");
+ $this->io->write("Installing {$name} files for recipe {$recipe}:");
$any = true;
}
@@ -85,7 +87,7 @@ protected function installProjectFiles($recipe, $sourceRoot, $destinationRoot, $
if (!isset($composerData['extra'])) {
$composerData['extra'] = [];
}
- $composerData['extra'][RecipePlugin::PROJECT_FILES_INSTALLED] = $installedFiles;
+ $composerData['extra'][$registrationKey] = $installedFiles;
$composerFile->write($composerData);
}
}
@@ -143,18 +145,41 @@ public function installLibrary(PackageInterface $package)
return;
}
+ // Find recipe base dir
+ $recipePath = $this->getInstallPath($package);
+
// Find project path
- $destinationPath = dirname(realpath(Factory::getComposerFile()));
+ $projectPath = dirname(realpath(Factory::getComposerFile()));
+
+ // Find public path
+ $candidatePublicPath = $projectPath . DIRECTORY_SEPARATOR . RecipePlugin::PUBLIC_PATH;
+ $publicPath = is_dir($candidatePublicPath) ? $candidatePublicPath : $projectPath;
// Copy project files to root
$name = $package->getName();
$extra = $package->getExtra();
+
+ // Install project-files
if (isset($extra[RecipePlugin::PROJECT_FILES])) {
$this->installProjectFiles(
$name,
- $this->getInstallPath($package),
- $destinationPath,
- $extra[RecipePlugin::PROJECT_FILES]
+ $recipePath,
+ $projectPath,
+ $extra[RecipePlugin::PROJECT_FILES],
+ RecipePlugin::PROJECT_FILES_INSTALLED,
+ 'project'
+ );
+ }
+
+ // Install public-files
+ if (isset($extra[RecipePlugin::PUBLIC_FILES])) {
+ $this->installProjectFiles(
+ $name,
+ $recipePath . '/' . RecipePlugin::PUBLIC_PATH,
+ $publicPath,
+ $extra[RecipePlugin::PUBLIC_FILES],
+ RecipePlugin::PUBLIC_FILES_INSTALLED,
+ 'public'
);
}
}
diff --git a/src/RecipePlugin.php b/src/RecipePlugin.php
index 262b1c6..2e9e716 100644
--- a/src/RecipePlugin.php
+++ b/src/RecipePlugin.php
@@ -34,11 +34,26 @@ class RecipePlugin implements PluginInterface, EventSubscriberInterface, Capable
*/
const PROJECT_FILES = 'project-files';
+ /**
+ * 'extra' key for public files
+ */
+ const PUBLIC_FILES = 'public-files';
+
+ /**
+ * Hard-coded 'public' web-root folder
+ */
+ const PUBLIC_PATH = 'public';
+
/**
* 'extra' key for list of project files installed
*/
const PROJECT_FILES_INSTALLED = 'project-files-installed';
+ /**
+ * 'extra' key for list of public files installed
+ */
+ const PUBLIC_FILES_INSTALLED = 'public-files-installed';
+
/**
* 'extra' key for project dependencies installed
*/
@@ -81,8 +96,11 @@ public function cleanupProject(Event $event)
$file = new JsonFile(Factory::getComposerFile());
$data = $file->read();
- // Remove project-files from project, and any empty extra
- unset($data['extra']['project-files']);
+ // Remove project and public files from project
+ unset($data['extra'][self::PROJECT_FILES]);
+ unset($data['extra'][self::PUBLIC_FILES]);
+
+ // Remove redundant empty extra
if (empty($data['extra'])) {
unset($data['extra']);
}