2016-09-12 05:35:13 +02:00
|
|
|
<?php
|
|
|
|
|
2016-09-12 05:43:34 +02:00
|
|
|
namespace SilverStripe\RecipePlugin;
|
2016-09-12 05:35:13 +02:00
|
|
|
|
|
|
|
use Composer\Installer\LibraryInstaller;
|
|
|
|
use Composer\Composer;
|
|
|
|
use Composer\IO\IOInterface;
|
|
|
|
use Composer\Package\PackageInterface;
|
2016-09-12 07:37:50 +02:00
|
|
|
use FilesystemIterator;
|
|
|
|
use Iterator;
|
|
|
|
use RecursiveDirectoryIterator;
|
|
|
|
use RecursiveIteratorIterator;
|
|
|
|
use RegexIterator;
|
2016-09-12 05:35:13 +02:00
|
|
|
|
|
|
|
class RecipeInstaller extends LibraryInstaller {
|
|
|
|
|
2016-09-20 03:40:10 +02:00
|
|
|
public function __construct(IOInterface $io, Composer $composer) {
|
|
|
|
parent::__construct($io, $composer, null);
|
2016-09-12 07:37:50 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* 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`)
|
|
|
|
*/
|
2016-09-20 03:40:10 +02:00
|
|
|
protected function installProjectFiles($recipe, $sourceRoot, $destinationRoot, $filePatterns)
|
2016-09-12 07:37:50 +02:00
|
|
|
{
|
|
|
|
$fileIterator = $this->getFileIterator($sourceRoot, $filePatterns);
|
2017-07-10 03:59:00 +02:00
|
|
|
$any = false;
|
2016-09-12 07:37:50 +02:00
|
|
|
foreach($fileIterator as $path => $info) {
|
|
|
|
$relativePath = substr($path, strlen($sourceRoot));
|
|
|
|
$destination = $destinationRoot . $relativePath;
|
|
|
|
|
2017-07-10 03:59:00 +02:00
|
|
|
// Write header
|
|
|
|
if (!$any) {
|
|
|
|
$this->io->write("Installing project files for recipe <info>{$recipe}</info>:");
|
|
|
|
$any = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Check if file exists
|
2016-09-12 07:37:50 +02:00
|
|
|
if (file_exists($destination)) {
|
2017-07-10 03:59:00 +02:00
|
|
|
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>)"
|
|
|
|
);
|
|
|
|
}
|
|
|
|
} else {
|
2017-07-10 07:34:43 +02:00
|
|
|
$this->io->write(" - Copying <info>$relativePath</info>");
|
2017-07-10 03:59:00 +02:00
|
|
|
$this->filesystem->ensureDirectoryExists(dirname($destination));
|
|
|
|
copy($path, $destination);
|
2016-09-12 07:37:50 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2016-09-12 06:04:00 +02:00
|
|
|
|
2016-09-12 07:37:50 +02:00
|
|
|
/**
|
|
|
|
* 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
|
|
|
|
*/
|
2016-09-20 03:40:10 +02:00
|
|
|
protected function getFileIterator($sourceRoot, $patterns) {
|
2016-09-12 07:37:50 +02:00
|
|
|
// Build regexp pattern
|
|
|
|
$expressions = [];
|
|
|
|
foreach($patterns as $pattern) {
|
|
|
|
$expressions[] = $this->globToRegexp($pattern);
|
2016-09-12 06:04:00 +02:00
|
|
|
}
|
2016-09-13 00:25:47 +02:00
|
|
|
$regExp = '#^' . $this->globToRegexp($sourceRoot . '/').'(('.implode(')|(', $expressions).'))$#';
|
2016-09-12 07:37:50 +02:00
|
|
|
|
|
|
|
// 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);
|
|
|
|
}
|
2016-09-12 06:04:00 +02:00
|
|
|
|
2016-09-12 07:37:50 +02:00
|
|
|
/**
|
|
|
|
* 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);
|
2016-09-12 05:35:13 +02:00
|
|
|
}
|
2016-09-20 03:40:10 +02:00
|
|
|
|
|
|
|
/**
|
|
|
|
* @param PackageInterface $package
|
|
|
|
*/
|
|
|
|
public function installLibrary(PackageInterface $package)
|
|
|
|
{
|
2017-07-07 05:47:49 +02:00
|
|
|
// Check if silverstripe-recipe type
|
2017-07-07 07:17:12 +02:00
|
|
|
if ($package->getType() !== 'silverstripe-recipe') {
|
2017-07-07 05:47:49 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2016-09-20 03:40:10 +02:00
|
|
|
// 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']
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
2016-09-12 05:35:13 +02:00
|
|
|
}
|