Completed
Push — master ( b1adff...449a59 )
by Théo
02:23
created

HandleAddPrefix::scopeFile()   B

Complexity

Conditions 2
Paths 2

Size

Total Lines 24
Code Lines 17

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 12
CRAP Score 2

Importance

Changes 0
Metric Value
cc 2
eloc 17
nc 2
nop 5
dl 0
loc 24
ccs 12
cts 12
cp 1
crap 2
rs 8.9713
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 PhpParser\Error as PhpParserError;
22
use SplFileInfo;
23
use Symfony\Component\Filesystem\Filesystem;
24
use Symfony\Component\Finder\Finder;
25
use Throwable;
26
use function Humbug\PhpScoper\get_common_path;
27
28
/**
29
 * @final
30
 */
31
class HandleAddPrefix
32
{
33
    private $fileSystem;
34
    private $scoper;
35
36 9
    public function __construct(Scoper $scoper)
37
    {
38 9
        $this->fileSystem = new Filesystem();
39 9
        $this->scoper = $scoper;
40 9
    }
41
42
    /**
43
     * Apply prefix to all the code found in the given paths, AKA scope all the files found.
44
     *
45
     * @param string        $prefix   e.g. 'Foo'
46
     * @param string[]      $paths    List of files to scan (absolute paths)
47
     * @param string        $output   absolute path to the output directory
48
     * @param callable[]    $patchers
49
     * @param ConsoleLogger $logger
50
     */
51 9
    public function __invoke(string $prefix, array $paths, string $output, array $patchers, ConsoleLogger $logger)
52
    {
53 9
        $this->fileSystem->mkdir($output);
54
55
        try {
56 9
            $files = $this->retrieveFiles($paths, $output);
57
58 8
            $this->scopeFiles($files, $prefix, $patchers, $logger);
59 3
        } catch (Throwable $throwable) {
60 3
            $this->fileSystem->remove($output);
61
62 3
            throw $throwable;
63
        }
64 6
    }
65
66
    /**
67
     * @param string[] $paths
68
     * @param string   $output
69
     *
70
     * @return string[]
71
     */
72 9
    private function retrieveFiles(array $paths, string $output): array
73
    {
74 9
        $pathsToSearch = [];
75 9
        $filesToAppend = [];
76
77 9
        foreach ($paths as $path) {
78 9
            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 8
            if (is_dir($path)) {
88 3
                $pathsToSearch[] = $path;
89
            } else {
90 8
                $filesToAppend[] = $path;
91
            }
92
        }
93
94 8
        $finder = new Finder();
95
96 8
        $finder->files()
97 8
            ->in($pathsToSearch)
98 8
            ->append($filesToAppend)
99 8
            ->sortByName()
100
        ;
101
102 8
        $files = array_values(
103 8
            array_map(
104
                function (SplFileInfo $fileInfo) {
105 7
                    return $fileInfo->getRealPath();
106 8
                },
107 8
                iterator_to_array($finder)
108
            )
109
        );
110
111 8
        $commonPath = get_common_path($files);
112
113 8
        return array_reduce(
114 8
            $files,
115 8
            function (array $files, string $file) use ($output, $commonPath): array {
116 7
                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 7
                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 7
                $files[$file] = $output.str_replace($commonPath, '', $file);
135
136 7
                return $files;
137 8
            },
138 8
            []
139
        );
140
    }
141
142
    /**
143
     * @param string[]      $files
144
     * @param string        $prefix
145
     * @param callable[]    $patchers
146
     * @param ConsoleLogger $logger
147
     */
148 8
    private function scopeFiles(array $files, string $prefix, array $patchers, ConsoleLogger $logger)
149
    {
150 8
        $count = count($files);
151 8
        $logger->outputFileCount($count);
152
153 8
        foreach ($files as $inputFilePath => $outputFilePath) {
154 7
            $this->scopeFile($inputFilePath, $outputFilePath, $prefix, $patchers, $logger);
155
        }
156 6
    }
157
158
    /**
159
     * @param string        $inputFilePath
160
     * @param string        $outputFilePath
161
     * @param string        $prefix
162
     * @param callable[]    $patchers
163
     * @param ConsoleLogger $logger
164
     */
165 7
    private function scopeFile(
166
        string $inputFilePath,
167
        string $outputFilePath,
168
        string $prefix,
169
        array $patchers,
170
        ConsoleLogger $logger
171
    ) {
172
        try {
173 7
            $scoppedContent = $this->scoper->scope($inputFilePath, $prefix, $patchers);
174 2
        } catch (PhpParserError $error) {
175 1
            throw new ParsingException(
176 1
                sprintf(
177 1
                    'Could not parse the file "%s".',
178 1
                    $inputFilePath
179
                ),
180 1
                0,
181 1
                $error
182
            );
183
        }
184
185 5
        $this->fileSystem->dumpFile($outputFilePath, $scoppedContent);
186
187 5
        $logger->outputSuccess($inputFilePath);
188 5
    }
189
}
190