These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
1 | <?php |
||
2 | namespace RoboExample\Robo\Plugin\Commands; |
||
3 | |||
4 | use Robo\Result; |
||
5 | |||
6 | use Consolidation\AnnotatedCommand\CommandData; |
||
7 | use Consolidation\OutputFormatters\Options\FormatterOptions; |
||
8 | use Consolidation\OutputFormatters\StructuredData\RowsOfFields; |
||
9 | use Consolidation\OutputFormatters\StructuredData\PropertyList; |
||
10 | use Symfony\Component\Console\Input\InputOption; |
||
11 | use Symfony\Component\Console\Input\InputInterface; |
||
12 | use Symfony\Component\Console\Style\SymfonyStyle; |
||
13 | |||
14 | /** |
||
15 | * Example Robo Plugin Commands. |
||
16 | * |
||
17 | * To create a Robo Plugin, create a standard Composer project. The |
||
18 | * namespace for your commands must end Robo\Plugin\Commands, and |
||
19 | * this suffix must immediately follow some namespace in your composer.json |
||
20 | * file's autoload section. |
||
21 | * |
||
22 | * For example: |
||
23 | * |
||
24 | * "autoload": { |
||
25 | * "psr-4": { |
||
26 | * "RoboExample\\": "src" |
||
27 | * } |
||
28 | * }, |
||
29 | * |
||
30 | * In this instance, the namespace for your plugin commands must be |
||
31 | * RoboExample\Robo\Plugin\Commands. |
||
32 | */ |
||
33 | class ExampleCommands extends \Robo\Tasks |
||
34 | { |
||
35 | /** |
||
36 | * Watch a file. |
||
37 | * |
||
38 | * Demonstrates the 'watch' command. Runs 'composer update' any time |
||
39 | * composer.json changes. |
||
40 | */ |
||
41 | public function tryWatch() |
||
42 | { |
||
43 | $this->taskWatch()->monitor(['composer.json', 'composer.lock'], function () { |
||
44 | $this->taskComposerUpdate()->run(); |
||
45 | })->run(); |
||
46 | } |
||
47 | |||
48 | /** |
||
49 | * Demonstrates Robo input APIs. |
||
50 | */ |
||
51 | public function tryInput() |
||
52 | { |
||
53 | $this->say('The <b>expression</b> <bogus>is</bogus> <info>a < b</> it even works'); |
||
54 | $answer = $this->ask('how are you?'); |
||
55 | $this->say('You are '.$answer); |
||
56 | $yes = $this->confirm('Do you want one more question?'); |
||
57 | if (!$yes) { |
||
58 | return Result::cancelled(); |
||
59 | } |
||
60 | $lang = $this->askDefault('what is your favorite scripting language?', 'PHP'); |
||
61 | $this->say($lang); |
||
62 | $pin = $this->askHidden('Ok, now tell your PIN code (it is hidden)'); |
||
63 | $this->yell('Ha-ha, your pin code is: '.$pin); |
||
64 | $this->say('Bye!'); |
||
65 | } |
||
66 | |||
67 | /** |
||
68 | * Demonstrate Robo configuration. |
||
69 | * |
||
70 | * Config values are loaded from the followig locations: |
||
71 | * |
||
72 | * - [Robo Project]/robo.yml |
||
73 | * - $HOME/.robo/robo.yml |
||
74 | * - $CWD/robo.yml |
||
75 | * - Environment variables ROBO_CONFIG_KEY (e.g. ROBO_OPTIONS_PROGRESS_DELAY) |
||
76 | * - Overridden on the commandline via -Doptions.progress-delay=value |
||
77 | * |
||
78 | * @param string $key Name of the option to read (e.g. options.progress-delay) |
||
79 | * @option opt An option whose value is printed. Can be overridden in |
||
80 | * configuration via the configuration key command.try.config.options.opt. |
||
81 | * @option show-all Also print out the value of all configuration options |
||
82 | */ |
||
83 | public function tryConfig($key = 'options.progress-delay', $options = ['opt' => '0', 'show-all' => false]) |
||
84 | { |
||
85 | $value = \Robo\Robo::config()->get($key); |
||
86 | |||
87 | $this->say("The value of $key is " . var_export($value, true)); |
||
88 | $this->say("The value of --opt (command.try.config.options.opt) is " . var_export($options['opt'], true)); |
||
89 | |||
90 | if ($options['show-all']) { |
||
91 | $this->say(var_export(\Robo\Robo::config()->export(), true) . "\n"); |
||
92 | } |
||
93 | } |
||
94 | |||
95 | /** |
||
96 | * Demonstrates serial execution. |
||
97 | * |
||
98 | * @option $printed Print the output of each process. |
||
99 | * @option $error Include an extra process that fails. |
||
100 | */ |
||
101 | public function tryExec($options = ['printed' => true, 'error' => false]) |
||
102 | { |
||
103 | $dir = dirname(dirname(dirname(dirname(dirname(__DIR__))))); |
||
104 | $tasks = $this |
||
105 | ->taskExec('php') |
||
106 | ->args(["$dir/tests/_data/parascript.php", "hey", "4"]) |
||
107 | ->taskExec('php') |
||
108 | ->args(["$dir/tests/_data/parascript.php", "hoy", "3"]) |
||
109 | ->taskExec('php') |
||
110 | ->args(["$dir/tests/_data/parascript.php", "gou", "2"]) |
||
111 | ->taskExec('php') |
||
112 | ->args(["$dir/tests/_data/parascript.php", "die", "1"]); |
||
113 | if ($options['error']) { |
||
114 | $tasks->taskExec('ls')->arg("$dir/tests/_data/filenotfound"); |
||
115 | } |
||
116 | return $tasks->run(); |
||
117 | } |
||
118 | |||
119 | /** |
||
120 | * Demonstrates parallel execution. |
||
121 | * |
||
122 | * @option $printed Print the output of each process. |
||
123 | * @option $error Include an extra process that fails. |
||
124 | */ |
||
125 | public function tryPara($options = ['printed' => true, 'error' => false]) |
||
126 | { |
||
127 | $dir = dirname(dirname(dirname(dirname(dirname(__DIR__))))); |
||
128 | $para = $this->taskParallelExec() |
||
129 | ->printed($options['printed']) |
||
130 | ->process("php $dir/tests/_data/parascript.php hey 4") |
||
131 | ->process("php $dir/tests/_data/parascript.php hoy 3") |
||
132 | ->process("php $dir/tests/_data/parascript.php gou 2") |
||
133 | ->process("php $dir/tests/_data/parascript.php die 1"); |
||
134 | if ($options['error']) { |
||
135 | $para->process("ls $dir/tests/_data/filenotfound"); |
||
136 | } |
||
137 | return $para->run(); |
||
138 | } |
||
139 | |||
140 | /** |
||
141 | * try:opt-required |
||
142 | */ |
||
143 | public function tryOptRequired($options = ['foo' => InputOption::VALUE_REQUIRED]) |
||
144 | { |
||
145 | print "foo is " . $options['foo']; |
||
146 | } |
||
147 | |||
148 | /** |
||
149 | * Demonstrates Robo argument passing. |
||
150 | * |
||
151 | * @param string $a The first parameter. Required. |
||
152 | * @param string $b The second parameter. Optional. |
||
153 | */ |
||
154 | public function tryArgs($a, $b = 'default') |
||
155 | { |
||
156 | $this->say("The parameter a is $a and b is $b"); |
||
157 | } |
||
158 | |||
159 | /** |
||
160 | * Demonstrate Robo variable argument passing. |
||
161 | * |
||
162 | * @param array $a A list of commandline parameters. |
||
163 | * @param array $options |
||
164 | */ |
||
165 | public function tryArrayArgs(array $a, array $options = ['foo' => []]) |
||
166 | { |
||
167 | $this->say("The parameters passed are:\n" . var_export($a, true)); |
||
168 | if (!empty($options['foo'])) { |
||
169 | $this->say("The options passed via --foo are:\n" . var_export($options['foo'], true)); |
||
170 | } |
||
171 | } |
||
172 | |||
173 | /** |
||
174 | * Demonstrate use of SymfonyStyle $io object and Symfony $input object in |
||
175 | * Robo in place of the usual "parameter arguments". |
||
176 | * |
||
177 | * @arg array $a A list of commandline parameters. |
||
178 | * @option foo |
||
179 | * @default a [] |
||
180 | * @default foo [] |
||
181 | */ |
||
182 | View Code Duplication | public function trySymfony(SymfonyStyle $io, InputInterface $input) |
|
0 ignored issues
–
show
|
|||
183 | { |
||
184 | $io->title('Symfony Style demo'); |
||
185 | $a = $input->getArgument('a'); |
||
186 | $io->writeln("The parameters passed are:\n" . var_export($a, true)); |
||
187 | $foo = $input->getOption('foo'); |
||
188 | if (!empty($foo)) { |
||
189 | $this->say("The options passed via --foo are:\n" . var_export($foo, true)); |
||
190 | } |
||
191 | } |
||
192 | |||
193 | public function tryText() |
||
194 | { |
||
195 | $this->io()->text('This is some text'); |
||
196 | $this->io()->text('This is some more text'); |
||
197 | $this->io()->text('This is the last text'); |
||
198 | } |
||
199 | |||
200 | /** |
||
201 | * Demonstrate Robo boolean options. |
||
202 | * |
||
203 | * @param $opts The options. |
||
204 | * @option boolean $silent Supress output. |
||
205 | */ |
||
206 | public function tryOptbool($opts = ['silent|s' => false]) |
||
207 | { |
||
208 | if (!$opts['silent']) { |
||
209 | $this->say("Hello, world"); |
||
210 | } |
||
211 | } |
||
212 | |||
213 | /** |
||
214 | * Demonstrate the use of the PHP built-in webserver. |
||
215 | */ |
||
216 | public function tryServer() |
||
217 | { |
||
218 | return $this->taskServer(8000) |
||
219 | ->dir('site') |
||
220 | ->arg('site/index.php') |
||
221 | ->run(); |
||
222 | } |
||
223 | |||
224 | /** |
||
225 | * Demonstrate the use of the Robo open-browser task. |
||
226 | */ |
||
227 | public function tryOpenBrowser() |
||
228 | { |
||
229 | return $this->taskOpenBrowser([ |
||
230 | 'http://robo.li', |
||
231 | 'https://github.com/consolidation-org/Robo' |
||
232 | ])->run(); |
||
233 | } |
||
234 | |||
235 | /** |
||
236 | * Demonstrate Robo error output and command failure. |
||
237 | */ |
||
238 | public function tryError() |
||
239 | { |
||
240 | return $this->taskExec('ls xyzzy' . date('U'))->dir('/tmp')->run(); |
||
241 | } |
||
242 | |||
243 | /** |
||
244 | * Demonstrate Robo standard output and command success. |
||
245 | */ |
||
246 | public function trySuccess() |
||
247 | { |
||
248 | return $this->_exec('pwd'); |
||
249 | } |
||
250 | |||
251 | /** |
||
252 | * @field-labels |
||
253 | * name: Name |
||
254 | * species: Species |
||
255 | * legs: Legs |
||
256 | * food: Favorite Food |
||
257 | * id: Id |
||
258 | * @return PropertyList |
||
259 | */ |
||
260 | public function tryInfo() |
||
261 | { |
||
262 | $outputData = [ |
||
263 | 'name' => 'fluffy', |
||
264 | 'species' => 'cat', |
||
265 | 'legs' => 4, |
||
266 | 'food' => 'salmon', |
||
267 | 'id' => 389245032, |
||
268 | ]; |
||
269 | |||
270 | $data = new PropertyList($outputData); |
||
271 | |||
272 | // Add a render function to transform cell data when the output |
||
273 | // format is a table, or similar. This allows us to add color |
||
274 | // information to the output without modifying the data cells when |
||
275 | // using yaml or json output formats. |
||
276 | $data->addRendererFunction( |
||
277 | // n.b. There is a fourth parameter $rowData that may be added here. |
||
278 | function ($key, $cellData, FormatterOptions $options) { |
||
279 | if ($key == 'name') { |
||
280 | return "<info>$cellData</>"; |
||
281 | } |
||
282 | return $cellData; |
||
283 | } |
||
284 | ); |
||
285 | |||
286 | return $data; |
||
287 | } |
||
288 | |||
289 | /** |
||
290 | * Demonstrate Robo formatters. Default format is 'table'. |
||
291 | * |
||
292 | * @field-labels |
||
293 | * first: I |
||
294 | * second: II |
||
295 | * third: III |
||
296 | * @default-string-field second |
||
297 | * @usage try:formatters --format=yaml |
||
298 | * @usage try:formatters --format=csv |
||
299 | * @usage try:formatters --fields=first,third |
||
300 | * @usage try:formatters --fields=III,II |
||
301 | * @aliases tf |
||
302 | * |
||
303 | * @return \Consolidation\OutputFormatters\StructuredData\RowsOfFields |
||
304 | */ |
||
305 | public function tryFormatters($somthing = 'default', $options = ['format' => 'table', 'fields' => '']) |
||
306 | { |
||
307 | $outputData = [ |
||
308 | 'en' => [ 'first' => 'One', 'second' => 'Two', 'third' => 'Three' ], |
||
309 | 'de' => [ 'first' => 'Eins', 'second' => 'Zwei', 'third' => 'Drei' ], |
||
310 | 'jp' => [ 'first' => 'Ichi', 'second' => 'Ni', 'third' => 'San' ], |
||
311 | 'es' => [ 'first' => 'Uno', 'second' => 'Dos', 'third' => 'Tres' ], |
||
312 | ]; |
||
313 | return new RowsOfFields($outputData); |
||
314 | } |
||
315 | |||
316 | /** |
||
317 | * Try word wrapping |
||
318 | * |
||
319 | * @field-labels |
||
320 | * first: First |
||
321 | * second: Second |
||
322 | * |
||
323 | * @return \Consolidation\OutputFormatters\StructuredData\RowsOfFields |
||
324 | */ |
||
325 | public function tryWrap() |
||
326 | { |
||
327 | $data = [ |
||
328 | [ |
||
329 | 'first' => 'This is a really long cell that contains a lot of data. When it is rendered, it should be wrapped across multiple lines.', |
||
330 | 'second' => 'This is the second column of the same table. It is also very long, and should be wrapped across multiple lines, just like the first column.', |
||
331 | ] |
||
332 | ]; |
||
333 | return new RowsOfFields($data); |
||
334 | } |
||
335 | |||
336 | /** |
||
337 | * Demonstrate an alter hook with an option |
||
338 | * |
||
339 | * @hook alter try:formatters |
||
340 | * @option $french Add a row with French numbers. |
||
341 | * @usage try:formatters --french |
||
342 | */ |
||
343 | public function alterFormatters($result, CommandData $commandData) |
||
344 | { |
||
345 | if ($commandData->input()->getOption('french')) { |
||
346 | $result['fr'] = [ 'first' => 'Un', 'second' => 'Deux', 'third' => 'Trois' ]; |
||
347 | } |
||
348 | |||
349 | return $result; |
||
350 | } |
||
351 | |||
352 | /** |
||
353 | * Demonstrate what happens when a command or a task |
||
354 | * throws an exception. Note that typically, Robo commands |
||
355 | * should return Result objects rather than throw exceptions. |
||
356 | */ |
||
357 | public function tryException($options = ['task' => false]) |
||
358 | { |
||
359 | if (!$options['task']) { |
||
360 | throw new RuntimeException('Command failed with an exception.'); |
||
361 | } |
||
362 | return new ExceptionTask('Task failed with an exception.'); |
||
363 | } |
||
364 | |||
365 | /** |
||
366 | * Demonstrate deprecated task behavior. |
||
367 | * |
||
368 | * Demonstrate what happens when using a task that is created via |
||
369 | * direct instantiation, which omits initialization done by the |
||
370 | * container. Emits a warning message. |
||
371 | */ |
||
372 | public function tryDeprecated() |
||
373 | { |
||
374 | // Calling 'new' directly without manually setting |
||
375 | // up dependencies will result in a deprecation warning. |
||
376 | // @see RoboFile::trySuccess() |
||
377 | return (new \Robo\Task\Base\Exec('pwd'))->run(); |
||
378 | } |
||
379 | |||
380 | /** |
||
381 | * Demonstrate the use of a collection builder to chain multiple tasks |
||
382 | * together into a collection, which is executed once constructed. |
||
383 | * |
||
384 | * For demonstration purposes only; this could, of course, be done |
||
385 | * with a single FilesystemStack. |
||
386 | */ |
||
387 | public function tryBuilder() |
||
388 | { |
||
389 | return $this->collectionBuilder() |
||
390 | ->taskFilesystemStack() |
||
391 | ->mkdir('a') |
||
392 | ->touch('a/a.txt') |
||
393 | ->taskFilesystemStack() |
||
394 | ->mkdir('a/b') |
||
395 | ->touch('a/b/b.txt') |
||
396 | ->taskFilesystemStack() |
||
397 | ->mkdir('a/b/c') |
||
398 | ->touch('a/b/c/c.txt') |
||
399 | ->run(); |
||
400 | } |
||
401 | |||
402 | public function tryState() |
||
403 | { |
||
404 | return $this->collectionBuilder() |
||
405 | ->taskExec('uname -n') |
||
406 | ->printOutput(false) |
||
407 | ->storeState('system-name') |
||
408 | ->taskFilesystemStack() |
||
409 | ->deferTaskConfiguration('mkdir', 'system-name') |
||
410 | ->run(); |
||
411 | } |
||
412 | |||
413 | public function tryBuilderRollback() |
||
414 | { |
||
415 | // This example will create two builders, and add |
||
416 | // the first one as a child of the second in order |
||
417 | // to demonstrate nested rollbacks. |
||
418 | $collection = $this->collectionBuilder() |
||
419 | ->taskFilesystemStack() |
||
420 | ->mkdir('g') |
||
421 | ->touch('g/g.txt') |
||
422 | ->rollback( |
||
423 | $this->taskDeleteDir('g') |
||
424 | ) |
||
425 | ->taskFilesystemStack() |
||
426 | ->mkdir('g/h') |
||
427 | ->touch('g/h/h.txt') |
||
428 | ->taskFilesystemStack() |
||
429 | ->mkdir('g/h/i/c') |
||
430 | ->touch('g/h/i/i.txt'); |
||
431 | |||
432 | return $this->collectionBuilder() |
||
433 | ->progressMessage('Start recursive collection') |
||
434 | ->addTask($collection) |
||
435 | ->progressMessage('Done with recursive collection') |
||
436 | ->taskExec('ls xyzzy' . date('U')) |
||
437 | ->dir('/tmp') |
||
438 | ->run(); |
||
439 | } |
||
440 | |||
441 | public function tryWorkdir() |
||
442 | { |
||
443 | // This example works like tryBuilderRollback, |
||
444 | // but does equivalent operations using a working |
||
445 | // directory. The working directory is deleted on rollback |
||
446 | $collection = $this->collectionBuilder(); |
||
447 | |||
448 | $workdir = $collection->workDir('w'); |
||
449 | |||
450 | $collection |
||
451 | ->taskFilesystemStack() |
||
452 | ->touch("$workdir/g.txt") |
||
453 | ->taskFilesystemStack() |
||
454 | ->mkdir("$workdir/h") |
||
455 | ->touch("$workdir/h/h.txt") |
||
456 | ->taskFilesystemStack() |
||
457 | ->mkdir("$workdir/h/i/c") |
||
458 | ->touch("$workdir/h/i/i.txt"); |
||
459 | |||
460 | return $this->collectionBuilder() |
||
461 | ->progressMessage('Start recursive collection') |
||
462 | ->addTask($collection) |
||
463 | ->progressMessage('Done with recursive collection') |
||
464 | ->taskExec('ls xyzzy' . date('U')) |
||
465 | ->dir('/tmp') |
||
466 | ->run(); |
||
467 | } |
||
468 | |||
469 | /** |
||
470 | * Demonstrates Robo temporary directory usage. |
||
471 | */ |
||
472 | public function tryTmpDir() |
||
473 | { |
||
474 | // Set up a collection to add tasks to |
||
475 | $collection = $this->collectionBuilder(); |
||
476 | |||
477 | // Get a temporary directory to work in. Note that we get a path |
||
478 | // back, but the directory is not created until the task runs. |
||
479 | $tmpPath = $collection->tmpDir(); |
||
480 | |||
481 | $result = $collection |
||
482 | ->taskWriteToFile("$tmpPath/file.txt") |
||
483 | ->line('Example file') |
||
484 | ->run(); |
||
485 | |||
486 | if (is_dir($tmpPath)) { |
||
487 | $this->say("The temporary directory at $tmpPath was not cleaned up after the collection completed."); |
||
488 | } else { |
||
489 | $this->say("The temporary directory at $tmpPath was automatically deleted."); |
||
490 | } |
||
491 | |||
492 | return $result; |
||
493 | } |
||
494 | |||
495 | /** |
||
496 | * Description |
||
497 | * @param $options |
||
498 | * @option delay Miliseconds delay |
||
499 | * @return type |
||
500 | */ |
||
501 | public function tryProgress($options = ['delay' => 500]) |
||
502 | { |
||
503 | $delay = $options['delay']; |
||
504 | $delayUntilProgressStart = \Robo\Robo::config()->get(\Robo\Config::PROGRESS_BAR_AUTO_DISPLAY_INTERVAL); |
||
505 | $this->say("Progress bar will display after $delayUntilProgressStart seconds of activity."); |
||
506 | |||
507 | $processList = range(1, 10); |
||
508 | return $this->collectionBuilder() |
||
509 | ->taskForEach($processList) |
||
510 | ->iterationMessage('Processing {value}') |
||
511 | ->call( |
||
512 | function ($value) use($delay) { |
||
513 | // TaskForEach::call should only be used to do |
||
514 | // non-Robo operations. To use Robo tasks in an |
||
515 | // iterator, @see TaskForEach::withBuilder. |
||
516 | usleep($delay * 1000); // delay units: msec, usleep units: usec |
||
517 | } |
||
518 | ) |
||
519 | ->run(); |
||
520 | } |
||
521 | |||
522 | public function tryIter() |
||
523 | { |
||
524 | $workdir = 'build/iter-example'; |
||
525 | $this->say("Creating sample direcories in $workdir."); |
||
526 | |||
527 | $processList = ['cats', 'dogs', 'sheep', 'fish', 'horses', 'cows']; |
||
528 | return $this->collectionBuilder() |
||
529 | ->taskFilesystemStack() |
||
530 | ->mkdir($workdir) |
||
531 | ->taskCleanDir($workdir) |
||
532 | ->taskForEach($processList) |
||
533 | ->withBuilder( |
||
534 | function ($builder, $key, $value) use ($workdir) { |
||
535 | return $builder |
||
536 | ->taskFilesystemStack() |
||
537 | ->mkdir("$workdir/$value"); |
||
538 | } |
||
539 | ) |
||
540 | ->run(); |
||
541 | } |
||
542 | } |
||
543 | |||
544 | class ExceptionTask extends \Robo\Task\BaseTask |
||
545 | { |
||
546 | protected $message; |
||
547 | |||
548 | public function __construct($message) |
||
549 | { |
||
550 | $this->message = $message; |
||
551 | } |
||
552 | |||
553 | public function run() |
||
554 | { |
||
555 | throw new RuntimeException($this->message); |
||
556 | } |
||
557 | } |
||
558 |
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.