Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
0.00% |
0 / 62 |
|
0.00% |
0 / 4 |
CRAP | |
0.00% |
0 / 1 |
FileEnumerator | |
0.00% |
0 / 62 |
|
0.00% |
0 / 4 |
462 | |
0.00% |
0 / 1 |
__construct | |
0.00% |
0 / 8 |
|
0.00% |
0 / 1 |
2 | |||
compileFileList | |
0.00% |
0 / 33 |
|
0.00% |
0 / 1 |
210 | |||
addFile | |
0.00% |
0 / 14 |
|
0.00% |
0 / 1 |
20 | |||
findFilesInDirectory | |
0.00% |
0 / 7 |
|
0.00% |
0 / 1 |
6 |
1 | <?php |
2 | /** |
3 | * Build a list of files from the composer autoloaders. |
4 | * |
5 | * Also record the `files` autoloaders. |
6 | */ |
7 | |
8 | namespace BrianHenryIE\Strauss; |
9 | |
10 | use BrianHenryIE\Strauss\Composer\ComposerPackage; |
11 | use BrianHenryIE\Strauss\Composer\Extra\StraussConfig; |
12 | use BrianHenryIE\Strauss\Helpers\Path; |
13 | use League\Flysystem\Filesystem; |
14 | use League\Flysystem\Local\LocalFilesystemAdapter; |
15 | use RecursiveDirectoryIterator; |
16 | use RecursiveIteratorIterator; |
17 | use RegexIterator; |
18 | use Symfony\Component\Finder\Finder; |
19 | |
20 | class FileEnumerator |
21 | { |
22 | /** |
23 | * The only path variable with a leading slash. |
24 | * All directories in project end with a slash. |
25 | * |
26 | * @var string |
27 | */ |
28 | protected string $workingDir; |
29 | |
30 | /** @var string */ |
31 | protected string $vendorDir; |
32 | |
33 | /** @var ComposerPackage[] */ |
34 | protected array $dependencies; |
35 | |
36 | /** @var string[] */ |
37 | protected array $excludePackageNames = array(); |
38 | |
39 | /** @var string[] */ |
40 | protected array $excludeNamespaces = array(); |
41 | |
42 | /** @var string[] */ |
43 | protected array $excludeFilePatterns = array(); |
44 | |
45 | /** @var Filesystem */ |
46 | protected Filesystem $filesystem; |
47 | |
48 | protected DiscoveredFiles $discoveredFiles; |
49 | |
50 | /** |
51 | * Record the files autoloaders for later use in building our own autoloader. |
52 | * |
53 | * Package-name: [ dir1, file1, file2, ... ]. |
54 | * |
55 | * @var array<string, string[]> |
56 | */ |
57 | protected array $filesAutoloaders = []; |
58 | |
59 | /** |
60 | * Copier constructor. |
61 | * @param ComposerPackage[] $dependencies |
62 | * @param string $workingDir |
63 | */ |
64 | public function __construct( |
65 | array $dependencies, |
66 | string $workingDir, |
67 | StraussConfig $config |
68 | ) { |
69 | $this->discoveredFiles = new DiscoveredFiles(); |
70 | |
71 | $this->workingDir = $workingDir; |
72 | $this->vendorDir = $config->getVendorDirectory(); |
73 | |
74 | $this->dependencies = $dependencies; |
75 | |
76 | $this->excludeNamespaces = $config->getExcludeNamespacesFromCopy(); |
77 | $this->excludePackageNames = $config->getExcludePackagesFromCopy(); |
78 | $this->excludeFilePatterns = $config->getExcludeFilePatternsFromCopy(); |
79 | |
80 | $this->filesystem = new Filesystem(new LocalFilesystemAdapter($this->workingDir)); |
81 | } |
82 | |
83 | /** |
84 | * Read the autoload keys of the dependencies and generate a list of the files referenced. |
85 | * |
86 | * Includes all files in the directories and subdirectories mentioned in the autoloaders. |
87 | */ |
88 | public function compileFileList(): DiscoveredFiles |
89 | { |
90 | foreach ($this->dependencies as $dependency) { |
91 | if (in_array($dependency->getPackageName(), $this->excludePackageNames)) { |
92 | continue; |
93 | } |
94 | |
95 | /** |
96 | * Where $dependency->autoload is ~ |
97 | * |
98 | * [ "psr-4" => [ "BrianHenryIE\Strauss" => "src" ] ] |
99 | * Exclude "exclude-from-classmap" |
100 | * @see https://getcomposer.org/doc/04-schema.md#exclude-files-from-classmaps |
101 | */ |
102 | $autoloaders = array_filter($dependency->getAutoload(), function ($type) { |
103 | return 'exclude-from-classmap' !== $type; |
104 | }, ARRAY_FILTER_USE_KEY); |
105 | |
106 | foreach ($autoloaders as $type => $value) { |
107 | // Might have to switch/case here. |
108 | |
109 | if ('files' === $type) { |
110 | $this->filesAutoloaders[$dependency->getRelativePath()] = $value; |
111 | } |
112 | |
113 | foreach ($value as $namespace => $namespace_relative_paths) { |
114 | if (!empty($namespace) && in_array($namespace, $this->excludeNamespaces)) { |
115 | continue; |
116 | } |
117 | |
118 | if (! is_array($namespace_relative_paths)) { |
119 | $namespace_relative_paths = array( $namespace_relative_paths ); |
120 | } |
121 | |
122 | foreach ($namespace_relative_paths as $namespaceRelativePath) { |
123 | $sourceAbsolutePath = $dependency->getPackageAbsolutePath() . $namespaceRelativePath; |
124 | |
125 | if (is_file($sourceAbsolutePath)) { |
126 | $this->addFile($dependency, $namespaceRelativePath, $type); |
127 | } elseif (is_dir($sourceAbsolutePath)) { |
128 | // trailingslashit(). (to remove duplicates). |
129 | $sourcePath = Path::normalize($sourceAbsolutePath); |
130 | |
131 | // $this->findFilesInDirectory() |
132 | $finder = new Finder(); |
133 | $finder->files()->in($sourcePath)->followLinks(); |
134 | |
135 | foreach ($finder as $foundFile) { |
136 | $sourceAbsoluteFilepath = $foundFile->getPathname(); |
137 | |
138 | // No need to record the directory itself. |
139 | if (is_dir($sourceAbsoluteFilepath)) { |
140 | continue; |
141 | } |
142 | |
143 | $namespaceRelativePath = Path::normalize($namespaceRelativePath); |
144 | |
145 | $this->addFile( |
146 | $dependency, |
147 | $namespaceRelativePath . str_replace($sourcePath, '', $sourceAbsoluteFilepath), |
148 | $type |
149 | ); |
150 | } |
151 | } |
152 | } |
153 | } |
154 | } |
155 | } |
156 | |
157 | return $this->discoveredFiles; |
158 | } |
159 | |
160 | /** |
161 | * @uses \BrianHenryIE\Strauss\DiscoveredFiles::add() |
162 | * |
163 | * @param ComposerPackage $dependency |
164 | * @param string $packageRelativePath |
165 | * @param string $autoloaderType |
166 | * @throws \League\Flysystem\FilesystemException |
167 | */ |
168 | protected function addFile(ComposerPackage $dependency, string $packageRelativePath, string $autoloaderType): void |
169 | { |
170 | $sourceAbsoluteFilepath = $dependency->getPackageAbsolutePath() . $packageRelativePath; |
171 | $outputRelativeFilepath = $dependency->getRelativePath() . $packageRelativePath; |
172 | $projectRelativePath = $this->vendorDir . $outputRelativeFilepath; |
173 | $isOutsideProjectDir = 0 !== strpos($sourceAbsoluteFilepath, $this->workingDir); |
174 | |
175 | $f = $this->discoveredFiles->getFiles()[$outputRelativeFilepath] |
176 | ?? new File($dependency, $packageRelativePath, $sourceAbsoluteFilepath); |
177 | |
178 | $f->addAutoloader($autoloaderType); |
179 | $f->setDoDelete($isOutsideProjectDir); |
180 | |
181 | foreach ($this->excludeFilePatterns as $excludePattern) { |
182 | if (1 === preg_match($excludePattern, $outputRelativeFilepath)) { |
183 | $f->setDoCopy(false); |
184 | } |
185 | } |
186 | |
187 | if ('<?php // This file was deleted by {@see https://github.com/BrianHenryIE/strauss}.' |
188 | === |
189 | $this->filesystem->read($projectRelativePath) |
190 | ) { |
191 | $f->setDoCopy(false); |
192 | } |
193 | |
194 | $this->discoveredFiles->add($f); |
195 | } |
196 | |
197 | /** |
198 | * @param string $workingDir Absolute path to the working directory, results will be relative to this. |
199 | * @param string $relativeDirectory |
200 | * @param string $regexPattern Default to PHP files. |
201 | * |
202 | * @return string[] |
203 | */ |
204 | public function findFilesInDirectory(string $workingDir, string $relativeDirectory = '.', string $regexPattern = '/.+\.php$/'): array |
205 | { |
206 | $dir = new RecursiveDirectoryIterator($workingDir . $relativeDirectory); |
207 | $ite = new RecursiveIteratorIterator($dir); |
208 | $files = new RegexIterator($ite, $regexPattern, RegexIterator::GET_MATCH); |
209 | $fileList = array(); |
210 | foreach ($files as $file) { |
211 | $fileList = array_merge($fileList, str_replace($workingDir, '', $file)); |
212 | } |
213 | return $fileList; |
214 | } |
215 | } |