GitHub Access Token became invalid

It seems like the GitHub access token used for retrieving details about this repository from GitHub became invalid. This might prevent certain types of inspections from being run (in particular, everything related to pull requests).
Please ask an admin of your repository to re-new the access token on this website.

Tasks::doExit()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 2
nc 1
nop 2
dl 0
loc 4
rs 10
c 0
b 0
f 0
1
<?php
2
/**
3
 * See class comment
4
 *
5
 * PHP Version 5
6
 *
7
 * @category Netresearch
8
 * @package  Netresearch\Kite
9
 * @author   Christian Opitz <[email protected]>
10
 * @license  http://www.netresearch.de Netresearch Copyright
11
 * @link     http://www.netresearch.de
12
 */
13
14
namespace Netresearch\Kite;
15
use Netresearch\Kite\Exception\BreakException;
16
use Netresearch\Kite\Exception\ExitException;
17
use Netresearch\Kite\Exception\ForcedTaskException;
18
use Netresearch\Kite\Task\SchemaMigrationTask;
19
use Symfony\Component\Console\Output\OutputInterface;
20
21
/**
22
 * A task to aggregate and run a bunch of tasks
23
 *
24
 * @category Netresearch
25
 * @package  Netresearch\Kite
26
 * @author   Christian Opitz <[email protected]>
27
 * @license  http://www.netresearch.de Netresearch Copyright
28
 * @link     http://www.netresearch.de
29
 */
30
abstract class Tasks extends Task
31
{
32
    /**
33
     * @var \Netresearch\Kite\Service\Factory
34
     */
35
    protected $factory;
36
37
    /**
38
     * @var bool|array
39
     */
40
    private $isPrepare;
41
42
    /**
43
     * @var \Netresearch\Kite\Task[]
44
     */
45
    private $tasks = array();
46
47
    /**
48
     * @var array
49
     */
50
    private $deferredTasks = array();
51
52
    /**
53
     * @var bool
54
     */
55
    private $started = false;
56
57
    /**
58
     * @var bool
59
     */
60
    private $initialized = false;
61
62
    /**
63
     * @var bool
64
     */
65
    private $isWorkflow = false;
66
67
    /**
68
     * Tasks constructor.
69
     *
70
     * @param Variables $parent Parent object (Task/Job/Workflow)
71
     */
72
    public function __construct(Variables $parent)
73
    {
74
        parent::__construct($parent);
75
        $this->factory = $this->console->getFactory();
76
    }
77
78
    /**
79
     * Clone and reparent the tasks to $this
80
     *
81
     * @return void
82
     */
83
    function __clone()
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
84
    {
85
        // Clone the tasks and bind (reparent) them to $this
86
        $tasks = array();
87
        foreach ($this->tasks as $task) {
88
            $tasks[] = $clone = clone $task;
89
            $clone->bindTo($this);
90
        }
91
        $this->tasks = $tasks;
92
93
        // Do this at last because otherwise tasks will be doubly cloned as they
94
        // are in both, Variables::$children and Tasks::$tasks
0 ignored issues
show
Unused Code Comprehensibility introduced by
36% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
95
        // After the previous reparenting there should only be deferred tasks be
96
        // left in Variables::$children
97
        parent::__clone();
98
    }
99
100
101
    /**
102
     * Configures the available options
103
     *
104
     * @return array
105
     */
106 View Code Duplication
    protected function configureVariables()
0 ignored issues
show
Duplication introduced by
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...
107
    {
108
        return array(
0 ignored issues
show
Best Practice introduced by
The expression return array('tasks' => ...::configureVariables(); seems to be an array, but some of its elements' types (string) are incompatible with the return type of the parent method Netresearch\Kite\Task::configureVariables of type array<string,array>.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
109
            'tasks' => array(
110
                'type' => 'array',
111
                'label' => 'Array of tasks to add to the subTask'
112
            ),
113
            'task' => array(
114
                'type' => 'mixed',
115
                'label' => 'Task to run as a sub task'
116
            ),
117
            'workflow' => array(
118
                'type' => 'array',
119
                'label' => 'Workflow to run as a subtask',
120
            ),
121
            'script' => array(
122
                'type' => 'string',
123
                'label' => 'Script to include which configures the tasks'
124
            ),
125
            '--'
126
        ) + parent::configureVariables();
127
    }
128
129
    /**
130
     * Called from parent task as soon as task is ready to run - which doesn't
131
     * necessarely mean that it'll be run.
132
     *
133
     * @return void
134
     */
135
    protected function initialize()
136
    {
137
        parent::initialize();
138
        
139
        $this->isWorkflow = false;
140
        foreach ($this->tasks as $task) {
141
            $task->initialize();
142
        }
143
        $this->initialized = true;
144
    }
145
146
147
    /**
148
     * Override to create the tasks from the according options
149
     *
150
     * @param string $name  Variable name
151
     * @param mixed  $value Variable value
152
     *
153
     * @return void
154
     */
155
    public function offsetSet($name, $value)
156
    {
157
        if ($this->isWorkflow) {
158
            // Forward everything to the workflow, as soon as it is set
159
            $this->tasks[0]->offsetSet($name, $value);
160
            return;
161
        }
162
        if (in_array($name, ['workflow', 'script', 'task', 'tasks'], true)) {
163
            if ($this->tasks) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->tasks of type Netresearch\Kite\Task[] is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
164
                throw new Exception('Can either use workflow, script, task or tasks');
165
            }
166
            $value = $this->expand($value);
167
        }
168
        if ($name === 'workflow') {
169
            $this->addTask($this->factory->createWorkflow($value, $this));
170
            $this->isWorkflow = true;
171
            return;
172
        }
173
        if ($name === 'script') {
174
            include $value;
175
            return;
176
        }
177
        if ($name === 'task') {
178
            $name = 'tasks';
179
            $value = array($value);
180
        }
181
        if ($name === 'tasks') {
182
            foreach ($value as $name => $task) {
183
                $task = $this->expand($task);
184
                $options = array();
185
                if (!is_numeric($name)) {
186
                    $options['name'] = $name;
187
                }
188
                $this->addTask($this->factory->createTask($task, $this, $options));
189
            }
190
            return;
191
        }
192
        parent::offsetSet($name, $value);
193
    }
194
195
    /**
196
     * Run an array of tasks
197
     *
198
     * @return $this
199
     */
200
    public function run()
201
    {
202
        if ($this->started) {
203
            throw new Exception('Task was already started');
204
        }
205
206
        $this->started = true;
207
208
        $exception = null;
209
210
        $this->preview();
211
212
        $isMain = $this === $this->job;
213
        $indent = !$isMain && $this->getParent() !== $this->job ? 1 : 0;
214
        $this->console->indent($indent);
215
216
        $tasks = $this->tasks;
217
        $name = $this->get('name');
218
        $this->addDeferredTasks($tasks, 'before', $name);
219
        if ($isMain) {
220
            $this->addDeferredTasks($tasks, 'before', '@all');
221
        }
222
        do {
223
            do {
224
                while ($task = array_shift($tasks)) {
225
                    $taskName = $task->get('name', null);
226
                    if ($taskName) {
227
                        array_unshift($tasks, $task);
228
                        $this->addDeferredTasks($tasks, 'before', $taskName);
229
                        $task = array_shift($tasks);
230
                    }
231
                    if (!$exception) {
232
                        try {
233
                            $this->runTask($task);
234
                        } catch (ForcedTaskException $e) {
235
                            throw $e;
236
                        } catch (\Exception $e) {
237
                            $exception = $e;
238
                        }
239
                    } elseif ($task->has('force') && $task->get('force')) {
240
                        try {
241
                            $this->runTask($task);
242
                        } catch (\Exception $e) {
243
                            throw new ForcedTaskException($e->getMessage(), $e->getCode(), $exception);
244
                        }
245
                    }
246
                    if ($taskName) {
247
                        $this->addDeferredTasks($tasks, 'after', $taskName);
248
                    }
249
                }
250
            } while ($this->addDeferredTasks($tasks, 'after', $name));
251
        } while ($isMain && $this->addDeferredTasks($tasks, 'after', '@all'));
252
253
        $this->console->outdent($indent);
254
255 View Code Duplication
        if ($exception) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
256
            if ($exception instanceof BreakException) {
257
                $message = $exception->getMessage();
258
                if ($message) {
259
                    $this->console->output($task->expand($message));
260
                }
261
            } else {
262
                throw $exception;
263
            }
264
        }
265
266
        return $this;
267
    }
268
269
    /**
270
     * Adds tasks that should be run before/after the task with $name
271
     *
272
     * @param array  $tasks The tasks to add the deferred tasks to
273
     * @param string $type  "before" or "after"
274
     * @param string $name  The task name
275
     *
276
     * @return int
277
     */
278
    private function addDeferredTasks(&$tasks, $type, $name)
279
    {
280
        if (!$name) {
281
            return 0;
282
        }
283
        $key = $type . ':' . $name;
284
        $tasksAdded = 0;
285
        if (array_key_exists($key, $this->job->deferredTasks)) {
286
            while ($task = array_shift($this->job->deferredTasks[$key])) {
287
                $tasksAdded++;
288
                $type == ($type === 'after') ? array_push($tasks, $task) : array_unshift($tasks, $task);
289
            }
290
        }
291
        return $tasksAdded;
292
    }
293
294
    /**
295
     * Run a task
296
     *
297
     * @param Task $task The task
298
     *
299
     * @internal Use addTask unless you know what you're doing
300
     *
301
     * @return mixed|null The task return value or null when if failed or dry run
302
     */
303
    protected function runTask(Task $task)
304
    {
305
        if ($if = $task->get('if')) {
306
            if (is_bool($if)) {
307
                $shouldRun = $if;
308
            } elseif (is_string($if)) {
309
                $shouldRun = (boolean) $task->expand(
310
                    '{' . $if . ' ? 1 : 0}'
311
                );
312
            } else {
313
                $shouldRun = call_user_func_array($if, array($task, $this->console));
314
                if (!is_bool($shouldRun)) {
315
                    throw new Exception('Callback must return TRUE or FALSE');
316
                }
317
            }
318
        } else {
319
            $shouldRun = true;
320
        }
321
        if ($shouldRun) {
322
            $return = $task->run();
323
            $toVar = $task->get('toVar', null);
324
            if ($toVar) {
325
                $task->getParent()->set($toVar, $return);
326
            }
327
            return $return;
328
        }
329
        return null;
330
    }
331
332
    /**
333
     * Add a task - or run it immediately when $this->started
334
     *
335
     * @param Task $task The task
336
     *
337
     * @return $this|mixed $this or the task return value when this is running
338
     */
339
    public function addTask(Task $task)
340
    {
341
        $deferred = false;
342
        foreach (array('before', 'after') as $type) {
343
            if ($task->get($type)) {
344
                $deferred = true;
345
                foreach ((array) $task->get($type) as $name) {
346
                    if ($name === '@self') {
347
                        $name = $this->get('name');
348
                    }
349
                    $key = $type . ':' . $name;
350
                    $this->job->deferredTasks[$key][] = $task;
351
                }
352
            }
353
        }
354
355
        if ($this->initialized || $deferred) {
356
            $task->initialize();
357
        }
358
359
        if (!$deferred && $this->started) {
360
            return $this->runTask($task);
361
        }
362
363
        if (!$deferred) {
364
            $this->tasks[] = $task;
365
        }
366
        return $this;
367
    }
368
369
    /**
370
     * Setup and add (which eventually runs) a task
371
     *
372
     * @param string|array $type    The task type or configuration
373
     * @param array        $options The options
374
     *
375
     * @return \Netresearch\Kite\Task|mixed The task or the task return when !$this->prepare
376
     */
377
    private function createAndAddTask($type, array $options = array())
378
    {
379
        $task = $this->factory->createTask($type, $this, $options);
380
        if (is_array($this->isPrepare)) {
381
            $beforeOrAfter = $this->isPrepare[0];
382
            $beforeOrAfterTask = $this->isPrepare[1];
383
            if ($beforeOrAfterTask instanceof Task) {
384
                $beforeOrAfterTask = $beforeOrAfterTask->get('name');
385
            }
386
            $task->set($beforeOrAfter, $beforeOrAfterTask);
387
            $this->isPrepare = false;
388
        }
389
        if ($this->isPrepare === true) {
390
            $this->isPrepare = false;
391
            return $task;
392
        } else {
393
            $return = $this->addTask($task);
394
        }
395
        return $this->started ? $return : $task;
396
    }
397
398
    /**
399
     * Makes that the next fetched task (from the methods below)
400
     * is not added to the workflow
401
     *
402
     * @return $this
403
     */
404
    public function prepare()
405
    {
406
        $this->isPrepare = true;
407
        return $this;
408
    }
409
410
    /**
411
     * Execute the next fetched task before given $task
412
     *
413
     * @param Task|string $task Task or task name
414
     *
415
     * @return $this
416
     */
417
    public function before($task)
418
    {
419
        $this->isPrepare = array('before', $task);
420
        return $this;
421
    }
422
423
    /**
424
     * Execute the next fetched task after given $task
425
     *
426
     * @param Task|string $task Task or task name
427
     *
428
     * @return $this
429
     */
430
    public function after($task)
431
    {
432
        $this->isPrepare = array('after', $task);
433
        return $this;
434
    }
435
436
    // Following are shortcuts to create and eventually run tasks
437
438
    /**
439
     * Answer a question
440
     *
441
     * @param string $question The question
442
     * @param string $default  The default value
443
     *
444
     * @return mixed|\Netresearch\Kite\Task
445
     */
446
    public function answer($question, $default = null)
447
    {
448
        return $this->createAndAddTask(__FUNCTION__, compact('question', 'default'));
449
    }
450
451
    /**
452
     * Run a callback
453
     *
454
     * @param callable $callback The callback
455
     *
456
     * @return mixed|\Netresearch\Kite\Task\CallbackTask
457
     */
458
    public function callback($callback)
459
    {
460
        return $this->createAndAddTask(__FUNCTION__, compact('callback'));
461
    }
462
463
    /**
464
     * Ask a selection question
465
     *
466
     * @param string $question The question
467
     * @param array  $choices  The choices
468
     * @param mixed  $default  Default value
469
     *
470
     * @return mixed|\Netresearch\Kite\Task\ChooseTask
471
     */
472
    public function choose($question, array $choices, $default = null)
473
    {
474
        return $this->createAndAddTask(__FUNCTION__, compact('question', 'choices', 'default'));
475
    }
476
477
    /**
478
     * Clear the TYPO3 cache
479
     *
480
     * @param string $cmd The clearcache command
481
     *
482
     * @return null|\Netresearch\Kite\Task\IncludeTask
483
     */
484
    public function clearCache($cmd = null)
485
    {
486
        return $this->createAndAddTask(__FUNCTION__, $cmd ? compact('cmd') : array());
487
    }
488
489
    /**
490
     * Ask a confirmation question
491
     *
492
     * @param string $question The question
493
     * @param bool   $default  Default value
494
     *
495
     * @return bool|\Netresearch\Kite\Task\ConfirmTask
496
     */
497
    public function confirm($question, $default = true)
498
    {
499
        return $this->createAndAddTask(__FUNCTION__, compact('question', 'default'));
500
    }
501
502
    /**
503
     * Run a composer command
504
     *
505
     * @param string            $command         The command to execute
506
     * @param array|string|null $optArg          Options and arguments
507
     *                                           {@see \Netresearch\Kite\Task\ShellTask}
508
     * @param array             $processSettings Settings for symfony process class
509
     *
510
     * @return string|\Netresearch\Kite\Task\ComposerTask
511
     */
512
    public function composer($command, $optArg = null, array $processSettings = array())
513
    {
514
        return $this->createAndAddTask(__FUNCTION__, compact('command', 'optArg', 'processSettings'));
515
    }
516
517
    /**
518
     * Evaluate an expression
519
     *
520
     * {@see http://symfony.com/doc/current/components/expression_language/syntax.html}
521
     *
522
     * @param string $expression The expression
523
     *
524
     * @return mixed|\Netresearch\Kite\Task\EvaluateTask
525
     */
526
    public function evaluate($expression)
527
    {
528
        return $this->createAndAddTask(__FUNCTION__, compact('expression'));
529
    }
530
531
    /**
532
     * Break a tasks loop
533
     *
534
     * @param string $message The message
535
     *
536
     * @return void
537
     */
538
    public function doBreak($message = '')
539
    {
540
        throw new BreakException($message);
541
    }
542
543
    /**
544
     * Exit - return code is return code of application
545
     * (thus, when it's not 0 the message will be rendered as exception)
546
     *
547
     * @param string $message The message
548
     * @param int    $code    The code
549
     *
550
     * @return void
551
     */
552
    public function doExit($message = '', $code = 0)
553
    {
554
        throw new ExitException($message, $code);
555
    }
556
557
    /**
558
     * Run a git command
559
     *
560
     * @param string            $command         The command to execute
561
     * @param string|null       $cwd             The directory to change into before execution
562
     * @param array|string|null $optArg          Options and arguments
563
     *                                           {@see \Netresearch\Kite\Task\ShellTask}
564
     * @param array             $processSettings Settings for symfony process class
565
     *
566
     * @return Task\GitTask|string
567
     */
568
    public function git($command, $cwd = null, $optArg = null, array $processSettings = array())
569
    {
570
        return $this->createAndAddTask(__FUNCTION__, compact('command', 'cwd', 'optArg', 'processSettings'));
571
    }
572
573
    /**
574
     * Run a workflow for each of the $array's values.
575
     *
576
     * @param array|\Traversable $array    The object to iterate over
577
     * @param string|array       $as       Either string for
578
     *                                     foreach ($array as $as)
579
     *                                     or array for
580
     *                                     foreach($array as key($as) => current($as))
581
     * @param string|null        $workflow Optional workflow class name
582
     *
583
     * @return array|\Netresearch\Kite\Task\IterateTask
584
     */
585
    public function iterate($array, $as, $workflow = null)
586
    {
587
        $options = compact('array', 'as');
588
        if ($workflow) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $workflow of type string|null is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
589
            $options['workflow'] = $workflow;
590
        }
591
        return $this->createAndAddTask(__FUNCTION__, $options);
592
    }
593
594
    /**
595
     * Do something on the filesystem
596
     *
597
     * @return \Netresearch\Kite\Task\FsTask
598
     */
599
    public function fs()
600
    {
601
        return $this->createAndAddTask(__FUNCTION__);
602
    }
603
604
    /**
605
     * Output a message
606
     *
607
     * @param string   $message           The message
608
     * @param int|bool $severityOrNewLine Severity or whether to print a newline
609
     * @param bool     $newLine           Whether to print a newline
610
     *
611
     * @return mixed|\Netresearch\Kite\Task\OutputTask
612
     */
613
    public function output($message, $severityOrNewLine = OutputInterface::VERBOSITY_NORMAL, $newLine = true)
614
    {
615
        if (is_bool($severityOrNewLine)) {
616
            $newLine = $severityOrNewLine;
617
            $severity = OutputInterface::VERBOSITY_NORMAL;
618
        } else {
619
            $severity = $severityOrNewLine;
620
        }
621
        return $this->createAndAddTask(__FUNCTION__, compact('message', 'severity', 'newLine'));
622
    }
623
624
    /**
625
     * Execute a command remote
626
     *
627
     * @param string            $command         The command to execute
628
     * @param string|null       $cwd             The directory to change into before execution
629
     * @param array|string|null $optArg          Options and arguments
630
     *                                           {@see \Netresearch\Kite\Task\ShellTask}
631
     * @param array             $processSettings Settings for symfony process class
632
     *
633
     * @return Task\RemoteShellTask|string
634
     */
635
    public function remoteShell($command, $cwd = null, $optArg = null, array $processSettings = array())
636
    {
637
        return $this->createAndAddTask(__FUNCTION__, compact('command', 'cwd', 'optArg', 'processSettings'));
638
    }
639
640
    /**
641
     * Rsync from/to somewhere - prefix $from/$to with {node}: to rsync from/to nodes
642
     *
643
     * @param string $from    From
644
     * @param string $to      To
645
     * @param array  $options Options for rsync
646
     * @param array  $exclude Files/dirs to exclude
647
     * @param array  $include Files/dirs to explicitely include
648
     *
649
     * @return string|\Netresearch\Kite\Task\RsyncTask
650
     */
651
    public function rsync($from, $to, array $options = array(), array $exclude = array(), array $include = array())
652
    {
653
        return $this->createAndAddTask(__FUNCTION__, compact('from', 'to', 'options', 'exclude', 'include'));
654
    }
655
656
    /**
657
     * Migrate the TYPO3 schema definitions from ext_table.sql files
658
     *
659
     * @return string|SchemaMigrationTask
660
     */
661
    public function schemaMigration()
662
    {
663
        return $this->createAndAddTask(__FUNCTION__);
664
    }
665
666
    /**
667
     * Upload a file via scp
668
     *
669
     * @param string $from File to upload (prefix with {node}: to download)
670
     * @param string $to   Path to upload to (prefix with {node}: to upload)
671
     *
672
     * @return mixed|\Netresearch\Kite\Task
673
     */
674
    public function scp($from, $to)
675
    {
676
        return $this->createAndAddTask(__FUNCTION__, compact('from', 'to'));
677
    }
678
679
    /**
680
     * Execute a command locally
681
     *
682
     * @param string            $command         The command to execute
683
     * @param string|null       $cwd             The directory to change into before execution
684
     * @param array|string|null $optArg          Options and arguments
685
     *                                           {@see \Netresearch\Kite\Task\ShellTask}
686
     * @param array             $processSettings Settings for symfony process class
687
     *
688
     * @return Task\ShellTask|string
689
     */
690
    public function shell($command, $cwd = null, $optArg = null, array $processSettings = array())
691
    {
692
        return $this->createAndAddTask(__FUNCTION__, compact('command', 'cwd', 'optArg', 'processSettings'));
693
    }
694
695
    /**
696
     * Run tasks as sub tasks
697
     *
698
     * @param string|array $workflowOrOptions Options for the class factory or workflow class name
699
     * @param array        $workflowOptions   Options for the workflow (when $workflowOrOptions is string)
700
     *
701
     * @return Task\SubTask|Workflow
702
     */
703
    public function sub($workflowOrOptions = array(), array $workflowOptions = array())
704
    {
705
        if (is_string($workflowOrOptions)) {
706
            return $this->createAndAddTask($workflowOrOptions, $workflowOptions);
707
        }
708
        return $this->createAndAddTask($workflowOrOptions);
709
    }
710
711
    /**
712
     * Run tasks as sub tasks and catch exceptions
713
     *
714
     * @param string $errorMessage Error message to display on failure
715
     *
716
     * @return \Netresearch\Kite\Task\TryCatchTask
717
     */
718
    public function tryCatch($errorMessage = null)
719
    {
720
        return $this->createAndAddTask(__FUNCTION__, compact('errorMessage'));
721
    }
722
723
    /**
724
     * Create a Tar archive from the file or files in $file
725
     *
726
     * @param string|array $files  File(s) to tar
727
     * @param string       $toFile Path to tar file
728
     *
729
     * @return mixed|\Netresearch\Kite\Task\TarTask
730
     */
731
    public function tar($files, $toFile)
732
    {
733
        return $this->createAndAddTask(__FUNCTION__, compact('files', 'toFile'));
734
    }
735
}
736
?>
737