Passed
Push — master ( 3a3a08...a5b8f2 )
by Théo
02:09
created

HandleAddPrefix::__invoke()   A

Complexity

Conditions 2
Paths 3

Size

Total Lines 14
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 8
CRAP Score 2

Importance

Changes 0
Metric Value
cc 2
eloc 8
nc 3
nop 6
dl 0
loc 14
ccs 8
cts 8
cp 1
crap 2
rs 9.4285
c 0
b 0
f 0
1
<?php
2
3
declare(strict_types=1);
4
5
/*
6
 * This file is part of the humbug/php-scoper package.
7
 *
8
 * Copyright (c) 2017 Théo FIDRY <[email protected]>,
9
 *                    Pádraic Brady <[email protected]>
10
 *
11
 * For the full copyright and license information, please view the LICENSE
12
 * file that was distributed with this source code.
13
 */
14
15
namespace Humbug\PhpScoper\Handler;
16
17
use Humbug\PhpScoper\Logger\ConsoleLogger;
18
use Humbug\PhpScoper\Scoper;
19
use Humbug\PhpScoper\Throwable\Exception\ParsingException;
20
use Humbug\PhpScoper\Throwable\Exception\RuntimeException;
21
use SplFileInfo;
22
use Symfony\Component\Filesystem\Filesystem;
23
use Symfony\Component\Finder\Finder;
24
use Throwable;
25
use function Humbug\PhpScoper\get_common_path;
26
27
/**
28
 * @final
29
 */
30
class HandleAddPrefix
31
{
32
    private $fileSystem;
33
    private $scoper;
34
35 10
    public function __construct(Scoper $scoper)
36
    {
37 10
        $this->fileSystem = new Filesystem();
38 10
        $this->scoper = $scoper;
39 10
    }
40
41
    /**
42
     * Apply prefix to all the code found in the given paths, AKA scope all the files found.
43
     *
44
     * @param string        $prefix        e.g. 'Foo'
45
     * @param string[]      $paths         List of files to scan (absolute paths)
46
     * @param string        $output        absolute path to the output directory
47
     * @param callable[]    $patchers
48
     * @param bool          $stopOnFailure
49
     * @param ConsoleLogger $logger
50
     */
51 10
    public function __invoke(string $prefix, array $paths, string $output, array $patchers, bool $stopOnFailure, ConsoleLogger $logger)
52
    {
53 10
        $this->fileSystem->mkdir($output);
54
55
        try {
56 10
            $files = $this->retrieveFiles($paths, $output);
57
58 9
            $this->scopeFiles($files, $prefix, $patchers, $stopOnFailure, $logger);
59 3
        } catch (Throwable $throwable) {
60 3
            $this->fileSystem->remove($output);
61
62 3
            throw $throwable;
63
        }
64 7
    }
65
66
    /**
67
     * @param string[] $paths
68
     * @param string   $output
69
     *
70
     * @return string[]
71
     */
72 10
    private function retrieveFiles(array $paths, string $output): array
73
    {
74 10
        $pathsToSearch = [];
75 10
        $filesToAppend = [];
76
77 10
        foreach ($paths as $path) {
78 10
            if (false === file_exists($path)) {
79 1
                throw new RuntimeException(
80 1
                    sprintf(
81 1
                        'Could not find the file "%s".',
82 1
                        $path
83
                    )
84
                );
85
            }
86
87 9
            if (is_dir($path)) {
88 3
                $pathsToSearch[] = $path;
89
            } else {
90 9
                $filesToAppend[] = $path;
91
            }
92
        }
93
94 9
        $finder = new Finder();
95
96 9
        $finder->files()
97 9
            ->in($pathsToSearch)
98 9
            ->append($filesToAppend)
99 9
            ->sortByName()
100
        ;
101
102 9
        $files = array_values(
103 9
            array_map(
104
                function (SplFileInfo $fileInfo) {
105 8
                    return $fileInfo->getRealPath();
106 9
                },
107 9
                iterator_to_array($finder)
108
            )
109
        );
110
111 9
        $commonPath = get_common_path($files);
112
113 9
        return array_reduce(
114 9
            $files,
115 9
            function (array $files, string $file) use ($output, $commonPath): array {
116 8
                if (false === file_exists($file)) {
117
                    throw new RuntimeException(
118
                        sprintf(
119
                            'Could not find the file "%s".',
120
                            $file
121
                        )
122
                    );
123
                }
124
125 8
                if (false === is_readable($file)) {
126
                    throw new RuntimeException(
127
                        sprintf(
128
                            'Could not read the file "%s".',
129
                            $file
130
                        )
131
                    );
132
                }
133
134 8
                $files[$file] = $output.str_replace($commonPath, '', $file);
135
136 8
                return $files;
137 9
            },
138 9
            []
139
        );
140
    }
141
142
    /**
143
     * @param string[]      $files
144
     * @param string        $prefix
145
     * @param callable[]    $patchers
146
     * @param bool          $stopOnFailure
147
     * @param ConsoleLogger $logger
148
     */
149 9
    private function scopeFiles(array $files, string $prefix, array $patchers, bool $stopOnFailure, ConsoleLogger $logger)
150
    {
151 9
        $count = count($files);
152 9
        $logger->outputFileCount($count);
153
154 9
        foreach ($files as $inputFilePath => $outputFilePath) {
155 8
            $this->scopeFile($inputFilePath, $outputFilePath, $prefix, $patchers, $stopOnFailure, $logger);
156
        }
157 7
    }
158
159
    /**
160
     * @param string        $inputFilePath
161
     * @param string        $outputFilePath
162
     * @param string        $prefix
163
     * @param callable[]    $patchers
164
     * @param bool          $stopOnFailure
165
     * @param ConsoleLogger $logger
166
     */
167 8
    private function scopeFile(
168
        string $inputFilePath,
169
        string $outputFilePath,
170
        string $prefix,
171
        array $patchers,
172
        bool $stopOnFailure,
173
        ConsoleLogger $logger
174
    ) {
175
        try {
176 8
            $scoppedContent = $this->scoper->scope($inputFilePath, $prefix, $patchers);
177 3
        } catch (\Throwable $error) {
178 3
            $exception = new ParsingException(
179 3
                sprintf(
180 3
                    'Could not parse the file "%s".',
181 3
                    $inputFilePath
182
                ),
183 3
                0,
184 3
                $error
185
            );
186
187 3
            if ($stopOnFailure) {
188 2
                throw $exception;
189
            }
190
191 1
            $logger->outputWarnOfFailure($inputFilePath, $exception);
192
193 1
            $scoppedContent = file_get_contents($inputFilePath);
194
        }
195
196 6
        $this->fileSystem->dumpFile($outputFilePath, $scoppedContent);
197
198 6
        if (false === isset($exception)) {
199 5
            $logger->outputSuccess($inputFilePath);
200
        }
201 6
    }
202
}
203