|
1
|
|
|
<?php |
|
2
|
|
|
|
|
3
|
|
|
/** |
|
4
|
|
|
* @param string $current_dir |
|
5
|
|
|
* @param bool $has_explicit_root |
|
6
|
|
|
* @param string $vendor_dir |
|
7
|
|
|
* |
|
8
|
|
|
* @return void |
|
9
|
|
|
*/ |
|
10
|
|
|
function requireAutoloaders($current_dir, $has_explicit_root, $vendor_dir) |
|
11
|
|
|
{ |
|
12
|
|
|
$autoload_roots = [$current_dir]; |
|
13
|
|
|
|
|
14
|
|
|
$psalm_dir = dirname(__DIR__); |
|
15
|
|
|
|
|
16
|
|
|
if (realpath($psalm_dir) !== realpath($current_dir)) { |
|
17
|
|
|
$autoload_roots[] = $psalm_dir; |
|
18
|
|
|
} |
|
19
|
|
|
|
|
20
|
|
|
$autoload_files = []; |
|
21
|
|
|
|
|
22
|
|
|
foreach ($autoload_roots as $autoload_root) { |
|
23
|
|
|
$has_autoloader = false; |
|
24
|
|
|
|
|
25
|
|
|
$nested_autoload_file = dirname(dirname($autoload_root)) . DIRECTORY_SEPARATOR . 'autoload.php'; |
|
26
|
|
|
|
|
27
|
|
|
if (file_exists($nested_autoload_file)) { |
|
28
|
|
|
$autoload_files[] = realpath($nested_autoload_file); |
|
29
|
|
|
$has_autoloader = true; |
|
30
|
|
|
} |
|
31
|
|
|
|
|
32
|
|
|
$vendor_autoload_file = $autoload_root . DIRECTORY_SEPARATOR . $vendor_dir . DIRECTORY_SEPARATOR . 'autoload.php'; |
|
33
|
|
|
|
|
34
|
|
|
if (file_exists($vendor_autoload_file)) { |
|
35
|
|
|
$autoload_files[] = realpath($vendor_autoload_file); |
|
36
|
|
|
$has_autoloader = true; |
|
37
|
|
|
} |
|
38
|
|
|
|
|
39
|
|
|
if (!$has_autoloader) { |
|
40
|
|
|
$error_message = 'Could not find any composer autoloaders in ' . $autoload_root; |
|
41
|
|
|
|
|
42
|
|
|
if (!$has_explicit_root) { |
|
43
|
|
|
$error_message .= PHP_EOL . 'Add a --root=[your/project/directory] flag ' |
|
44
|
|
|
. 'to specify a particular project to run Psalm on.'; |
|
45
|
|
|
} |
|
46
|
|
|
|
|
47
|
|
|
die($error_message . PHP_EOL); |
|
|
|
|
|
|
48
|
|
|
} |
|
49
|
|
|
} |
|
50
|
|
|
|
|
51
|
|
|
foreach ($autoload_files as $file) { |
|
52
|
|
|
/** @psalm-suppress UnresolvableInclude */ |
|
53
|
|
|
require_once $file; |
|
54
|
|
|
} |
|
55
|
|
|
} |
|
56
|
|
|
|
|
57
|
|
|
/** |
|
58
|
|
|
* @param string $current_dir |
|
59
|
|
|
* |
|
60
|
|
|
* @return string |
|
61
|
|
|
* |
|
62
|
|
|
* @psalm-suppress PossiblyFalseArgument |
|
63
|
|
|
* @psalm-suppress MixedArrayAccess |
|
64
|
|
|
* @psalm-suppress MixedAssignment |
|
65
|
|
|
*/ |
|
66
|
|
View Code Duplication |
function getVendorDir($current_dir) |
|
|
|
|
|
|
67
|
|
|
{ |
|
68
|
|
|
$composer_json_path = $current_dir . DIRECTORY_SEPARATOR . 'composer.json'; // this should ideally not be hardcoded |
|
69
|
|
|
|
|
70
|
|
|
if (!file_exists($composer_json_path)) { |
|
71
|
|
|
return 'vendor'; |
|
72
|
|
|
} |
|
73
|
|
|
|
|
74
|
|
|
if (!$composer_json = json_decode(file_get_contents($composer_json_path), true)) { |
|
75
|
|
|
throw new \UnexpectedValueException('Invalid composer.json at ' . $composer_json_path); |
|
76
|
|
|
} |
|
77
|
|
|
|
|
78
|
|
|
if (isset($composer_json['config']['vendor-dir'])) { |
|
79
|
|
|
return (string) $composer_json['config']['vendor-dir']; |
|
80
|
|
|
} |
|
81
|
|
|
|
|
82
|
|
|
return 'vendor'; |
|
83
|
|
|
} |
|
84
|
|
|
|
|
85
|
|
|
/** |
|
86
|
|
|
* @param string|array|null|false $f_paths |
|
87
|
|
|
* |
|
88
|
|
|
* @return string[]|null |
|
89
|
|
|
*/ |
|
90
|
|
|
function getPathsToCheck($f_paths) |
|
91
|
|
|
{ |
|
92
|
|
|
global $argv; |
|
|
|
|
|
|
93
|
|
|
|
|
94
|
|
|
$paths_to_check = []; |
|
95
|
|
|
|
|
96
|
|
|
if ($f_paths) { |
|
97
|
|
|
$input_paths = is_array($f_paths) ? $f_paths : [$f_paths]; |
|
98
|
|
|
} else { |
|
99
|
|
|
$input_paths = $argv ? $argv : null; |
|
100
|
|
|
} |
|
101
|
|
|
|
|
102
|
|
|
if ($input_paths) { |
|
103
|
|
|
$filtered_input_paths = []; |
|
104
|
|
|
|
|
105
|
|
|
for ($i = 0; $i < count($input_paths); ++$i) { |
|
|
|
|
|
|
106
|
|
|
/** @var string */ |
|
107
|
|
|
$input_path = $input_paths[$i]; |
|
108
|
|
|
|
|
109
|
|
|
if (realpath($input_path) === realpath(dirname(__DIR__) . DIRECTORY_SEPARATOR . 'psalm') |
|
110
|
|
|
|| realpath($input_path) === realpath(dirname(__DIR__) . DIRECTORY_SEPARATOR . 'psalter') |
|
111
|
|
|
) { |
|
112
|
|
|
continue; |
|
113
|
|
|
} |
|
114
|
|
|
|
|
115
|
|
|
if ($input_path[0] === '-' && strlen($input_path) === 2) { |
|
116
|
|
|
if ($input_path[1] === 'c' || $input_path[1] === 'f') { |
|
117
|
|
|
++$i; |
|
118
|
|
|
} |
|
119
|
|
|
continue; |
|
120
|
|
|
} |
|
121
|
|
|
|
|
122
|
|
|
if ($input_path[0] === '-' && $input_path[2] === '=') { |
|
123
|
|
|
continue; |
|
124
|
|
|
} |
|
125
|
|
|
|
|
126
|
|
|
if (substr($input_path, 0, 2) === '--' && strlen($input_path) > 2) { |
|
127
|
|
|
continue; |
|
128
|
|
|
} |
|
129
|
|
|
|
|
130
|
|
|
$filtered_input_paths[] = $input_path; |
|
131
|
|
|
} |
|
132
|
|
|
|
|
133
|
|
|
if ($filtered_input_paths === ['-']) { |
|
134
|
|
|
$meta = stream_get_meta_data(STDIN); |
|
135
|
|
|
stream_set_blocking(STDIN, false); |
|
136
|
|
|
if ($stdin = fgets(STDIN)) { |
|
137
|
|
|
$filtered_input_paths = preg_split('/\s+/', trim($stdin)); |
|
138
|
|
|
} |
|
139
|
|
|
/** @var bool */ |
|
140
|
|
|
$blocked = $meta['blocked']; |
|
141
|
|
|
stream_set_blocking(STDIN, $blocked); |
|
142
|
|
|
} |
|
143
|
|
|
|
|
144
|
|
|
foreach ($filtered_input_paths as $i => $path_to_check) { |
|
145
|
|
|
if ($path_to_check[0] === '-') { |
|
146
|
|
|
die('Invalid usage, expecting psalm [options] [file...]' . PHP_EOL); |
|
|
|
|
|
|
147
|
|
|
} |
|
148
|
|
|
|
|
149
|
|
|
if (!file_exists($path_to_check)) { |
|
150
|
|
|
die('Cannot locate ' . $path_to_check . PHP_EOL); |
|
|
|
|
|
|
151
|
|
|
} |
|
152
|
|
|
|
|
153
|
|
|
$path_to_check = realpath($path_to_check); |
|
154
|
|
|
|
|
155
|
|
|
if (!$path_to_check) { |
|
156
|
|
|
die('Error getting realpath for file' . PHP_EOL); |
|
|
|
|
|
|
157
|
|
|
} |
|
158
|
|
|
|
|
159
|
|
|
$paths_to_check[] = $path_to_check; |
|
160
|
|
|
} |
|
161
|
|
|
|
|
162
|
|
|
if (!$paths_to_check) { |
|
|
|
|
|
|
163
|
|
|
$paths_to_check = null; |
|
164
|
|
|
} |
|
165
|
|
|
} |
|
166
|
|
|
|
|
167
|
|
|
return $paths_to_check; |
|
168
|
|
|
} |
|
169
|
|
|
|
An exit expression should only be used in rare cases. For example, if you write a short command line script.
In most cases however, using an
exitexpression makes the code untestable and often causes incompatibilities with other libraries. Thus, unless you are absolutely sure it is required here, we recommend to refactor your code to avoid its usage.