Passed
Push — master ( e1f86a...4e1a3a )
by Siad
05:23
created

ApplyTask::process()   F

Complexity

Conditions 27
Paths 1296

Size

Total Lines 143
Code Lines 90

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 64
CRAP Score 34.7095

Importance

Changes 0
Metric Value
cc 27
eloc 90
nc 1296
nop 2
dl 0
loc 143
ccs 64
cts 82
cp 0.7805
crap 34.7095
rs 0
c 0
b 0
f 0

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
/**
3
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
4
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
5
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
6
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
7
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
8
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
9
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
10
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
11
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
12
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
13
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
14
 *
15
 * This software consists of voluntary contributions made by many individuals
16
 * and is licensed under the LGPL. For more information please see
17
 * <http://phing.info>.
18
 */
19
20
namespace Phing\Tasks\System;
21
22
use Phing\Exception\BuildException;
23
use Phing\Exception\NullPointerException;
24
use Phing\Io\DirectoryScanner;
25
use Phing\Io\FileUtils;
26
use Phing\Io\IOException;
27
use Phing\Io\File;
28
use Phing\Io\SourceFileScanner;
29
use Phing\Phing;
30
use Phing\Project;
31
use Phing\Type\Commandline;
32
use Phing\Type\CommandlineMarker;
33
use Phing\Type\DirSet;
34
use Phing\Type\Element\ResourceAware;
35
use Phing\Type\FileList;
36
use Phing\Type\Mapper;
37
38
/**
39
 * Executes a command on the (filtered) file list/set.
40
 * (Loosely based on the "Ant Apply" task - http://ant.apache.org/manual/Tasks/apply.html)
41
 *
42
 * @author  Utsav Handa <handautsav at hotmail dot com>
43
 * @package phing.tasks.system
44
 *
45
 * @todo Add support for mapper, targetfile expressions
46
 */
47
class ApplyTask extends ExecTask
48
{
49
    use ResourceAware;
50
51
    public const SOURCEFILE_ID = '__SOURCEFILE__';
52
    protected $currentdirectory;
53
54
    /**
55
     * Whether output should be appended to or overwrite an existing file
56
     *
57
     * @var boolean
58
     */
59
    protected $appendoutput = false;
60
61
    /**
62
     * Runs the command only once, appending all files as arguments
63
     * else command will be executed once for every file.
64
     *
65
     * @var boolean
66
     */
67
    protected $parallel = false;
68
69
    /**
70
     * Whether source file name should be added to the end of command automatically
71
     *
72
     * @var boolean
73
     */
74
    protected $addsourcefile = true;
75
76
    /**
77
     * Whether the filenames should be passed on the command line as relative pathnames (relative to the base directory of the corresponding fileset/list)
78
     *
79
     * @var boolean
80
     */
81
    protected $relative = false;
82
83
    protected $currentos;
84
    protected $osvariant;
85
86
    /**
87
     * Logging level for status messages
88
     *
89
     * @var integer
90
     */
91
    protected $loglevel = null;
92
93
    /**
94
     * Whether to use forward-slash as file-separator on the file names
95
     *
96
     * @var boolean
97
     */
98
    protected $forwardslash = false;
99
100
    /**
101
     * Limit the amount of parallelism by passing at most this many sourcefiles at once
102
     * (Set it to <= 0 for unlimited)
103
     *
104
     * @var integer
105
     */
106
    protected $maxparallel = 0;
107
108
    protected static $types = [
109
        'FILE' => 'file',
110
        'DIR' => 'dir',
111
        'BOTH' => 'both',
112
    ];
113
114
    protected $type = 'file';
115
    /**
116
     * @var CommandlineMarker $targetFilePos
117
     */
118
    protected $targetFilePos;
119
    /**
120
     * @var CommandlineMarker $srcFilePos
121
     */
122
    protected $srcFilePos;
123
    protected $srcIsFirst = true;
124
125
    protected $skipEmpty = false;
126
    private $force = false;
127
    private $mapper;
128
    private $destDir;
129
130
    /**
131
     * @var Mapper $mapperElement
132
     */
133
    private $mapperElement;
134
    private $additionalCmds;
135
136
    /**
137
     * Set whether empty filesets will be skipped.  If true and
138
     * no source files have been found or are newer than their
139
     * corresponding target files, the command will not be run.
140
     *
141
     * @param boolean $skip whether to skip empty filesets.
142
     */
143
    public function setSkipEmptyFilesets(bool $skip)
144
    {
145
        $this->skipEmpty = $skip;
146
    }
147
148
    /**
149
     * Specify the directory where target files are to be placed.
150
     *
151
     * @param File $dest the File object representing the destination directory.
152
     */
153 1
    public function setDest(File $dest)
154
    {
155 1
        $this->destDir = $dest;
156 1
    }
157
158
    /**
159
     * File to which output should be written
160
     *
161
     * @param    $append
162
     * @internal param PhingFile $outputfile Output log file
163
     *
164
     * @return void
165
     */
166 3
    public function setAppend(bool $append)
167
    {
168 3
        $this->appendoutput = $append;
169 3
    }
170
171
    /**
172
     * Run the command only once, appending all files as arguments
173
     *
174
     * @param Boolean $parallel Identifier for files as arguments appending
175
     *
176
     * @return void
177
     */
178 15
    public function setParallel(bool $parallel)
179
    {
180 15
        $this->parallel = $parallel;
181 15
    }
182
183
    /**
184
     * To add the source filename at the end of command of automatically
185
     *
186
     * @param Boolean $addsourcefile Identifier for adding source file at the end of command
187
     *
188
     * @return void
189
     */
190 19
    public function setAddsourcefile(bool $addsourcefile)
191
    {
192 19
        $this->addsourcefile = $addsourcefile;
193 19
    }
194
195
    /**
196
     * Whether the filenames should be passed on the command line as relative
197
     * pathnames (relative to the base directory of the corresponding fileset/list)
198
     *
199
     * @param    $relative
200
     * @internal param bool $escape Escape command before execution
201
     *
202
     * @return void
203
     */
204 3
    public function setRelative(bool $relative)
205
    {
206 3
        $this->relative = $relative;
207 3
    }
208
209
    /**
210
     * Fail on command exits with a returncode other than zero
211
     *
212
     * @param boolean $failonerror Indicator to fail on error
213
     *
214
     * @return void
215
     */
216 1
    public function setFailonerror(bool $failonerror)
217
    {
218 1
        $this->checkreturn = $failonerror;
219 1
    }
220
221
    /**
222
     * Whether to use forward-slash as file-separator on the file names
223
     *
224
     * @param boolean $forwardslash Indicator to use forward-slash
225
     *
226
     * @return void
227
     */
228 1
    public function setForwardslash(bool $forwardslash)
229
    {
230 1
        $this->forwardslash = $forwardslash;
231 1
    }
232
233
    /**
234
     * Limit the amount of parallelism by passing at most this many sourcefiles at once
235
     *
236
     * @param    $max
237
     * @internal param bool $forwardslash Indicator to use forward-slash
238
     *
239
     * @return void
240
     */
241 1
    public function setMaxparallel($max)
242
    {
243 1
        $this->maxparallel = (int) $max;
244 1
    }
245
246
    public function setForce(bool $force)
247
    {
248
        $this->force = $force;
249
    }
250
251
    /**
252
     * Set whether the command works only on files, directories or both.
253
     *
254
     * @param string $type a FileDirBoth EnumeratedAttribute.
255
     */
256
    public function setType(string $type)
257
    {
258
        $this->type = $type;
259
    }
260
261
    /**
262
     * Supports embedded <targetfile> element.
263
     *
264
     * @return CommandlineMarker
265
     * @throws \Phing\Exception\BuildException
266
     */
267 1
    public function createTargetfile()
268
    {
269 1
        if ($this->targetFilePos !== null) {
270
            throw new BuildException(
271
                $this->getTaskType() . " doesn\'t support multiple "
272
                . "targetfile elements.",
273
                $this->getLocation()
274
            );
275
        }
276
277 1
        $this->targetFilePos = $this->commandline->createMarker();
278 1
        $this->srcIsFirst = ($this->srcFilePos !== null);
279
280 1
        return $this->targetFilePos;
281
    }
282
283
    /**
284
     * Supports embedded <srcfile> element.
285
     *
286
     * @return CommandlineMarker
287
     * @throws \Phing\Exception\BuildException
288
     */
289 1
    public function createSrcfile()
290
    {
291 1
        if ($this->srcFilePos !== null) {
292
            throw new BuildException(
293
                $this->getTaskType() . " doesn\'t support multiple "
294
                . "srcfile elements.",
295
                $this->getLocation()
296
            );
297
        }
298
299 1
        $this->srcFilePos = $this->commandline->createMarker();
300 1
        return $this->srcFilePos;
301
    }
302
303
    /**
304
     * @return Mapper
305
     * @throws \Phing\Exception\BuildException
306
     */
307 1
    public function createMapper()
308
    {
309 1
        if ($this->mapperElement !== null) {
310
            throw new BuildException(
311
                'Cannot define more than one mapper',
312
                $this->getLocation()
313
            );
314
        }
315 1
        $this->mapperElement = new Mapper($this->getProject());
316 1
        return $this->mapperElement;
317
    }
318
319
    /**********************************************************************************/
320
    /**************************** T A S K  M E T H O D S ******************************/
321
    /**********************************************************************************/
322
323
    /**
324
     * Do work
325
     *
326
     * @throws \Phing\Exception\BuildException
327
     */
328 21
    public function main()
329
    {
330
        try {
331
            // Log
332 21
            $this->log('Started ', $this->loglevel);
333
            // Initialize //
334 21
            $this->prepare();
335 19
            $haveExecuted = false;
336
            // Validate O.S. applicability
337 19
            if ($this->isValidOs()) {
338
                // Build the command //
339 18
                $this->buildCommand();
340
                // Process //
341 18
                $totalFiles = 0;
342 18
                $totalDirs = 0;
343 18
                $fileNames = [];
344
                // - FileSets
345 18
                foreach ($this->filesets as $fs) {
346 18
                    $currentType = $this->type;
347 18
                    if ($fs instanceof DirSet) {
348
                        if ($this->type !== self::$types['DIR']) {
349
                            $this->log(
350
                                "Found a nested dirset but type is $this->type . "
351
                                . "Temporarily switching to type=\"dir\" on the"
352
                                . " assumption that you really did mean"
353
                                . " <dirset> not <fileset>.",
354
                                Project::MSG_DEBUG
355
                            );
356
                            $currentType = 'dir';
357
                        }
358
                    }
359 18
                    $base = $fs->getDir($this->project);
360 18
                    $ds = $fs->getDirectoryScanner($this->project);
361 18
                    if ($currentType !== self::$types['DIR']) {
362 18
                        $s = $this->getFiles($base, $ds);
363 18
                        foreach ($s as $fileName) {
364 18
                            $totalFiles++;
365 18
                            $fileNames[] = $fileName;
366 18
                            $baseDirs[] = $base;
367
                        }
368
                    }
369 18
                    if ($currentType !== self::$types['FILE']) {
370
                        $s = $this->getDirs($base, $ds);
371
                        foreach ($s as $fileName) {
372
                            $totalDirs++;
373
                            $fileNames[] = $fileName;
374
                            $baseDirs[] = $base;
375
                        }
376
                    }
377 18
                    if (count($fileNames) === 0 && $this->skipEmpty) {
378
                        $this->logSkippingFileset($currentType, $ds, $base);
379
                        continue;
380
                    }
381 18
                    $this->process(
382 18
                        $fs->getDirectoryScanner($this->project)->getIncludedFiles(),
383 18
                        $fs->getDir($this->project)
384
                    );
385 17
                    $haveExecuted = true;
386
                }
387 17
                unset($this->filesets);
388
                // - FileLists
389
                /**
390
                 * @var FileList $fl
391
                 */
392 17
                foreach ($this->filelists as $fl) {
393
                    $totalFiles++;
394
                    $this->process($fl->getFiles($this->project), $fl->getDir($this->project));
395
                    $haveExecuted = true;
396
                }
397 17
                unset($this->filelists);
398
            }
399 18
            if ($haveExecuted) {
400 17
                $this->log(
401 17
                    "Applied " . $this->commandline->getExecutable() . " to "
402 17
                    . $totalFiles . " file"
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $totalFiles does not seem to be defined for all execution paths leading up to this point.
Loading history...
403 17
                    . ($totalFiles !== 1 ? "s" : "") . " and "
404 17
                    . $totalDirs . " director"
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $totalDirs does not seem to be defined for all execution paths leading up to this point.
Loading history...
405 17
                    . ($totalDirs !== 1 ? "ies" : "y") . ".",
406 17
                    $this->loglevel
407
                );
408
            }
409
            /// Cleanup //
410 18
            $this->cleanup();
411
            // Log
412 18
            $this->log('End ', $this->loglevel);
413 3
        } catch (IOException | NullPointerException | \UnexpectedValueException $e) {
414
            throw new BuildException('Execute failed: ' . $e, $e, $this->getLocation());
415
        }
416 18
    }
417
418
    /**********************************************************************************/
419
    /********************** T A S K  C O R E  M E T H O D S ***************************/
420
    /**********************************************************************************/
421
422 18
    protected function getFiles(File $baseDir, DirectoryScanner $ds)
423
    {
424 18
        return $this->restrict($ds->getIncludedFiles(), $baseDir);
425
    }
426
427
    protected function getDirs(File $baseDir, DirectoryScanner $ds)
428
    {
429
        return $this->restrict($ds->getIncludedDirectories(), $baseDir);
430
    }
431
432 18
    protected function restrict($s, File $baseDir)
433
    {
434 18
        $sfs = new SourceFileScanner($this);
435 18
        return ($this->mapper === null || $this->force)
436 17
            ? $s
437 18
            : $sfs->restrict($s, $baseDir, $this->destDir, $this->mapper);
438
    }
439
440
    private function logSkippingFileset($currentType, DirectoryScanner $ds, File $base)
441
    {
442
        $includedCount = (
443
            ($currentType !== self::$types['DIR']) ? $ds->getIncludedFilesCount() : 0
444
            ) + (
445
            ($currentType !== self::$types['FILES']) ? $ds->getIncludedDirectoriesCount() : 0
446
            );
447
        $this->log(
448
            "Skipping fileset for directory " . $base . ". It is "
449
            . (($includedCount > 0) ? "up to date." : "empty."),
450
            $this->loglevel
451
        );
452
    }
453
454
    /**
455
     * Initializes the task operations, i.e.
456
     * - Required information validation
457
     * - Working directory
458
     *
459
     * @return void
460
     * @throws \Phing\Exception\BuildException
461
     * @throws IOException
462
     */
463 21
    protected function prepare()
464
    {
465
        // Log
466 21
        $this->log('Initializing started ', $this->loglevel);
467
468
        ///// Validating the required parameters /////
469
470 21
        if (!in_array($this->type, self::$types)) {
471
            throw new BuildException('Type must be one of \'file\', \'dir\' or \'both\'.');
472
        }
473
474
        // Executable
475 21
        if ($this->commandline->getExecutable() === null) {
0 ignored issues
show
introduced by
The condition $this->commandline->getExecutable() === null is always false.
Loading history...
476 1
            $this->throwBuildException('Please provide "executable" information');
477
        }
478
479
        // Retrieving the current working directory
480 20
        $this->currentdirectory = getcwd();
481
482
        // Directory (in which the command should be executed)
483 20
        if ($this->dir !== null) {
484
            // Try expanding (any) symbolic links
485 4
            if (!$this->dir->getCanonicalFile()->isDirectory()) {
486 1
                $this->throwBuildException("'" . $this->dir . "' is not a valid directory");
487
            }
488
489
            // Change working directory
490 3
            $dirchangestatus = @chdir($this->dir->getPath());
491
492
            // Log
493 3
            $this->log(
494 3
                'Working directory change ' . ($dirchangestatus ? 'successful' : 'failed') . ' to ' . $this->dir->getPath(),
495 3
                $this->loglevel
496
            );
497
        }
498
499
        ///// Preparing the task environment /////
500
501
        // Getting current operationg system
502 19
        $this->currentos = Phing::getProperty('os.name');
503
504
        // Log
505 19
        $this->log('Operating System identified : ' . $this->currentos, $this->loglevel);
506
507
        // Getting the O.S. type identifier
508
        // Validating the 'filesystem' for determining the OS type [UNIX, WINNT and WIN32]
509
        // (Another usage could be with 'os.name' for determination)
510 19
        if ('WIN' === strtoupper(substr(Phing::getProperty('host.fstype'), 0, 3))) {
511
            $this->osvariant = 'WIN'; // Probable Windows flavour
512
        } else {
513 19
            $this->osvariant = 'LIN'; // Probable GNU/Linux flavour
514
        }
515
516
        // Log
517 19
        $this->log('Operating System variant identified : ' . $this->osvariant, $this->loglevel);
518
519 19
        if (count($this->filesets) === 0 && count($this->filelists) === 0 && count($this->getDirSets()) === 0) {
520
            throw new BuildException(
521
                "no resources specified",
522
                $this->getLocation()
523
            );
524
        }
525 19
        if ($this->targetFilePos !== null && $this->mapperElement === null) {
526
            throw new BuildException(
527
                "targetfile specified without mapper",
528
                $this->getLocation()
529
            );
530
        }
531 19
        if ($this->destDir !== null && $this->mapperElement === null) {
532
            throw new BuildException(
533
                "dest specified without mapper",
534
                $this->getLocation()
535
            );
536
        }
537
538 19
        if ($this->mapperElement !== null) {
539 1
            $this->mapper = $this->mapperElement->getImplementation();
540 1
            $this->log('Mapper identified : ' . get_class($this->mapper), $this->loglevel);
541
        }
542
543 19
        $this->commandline->setEscape($this->escape);
544
545
        // Log
546 19
        $this->log('Initializing completed ', $this->loglevel);
547 19
    }
548
549
    /**
550
     * Builds the full command to execute and stores it in $realCommand.
551
     *
552
     * @return void
553
     *
554
     * @throws \Phing\Exception\BuildException
555
     */
556 18
    protected function buildCommand()
557
    {
558
559
        // Log
560 18
        $this->log('Command building started ', $this->loglevel);
561
562
        // Building the executable
563 18
        $this->realCommand = (string) $this->commandline;
564
565 18
        $this->additionalCmds = '';
566
567
        // Adding the source filename at the end of command, validating the existing
568
        // sourcefile position explicit mentioning
569 18
        if ($this->addsourcefile === true) {
570 1
            $this->realCommand .= ' ' . self::SOURCEFILE_ID;
571
        }
572
573
        // Setting command output redirection with content appending
574 18
        if ($this->output !== null) {
575 3
            $this->additionalCmds .= sprintf(
576 3
                ' 1>%s %s',
577 3
                $this->appendoutput ? '>' : '',
578 3
                escapeshellarg($this->output->getPath())
579
            );
580 15
        } elseif ($this->spawn) { // Validating the 'spawn' configuration, and redirecting the output to 'null'
581 1
            $this->additionalCmds .= sprintf(' %s', 'WIN' === $this->osvariant ? '> NUL' : '1>/dev/null');
582
583 1
            $this->log("For process spawning, setting Output nullification ", $this->loglevel);
584
        }
585
586
        // Setting command error redirection with content appending
587 18
        if ($this->error !== null) {
588 1
            $this->additionalCmds .= sprintf(
589 1
                ' 2>%s %s',
590 1
                $this->appendoutput ? '>' : '',
591 1
                escapeshellarg($this->error->getPath())
592
            );
593
        }
594
595
        // Setting the execution as a background process
596 18
        if ($this->spawn) {
597
            // Validating the O.S. variant
598 1
            if ('WIN' === $this->osvariant) {
599
                $this->additionalCmds = 'start /b ' . $this->additionalCmds; // MS Windows background process forking
600
            } else {
601 1
                $this->additionalCmds .= ' &'; // GNU/Linux background process forking
602
            }
603
        }
604
605 18
        $this->additionalCmds = rtrim($this->additionalCmds);
606
607
        // Log
608 18
        $this->log('Command built : ' . $this->realCommand . $this->additionalCmds, $this->loglevel);
609
610
        // Log
611 18
        $this->log('Command building completed ', $this->loglevel);
612 18
    }
613
614
    /**
615
     * Processes the files list with provided information for execution
616
     *
617
     * @param array $srcFiles File list for processing
618
     * @param string $basedir Base directory of the file list
619
     *
620
     * @return void
621
     * @throws \Phing\Exception\BuildException
622
     * @throws IOException
623
     * @throws NullPointerException
624
     */
625 18
    private function process($srcFiles, $basedir)
626
    {
627
        // Log
628 18
        $this->log("Processing files with base directory ($basedir) ", $this->loglevel);
629 18
        $targets = [];
630 18
        if ($this->targetFilePos !== null) {
631 1
            $addedFiles = [];
632 1
            foreach ($srcFiles as $count => $file) {
633 1
                if ($this->mapper !== null) {
634 1
                    $subTargets = $this->mapper->main($file);
635 1
                    if ($subTargets !== null) {
636 1
                        foreach ($subTargets as $subTarget) {
637 1
                            if ($this->relative) {
638
                                $name = $subTarget;
639
                            } else {
640 1
                                $name = (new File($this->destDir, $subTarget))->getAbsolutePath();
641
                            }
642 1
                            if ($this->forwardslash && FileUtils::getSeparator() !== '/') {
643
                                $name = str_replace(FileUtils::getSeparator(), '/', $name);
644
                            }
645 1
                            if (!isset($addedFiles[$name])) {
646 1
                                $targets[] = $name;
647 1
                                $addedFiles[] = $name;
648
                            }
649
                        }
650
                    }
651
                }
652
            }
653
        }
654 18
        $targetFiles = $targets;
655
656 18
        if (!$this->addsourcefile) {
657 17
            $srcFiles = [];
658
        }
659 18
        $orig = $this->commandline->getCommandline();
660 18
        $result = []; // range(0,count($orig) + count($srcFiles) + count($targetFiles));
661
662 18
        $srcIndex = count($orig);
663 18
        if ($this->srcFilePos !== null) {
664 1
            $srcIndex = $this->srcFilePos->getPosition();
665
        }
666 18
        if ($this->targetFilePos !== null) {
667 1
            $targetIndex = $this->targetFilePos->getPosition();
668
669 1
            if ($srcIndex < $targetIndex || ($srcIndex === $targetIndex && $this->srcIsFirst)) {
670
                // 0 --> srcIndex
671
                $result[] = $orig;
672
673
                // srcIndex --> targetIndex
674
                $result += array_slice($orig, $srcIndex + count($srcFiles), $targetIndex - $srcIndex, true);
675
676
                $result[] = $orig;
677
                $result[] = $targetFiles;
678
                $result = array_merge(... $result);
679
680
                // targetIndex --> end
681
                $result = array_merge(
682
                    array_slice(
683
                        $orig,
684
                        $targetIndex + count($srcFiles) + count($targetFiles),
685
                        count($orig) - $targetIndex,
686
                        true
687
                    ),
688
                    $result
689
                );
690
            } else {
691
                // 0 --> targetIndex
692 1
                $result[] = $orig;
693 1
                $result[] = $targetFiles;
694 1
                $result = array_merge(... $result);
695
696
                // targetIndex --> srcIndex
697 1
                $result = array_merge(
698 1
                    array_slice(
699 1
                        $orig,
700 1
                        $targetIndex + count($targetFiles),
701 1
                        $srcIndex - $targetIndex,
702 1
                        true
703
                    ),
704
                    $result
705
                );
706
707
                // srcIndex --> end
708 1
                $result = array_merge(
709 1
                    array_slice(
710 1
                        $orig,
711 1
                        $srcIndex + count($srcFiles) + count($targetFiles),
712 1
                        count($orig) - $srcIndex,
713 1
                        true
714
                    ),
715
                    $result
716
                );
717 1
                $srcIndex += count($targetFiles);
718
            }
719
        } else { // no targetFilePos
720
            // 0 --> srcIndex
721 17
            $result = array_merge(array_slice($orig, 0, $srcIndex, true), $result);
722
            // srcIndex --> end
723 17
            $result = array_merge(
724 17
                array_slice($orig, $srcIndex + count($srcFiles), count($orig) - $srcIndex, true),
725
                $result
726
            );
727
        }
728
        // fill in source file names
729 18
        foreach ($srcFiles as $i => $file) {
730 1
            if ($this->relative) {
731 1
                $src = $file;
732
            } else {
733
                $src = (new File($basedir, $file))->getAbsolutePath();
734
            }
735 1
            if ($this->forwardslash && FileUtils::getSeparator() !== '/') {
736
                $src = str_replace(FileUtils::getSeparator(), '/', $src);
737
            }
738
            if (
739 1
                $this->srcFilePos !== null
740
                && ($this->srcFilePos->getPrefix() !== ''
741 1
                    || $this->srcFilePos->getSuffix() !== '')
742
            ) {
743
                $src = $this->srcFilePos->getPrefix() . $src . $this->srcFilePos->getSuffix();
744
            }
745 1
            $result[$srcIndex + $i] = $src;
746
        }
747
748 18
        $this->commandline = new Commandline(implode(' ', $result));
749 18
        $this->commandline->setEscape($this->escape);
750 18
        $this->realCommand = (string) $this->commandline . $this->additionalCmds;
751
752 18
        [$returncode, $output] = $this->executeCommand();
753
754 18
        $this->maybeSetReturnPropertyValue($returncode);
755
756
        // Sets the output property
757 18
        if ($this->outputProperty) {
758 2
            $previousValue = $this->project->getProperty($this->outputProperty);
759 2
            if (!empty($previousValue)) {
760
                $previousValue .= "\n";
761
            }
762 2
            $this->project->setProperty($this->outputProperty, $previousValue . implode("\n", $output));
763
        }
764
765
        // Validating the 'return-code'
766 18
        if ($this->checkreturn && ($returncode !== 0)) {
767 1
            $this->throwBuildException("Task exited with code ($returncode)");
768
        }
769 17
    }
770
771
    /**
772
     * Runs cleanup tasks post execution
773
     * - Restore working directory
774
     *
775
     * @return void
776
     */
777 18
    protected function cleanup($return = null, $output = null): void
778
    {
779
        // Restore working directory
780 18
        if ($this->dir !== null) {
781 3
            @chdir($this->currentdirectory);
1 ignored issue
show
Security Best Practice introduced by
It seems like you do not handle an error condition for chdir(). This can introduce security issues, and is generally not recommended. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unhandled  annotation

781
            /** @scrutinizer ignore-unhandled */ @chdir($this->currentdirectory);

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
782
        }
783 18
    }
784
785
    /**
786
     * Prepares the filename per base directory and relative path information
787
     *
788
     * @param array|string $filename
789
     * @param $basedir
790
     * @param $relative
791
     *
792
     * @return mixed processed filenames
793
     *
794
     * @throws IOException
795
     */
796
    public function getFilePath($filename, $basedir, $relative)
797
    {
798
        // Validating the 'file' information
799
        $files = (array) $filename;
800
801
        // Processing the file information
802
        foreach ($files as $index => $file) {
803
            $absolutefilename = (($relative === false) ? ($basedir . FileUtils::getSeparator()) : '');
804
            $absolutefilename .= $file;
805
            if ($relative === false) {
806
                $files[$index] = (new FileUtils())->normalize($absolutefilename);
807
            } else {
808
                $files[$index] = $absolutefilename;
809
            }
810
        }
811
812
        return (is_array($filename) ? $files : $files[0]);
813
    }
814
815
    /**
816
     * Throws the exception with specified information
817
     *
818
     * @param string $information Exception information
819
     *
820
     * @throws BuildException
821
     *
822
     * @return void
823
     */
824 3
    private function throwBuildException($information): void
825
    {
826 3
        throw new BuildException('ApplyTask: ' . (string) $information);
827
    }
828
}
829