mirror of
https://github.com/silverstripe/recipe-plugin.git
synced 2024-09-30 03:29:00 +02:00
Compare commits
23 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
acb067fdc2 | ||
|
e5dceb4546 | ||
|
c4e8728ff9 | ||
|
da89aa5dcc | ||
|
4ec7b15347 | ||
|
2f74096ea4 | ||
|
2175573ca5 | ||
|
f68a4cc2be | ||
|
301daf2437 | ||
|
8a77da94d1 | ||
|
02f5008b46 | ||
|
a76509e8a6 | ||
|
102c2bc100 | ||
|
68c7402854 | ||
|
da7ccb0a09 | ||
|
01c9b45185 | ||
|
374f223a17 | ||
|
88cd7ed3a0 | ||
|
96cd4972a0 | ||
|
eacf7e3c06 | ||
|
9ab71cf1e9 | ||
|
3e16a5b138 | ||
|
a959a68e54 |
@ -13,3 +13,6 @@ insert_final_newline = true
|
|||||||
trim_trailing_whitespace = true
|
trim_trailing_whitespace = true
|
||||||
indent_style = space
|
indent_style = space
|
||||||
indent_size = 4
|
indent_size = 4
|
||||||
|
|
||||||
|
[composer.json]
|
||||||
|
indent_size = 4
|
||||||
|
11
.github/workflows/ci.yml
vendored
Normal file
11
.github/workflows/ci.yml
vendored
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
name: CI
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
pull_request:
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
ci:
|
||||||
|
name: CI
|
||||||
|
uses: silverstripe/gha-ci/.github/workflows/ci.yml@v1
|
16
.github/workflows/dispatch-ci.yml
vendored
Normal file
16
.github/workflows/dispatch-ci.yml
vendored
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
name: Dispatch CI
|
||||||
|
|
||||||
|
on:
|
||||||
|
# At 12:00 PM UTC, only on Friday and Saturday
|
||||||
|
schedule:
|
||||||
|
- cron: '0 12 * * 5,6'
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
dispatch-ci:
|
||||||
|
name: Dispatch CI
|
||||||
|
# Only run cron on the silverstripe account
|
||||||
|
if: (github.event_name == 'schedule' && github.repository_owner == 'silverstripe') || (github.event_name != 'schedule')
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Dispatch CI
|
||||||
|
uses: silverstripe/gha-dispatch-ci@v1
|
17
.github/workflows/keepalive.yml
vendored
Normal file
17
.github/workflows/keepalive.yml
vendored
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
name: Keepalive
|
||||||
|
|
||||||
|
on:
|
||||||
|
workflow_dispatch:
|
||||||
|
# The 4th of every month at 10:50am UTC
|
||||||
|
schedule:
|
||||||
|
- cron: '50 10 4 * *'
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
keepalive:
|
||||||
|
name: Keepalive
|
||||||
|
# Only run cron on the silverstripe account
|
||||||
|
if: (github.event_name == 'schedule' && github.repository_owner == 'silverstripe') || (github.event_name != 'schedule')
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Keepalive
|
||||||
|
uses: silverstripe/gha-keepalive@v1
|
30
README.md
30
README.md
@ -1,4 +1,7 @@
|
|||||||
# SilverStripe recipe-plugin
|
# Silverstripe recipe-plugin
|
||||||
|
|
||||||
|
[![CI](https://github.com/silverstripe/recipe-plugin/actions/workflows/ci.yml/badge.svg)](https://github.com/silverstripe/recipe-plugin/actions/workflows/ci.yml)
|
||||||
|
[![Silverstripe supported module](https://img.shields.io/badge/silverstripe-supported-0071C4.svg)](https://www.silverstripe.org/software/addons/silverstripe-commercially-supported-module-list/)
|
||||||
|
|
||||||
## Introduction
|
## Introduction
|
||||||
|
|
||||||
@ -133,6 +136,9 @@ Recipe types should follow the following rules:
|
|||||||
- The `require` must have `silverstripe/recipe-plugin` as a dependency.
|
- 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
|
- `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.
|
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:
|
An example recipe:
|
||||||
|
|
||||||
@ -151,9 +157,31 @@ An example recipe:
|
|||||||
"project-files": [
|
"project-files": [
|
||||||
"mysite/_config/*.yml",
|
"mysite/_config/*.yml",
|
||||||
"mysite/code/MyBlogPage.php"
|
"mysite/code/MyBlogPage.php"
|
||||||
|
"client/src/*"
|
||||||
|
],
|
||||||
|
"public-files": [
|
||||||
|
"client/dist/*"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"prefer-stable": true,
|
"prefer-stable": true,
|
||||||
"minimum-stability": "dev"
|
"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
|
||||||
|
```
|
||||||
|
@ -17,11 +17,16 @@
|
|||||||
"extra": {
|
"extra": {
|
||||||
"class": "SilverStripe\\RecipePlugin\\RecipePlugin"
|
"class": "SilverStripe\\RecipePlugin\\RecipePlugin"
|
||||||
},
|
},
|
||||||
|
"scripts": {
|
||||||
|
"lint": "phpcs src/",
|
||||||
|
"lint-clean": "phpcbf src/"
|
||||||
|
},
|
||||||
"require": {
|
"require": {
|
||||||
"composer-plugin-api": "^1.1"
|
"composer-plugin-api": "^1.1 || ^2"
|
||||||
},
|
},
|
||||||
"require-dev": {
|
"require-dev": {
|
||||||
"composer/composer": "^1.2"
|
"composer/composer": "^1.2 || 2",
|
||||||
|
"squizlabs/php_codesniffer": "^3.5"
|
||||||
},
|
},
|
||||||
"minimum-stability": "dev"
|
"minimum-stability": "dev"
|
||||||
}
|
}
|
||||||
|
12
phpcs.xml.dist
Normal file
12
phpcs.xml.dist
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<ruleset name="SilverStripe">
|
||||||
|
<description>CodeSniffer ruleset for SilverStripe coding conventions.</description>
|
||||||
|
|
||||||
|
<file>src</file>
|
||||||
|
|
||||||
|
<!-- base rules are PSR-12 -->
|
||||||
|
<rule ref="PSR12" >
|
||||||
|
<exclude name="PSR1.Methods.CamelCapsMethodName.NotCamelCaps" />
|
||||||
|
<exclude name="PSR1.Files.SideEffects.FoundWithSymbols" />
|
||||||
|
</rule>
|
||||||
|
</ruleset>
|
@ -14,31 +14,6 @@ use Symfony\Component\Console\Output\OutputInterface;
|
|||||||
|
|
||||||
trait RecipeCommandBehaviour
|
trait RecipeCommandBehaviour
|
||||||
{
|
{
|
||||||
/**
|
|
||||||
* Gets the application instance for this command.
|
|
||||||
*
|
|
||||||
* @return Application An Application instance
|
|
||||||
*/
|
|
||||||
public abstract function getApplication();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param bool $required
|
|
||||||
* @param bool|null $disablePlugins
|
|
||||||
* @throws \RuntimeException
|
|
||||||
* @return Composer
|
|
||||||
*/
|
|
||||||
public abstract function getComposer($required = true, $disablePlugins = null);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Removes the cached composer instance
|
|
||||||
*/
|
|
||||||
public abstract function resetComposer();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return IOInterface
|
|
||||||
*/
|
|
||||||
abstract public function getIO();
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param OutputInterface $output
|
* @param OutputInterface $output
|
||||||
* @param string $recipe
|
* @param string $recipe
|
||||||
@ -128,17 +103,17 @@ trait RecipeCommandBehaviour
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Existing version is already a ^1.0.0 or ~1.0.0 constraint
|
// Existing version is already a ^1.0.0 or ~1.0.0 constraint
|
||||||
if (preg_match('#^[~^]#', $existingVersion)) {
|
if (preg_match('#^[~^]#', $existingVersion ?? '')) {
|
||||||
return $existingVersion;
|
return $existingVersion;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Existing version is already a dev constraint
|
// Existing version is already a dev constraint
|
||||||
if (stristr($existingVersion, 'dev') !== false) {
|
if (stristr($existingVersion ?? '', 'dev') !== false) {
|
||||||
return $existingVersion;
|
return $existingVersion;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Numeric-only version maps to semver constraint
|
// Numeric-only version maps to semver constraint
|
||||||
if (preg_match('#^([\d.]+)$#', $existingVersion)) {
|
if (preg_match('#^([\d.]+)$#', $existingVersion ?? '')) {
|
||||||
return "^{$existingVersion}";
|
return "^{$existingVersion}";
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -242,7 +217,7 @@ trait RecipeCommandBehaviour
|
|||||||
|
|
||||||
// Add new require / extra-installed
|
// Add new require / extra-installed
|
||||||
$composerData['require'] = $require;
|
$composerData['require'] = $require;
|
||||||
if ($previouslyInstalled){
|
if ($previouslyInstalled) {
|
||||||
if (!isset($composerData['extra'])) {
|
if (!isset($composerData['extra'])) {
|
||||||
$composerData['extra'] = [];
|
$composerData['extra'] = [];
|
||||||
}
|
}
|
||||||
|
@ -14,9 +14,15 @@ use RecursiveDirectoryIterator;
|
|||||||
use RecursiveIteratorIterator;
|
use RecursiveIteratorIterator;
|
||||||
use RegexIterator;
|
use RegexIterator;
|
||||||
|
|
||||||
class RecipeInstaller extends LibraryInstaller {
|
class RecipeInstaller extends LibraryInstaller
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @var bool
|
||||||
|
*/
|
||||||
|
private $hasWrittenFiles = false;
|
||||||
|
|
||||||
public function __construct(IOInterface $io, Composer $composer) {
|
public function __construct(IOInterface $io, Composer $composer)
|
||||||
|
{
|
||||||
parent::__construct($io, $composer, null);
|
parent::__construct($io, $composer, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -27,69 +33,100 @@ class RecipeInstaller extends LibraryInstaller {
|
|||||||
* @param string $sourceRoot Base of source files (no trailing slash)
|
* @param string $sourceRoot Base of source files (no trailing slash)
|
||||||
* @param string $destinationRoot Base of destination directory (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 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
|
// load composer json data
|
||||||
$composerFile = new JsonFile(Factory::getComposerFile(), null, $this->io);
|
$composerFile = new JsonFile(Factory::getComposerFile(), null, $this->io);
|
||||||
$composerData = $composerFile->read();
|
$composerData = $composerFile->read();
|
||||||
$installedFiles = isset($composerData['extra'][RecipePlugin::PROJECT_FILES_INSTALLED])
|
$installedFiles = isset($composerData['extra'][$registrationKey])
|
||||||
? $composerData['extra'][RecipePlugin::PROJECT_FILES_INSTALLED]
|
? $composerData['extra'][$registrationKey]
|
||||||
: [];
|
: [];
|
||||||
|
|
||||||
// Load all project files
|
// Load all project files
|
||||||
$fileIterator = $this->getFileIterator($sourceRoot, $filePatterns);
|
$fileIterator = $this->getFileIterator($sourceRoot, $filePatterns);
|
||||||
$any = false;
|
$any = false;
|
||||||
foreach($fileIterator as $path => $info) {
|
foreach ($fileIterator as $path => $info) {
|
||||||
$destination = $destinationRoot . substr($path, strlen($sourceRoot));
|
// Write header on first file
|
||||||
$relativePath = substr($path, strlen($sourceRoot) + 1); // Name path without leading '/'
|
|
||||||
|
|
||||||
// Write header
|
|
||||||
if (!$any) {
|
if (!$any) {
|
||||||
$this->io->write("Installing project files for recipe <info>{$recipe}</info>:");
|
$this->io->write("Installing {$name} files for recipe <info>{$recipe}</info>:");
|
||||||
$any = true;
|
$any = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if file exists
|
// Install this file
|
||||||
if (file_exists($destination)) {
|
$relativePath = $this->installProjectFile($sourceRoot, $destinationRoot, $path, $installedFiles);
|
||||||
if (file_get_contents($destination) === file_get_contents($path)) {
|
|
||||||
$this->io->write(
|
|
||||||
" - Skipping <info>$relativePath</info> (<comment>existing, but unchanged</comment>)"
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
$this->io->write(
|
|
||||||
" - Skipping <info>$relativePath</info> (<comment>existing and modified in project</comment>)"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
} elseif (in_array($relativePath, $installedFiles)) {
|
|
||||||
// Don't re-install previously installed files that have been deleted
|
|
||||||
$this->io->write(
|
|
||||||
" - Skipping <info>$relativePath</info> (<comment>previously installed</comment>)"
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
$any++;
|
|
||||||
$this->io->write(" - Copying <info>$relativePath</info>");
|
|
||||||
$this->filesystem->ensureDirectoryExists(dirname($destination));
|
|
||||||
copy($path, $destination);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add file to installed (even if already exists)
|
// Add file to installed (even if already exists)
|
||||||
if (!in_array($relativePath, $installedFiles)) {
|
if (!in_array($relativePath, $installedFiles ?? [])) {
|
||||||
$installedFiles[] = $relativePath;
|
$installedFiles[] = $relativePath;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// If any files are written, modify composer.json with newly installed files
|
// If any files are written, modify composer.json with newly installed files
|
||||||
if ($installedFiles) {
|
if ($this->hasWrittenFiles) {
|
||||||
sort($installedFiles);
|
sort($installedFiles);
|
||||||
if (!isset($composerData['extra'])) {
|
if (!isset($composerData['extra'])) {
|
||||||
$composerData['extra'] = [];
|
$composerData['extra'] = [];
|
||||||
}
|
}
|
||||||
$composerData['extra'][RecipePlugin::PROJECT_FILES_INSTALLED] = $installedFiles;
|
$composerData['extra'][$registrationKey] = $installedFiles;
|
||||||
$composerFile->write($composerData);
|
$composerFile->write($composerData);
|
||||||
|
// Reset the variable so that we can try this trick again later
|
||||||
|
$this->hasWrittenFiles = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $sourceRoot Base of source files (no trailing slash)
|
||||||
|
* @param string $destinationRoot Base of destination directory (no trailing slash)
|
||||||
|
* @param string $sourcePath Full filesystem path to the file to copy
|
||||||
|
* @param array $installedFiles List of installed files
|
||||||
|
* @return bool|string
|
||||||
|
*/
|
||||||
|
protected function installProjectFile($sourceRoot, $destinationRoot, $sourcePath, $installedFiles)
|
||||||
|
{
|
||||||
|
// Relative path
|
||||||
|
$relativePath = substr($sourcePath ?? '', strlen($sourceRoot ?? '') + 1); // Name path without leading '/'
|
||||||
|
|
||||||
|
// Get destination path
|
||||||
|
$relativeDestination = $this->rewriteFilePath($destinationRoot, $relativePath);
|
||||||
|
$destination = $destinationRoot . DIRECTORY_SEPARATOR . $relativeDestination;
|
||||||
|
|
||||||
|
// Check if file exists
|
||||||
|
if (file_exists($destination ?? '')) {
|
||||||
|
if (file_get_contents($destination ?? '') === file_get_contents($sourcePath ?? '')) {
|
||||||
|
$this->io->write(
|
||||||
|
" - Skipping <info>$relativePath</info> (<comment>existing, but unchanged</comment>)"
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
$this->io->write(
|
||||||
|
" - Skipping <info>$relativePath</info> (<comment>existing and modified in project</comment>)"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} elseif (
|
||||||
|
in_array($relativePath, $installedFiles ?? []) ||
|
||||||
|
in_array($relativeDestination, $installedFiles ?? [])
|
||||||
|
) {
|
||||||
|
// Don't re-install previously installed files that have been deleted
|
||||||
|
$this->io->write(
|
||||||
|
" - Skipping <info>$relativePath</info> (<comment>previously installed</comment>)"
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
$this->io->write(" - Copying <info>$relativePath</info>");
|
||||||
|
$this->filesystem->ensureDirectoryExists(dirname($destination ?? ''));
|
||||||
|
copy($sourcePath ?? '', $destination ?? '');
|
||||||
|
$this->hasWrittenFiles = true;
|
||||||
|
}
|
||||||
|
return $relativePath;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get iterator of matching source files to copy
|
* Get iterator of matching source files to copy
|
||||||
*
|
*
|
||||||
@ -97,13 +134,14 @@ class RecipeInstaller extends LibraryInstaller {
|
|||||||
* @param array $patterns List of wildcard patterns to match
|
* @param array $patterns List of wildcard patterns to match
|
||||||
* @return Iterator File iterator, where key is path and value is file info object
|
* @return Iterator File iterator, where key is path and value is file info object
|
||||||
*/
|
*/
|
||||||
protected function getFileIterator($sourceRoot, $patterns) {
|
protected function getFileIterator($sourceRoot, $patterns)
|
||||||
|
{
|
||||||
// Build regexp pattern
|
// Build regexp pattern
|
||||||
$expressions = [];
|
$expressions = [];
|
||||||
foreach($patterns as $pattern) {
|
foreach ($patterns as $pattern) {
|
||||||
$expressions[] = $this->globToRegexp($pattern);
|
$expressions[] = $this->globToRegexp($pattern);
|
||||||
}
|
}
|
||||||
$regExp = '#^' . $this->globToRegexp($sourceRoot . '/').'(('.implode(')|(', $expressions).'))$#';
|
$regExp = '#^' . $this->globToRegexp($sourceRoot . '/') . '((' . implode(')|(', $expressions) . '))$#';
|
||||||
|
|
||||||
// Build directory iterator
|
// Build directory iterator
|
||||||
$directoryIterator = new RecursiveDirectoryIterator(
|
$directoryIterator = new RecursiveDirectoryIterator(
|
||||||
@ -125,11 +163,12 @@ class RecipeInstaller extends LibraryInstaller {
|
|||||||
* @param string $glob
|
* @param string $glob
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
protected function globToRegexp($glob) {
|
protected function globToRegexp($glob)
|
||||||
$sourceParts = explode('*', $glob);
|
{
|
||||||
$regexParts = array_map(function($part) {
|
$sourceParts = explode('*', $glob ?? '');
|
||||||
return preg_quote($part, '#');
|
$regexParts = array_map(function ($part) {
|
||||||
}, $sourceParts);
|
return preg_quote($part ?? '', '#');
|
||||||
|
}, $sourceParts ?? []);
|
||||||
return implode('(.+)', $regexParts);
|
return implode('(.+)', $regexParts);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -143,19 +182,77 @@ class RecipeInstaller extends LibraryInstaller {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Find recipe base dir
|
||||||
|
$recipePath = $this->getInstallPath($package);
|
||||||
|
|
||||||
// Find project path
|
// 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
|
// Copy project files to root
|
||||||
$name = $package->getName();
|
$name = $package->getName();
|
||||||
$extra = $package->getExtra();
|
$extra = $package->getExtra();
|
||||||
|
|
||||||
|
// Install project-files
|
||||||
if (isset($extra[RecipePlugin::PROJECT_FILES])) {
|
if (isset($extra[RecipePlugin::PROJECT_FILES])) {
|
||||||
$this->installProjectFiles(
|
$this->installProjectFiles(
|
||||||
$name,
|
$name,
|
||||||
$this->getInstallPath($package),
|
$recipePath,
|
||||||
$destinationPath,
|
$projectPath,
|
||||||
$extra[RecipePlugin::PROJECT_FILES]
|
$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'
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Perform any file rewrites necessary to a relative path of a file being installed.
|
||||||
|
* E.g. if 'mysite' folder exists, rewrite 'mysite' to 'app' and 'mysite/code' to 'app/src'
|
||||||
|
*
|
||||||
|
* This will be removed in 2.0 as the app folder will be hard coded and no rewrites supported.
|
||||||
|
*
|
||||||
|
* @deprecated 1.2.0 Will be removed without equivalent functionality to replace it
|
||||||
|
* @param string $destinationRoot Project root
|
||||||
|
* @param string $relativePath Relative path to the resource being installed
|
||||||
|
* @return string Relative path we should write to
|
||||||
|
*/
|
||||||
|
protected function rewriteFilePath($destinationRoot, $relativePath)
|
||||||
|
{
|
||||||
|
// If app folder exists, no rewrite
|
||||||
|
if (is_dir($destinationRoot . DIRECTORY_SEPARATOR . 'app')) {
|
||||||
|
return $relativePath;
|
||||||
|
}
|
||||||
|
// if mysite folder does NOT exist, no rewrite
|
||||||
|
if (!is_dir($destinationRoot . DIRECTORY_SEPARATOR . 'mysite')) {
|
||||||
|
return $relativePath;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return first rewrite
|
||||||
|
$rewrites = [
|
||||||
|
'app/src' => 'mysite/code',
|
||||||
|
'app' => 'mysite',
|
||||||
|
];
|
||||||
|
foreach ($rewrites as $from => $to) {
|
||||||
|
if (stripos($relativePath ?? '', $from ?? '') === 0) {
|
||||||
|
return $to . substr($relativePath ?? '', strlen($from ?? ''));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return $relativePath;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
|
||||||
namespace SilverStripe\RecipePlugin;
|
namespace SilverStripe\RecipePlugin;
|
||||||
|
|
||||||
use Composer\Composer;
|
use Composer\Composer;
|
||||||
@ -27,22 +26,37 @@ class RecipePlugin implements PluginInterface, EventSubscriberInterface, Capable
|
|||||||
/**
|
/**
|
||||||
* Type of recipe to check for
|
* Type of recipe to check for
|
||||||
*/
|
*/
|
||||||
const RECIPE_TYPE = 'silverstripe-recipe';
|
public const RECIPE_TYPE = 'silverstripe-recipe';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 'extra' key for project files
|
* 'extra' key for project files
|
||||||
*/
|
*/
|
||||||
const PROJECT_FILES = 'project-files';
|
public const PROJECT_FILES = 'project-files';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 'extra' key for public files
|
||||||
|
*/
|
||||||
|
public const PUBLIC_FILES = 'public-files';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Hard-coded 'public' web-root folder
|
||||||
|
*/
|
||||||
|
public const PUBLIC_PATH = 'public';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 'extra' key for list of project files installed
|
* 'extra' key for list of project files installed
|
||||||
*/
|
*/
|
||||||
const PROJECT_FILES_INSTALLED = 'project-files-installed';
|
public const PROJECT_FILES_INSTALLED = 'project-files-installed';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 'extra' key for list of public files installed
|
||||||
|
*/
|
||||||
|
public const PUBLIC_FILES_INSTALLED = 'public-files-installed';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 'extra' key for project dependencies installed
|
* 'extra' key for project dependencies installed
|
||||||
*/
|
*/
|
||||||
const PROJECT_DEPENDENCIES_INSTALLED = 'project-dependencies-installed';
|
public const PROJECT_DEPENDENCIES_INSTALLED = 'project-dependencies-installed';
|
||||||
|
|
||||||
public function activate(Composer $composer, IOInterface $io)
|
public function activate(Composer $composer, IOInterface $io)
|
||||||
{
|
{
|
||||||
@ -81,8 +95,11 @@ class RecipePlugin implements PluginInterface, EventSubscriberInterface, Capable
|
|||||||
$file = new JsonFile(Factory::getComposerFile());
|
$file = new JsonFile(Factory::getComposerFile());
|
||||||
$data = $file->read();
|
$data = $file->read();
|
||||||
|
|
||||||
// Remove project-files from project, and any empty extra
|
// Remove project and public files from project
|
||||||
unset($data['extra']['project-files']);
|
unset($data['extra'][self::PROJECT_FILES]);
|
||||||
|
unset($data['extra'][self::PUBLIC_FILES]);
|
||||||
|
|
||||||
|
// Remove redundant empty extra
|
||||||
if (empty($data['extra'])) {
|
if (empty($data['extra'])) {
|
||||||
unset($data['extra']);
|
unset($data['extra']);
|
||||||
}
|
}
|
||||||
@ -115,4 +132,13 @@ class RecipePlugin implements PluginInterface, EventSubscriberInterface, Capable
|
|||||||
CommandProvider::class => RecipeCommandProvider::class
|
CommandProvider::class => RecipeCommandProvider::class
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public function deactivate(Composer $composer, IOInterface $io)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public function uninstall(Composer $composer, IOInterface $io)
|
||||||
|
{
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user