This project does not seem to handle request data directly as such no vulnerable execution paths were found.
include
, or for example
via PHP's auto-loading mechanism.
These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
1 | <?php |
||
2 | |||
3 | namespace Consolidation\Cgr; |
||
4 | |||
5 | /** |
||
6 | * Note that this command is deliberately written using only php-native |
||
7 | * libraries, and no external dependencies whatsoever, so that it may |
||
8 | * be installed via `composer global require` without causing any conflicts |
||
9 | * with any other project. |
||
10 | * |
||
11 | * This technique is NOT recommended for other tools. Use Symfony Console |
||
12 | * directly, or, better yet, use Robo (http://robo.li) as a framework. |
||
13 | * See: http://robo.li/framework/ |
||
14 | */ |
||
15 | class Application |
||
16 | { |
||
17 | protected $outputFile = ''; |
||
18 | |||
19 | /** |
||
20 | * Run the cgr tool, a safer alternative to `composer global require`. |
||
21 | * |
||
22 | * @param array $argv The global $argv array passed in by PHP |
||
23 | * @param string $home The path to the composer home directory |
||
24 | * @return integer |
||
25 | */ |
||
26 | public function run($argv, $home) |
||
27 | { |
||
28 | $optionDefaultValues = $this->getDefaultOptionValues($home); |
||
29 | $optionDefaultValues = $this->overlayEnvironmentValues($optionDefaultValues); |
||
30 | |||
31 | list($argv, $options) = $this->parseOutOurOptions($argv, $optionDefaultValues); |
||
32 | |||
33 | $helpArg = $this->getHelpArgValue($argv); |
||
34 | if (!empty($helpArg)) { |
||
35 | return $this->help($helpArg); |
||
36 | } |
||
37 | |||
38 | $commandList = $this->separateProjectAndGetCommandList($argv, $home, $options); |
||
39 | if (empty($commandList)) { |
||
40 | return 1; |
||
41 | } |
||
42 | return $this->runCommandList($commandList, $options); |
||
43 | } |
||
44 | |||
45 | /** |
||
46 | * Returns the first argument after `help`, or the |
||
47 | * first argument if `--help` is present. Otherwise, |
||
48 | * returns an empty string. |
||
49 | */ |
||
50 | public function getHelpArgValue($argv) |
||
51 | { |
||
52 | $hasHelp = false; |
||
53 | $helpArg = ''; |
||
54 | |||
55 | foreach ($argv as $arg) { |
||
56 | if (($arg == 'help') || ($arg == '--help') || ($arg == '-h')) { |
||
57 | $hasHelp = true; |
||
58 | } elseif (($arg[0] != '-') && empty($helpArg)) { |
||
59 | $helpArg = $arg; |
||
60 | } |
||
61 | } |
||
62 | |||
63 | if (!$hasHelp) { |
||
64 | return false; |
||
65 | } |
||
66 | |||
67 | if (empty($helpArg)) { |
||
68 | return 'help'; |
||
69 | } |
||
70 | |||
71 | return $helpArg; |
||
72 | } |
||
73 | |||
74 | public function help($helpArg) |
||
75 | { |
||
76 | $helpFile = dirname(__DIR__) . '/help/' . $helpArg; |
||
77 | |||
78 | if (!file_exists($helpFile)) { |
||
79 | print "No help available for '$helpArg'\n"; |
||
80 | return 1; |
||
81 | } |
||
82 | |||
83 | $helpContents = file_get_contents($helpFile); |
||
84 | print $helpContents; |
||
85 | return 0; |
||
86 | } |
||
87 | |||
88 | /** |
||
89 | * Set up output redirection. Used by tests. |
||
90 | */ |
||
91 | public function setOutputFile($outputFile) |
||
92 | { |
||
93 | $this->outputFile = $outputFile; |
||
94 | } |
||
95 | |||
96 | /** |
||
97 | * Figure out everything we're going to do, but don't do any of it |
||
98 | * yet, just return the command objects to run. |
||
99 | */ |
||
100 | public function parseArgvAndGetCommandList($argv, $home) |
||
101 | { |
||
102 | $optionDefaultValues = $this->getDefaultOptionValues($home); |
||
103 | $optionDefaultValues = $this->overlayEnvironmentValues($optionDefaultValues); |
||
104 | |||
105 | list($argv, $options) = $this->parseOutOurOptions($argv, $optionDefaultValues); |
||
106 | return $this->separateProjectAndGetCommandList($argv, $home, $options); |
||
107 | } |
||
108 | |||
109 | /** |
||
110 | * Figure out everything we're going to do, but don't do any of it |
||
111 | * yet, just return the command objects to run. |
||
112 | */ |
||
113 | public function separateProjectAndGetCommandList($argv, $home, $options) |
||
114 | { |
||
115 | list($command, $projects, $composerArgs) = $this->separateProjectsFromArgs($argv, $options); |
||
116 | |||
117 | // If command was unknown, then exit with an error message |
||
118 | if (empty($command)) { |
||
119 | print "Unknown command: " . implode(' ', $composerArgs) . "\n"; |
||
120 | exit(1); |
||
121 | } |
||
122 | |||
123 | $commandList = $this->getCommandsToExec($command, $composerArgs, $projects, $options); |
||
124 | return $commandList; |
||
125 | } |
||
126 | |||
127 | /** |
||
128 | * Run all of the commands in a list. Abort early if any fail. |
||
129 | * |
||
130 | * @param array $commandList An array of CommandToExec |
||
131 | * @return integer |
||
132 | */ |
||
133 | public function runCommandList($commandList, $options) |
||
134 | { |
||
135 | foreach ($commandList as $command) { |
||
136 | $exitCode = $command->run($this->outputFile); |
||
137 | if ($exitCode) { |
||
138 | return $exitCode; |
||
139 | } |
||
140 | } |
||
141 | return 0; |
||
142 | } |
||
143 | |||
144 | /** |
||
145 | * Return an array containing a list of commands to execute. Depending on |
||
146 | * the composition of the aguments and projects parameters, this list will |
||
147 | * contain either a single command string to call through to composer (if |
||
148 | * cgr is being used as a composer alias), or it will contain a list of |
||
149 | * appropriate replacement 'composer global require' commands that install |
||
150 | * each project in its own installation directory, while installing each |
||
151 | * projects' binaries in the global Composer bin directory, |
||
152 | * ~/.composer/vendor/bin. |
||
153 | * |
||
154 | * @param array $composerArgs |
||
155 | * @param array $projects |
||
156 | * @param array $options |
||
157 | * @return CommandToExec |
||
158 | */ |
||
159 | public function getCommandsToExec($command, $composerArgs, $projects, $options) |
||
160 | { |
||
161 | $execPath = $options['composer-path']; |
||
162 | |||
163 | // Call requireCommand, updateCommand, or removeCommand, as appropriate. |
||
164 | $methodName = "{$command}Command"; |
||
165 | if (method_exists($this, $methodName)) { |
||
166 | return $this->$methodName($execPath, $composerArgs, $projects, $options); |
||
167 | } else { |
||
168 | // If there is no specific implementation for the requested command, then call 'generalCommand'. |
||
169 | return $this->generalCommand($command, $execPath, $composerArgs, $projects, $options); |
||
170 | } |
||
171 | } |
||
172 | |||
173 | /** |
||
174 | * Return our list of default option values, with paths relative to |
||
175 | * the provided home directory. |
||
176 | * @param string $home The composer home directory |
||
177 | * @return array |
||
178 | */ |
||
179 | public function getDefaultOptionValues($home) |
||
180 | { |
||
181 | return array( |
||
182 | 'composer' => false, |
||
183 | 'composer-path' => 'composer', |
||
184 | 'base-dir' => "$home/global", |
||
185 | 'bin-dir' => "$home/vendor/bin", |
||
186 | 'stability' => false, |
||
187 | ); |
||
188 | } |
||
189 | |||
190 | /** |
||
191 | * Replace option default values with the corresponding |
||
192 | * environment variable value, if it is set. |
||
193 | */ |
||
194 | protected function overlayEnvironmentValues($defaults) |
||
195 | { |
||
196 | foreach ($defaults as $key => $value) { |
||
197 | $envKey = 'CGR_' . strtoupper(strtr($key, '-', '_')); |
||
198 | $envValue = getenv($envKey); |
||
199 | if ($envValue) { |
||
200 | $defaults[$key] = $envValue; |
||
201 | } |
||
202 | } |
||
203 | return $defaults; |
||
204 | } |
||
205 | |||
206 | /** |
||
207 | * We use our own special-purpose argv parser. The options that apply |
||
208 | * to this tool are identified by a simple associative array, where |
||
209 | * the key is the option name, and the value is its default value. |
||
210 | * The result of this function is an array of two items containing: |
||
211 | * - An array of the items in $argv not used to set an option value |
||
212 | * - An array of options containing the user-specified or default values |
||
213 | * |
||
214 | * @param array $argv The global $argv passed in by php |
||
215 | * @param array $optionDefaultValues An associative array |
||
216 | * @return array |
||
217 | */ |
||
218 | public function parseOutOurOptions($argv, $optionDefaultValues) |
||
219 | { |
||
220 | $argv0 = array_shift($argv); |
||
221 | $options['composer'] = (strpos($argv0, 'composer') !== false); |
||
222 | $passAlongArgvItems = array(); |
||
223 | $options = array(); |
||
224 | while (!empty($argv)) { |
||
225 | $arg = array_shift($argv); |
||
226 | if ((substr($arg, 0, 2) == '--') && array_key_exists(substr($arg, 2), $optionDefaultValues)) { |
||
227 | $options[substr($arg, 2)] = array_shift($argv); |
||
228 | } else { |
||
229 | $passAlongArgvItems[] = $arg; |
||
230 | } |
||
231 | } |
||
232 | return array($passAlongArgvItems, $options + $optionDefaultValues); |
||
233 | } |
||
234 | |||
235 | /** |
||
236 | * After our options are removed by parseOutOurOptions, those items remaining |
||
237 | * in $argv will be separated into a list of projects and versions, and |
||
238 | * anything else that is not a project:version. Returns an array of two |
||
239 | * items containing: |
||
240 | * - An associative array, where the key is the project name and the value |
||
241 | * is the version (or an empty string, if no version was specified) |
||
242 | * - The remaining $argv items not used to build the projects array. |
||
243 | * |
||
244 | * @param array $argv The $argv array from parseOutOurOptions() |
||
245 | * @return array |
||
246 | */ |
||
247 | public function separateProjectsFromArgs($argv, $options) |
||
248 | { |
||
249 | $cgrCommands = array('info', 'require', 'update', 'remove', 'extend'); |
||
250 | $command = 'require'; |
||
251 | $composerArgs = array(); |
||
252 | $projects = array(); |
||
253 | $globalMode = !$options['composer']; |
||
254 | foreach ($argv as $arg) { |
||
255 | if ($arg[0] == '-') { |
||
256 | // Any flags (first character is '-') will just be passed |
||
257 | // through to to composer. Flags interpreted by cgr have |
||
258 | // already been removed from $argv. |
||
259 | $composerArgs[] = $arg; |
||
260 | } elseif (strpos($arg, '/') !== false) { |
||
261 | // Arguments containing a '/' name projects. We will split |
||
262 | // the project from its version, allowing the separator |
||
263 | // character to be either a '=' or a ':', and then store the |
||
264 | // result in the $projects array. |
||
265 | $projectAndVersion = explode(':', strtr($arg, '=', ':'), 2) + array('', ''); |
||
266 | list($project, $version) = $projectAndVersion; |
||
267 | $projects[$project] = $version; |
||
268 | } elseif ($this->isComposerVersion($arg)) { |
||
269 | // If an argument is a composer version, then we will alter |
||
270 | // the last project we saw, attaching this version to it. |
||
271 | // This allows us to handle 'a/b:1.0' and 'a/b 1.0' equivalently. |
||
272 | $keys = array_keys($projects); |
||
273 | $lastProject = array_pop($keys); |
||
274 | unset($projects[$lastProject]); |
||
275 | $projects[$lastProject] = $arg; |
||
276 | } elseif ($arg == 'global') { |
||
277 | // Make note if we see the 'global' command. |
||
278 | $globalMode = true; |
||
279 | } elseif ($command == 'extend') { |
||
280 | $projects[$arg] = true; |
||
281 | } else { |
||
282 | // If we see any command other than 'global [require|update|remove]', |
||
283 | // then we will pass *all* of the arguments through to |
||
284 | // composer unchanged. We return an empty projects array |
||
285 | // to indicate that this should be a pass-through call |
||
286 | // to composer, rather than one or more calls to |
||
287 | // 'composer require' to install global projects. |
||
288 | if ((!$globalMode) || (!in_array($arg, $cgrCommands))) { |
||
289 | return array('', array(), $argv); |
||
290 | } |
||
291 | // Remember which command we saw |
||
292 | $command = $arg; |
||
293 | } |
||
294 | } |
||
295 | return array($command, $projects, $composerArgs); |
||
296 | } |
||
297 | |||
298 | /** |
||
299 | * Provide a safer version of `composer global require`. Each project |
||
300 | * listed in $projects will be installed into its own project directory. |
||
301 | * The binaries from each project will still be placed in the global |
||
302 | * composer bin directory. |
||
303 | * |
||
304 | * @param string $execPath The path to composer |
||
305 | * @param array $composerArgs Anything from the global $argv to be passed |
||
306 | * on to Composer |
||
307 | * @param array $projects A list of projects to install, with the key |
||
308 | * specifying the project name, and the value specifying its version. |
||
309 | * @param array $options User options from the command line; see |
||
310 | * $optionDefaultValues in the main() function. |
||
311 | * @return array |
||
312 | */ |
||
313 | public function requireCommand($execPath, $composerArgs, $projects, $options) |
||
314 | { |
||
315 | $stabilityCommands = array(); |
||
316 | if ($options['stability']) { |
||
317 | $stabilityCommands = $this->configureProjectStability($execPath, $composerArgs, $projects, $options); |
||
318 | } |
||
319 | $requireCommands = $this->generalCommand('require', $execPath, $composerArgs, $projects, $options); |
||
320 | return array_merge($stabilityCommands, $requireCommands); |
||
321 | } |
||
322 | |||
323 | public function extendCommand($execPath, $composerArgs, $projects, $options) |
||
324 | { |
||
325 | $projectToExtend = $this->getProjectToExtend($projects); |
||
326 | if (!$projectToExtend) { |
||
327 | print "No command to extend specified\n"; |
||
328 | exit(1); |
||
329 | } |
||
330 | array_shift($projects); |
||
331 | |||
332 | $options['base-dir'] .= '/' . $projectToExtend; |
||
333 | $options['extend-mode'] = true; |
||
334 | if (!is_dir($options['base-dir'])) { |
||
335 | print "Project $projectToExtend not found; try 'cgr require' first\n"; |
||
336 | exit(1); |
||
337 | } |
||
338 | |||
339 | return $this->requireCommand($execPath, $composerArgs, $projects, $options); |
||
340 | } |
||
341 | |||
342 | protected function getProjectToExtend($projects) |
||
343 | { |
||
344 | $keys = array_keys($projects); |
||
345 | $project = array_shift($keys); |
||
346 | |||
347 | return $project; |
||
348 | } |
||
349 | |||
350 | /** |
||
351 | * General command handler. |
||
352 | * |
||
353 | * @param string $composerCommand The composer command to run e.g. require |
||
354 | * @param string $execPath The path to composer |
||
355 | * @param array $composerArgs Anything from the global $argv to be passed |
||
356 | * on to Composer |
||
357 | * @param array $projects A list of projects to install, with the key |
||
358 | * specifying the project name, and the value specifying its version. |
||
359 | * @param array $options User options from the command line; see |
||
360 | * $optionDefaultValues in the main() function. |
||
361 | * @return array |
||
362 | */ |
||
363 | public function generalCommand($composerCommand, $execPath, $composerArgs, $projects, $options) |
||
364 | { |
||
365 | $globalBaseDir = $options['base-dir']; |
||
366 | $binDir = $options['bin-dir']; |
||
367 | $extendMode = !empty($options['extend-mode']); |
||
368 | $env = array("COMPOSER_BIN_DIR" => $binDir); |
||
369 | $result = array(); |
||
370 | foreach ($projects as $project => $version) { |
||
371 | $installLocation = $extendMode ? $globalBaseDir : "$globalBaseDir/$project"; |
||
372 | $projectWithVersion = $this->projectWithVersion($project, $version); |
||
373 | $commandToExec = $this->buildGlobalCommand($composerCommand, $execPath, $composerArgs, $projectWithVersion, $env, $installLocation); |
||
374 | $result[] = $commandToExec; |
||
375 | } |
||
376 | return $result; |
||
377 | } |
||
378 | |||
379 | /** |
||
380 | * Remove command handler. Build an `rm -rf` command. |
||
381 | * |
||
382 | * @param string $execPath The path to composer (ignored) |
||
383 | * @param array $composerArgs Anything from the global $argv to be passed |
||
384 | * on to Composer (ignored) |
||
385 | * @param array $projects A list of projects to install, with the key |
||
386 | * specifying the project name, and the value specifying its version. |
||
387 | * @param array $options User options from the command line; see |
||
388 | * $optionDefaultValues in the main() function. |
||
389 | * @return array |
||
390 | */ |
||
391 | public function removeCommand($execPath, $composerArgs, $projects, $options) |
||
392 | { |
||
393 | $globalBaseDir = $options['base-dir']; |
||
394 | $env = array(); |
||
395 | $result = $this->generalCommand('remove', $execPath, $composerArgs, $projects, $options); |
||
396 | foreach ($projects as $project => $version) { |
||
397 | $installLocation = "$globalBaseDir/$project"; |
||
398 | $result[] = new CommandToExec('rm', array('-rf', $installLocation), $env, $installLocation); |
||
399 | } |
||
400 | return $result; |
||
401 | } |
||
402 | |||
403 | /** |
||
404 | * Command handler for commands where the project should not be provided |
||
405 | * as a parameter to Composer (e.g. 'update'). |
||
406 | * |
||
407 | * @param string $composerCommand The composer command to run e.g. require |
||
408 | * @param string $execPath The path to composer |
||
409 | * @param array $composerArgs Anything from the global $argv to be passed |
||
410 | * on to Composer |
||
411 | * @param array $projects A list of projects to install, with the key |
||
412 | * specifying the project name, and the value specifying its version. |
||
413 | * @param array $options User options from the command line; see |
||
414 | * $optionDefaultValues in the main() function. |
||
415 | * @return array |
||
416 | */ |
||
417 | public function noProjectArgCommand($composerCommand, $execPath, $composerArgs, $projects, $options) |
||
418 | { |
||
419 | $globalBaseDir = $options['base-dir']; |
||
420 | $binDir = $options['bin-dir']; |
||
421 | $env = array("COMPOSER_BIN_DIR" => $binDir); |
||
422 | $result = array(); |
||
423 | foreach ($projects as $project => $version) { |
||
424 | $installLocation = "$globalBaseDir/$project"; |
||
425 | $commandToExec = $this->buildGlobalCommand($composerCommand, $execPath, $composerArgs, '', $env, $installLocation); |
||
426 | $result[] = $commandToExec; |
||
427 | } |
||
428 | return $result; |
||
429 | } |
||
430 | |||
431 | /** |
||
432 | * If --stability VALUE is provided, then run a `composer config minimum-stability VALUE` |
||
433 | * command to configure composer.json appropriately. |
||
434 | * |
||
435 | * @param string $execPath The path to composer |
||
436 | * @param array $composerArgs Anything from the global $argv to be passed |
||
437 | * on to Composer |
||
438 | * @param array $projects A list of projects to install, with the key |
||
439 | * specifying the project name, and the value specifying its version. |
||
440 | * @param array $options User options from the command line; see |
||
441 | * $optionDefaultValues in the main() function. |
||
442 | * @return array |
||
443 | */ |
||
444 | public function configureProjectStability($execPath, $composerArgs, $projects, $options) |
||
445 | { |
||
446 | $globalBaseDir = $options['base-dir']; |
||
447 | $stability = $options['stability']; |
||
448 | $result = array(); |
||
449 | $env = array(); |
||
450 | |||
451 | foreach ($projects as $project => $version) { |
||
452 | $installLocation = "$globalBaseDir/$project"; |
||
453 | FileSystemUtils::mkdirParents($installLocation); |
||
454 | if (!file_exists("$installLocation/composer.json")) { |
||
455 | file_put_contents("$installLocation/composer.json", '{}'); |
||
456 | } |
||
457 | $result[] = $this->buildConfigCommand($execPath, $composerArgs, 'minimum-stability', $stability, $env, $installLocation); |
||
458 | } |
||
459 | return $result; |
||
460 | } |
||
461 | |||
462 | /** |
||
463 | * Run `composer info`. Not only do we want to display the information of |
||
464 | * the "global" Composer project, we also want to get the infomation of |
||
465 | * all the "isolated" projects installed via cgr in ~/.composer/global. |
||
466 | * |
||
467 | * @param string $command The path to composer |
||
0 ignored issues
–
show
|
|||
468 | * @param array $composerArgs Anything from the global $argv to be passed |
||
469 | * on to Composer |
||
470 | * @param array $projects A list of projects to update. |
||
471 | * @param array $options User options from the command line; see |
||
472 | * $optionDefaultValues in the main() function. |
||
473 | * @return array |
||
474 | */ |
||
475 | View Code Duplication | public function infoCommand($execPath, $composerArgs, $projects, $options) |
|
0 ignored issues
–
show
This method seems to be duplicated in your project.
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation. You can also find more detailed suggestions in the “Code” section of your repository. ![]() |
|||
476 | { |
||
477 | // If 'projects' list is empty, make a list of everything currently installed |
||
478 | if (empty($projects)) { |
||
479 | $projects = FileSystemUtils::allInstalledProjectsInBaseDir($options['base-dir']); |
||
480 | $projects = $this->flipProjectsArray($projects); |
||
481 | } |
||
482 | return $this->generalCommand('info', $execPath, $composerArgs, $projects, $options); |
||
483 | } |
||
484 | |||
485 | /** |
||
486 | * Run `composer global update`. Not only do we want to update the |
||
487 | * "global" Composer project, we also want to update all of the |
||
488 | * "isolated" projects installed via cgr in ~/.composer/global. |
||
489 | * |
||
490 | * @param string $command The path to composer |
||
491 | * @param array $composerArgs Anything from the global $argv to be passed |
||
492 | * on to Composer |
||
493 | * @param array $projects A list of projects to update. |
||
494 | * @param array $options User options from the command line; see |
||
495 | * $optionDefaultValues in the main() function. |
||
496 | * @return array |
||
497 | */ |
||
498 | View Code Duplication | public function updateCommand($execPath, $composerArgs, $projects, $options) |
|
499 | { |
||
500 | // If 'projects' list is empty, make a list of everything currently installed |
||
501 | if (empty($projects)) { |
||
502 | $projects = FileSystemUtils::allInstalledProjectsInBaseDir($options['base-dir']); |
||
503 | $projects = $this->flipProjectsArray($projects); |
||
504 | } |
||
505 | return $this->noProjectArgCommand('update', $execPath, $composerArgs, $projects, $options); |
||
506 | } |
||
507 | |||
508 | /** |
||
509 | * Convert from an array of projects to an array where the key is the |
||
510 | * project name, and the value (version) is an empty string. |
||
511 | * |
||
512 | * @param string[] $projects |
||
513 | * @return array |
||
514 | */ |
||
515 | public function flipProjectsArray($projects) |
||
516 | { |
||
517 | return array_map(function () { |
||
518 | return ''; |
||
519 | }, array_flip($projects)); |
||
520 | } |
||
521 | |||
522 | /** |
||
523 | * Return $project:$version, or just $project if there is no $version. |
||
524 | * |
||
525 | * @param string $project The project to install |
||
526 | * @param string $version The version desired |
||
527 | * @return string |
||
528 | */ |
||
529 | public function projectWithVersion($project, $version) |
||
530 | { |
||
531 | if (empty($version)) { |
||
532 | return $project; |
||
533 | } |
||
534 | return "$project:$version"; |
||
535 | } |
||
536 | |||
537 | /** |
||
538 | * Generate command string to call `composer COMMAND` to install one project. |
||
539 | * |
||
540 | * @param string $command The path to composer |
||
541 | * @param array $composerArgs The arguments to pass to composer |
||
542 | * @param string $projectWithVersion The project:version to install |
||
543 | * @param array $env Environment to set prior to exec |
||
544 | * @param string $installLocation Location to install the project |
||
545 | * @return CommandToExec |
||
546 | */ |
||
547 | public function buildGlobalCommand($composerCommand, $execPath, $composerArgs, $projectWithVersion, $env, $installLocation) |
||
548 | { |
||
549 | $projectSpecificArgs = array("--working-dir=$installLocation", $composerCommand); |
||
550 | if (!empty($projectWithVersion)) { |
||
551 | $projectSpecificArgs[] = $projectWithVersion; |
||
552 | } |
||
553 | $arguments = array_merge($composerArgs, $projectSpecificArgs); |
||
554 | return new CommandToExec($execPath, $arguments, $env, $installLocation); |
||
555 | } |
||
556 | |||
557 | /** |
||
558 | * Generate command string to call `composer config KEY VALUE` to install one project. |
||
559 | * |
||
560 | * @param string $execPath The path to composer |
||
561 | * @param array $composerArgs The arguments to pass to composer |
||
562 | * @param string $key The config item to set |
||
563 | * @param string $value The value to set the config item to |
||
564 | * @param array $env Environment to set prior to exec |
||
565 | * @param string $installLocation Location to install the project |
||
566 | * @return CommandToExec |
||
567 | */ |
||
568 | public function buildConfigCommand($execPath, $composerArgs, $key, $value, $env, $installLocation) |
||
569 | { |
||
570 | $projectSpecificArgs = array("--working-dir=$installLocation", 'config', $key, $value); |
||
571 | $arguments = array_merge($composerArgs, $projectSpecificArgs); |
||
572 | return new CommandToExec($execPath, $arguments, $env, $installLocation); |
||
573 | } |
||
574 | |||
575 | /** |
||
576 | * Identify an argument that could be a Composer version string. |
||
577 | * |
||
578 | * @param string $arg The argument to test |
||
579 | * @return boolean |
||
580 | */ |
||
581 | public function isComposerVersion($arg) |
||
582 | { |
||
583 | // Allow for 'dev-master', et. al. |
||
584 | if (substr($arg, 0, 4) == 'dev-') { |
||
585 | return true; |
||
586 | } |
||
587 | $specialVersionChars = array('^', '~', '<', '>'); |
||
588 | return is_numeric($arg[0]) || in_array($arg[0], $specialVersionChars); |
||
589 | } |
||
590 | } |
||
591 |
This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.
Consider the following example. The parameter
$italy
is not defined by the methodfinale(...)
.The most likely cause is that the parameter was removed, but the annotation was not.