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
/**
21
 * Executes a command on the (filtered) file list/set.
22
 * (Loosely based on the "Ant Apply" task - http://ant.apache.org/manual/Tasks/apply.html)
23
 *
24
 * @author  Utsav Handa <handautsav at hotmail dot com>
25
 * @package phing.tasks.system
26
 *
27
 * @todo Add support for mapper, targetfile expressions
28
 */
29
class ApplyTask extends ExecTask
30
{
31
    use ResourceAware;
32

33
    public const SOURCEFILE_ID = '__SOURCEFILE__';
34
    protected $currentdirectory;
35

36
    /**
37
     * Whether output should be appended to or overwrite an existing file
38
     *
39
     * @var boolean
40
     */
41
    protected $appendoutput = false;
42

43
    /**
44
     * Runs the command only once, appending all files as arguments
45
     * else command will be executed once for every file.
46
     *
47
     * @var boolean
48
     */
49
    protected $parallel = false;
50

51
    /**
52
     * Whether source file name should be added to the end of command automatically
53
     *
54
     * @var boolean
55
     */
56
    protected $addsourcefile = true;
57

58
    /**
59
     * Whether the filenames should be passed on the command line as relative pathnames (relative to the base directory of the corresponding fileset/list)
60
     *
61
     * @var boolean
62
     */
63
    protected $relative = false;
64

65
    protected $currentos;
66
    protected $osvariant;
67

68
    /**
69
     * Logging level for status messages
70
     *
71
     * @var integer
72
     */
73
    protected $loglevel = null;
74

75
    /**
76
     * Whether to use forward-slash as file-separator on the file names
77
     *
78
     * @var boolean
79
     */
80
    protected $forwardslash = false;
81

82
    /**
83
     * Limit the amount of parallelism by passing at most this many sourcefiles at once
84
     * (Set it to <= 0 for unlimited)
85
     *
86
     * @var integer
87
     */
88
    protected $maxparallel = 0;
89

90
    protected static $types = [
91
        'FILE' => 'file',
92
        'DIR' => 'dir',
93
        'BOTH' => 'both',
94
    ];
95

96
    protected $type = 'file';
97
    /**
98
     * @var CommandlineMarker $targetFilePos
99
     */
100
    protected $targetFilePos;
101
    /**
102
     * @var CommandlineMarker $srcFilePos
103
     */
104
    protected $srcFilePos;
105
    protected $srcIsFirst = true;
106

107
    protected $skipEmpty = false;
108
    private $force = false;
109
    private $mapper;
110
    private $destDir;
111

112
    /**
113
     * @var Mapper $mapperElement
114
     */
115
    private $mapperElement;
116
    private $additionalCmds;
117

118
    /**
119
     * Set whether empty filesets will be skipped.  If true and
120
     * no source files have been found or are newer than their
121
     * corresponding target files, the command will not be run.
122
     *
123
     * @param boolean $skip whether to skip empty filesets.
124
     */
125 0
    public function setSkipEmptyFilesets(bool $skip)
126
    {
127 0
        $this->skipEmpty = $skip;
128
    }
129

130
    /**
131
     * Specify the directory where target files are to be placed.
132
     *
133
     * @param PhingFile $dest the File object representing the destination directory.
134
     */
135 1
    public function setDest(PhingFile $dest)
136
    {
137 1
        $this->destDir = $dest;
138
    }
139

140
    /**
141
     * File to which output should be written
142
     *
143
     * @param    $append
144
     * @internal param PhingFile $outputfile Output log file
145
     *
146
     * @return void
147
     */
148 1
    public function setAppend(bool $append)
149
    {
150 1
        $this->appendoutput = $append;
151
    }
152

153
    /**
154
     * Run the command only once, appending all files as arguments
155
     *
156
     * @param Boolean $parallel Identifier for files as arguments appending
157
     *
158
     * @return void
159
     */
160 1
    public function setParallel(bool $parallel)
161
    {
162 1
        $this->parallel = $parallel;
163
    }
164

165
    /**
166
     * To add the source filename at the end of command of automatically
167
     *
168
     * @param Boolean $addsourcefile Identifier for adding source file at the end of command
169
     *
170
     * @return void
171
     */
172 1
    public function setAddsourcefile(bool $addsourcefile)
173
    {
174 1
        $this->addsourcefile = $addsourcefile;
175
    }
176

177
    /**
178
     * Whether the filenames should be passed on the command line as relative
179
     * pathnames (relative to the base directory of the corresponding fileset/list)
180
     *
181
     * @param    $relative
182
     * @internal param bool $escape Escape command before execution
183
     *
184
     * @return void
185
     */
186 1
    public function setRelative(bool $relative)
187
    {
188 1
        $this->relative = $relative;
189
    }
190

191
    /**
192
     * Fail on command exits with a returncode other than zero
193
     *
194
     * @param boolean $failonerror Indicator to fail on error
195
     *
196
     * @return void
197
     */
198 1
    public function setFailonerror(bool $failonerror)
199
    {
200 1
        $this->checkreturn = $failonerror;
201
    }
202

203
    /**
204
     * Whether to use forward-slash as file-separator on the file names
205
     *
206
     * @param boolean $forwardslash Indicator to use forward-slash
207
     *
208
     * @return void
209
     */
210 1
    public function setForwardslash(bool $forwardslash)
211
    {
212 1
        $this->forwardslash = $forwardslash;
213
    }
214

215
    /**
216
     * Limit the amount of parallelism by passing at most this many sourcefiles at once
217
     *
218
     * @param    $max
219
     * @internal param bool $forwardslash Indicator to use forward-slash
220
     *
221
     * @return void
222
     */
223 1
    public function setMaxparallel($max)
224
    {
225 1
        $this->maxparallel = (int) $max;
226
    }
227

228 0
    public function setForce(bool $force)
229
    {
230 0
        $this->force = $force;
231
    }
232

233
    /**
234
     * Set whether the command works only on files, directories or both.
235
     *
236
     * @param string $type a FileDirBoth EnumeratedAttribute.
237
     */
238 0
    public function setType(string $type)
239
    {
240 0
        $this->type = $type;
241
    }
242

243
    /**
244
     * Supports embedded <targetfile> element.
245
     *
246
     * @return CommandlineMarker
247
     * @throws \BuildException
248
     */
249 1
    public function createTargetfile()
250
    {
251 1
        if ($this->targetFilePos !== null) {
252 0
            throw new BuildException(
253 0
                $this->getTaskType() . " doesn\'t support multiple "
254 0
                . "targetfile elements.",
255 0
                $this->getLocation()
256
            );
257
        }
258

259 1
        $this->targetFilePos = $this->commandline->createMarker();
260 1
        $this->srcIsFirst = ($this->srcFilePos !== null);
261

262 1
        return $this->targetFilePos;
263
    }
264

265
    /**
266
     * Supports embedded <srcfile> element.
267
     *
268
     * @return CommandlineMarker
269
     * @throws \BuildException
270
     */
271 1
    public function createSrcfile()
272
    {
273 1
        if ($this->srcFilePos !== null) {
274 0
            throw new BuildException(
275 0
                $this->getTaskType() . " doesn\'t support multiple "
276 0
                . "srcfile elements.",
277 0
                $this->getLocation()
278
            );
279
        }
280

281 1
        $this->srcFilePos = $this->commandline->createMarker();
282 1
        return $this->srcFilePos;
283
    }
284

285
    /**
286
     * @return Mapper
287
     * @throws \BuildException
288
     */
289 1
    public function createMapper()
290
    {
291 1
        if ($this->mapperElement !== null) {
292 0
            throw new BuildException(
293 0
                'Cannot define more than one mapper',
294 0
                $this->getLocation()
295
            );
296
        }
297 1
        $this->mapperElement = new Mapper($this->getProject());
298 1
        return $this->mapperElement;
299
    }
300

301
    /**********************************************************************************/
302
    /**************************** T A S K  M E T H O D S ******************************/
303
    /**********************************************************************************/
304

305
    /**
306
     * Do work
307
     *
308
     * @throws \BuildException
309
     */
310 1
    public function main()
311
    {
312
        try {
313
            // Log
314 1
            $this->log('Started ', $this->loglevel);
315
            // Initialize //
316 1
            $this->prepare();
317 1
            $haveExecuted = false;
318
            // Validate O.S. applicability
319 1
            if ($this->isValidOs()) {
320
                // Build the command //
321 1
                $this->buildCommand();
322
                // Process //
323 1
                $totalFiles = 0;
324 1
                $totalDirs = 0;
325 1
                $fileNames = [];
326
                // - FileSets
327 1
                foreach ($this->filesets as $fs) {
328 1
                    $currentType = $this->type;
329 1
                    if ($fs instanceof DirSet) {
330 0
                        if ($this->type !== self::$types['DIR']) {
331 0
                            $this->log(
332 0
                                "Found a nested dirset but type is $this->type . "
333
                                . "Temporarily switching to type=\"dir\" on the"
334
                                . " assumption that you really did mean"
335 0
                                . " <dirset> not <fileset>.",
336 0
                                Project::MSG_DEBUG
337
                            );
338 0
                            $currentType = 'dir';
339
                        }
340
                    }
341 1
                    $base = $fs->getDir($this->project);
342 1
                    $ds = $fs->getDirectoryScanner($this->project);
343 1
                    if ($currentType !== self::$types['DIR']) {
344 1
                        $s = $this->getFiles($base, $ds);
345 1
                        foreach ($s as $fileName) {
346 1
                            $totalFiles++;
347 1
                            $fileNames[] = $fileName;
348 1
                            $baseDirs[] = $base;
349
                        }
350
                    }
351 1
                    if ($currentType !== self::$types['FILE']) {
352 0
                        $s = $this->getDirs($base, $ds);
353 0
                        foreach ($s as $fileName) {
354 0
                            $totalDirs++;
355 0
                            $fileNames[] = $fileName;
356 0
                            $baseDirs[] = $base;
357
                        }
358
                    }
359 1
                    if (count($fileNames) === 0 && $this->skipEmpty) {
360 0
                        $this->logSkippingFileset($currentType, $ds, $base);
361 0
                        continue;
362
                    }
363 1
                    $this->process(
364 1
                        $fs->getDirectoryScanner($this->project)->getIncludedFiles(),
365 1
                        $fs->getDir($this->project)
366
                    );
367 1
                    $haveExecuted = true;
368
                }
369 1
                unset($this->filesets);
370
                // - FileLists
371
                /**
372
                 * @var FileList $fl
373
                 */
374 1
                foreach ($this->filelists as $fl) {
375 0
                    $totalFiles++;
376 0
                    $this->process($fl->getFiles($this->project), $fl->getDir($this->project));
377 0
                    $haveExecuted = true;
378
                }
379 1
                unset($this->filelists);
380
            }
381 1
            if ($haveExecuted) {
382 1
                $this->log(
383 1
                    "Applied " . $this->commandline->getExecutable() . " to "
384 1
                    . $totalFiles . " file"
385 1
                    . ($totalFiles !== 1 ? "s" : "") . " and "
386 1
                    . $totalDirs . " director"
387 1
                    . ($totalDirs !== 1 ? "ies" : "y") . ".",
388 1
                    $this->loglevel
389
                );
390
            }
391
            /// Cleanup //
392 1
            $this->cleanup();
393
            // Log
394 1
            $this->log('End ', $this->loglevel);
395 1
        } catch (IOException | NullPointerException | UnexpectedValueException $e) {
396 0
            throw new BuildException('Execute failed: ' . $e, $e, $this->getLocation());
397
        }
398
    }
399

400
    /**********************************************************************************/
401
    /********************** T A S K  C O R E  M E T H O D S ***************************/
402
    /**********************************************************************************/
403

404 1
    protected function getFiles(PhingFile $baseDir, DirectoryScanner $ds)
405
    {
406 1
        return $this->restrict($ds->getIncludedFiles(), $baseDir);
407
    }
408

409 0
    protected function getDirs(PhingFile $baseDir, DirectoryScanner $ds)
410
    {
411 0
        return $this->restrict($ds->getIncludedDirectories(), $baseDir);
412
    }
413

414 1
    protected function restrict($s, PhingFile $baseDir)
415
    {
416 1
        $sfs = new SourceFileScanner($this);
417 1
        return ($this->mapper === null || $this->force)
418
            ? $s
419 1
            : $sfs->restrict($s, $baseDir, $this->destDir, $this->mapper);
420
    }
421

422 0
    private function logSkippingFileset($currentType, DirectoryScanner $ds, PhingFile $base)
423
    {
424
        $includedCount = (
425 0
            ($currentType !== self::$types['DIR']) ? $ds->getIncludedFilesCount() : 0
426
            ) + (
427 0
            ($currentType !== self::$types['FILES']) ? $ds->getIncludedDirectoriesCount() : 0
428
            );
429 0
        $this->log(
430 0
            "Skipping fileset for directory " . $base . ". It is "
431 0
            . (($includedCount > 0) ? "up to date." : "empty."),
432 0
            $this->loglevel
433
        );
434
    }
435

436
    /**
437
     * Initializes the task operations, i.e.
438
     * - Required information validation
439
     * - Working directory
440
     *
441
     * @return void
442
     * @throws \BuildException
443
     * @throws IOException
444
     */
445 1
    protected function prepare()
446
    {
447
        // Log
448 1
        $this->log('Initializing started ', $this->loglevel);
449

450
        ///// Validating the required parameters /////
451

452 1
        if (!in_array($this->type, self::$types)) {
453 0
            throw new BuildException('Type must be one of \'file\', \'dir\' or \'both\'.');
454
        }
455

456
        // Executable
457 1
        if ($this->commandline->getExecutable() === null) {
458 1
            $this->throwBuildException('Please provide "executable" information');
459
        }
460

461
        // Retrieving the current working directory
462 1
        $this->currentdirectory = getcwd();
463

464
        // Directory (in which the command should be executed)
465 1
        if ($this->dir !== null) {
466
            // Try expanding (any) symbolic links
467 1
            if (!$this->dir->getCanonicalFile()->isDirectory()) {
468 1
                $this->throwBuildException("'" . $this->dir . "' is not a valid directory");
469
            }
470

471
            // Change working directory
472 1
            $dirchangestatus = @chdir($this->dir->getPath());
473

474
            // Log
475 1
            $this->log(
476 1
                'Working directory change ' . ($dirchangestatus ? 'successful' : 'failed') . ' to ' . $this->dir->getPath(),
477 1
                $this->loglevel
478
            );
479
        }
480

481
        ///// Preparing the task environment /////
482

483
        // Getting current operationg system
484 1
        $this->currentos = Phing::getProperty('os.name');
485

486
        // Log
487 1
        $this->log('Operating System identified : ' . $this->currentos, $this->loglevel);
488

489
        // Getting the O.S. type identifier
490
        // Validating the 'filesystem' for determining the OS type [UNIX, WINNT and WIN32]
491
        // (Another usage could be with 'os.name' for determination)
492 1
        if ('WIN' === strtoupper(substr(Phing::getProperty('host.fstype'), 0, 3))) {
493 0
            $this->osvariant = 'WIN'; // Probable Windows flavour
494
        } else {
495 1
            $this->osvariant = 'LIN'; // Probable GNU/Linux flavour
496
        }
497

498
        // Log
499 1
        $this->log('Operating System variant identified : ' . $this->osvariant, $this->loglevel);
500

501 1
        if (count($this->filesets) === 0 && count($this->filelists) === 0 && count($this->getDirSets()) === 0) {
502 0
            throw new BuildException(
503 0
                "no resources specified",
504 0
                $this->getLocation()
505
            );
506
        }
507 1
        if ($this->targetFilePos !== null && $this->mapperElement === null) {
508 0
            throw new BuildException(
509 0
                "targetfile specified without mapper",
510 0
                $this->getLocation()
511
            );
512
        }
513 1
        if ($this->destDir !== null && $this->mapperElement === null) {
514 0
            throw new BuildException(
515 0
                "dest specified without mapper",
516 0
                $this->getLocation()
517
            );
518
        }
519

520 1
        if ($this->mapperElement !== null) {
521 1
            $this->mapper = $this->mapperElement->getImplementation();
522 1
            $this->log('Mapper identified : ' . get_class($this->mapper), $this->loglevel);
523
        }
524

525 1
        $this->commandline->setEscape($this->escape);
526

527
        // Log
528 1
        $this->log('Initializing completed ', $this->loglevel);
529
    }
530

531
    /**
532
     * Builds the full command to execute and stores it in $realCommand.
533
     *
534
     * @return void
535
     *
536
     * @throws \BuildException
537
     */
538 1
    protected function buildCommand()
539
    {
540

541
        // Log
542 1
        $this->log('Command building started ', $this->loglevel);
543

544
        // Building the executable
545 1
        $this->realCommand = (string) $this->commandline;
546

547 1
        $this->additionalCmds = '';
548

549
        // Adding the source filename at the end of command, validating the existing
550
        // sourcefile position explicit mentioning
551 1
        if ($this->addsourcefile === true) {
552 1
            $this->realCommand .= ' ' . self::SOURCEFILE_ID;
553
        }
554

555
        // Setting command output redirection with content appending
556 1
        if ($this->output !== null) {
557 1
            $this->additionalCmds .= sprintf(
558 1
                ' 1>%s %s',
559 1
                $this->appendoutput ? '>' : '',
560 1
                escapeshellarg($this->output->getPath())
561
            );
562 1
        } elseif ($this->spawn) { // Validating the 'spawn' configuration, and redirecting the output to 'null'
563 1
            $this->additionalCmds .= sprintf(' %s', 'WIN' === $this->osvariant ? '> NUL' : '1>/dev/null');
564

565 1
            $this->log("For process spawning, setting Output nullification ", $this->loglevel);
566
        }
567

568
        // Setting command error redirection with content appending
569 1
        if ($this->error !== null) {
570 1
            $this->additionalCmds .= sprintf(
571 1
                ' 2>%s %s',
572 1
                $this->appendoutput ? '>' : '',
573 1
                escapeshellarg($this->error->getPath())
574
            );
575
        }
576

577
        // Setting the execution as a background process
578 1
        if ($this->spawn) {
579
            // Validating the O.S. variant
580 1
            if ('WIN' === $this->osvariant) {
581 0
                $this->additionalCmds = 'start /b ' . $this->additionalCmds; // MS Windows background process forking
582
            } else {
583 1
                $this->additionalCmds .= ' &'; // GNU/Linux background process forking
584
            }
585
        }
586

587 1
        $this->additionalCmds = rtrim($this->additionalCmds);
588

589
        // Log
590 1
        $this->log('Command built : ' . $this->realCommand . $this->additionalCmds, $this->loglevel);
591

592
        // Log
593 1
        $this->log('Command building completed ', $this->loglevel);
594
    }
595

596
    /**
597
     * Processes the files list with provided information for execution
598
     *
599
     * @param array $srcFiles File list for processing
600
     * @param string $basedir Base directory of the file list
601
     *
602
     * @return void
603
     * @throws \BuildException
604
     * @throws IOException
605
     * @throws NullPointerException
606
     */
607 1
    private function process($srcFiles, $basedir)
608
    {
609
        // Log
610 1
        $this->log("Processing files with base directory ($basedir) ", $this->loglevel);
611 1
        $targets = [];
612 1
        if ($this->targetFilePos !== null) {
613 1
            $addedFiles = [];
614 1
            foreach ($srcFiles as $count => $file) {
615 1
                if ($this->mapper !== null) {
616 1
                    $subTargets = $this->mapper->main($file);
617 1
                    if ($subTargets !== null) {
618 1
                        foreach ($subTargets as $subTarget) {
619 1
                            if ($this->relative) {
620 0
                                $name = $subTarget;
621
                            } else {
622 1
                                $name = (new PhingFile($this->destDir, $subTarget))->getAbsolutePath();
623
                            }
624 1
                            if ($this->forwardslash && FileUtils::getSeparator() !== '/') {
625 0
                                $name = str_replace(FileUtils::getSeparator(), '/', $name);
626
                            }
627 1
                            if (!isset($addedFiles[$name])) {
628 1
                                $targets[] = $name;
629 1
                                $addedFiles[] = $name;
630
                            }
631
                        }
632
                    }
633
                }
634
            }
635
        }
636 1
        $targetFiles = $targets;
637

638 1
        if (!$this->addsourcefile) {
639 1
            $srcFiles = [];
640
        }
641 1
        $orig = $this->commandline->getCommandline();
642 1
        $result = []; // range(0,count($orig) + count($srcFiles) + count($targetFiles));
643

644 1
        $srcIndex = count($orig);
645 1
        if ($this->srcFilePos !== null) {
646 1
            $srcIndex = $this->srcFilePos->getPosition();
647
        }
648 1
        if ($this->targetFilePos !== null) {
649 1
            $targetIndex = $this->targetFilePos->getPosition();
650

651 1
            if ($srcIndex < $targetIndex || ($srcIndex === $targetIndex && $this->srcIsFirst)) {
652
                // 0 --> srcIndex
653 0
                $result[] = $orig;
654

655
                // srcIndex --> targetIndex
656 0
                $result += array_slice($orig, $srcIndex + count($srcFiles), $targetIndex - $srcIndex, true);
657

658 0
                $result[] = $orig;
659 0
                $result[] = $targetFiles;
660 0
                $result = array_merge(... $result);
661

662
                // targetIndex --> end
663 0
                $result = array_merge(
664 0
                    array_slice(
665 0
                        $orig,
666 0
                        $targetIndex + count($srcFiles) + count($targetFiles),
667 0
                        count($orig) - $targetIndex,
668 0
                        true
669
                    ),
670 0
                    $result
671
                );
672
            } else {
673
                // 0 --> targetIndex
674 1
                $result[] = $orig;
675 1
                $result[] = $targetFiles;
676 1
                $result = array_merge(... $result);
677

678
                // targetIndex --> srcIndex
679 1
                $result = array_merge(
680 1
                    array_slice(
681 1
                        $orig,
682 1
                        $targetIndex + count($targetFiles),
683 1
                        $srcIndex - $targetIndex,
684 1
                        true
685
                    ),
686 1
                    $result
687
                );
688

689
                // srcIndex --> end
690 1
                $result = array_merge(
691 1
                    array_slice(
692 1
                        $orig,
693 1
                        $srcIndex + count($srcFiles) + count($targetFiles),
694 1
                        count($orig) - $srcIndex,
695 1
                        true
696
                    ),
697 1
                    $result
698
                );
699 1
                $srcIndex += count($targetFiles);
700
            }
701
        } else { // no targetFilePos
702
            // 0 --> srcIndex
703 1
            $result = array_merge(array_slice($orig, 0, $srcIndex, true), $result);
704
            // srcIndex --> end
705 1
            $result = array_merge(
706 1
                array_slice($orig, $srcIndex + count($srcFiles), count($orig) - $srcIndex, true),
707 1
                $result
708
            );
709
        }
710
        // fill in source file names
711 1
        foreach ($srcFiles as $i => $file) {
712 1
            if ($this->relative) {
713 1
                $src = $file;
714
            } else {
715 0
                $src = (new PhingFile($basedir, $file))->getAbsolutePath();
716
            }
717 1
            if ($this->forwardslash && FileUtils::getSeparator() !== '/') {
718 0
                $src = str_replace(FileUtils::getSeparator(), '/', $src);
719
            }
720
            if (
721 1
                $this->srcFilePos !== null
722 0
                && ($this->srcFilePos->getPrefix() !== ''
723 0
                    || $this->srcFilePos->getSuffix() !== '')
724
            ) {
725 0
                $src = $this->srcFilePos->getPrefix() . $src . $this->srcFilePos->getSuffix();
726
            }
727 1
            $result[$srcIndex + $i] = $src;
728
        }
729

730 1
        $this->commandline = new Commandline(implode(' ', $result));
731 1
        $this->commandline->setEscape($this->escape);
732 1
        $this->realCommand = (string) $this->commandline . $this->additionalCmds;
733

734 1
        [$returncode, $output] = $this->executeCommand();
735

736 1
        $this->maybeSetReturnPropertyValue($returncode);
737

738
        // Sets the output property
739 1
        if ($this->outputProperty) {
740 1
            $previousValue = $this->project->getProperty($this->outputProperty);
741 1
            if (!empty($previousValue)) {
742 0
                $previousValue .= "\n";
743
            }
744 1
            $this->project->setProperty($this->outputProperty, $previousValue . implode("\n", $output));
745
        }
746

747
        // Validating the 'return-code'
748 1
        if ($this->checkreturn && ($returncode !== 0)) {
749 1
            $this->throwBuildException("Task exited with code ($returncode)");
750
        }
751
    }
752

753
    /**
754
     * Runs cleanup tasks post execution
755
     * - Restore working directory
756
     *
757
     * @return void
758
     */
759 1
    protected function cleanup($return = null, $output = null): void
760
    {
761
        // Restore working directory
762 1
        if ($this->dir !== null) {
763 1
            @chdir($this->currentdirectory);
764
        }
765
    }
766

767
    /**
768
     * Prepares the filename per base directory and relative path information
769
     *
770
     * @param array|string $filename
771
     * @param $basedir
772
     * @param $relative
773
     *
774
     * @return mixed processed filenames
775
     *
776
     * @throws IOException
777
     */
778 0
    public function getFilePath($filename, $basedir, $relative)
779
    {
780
        // Validating the 'file' information
781 0
        $files = (array) $filename;
782

783
        // Processing the file information
784 0
        foreach ($files as $index => $file) {
785 0
            $absolutefilename = (($relative === false) ? ($basedir . FileUtils::getSeparator()) : '');
786 0
            $absolutefilename .= $file;
787 0
            if ($relative === false) {
788 0
                $files[$index] = (new FileUtils())->normalize($absolutefilename);
789
            } else {
790 0
                $files[$index] = $absolutefilename;
791
            }
792
        }
793

794 0
        return (is_array($filename) ? $files : $files[0]);
795
    }
796

797
    /**
798
     * Throws the exception with specified information
799
     *
800
     * @param string $information Exception information
801
     *
802
     * @throws BuildException
803
     *
804
     * @return void
805
     */
806 1
    private function throwBuildException($information): void
807
    {
808 1
        throw new BuildException('ApplyTask: ' . (string) $information);
809
    }
810
}

Read our documentation on viewing source code .

Loading