-
Notifications
You must be signed in to change notification settings - Fork 3.4k
/
CommandScanner.php
129 lines (116 loc) · 3.98 KB
/
CommandScanner.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
<?php
/**
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
* Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
*
* Licensed under The MIT License
* For full copyright and license information, please see the LICENSE.txt
* Redistributions of files must retain the above copyright notice.
*
* @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
* @link http://cakephp.org CakePHP(tm) Project
* @since 3.5.0
* @license http://www.opensource.org/licenses/mit-license.php MIT License
*/
namespace Cake\Console;
use Cake\Core\App;
use Cake\Core\Configure;
use Cake\Core\Plugin;
use Cake\Filesystem\Folder;
use Cake\Utility\Inflector;
/**
* Used by CommanCollection and CommandTask to scan the filesystem
* for command classes.
*
* @internal
*/
class CommandScanner
{
/**
* Scan CakePHP core, the applications and plugins for shell classes
*
* @return array
*/
public function scanAll()
{
$shellList = [];
$appNamespace = Configure::read('App.namespace');
$coreShells = $this->scanDir(
dirname(__DIR__) . DIRECTORY_SEPARATOR . 'Shell' . DIRECTORY_SEPARATOR,
'Cake\Shell\\',
'',
['command_list']
);
$coreCommands = $this->scanDir(
dirname(__DIR__) . DIRECTORY_SEPARATOR . 'Command' . DIRECTORY_SEPARATOR,
'Cake\Command\\',
'',
['command_list']
);
$shellList['CORE'] = array_merge($coreShells, $coreCommands);
$appShells = $this->scanDir(
App::path('Shell')[0],
$appNamespace . '\Shell\\',
'',
['app']
);
$appCommands = $this->scanDir(
App::path('Command')[0],
$appNamespace . '\Command\\',
'',
['app']
);
$shellList['app'] = array_merge($appShells, $appCommands);
$plugins = [];
foreach (Plugin::loaded() as $plugin) {
$path = Plugin::classPath($plugin);
$namespace = str_replace('/', '\\', $plugin);
$prefix = Inflector::underscore($plugin) . '.';
$commands = $this->scanDir($path . 'Command', $namespace . '\Command\\', $prefix, []);
$shells = $this->scanDir($path . 'Shell', $namespace . '\Shell\\', $prefix, []);
$plugins[$plugin] = array_merge($shells, $commands);
}
$shellList['plugins'] = $plugins;
return $shellList;
}
/**
* Scan a directory for .php files and return the class names that
* should be within them.
*
* @param string $path The directory to read.
* @param string $namespace The namespace the shells live in.
* @param string $prefix The prefix to apply to commands for their full name.
* @param array $hide A list of command names to hide as they are internal commands.
* @return array The list of shell info arrays based on scanning the filesystem and inflection.
*/
protected function scanDir($path, $namespace, $prefix, array $hide)
{
$dir = new Folder($path);
$contents = $dir->read(true, true);
if (empty($contents[1])) {
return [];
}
$classPattern = '/(Shell|Command)$/';
$shells = [];
foreach ($contents[1] as $file) {
if (substr($file, -4) !== '.php') {
continue;
}
$shell = substr($file, 0, -4);
if (!preg_match($classPattern, $shell)) {
continue;
}
$name = Inflector::underscore(preg_replace($classPattern, '', $shell));
if (in_array($name, $hide, true)) {
continue;
}
$shells[] = [
'file' => $path . $file,
'fullName' => $prefix . $name,
'name' => $name,
'class' => $namespace . $shell
];
}
return $shells;
}
}