drupal/core/scripts/switch-psr4.sh

322 lines
8.4 KiB
Bash

#!/bin/php
<?php
namespace Drupal\Core\SwitchPsr4;
/**
* @file
* Moves module-provided class files to their PSR-4 location.
*
* E.g.:
* core/modules/action/{lib/Drupal/action → src}/ActionAccessController.php
* core/modules/action/{lib/Drupal/action → src}/ActionAddForm.php
*/
// Determine DRUPAL_ROOT.
$dir = dirname(__FILE__);
while (!defined('DRUPAL_ROOT')) {
if (is_dir($dir . '/core')) {
define('DRUPAL_ROOT', $dir);
}
$dir = dirname($dir);
}
// Run the script.
run();
/**
* Runs the script.
*/
function run() {
$cmd_arguments = $_SERVER['argv'];
// The first argument is the script name.
$scriptname = array_shift($cmd_arguments);
if (in_array('--help', $cmd_arguments)) {
print get_help_text($scriptname);
}
elseif (!empty($cmd_arguments)) {
// If one or more arguments are given, treat those arguments as directories,
// and process all modules found within these directories.
$directories = array();
foreach ($cmd_arguments as $arg) {
if ('-' === $arg{0}) {
// The only valid option is '--help'.
print "Invalid option '$arg'";
return;
}
if (!is_dir($arg)) {
print "The argument '$arg' is not a directory.";
continue;
}
$directories[] = $arg;
}
// Process all directories that were found in the argument list.
foreach ($directories as $dir) {
process_candidate_dir($dir);
}
}
else {
// If no arguments are given, process all modules and profiles in the core
// directories instead.
process_candidate_dir(DRUPAL_ROOT . '/core/modules');
process_candidate_dir(DRUPAL_ROOT . '/core/profiles');
}
}
/**
* @param string $scriptname
*
* @return string
* Help text in case the "--help" option is present.
*/
function get_help_text($scriptname) {
$script = basename($scriptname);
return <<<EOF
Move module class files from PSR-0 to PSR-4.
E.g. the following files would be moved.
- core/modules/action/{lib/Drupal/action → src}/ActionListController.php
- core/modules/action/tests/{Drupal/action/Tests → src}/Menu/ActionLocalTasksTest.php
Class files which are already in the PSR-4 path remain where they are.
Warning: Classes with an underscore in the class name (after the last namespace
separator) will end up in an incorrect location, and need to be fixed manually.
Such class names are not allowed in Drupal coding standards, but they may still
occur in some custom and contrib modules.
The script takes any number of arguments which, if present, specify the
directories to scan for modules and module class files.
If no arguments are given, the following directories will be processed:
- core/modules/
- core/profiles/
See:
- https://drupal.org/node/2083547 Drupal issue
- https://drupal.org/node/2156625 Documentation of PSR-4 in Drupal
Usage: {$script} [OPTIONS] [DIRECTORIES]
Examples: {$script}
{$script} core/modules/views
{$script} modules/contrib modules/custom
{$script} modules/contrib/devel
Options:
--help Display this help page and exit.
EOF;
}
/**
* Scans all subdirectories of a given directory for Drupal extensions, and runs
* process_extension() for each one that it finds.
*
* @param string $dir
* A directory whose subdirectories could contain Drupal extensions.
*/
function process_extensions_base_dir($dir) {
/**
* @var \DirectoryIterator $fileinfo
*/
foreach (new \DirectoryIterator($dir) as $fileinfo) {
if ($fileinfo->isDot()) {
// do nothing
}
elseif ($fileinfo->isDir()) {
process_candidate_dir($fileinfo->getPathname());
}
}
}
/**
* Recursively scans a directory for Drupal extensions, and runs
* process_extension() for each one that it finds.
*
* @param string $dir
* A directory that could be a Drupal extension directory.
*/
function process_candidate_dir($dir) {
/**
* @var \DirectoryIterator $fileinfo
*/
foreach (new \DirectoryIterator($dir) as $fileinfo) {
if ($fileinfo->isDot()) {
// Ignore "." and "..".
}
elseif ($fileinfo->isDir()) {
// It's a directory.
switch ($fileinfo->getFilename()) {
case 'lib':
case 'src':
// Ignore these directory names.
continue;
default:
// Look for more extensions in subdirectories.
process_candidate_dir($fileinfo->getPathname());
}
}
else {
// It's a file.
if (preg_match('/^(.+).info.yml$/', $fileinfo->getFilename(), $m)) {
// It's a *.info.yml file, so we found an extension directory.
$extension_name = $m[1];
}
}
}
if (isset($extension_name)) {
process_extension($extension_name, $dir);
process_extension_phpunit($extension_name, $dir);
}
}
/**
* Process a Drupal extension (module, theme) in a directory.
*
* This will move all class files in this extension from
* lib/Drupal/$extension_name/$path to src/$path.
*
* @param string $name
* Name of the extension.
* @param string $dir
* Directory of the extension.
* @throws \Exception
*/
function process_extension($name, $dir) {
if (!is_dir($source = "$dir/lib/Drupal/$name")) {
// Nothing to do in this module.
return;
}
if (!is_dir($destination = "$dir/src")) {
mkdir($destination);
}
// Move class files two levels up.
move_directory_contents($source, $destination);
// Clean up.
require_dir_empty("$dir/lib/Drupal");
rmdir("$dir/lib/Drupal");
require_dir_empty("$dir/lib");
rmdir("$dir/lib");
}
/**
* Process a Drupal extension (module, theme) in a directory.
*
* This will move all PHPUnit class files in this extension from
* tests/Drupal/$name/Tests/ to tests/src/.
*
* @param string $name
* Name of the extension.
* @param string $dir
* Directory of the extension.
*/
function process_extension_phpunit($name, $dir) {
if (!is_dir($source = "$dir/tests/Drupal/$name/Tests")) {
// Nothing to do in this module.
return;
}
if (!is_dir($dest = "$dir/tests/src")) {
mkdir($dest);
}
// Move class files two levels up.
move_directory_contents($source, $dest);
// Clean up.
require_dir_empty("$dir/tests/Drupal/$name");
rmdir("$dir/tests/Drupal/$name");
require_dir_empty("$dir/tests/Drupal");
rmdir("$dir/tests/Drupal");
}
/**
* Move directory contents from an existing source directory to an existing
* destination directory.
*
* @param string $source
* An existing source directory.
* @param string $destination
* An existing destination directory.
*
* @throws \Exception
*/
function move_directory_contents($source, $destination) {
if (!is_dir($source)) {
throw new \Exception("The source '$source' is not a directory.");
}
if (!is_dir($destination)) {
throw new \Exception("The destination '$destination' is not a directory.");
}
/**
* @var \DirectoryIterator $fileinfo
*/
foreach (new \DirectoryIterator($source) as $fileinfo) {
if ($fileinfo->isDot()) {
continue;
}
$dest_path = $destination . '/' . $fileinfo->getFilename();
if (!file_exists($dest_path)) {
rename($fileinfo->getPathname(), $dest_path);
}
elseif ($fileinfo->isFile()) {
throw new \Exception("Destination '$dest_path' already exists, cannot overwrite.");
}
elseif ($fileinfo->isDir()) {
if (!is_dir($dest_path)) {
throw new \Exception("Destination '$dest_path' is not a directory.");
}
move_directory_contents($fileinfo->getPathname(), $dest_path);
}
}
require_dir_empty($source);
rmdir($source);
}
/**
* Throws an exception if a directory is not empty.
*
* @param string $dir
* Directory to check.
*
* @throws \Exception
*/
function require_dir_empty($dir) {
if (is_file($dir)) {
throw new \Exception("The path '$dir' is a file, when it should be a directory.");
}
if (!is_dir($dir)) {
throw new \Exception("The directory '$dir' does not exist.");
}
if (!is_readable($dir)) {
throw new \Exception("The directory '$dir' is not readable.");
}
/**
* @var \DirectoryIterator $fileinfo
*/
foreach (new \DirectoryIterator($dir) as $fileinfo) {
if ($fileinfo->isDot()) {
continue;
}
$path = $fileinfo->getPathname();
if ($fileinfo->isFile()) {
throw new \Exception("File '$path' found in a directory that should be empty.");
}
elseif ($fileinfo->isDir()) {
throw new \Exception("Subdirectory '$path' found in a directory that should be empty.");
}
}
}