Completed
Push — master ( d3a073...5737c8 )
by Greg
02:21
created

src/Robo/Plugin/Commands/ExampleCommands.php (1 issue)

Upgrade to new PHP Analysis Engine

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
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.

Loading history...
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