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 | * The FileSet class provides methods and properties for accessing |
||
22 | * and managing filesets. It extends ProjectComponent and thus inherits |
||
23 | * all methods and properties (not explicitly declared). See ProjectComponent |
||
24 | * for further detail. |
||
25 | * |
||
26 | * TODO: |
||
27 | * - merge this with patternsets: FileSet extends PatternSet !!! |
||
28 | * requires additional mods to the parsing algo |
||
29 | * [HL] .... not sure if that really makes so much sense. I think |
||
30 | * that perhaps they should use common utility class if there really |
||
31 | * is that much shared functionality |
||
32 | * |
||
33 | * @author Andreas Aderhold <[email protected]> |
||
34 | * @author Hans Lellelid <[email protected]> |
||
35 | * @see ProjectComponent |
||
36 | * @package phing.types |
||
37 | */ |
||
38 | abstract class AbstractFileSet extends DataType implements SelectorContainer, IteratorAggregate |
||
39 | { |
||
40 | use SelectorAware; |
||
41 | |||
42 | // These vars are public for cloning purposes |
||
43 | |||
44 | /** |
||
45 | * @var boolean |
||
46 | */ |
||
47 | public $useDefaultExcludes = true; |
||
48 | |||
49 | /** |
||
50 | * Whether to expand/dereference symbolic links, default is false |
||
51 | * |
||
52 | * @var boolean |
||
53 | */ |
||
54 | protected $expandSymbolicLinks = false; |
||
55 | |||
56 | /** |
||
57 | * @var PatternSet |
||
58 | */ |
||
59 | public $defaultPatterns; |
||
60 | |||
61 | public $additionalPatterns = []; |
||
62 | public $dir; |
||
63 | public $isCaseSensitive = true; |
||
64 | private $errorOnMissingDir = false; |
||
65 | private $directoryScanner; |
||
66 | |||
67 | /** |
||
68 | * @param null $fileset |
||
69 | */ |
||
70 | 119 | public function __construct($fileset = null) |
|
71 | { |
||
72 | 119 | parent::__construct(); |
|
73 | |||
74 | 119 | if ($fileset !== null && ($fileset instanceof FileSet)) { |
|
75 | $this->dir = $fileset->dir; |
||
76 | $this->additionalPatterns = $fileset->additionalPatterns; |
||
77 | $this->useDefaultExcludes = $fileset->useDefaultExcludes; |
||
78 | $this->isCaseSensitive = $fileset->isCaseSensitive; |
||
79 | $this->selectorsList = $fileset->selectorsList; |
||
80 | $this->expandSymbolicLinks = $fileset->expandSymbolicLinks; |
||
81 | $this->errorOnMissingDir = $fileset->errorOnMissingDir; |
||
82 | $this->setProject($fileset->getProject()); |
||
83 | } |
||
84 | |||
85 | 119 | $this->defaultPatterns = new PatternSet(); |
|
86 | 119 | } |
|
87 | |||
88 | /** |
||
89 | * Sets whether to expand/dereference symbolic links, default is false |
||
90 | * |
||
91 | * @var boolean |
||
92 | */ |
||
93 | 1 | public function setExpandSymbolicLinks(bool $expandSymbolicLinks) |
|
94 | { |
||
95 | 1 | if ($this->isReference()) { |
|
96 | 1 | throw $this->tooManyAttributes(); |
|
97 | } |
||
98 | $this->expandSymbolicLinks = $expandSymbolicLinks; |
||
99 | } |
||
100 | |||
101 | /** |
||
102 | * Makes this instance in effect a reference to another PatternSet |
||
103 | * instance. |
||
104 | * You must not set another attribute or nest elements inside |
||
105 | * this element if you make it a reference. |
||
106 | * |
||
107 | * @param Reference $r |
||
108 | * @throws BuildException |
||
109 | */ |
||
110 | 2 | public function setRefid(Reference $r) |
|
111 | { |
||
112 | 2 | if ((isset($this->dir) && null !== $this->dir) || $this->defaultPatterns->hasPatterns()) { |
|
113 | 1 | throw $this->tooManyAttributes(); |
|
114 | } |
||
115 | 2 | if (!empty($this->additionalPatterns)) { |
|
116 | 1 | throw $this->noChildrenAllowed(); |
|
117 | } |
||
118 | 2 | if (!empty($this->selectorsList)) { |
|
119 | throw $this->noChildrenAllowed(); |
||
120 | } |
||
121 | 2 | parent::setRefid($r); |
|
122 | 2 | } |
|
123 | |||
124 | /** |
||
125 | * @param $dir |
||
126 | * @throws IOException |
||
127 | * @throws NullPointerException |
||
128 | */ |
||
129 | 116 | public function setDir($dir) |
|
130 | { |
||
131 | 116 | if ($this->isReference()) { |
|
132 | 1 | throw $this->tooManyAttributes(); |
|
133 | } |
||
134 | 115 | if ($dir instanceof PhingFile) { |
|
135 | $dir = $dir->getPath(); |
||
136 | } |
||
137 | 115 | $this->dir = new PhingFile((string) $dir); |
|
138 | 115 | $this->directoryScanner = null; |
|
139 | 115 | } |
|
140 | |||
141 | /** |
||
142 | * @param Project $p |
||
143 | * @return mixed |
||
144 | * @throws BuildException |
||
145 | */ |
||
146 | 91 | public function getDir(Project $p = null) |
|
147 | { |
||
148 | 91 | if ($p === null) { |
|
149 | $p = $this->getProject(); |
||
150 | } |
||
151 | |||
152 | 91 | if ($this->isReference()) { |
|
153 | 1 | return $this->getRef($p)->getDir($p); |
|
154 | } |
||
155 | |||
156 | 91 | return $this->dir; |
|
157 | } |
||
158 | |||
159 | /** |
||
160 | * @return mixed |
||
161 | * @throws BuildException |
||
162 | */ |
||
163 | 2 | public function createPatternSet() |
|
164 | { |
||
165 | 2 | if ($this->isReference()) { |
|
166 | 1 | throw $this->noChildrenAllowed(); |
|
167 | } |
||
168 | 2 | $num = array_push($this->additionalPatterns, new PatternSet()); |
|
169 | |||
170 | 2 | return $this->additionalPatterns[$num - 1]; |
|
171 | } |
||
172 | |||
173 | /** |
||
174 | * add a name entry on the include list |
||
175 | */ |
||
176 | 79 | public function createInclude() |
|
177 | { |
||
178 | 79 | if ($this->isReference()) { |
|
179 | 1 | throw $this->noChildrenAllowed(); |
|
180 | } |
||
181 | |||
182 | 79 | return $this->defaultPatterns->createInclude(); |
|
183 | } |
||
184 | |||
185 | /** |
||
186 | * add a name entry on the include files list |
||
187 | */ |
||
188 | 1 | public function createIncludesFile() |
|
189 | { |
||
190 | 1 | if ($this->isReference()) { |
|
191 | 1 | throw $this->noChildrenAllowed(); |
|
192 | } |
||
193 | |||
194 | return $this->defaultPatterns->createIncludesFile(); |
||
195 | } |
||
196 | |||
197 | /** |
||
198 | * add a name entry on the exclude list |
||
199 | */ |
||
200 | 2 | public function createExclude() |
|
201 | { |
||
202 | 2 | if ($this->isReference()) { |
|
203 | 1 | throw $this->noChildrenAllowed(); |
|
204 | } |
||
205 | |||
206 | 1 | return $this->defaultPatterns->createExclude(); |
|
207 | } |
||
208 | |||
209 | /** |
||
210 | * add a name entry on the include files list |
||
211 | */ |
||
212 | 1 | public function createExcludesFile() |
|
213 | { |
||
214 | 1 | if ($this->isReference()) { |
|
215 | 1 | throw $this->noChildrenAllowed(); |
|
216 | } |
||
217 | |||
218 | return $this->defaultPatterns->createExcludesFile(); |
||
219 | } |
||
220 | |||
221 | 1 | public function setFile(PhingFile $file) |
|
222 | { |
||
223 | 1 | if ($this->isReference()) { |
|
224 | 1 | throw $this->tooManyAttributes(); |
|
225 | } |
||
226 | $this->setDir($file->getParentFile()); |
||
227 | $this->createInclude()->setName($file->getName()); |
||
228 | } |
||
229 | |||
230 | /** |
||
231 | * Sets the set of include patterns. Patterns may be separated by a comma |
||
232 | * or a space. |
||
233 | * |
||
234 | * @param $includes |
||
235 | * @throws BuildException |
||
236 | */ |
||
237 | 5 | public function setIncludes($includes) |
|
238 | { |
||
239 | 5 | if ($this->isReference()) { |
|
240 | 1 | throw $this->tooManyAttributes(); |
|
241 | } |
||
242 | 5 | $this->defaultPatterns->setIncludes($includes); |
|
243 | 5 | } |
|
244 | |||
245 | /** |
||
246 | * Sets the set of exclude patterns. Patterns may be separated by a comma |
||
247 | * or a space. |
||
248 | * |
||
249 | * @param $excludes |
||
250 | * @throws BuildException |
||
251 | */ |
||
252 | 1 | public function setExcludes($excludes) |
|
253 | { |
||
254 | 1 | if ($this->isReference()) { |
|
255 | 1 | throw $this->tooManyAttributes(); |
|
256 | } |
||
257 | $this->defaultPatterns->setExcludes($excludes); |
||
258 | } |
||
259 | |||
260 | /** |
||
261 | * Sets the name of the file containing the includes patterns. |
||
262 | * |
||
263 | * @param PhingFile $incl The file to fetch the include patterns from. |
||
264 | * @throws BuildException |
||
265 | */ |
||
266 | 1 | public function setIncludesfile(PhingFile $incl) |
|
267 | { |
||
268 | 1 | if ($this->isReference()) { |
|
269 | 1 | throw $this->tooManyAttributes(); |
|
270 | } |
||
271 | $this->defaultPatterns->setIncludesFile($incl); |
||
272 | } |
||
273 | |||
274 | /** |
||
275 | * Sets the name of the file containing the includes patterns. |
||
276 | * |
||
277 | * @param PhingFile $excl The file to fetch the exclude patterns from. |
||
278 | * @throws BuildException |
||
279 | */ |
||
280 | 1 | public function setExcludesfile($excl) |
|
281 | { |
||
282 | 1 | if ($this->isReference()) { |
|
283 | 1 | throw $this->tooManyAttributes(); |
|
284 | } |
||
285 | $this->defaultPatterns->setExcludesFile($excl); |
||
286 | } |
||
287 | |||
288 | /** |
||
289 | * Sets whether default exclusions should be used or not. |
||
290 | * |
||
291 | * @param $useDefaultExcludes "true"|"on"|"yes" when default exclusions |
||
292 | * should be used, "false"|"off"|"no" when they |
||
293 | * shouldn't be used. |
||
294 | * @throws BuildException |
||
295 | * @return void |
||
296 | */ |
||
297 | 3 | public function setDefaultexcludes($useDefaultExcludes) |
|
298 | { |
||
299 | 3 | if ($this->isReference()) { |
|
300 | throw $this->tooManyAttributes(); |
||
301 | } |
||
302 | 3 | $this->useDefaultExcludes = $useDefaultExcludes; |
|
303 | 3 | } |
|
304 | |||
305 | /** |
||
306 | * Sets case sensitivity of the file system |
||
307 | * |
||
308 | * @param $isCaseSensitive |
||
309 | */ |
||
310 | 1 | public function setCaseSensitive($isCaseSensitive) |
|
311 | { |
||
312 | 1 | if ($this->isReference()) { |
|
313 | 1 | throw $this->tooManyAttributes(); |
|
314 | } |
||
315 | $this->isCaseSensitive = $isCaseSensitive; |
||
316 | } |
||
317 | |||
318 | /** |
||
319 | * returns a reference to the dirscanner object belonging to this fileset |
||
320 | * |
||
321 | * @param Project $p |
||
322 | * @throws BuildException |
||
323 | * @return \DirectoryScanner |
||
324 | */ |
||
325 | 100 | public function getDirectoryScanner(Project $p = null) |
|
326 | { |
||
327 | 100 | if ($p === null) { |
|
328 | $p = $this->getProject(); |
||
329 | } |
||
330 | |||
331 | 100 | if ($this->isReference()) { |
|
332 | 1 | $o = $this->getRef($p); |
|
333 | |||
334 | 1 | return $o->getDirectoryScanner($p); |
|
335 | } |
||
336 | |||
337 | 100 | if ($this->dir === null) { |
|
338 | throw new BuildException(sprintf("No directory specified for <%s>.", $this->getDataTypeName())); |
||
339 | } |
||
340 | 100 | if (!$this->dir->exists() && $this->errorOnMissingDir) { |
|
341 | throw new BuildException("Directory " . $this->dir->getAbsolutePath() . " not found."); |
||
342 | } |
||
343 | 100 | if (!$this->dir->isLink() || !$this->expandSymbolicLinks) { |
|
344 | 100 | if (!$this->dir->isDirectory()) { |
|
345 | 1 | throw new BuildException($this->dir->getAbsolutePath() . " is not a directory."); |
|
346 | } |
||
347 | } |
||
348 | 99 | $ds = new DirectoryScanner(); |
|
349 | 99 | $ds->setExpandSymbolicLinks($this->expandSymbolicLinks); |
|
350 | 99 | $ds->setErrorOnMissingDir($this->errorOnMissingDir); |
|
351 | 99 | $this->setupDirectoryScanner($ds, $p); |
|
352 | 99 | $ds->scan(); |
|
353 | |||
354 | 99 | return $ds; |
|
355 | } |
||
356 | |||
357 | /** |
||
358 | * feed dirscanner with infos defined by this fileset |
||
359 | * |
||
360 | * @param DirectoryScanner $ds |
||
361 | * @param Project $p |
||
362 | * @throws BuildException |
||
363 | */ |
||
364 | 99 | protected function setupDirectoryScanner(DirectoryScanner $ds, Project $p = null) |
|
365 | { |
||
366 | 99 | if ($p === null) { |
|
367 | $p = $this->getProject(); |
||
368 | } |
||
369 | |||
370 | 99 | if ($this->isReference()) { |
|
371 | $this->getRef($p)->setupDirectoryScanner($ds, $p); |
||
372 | return; |
||
373 | } |
||
374 | |||
375 | 99 | $stk[] = $this; |
|
376 | 99 | $this->dieOnCircularReference($stk, $p); |
|
377 | 99 | array_pop($stk); |
|
378 | |||
379 | // FIXME - pass dir directly when dirscanner supports File |
||
380 | 99 | $ds->setBasedir($this->dir->getPath()); |
|
381 | |||
382 | 99 | foreach ($this->additionalPatterns as $addPattern) { |
|
383 | 1 | $this->defaultPatterns->append($addPattern, $p); |
|
384 | } |
||
385 | |||
386 | 99 | $ds->setIncludes($this->defaultPatterns->getIncludePatterns($p)); |
|
387 | 99 | $ds->setExcludes($this->defaultPatterns->getExcludePatterns($p)); |
|
388 | |||
389 | 99 | $p->log( |
|
390 | 99 | $this->getDataTypeName() . ": Setup file scanner in dir " . (string) $this->dir . " with " . (string) $this->defaultPatterns, |
|
391 | 99 | Project::MSG_DEBUG |
|
392 | ); |
||
393 | |||
394 | 99 | if ($ds instanceof SelectorScanner) { |
|
395 | 99 | $selectors = $this->getSelectors($p); |
|
396 | 99 | foreach ($selectors as $selector) { |
|
397 | 4 | $p->log((string) $selector . PHP_EOL, Project::MSG_DEBUG); |
|
398 | } |
||
399 | 99 | $ds->setSelectors($selectors); |
|
400 | } |
||
401 | |||
402 | 99 | if ($this->useDefaultExcludes) { |
|
403 | 97 | $ds->addDefaultExcludes(); |
|
404 | } |
||
405 | 99 | $ds->setCaseSensitive($this->isCaseSensitive); |
|
406 | 99 | } |
|
407 | |||
408 | 99 | public function dieOnCircularReference(&$stk, Project $p = null) |
|
409 | { |
||
410 | 99 | if ($this->checked) { |
|
411 | 96 | return; |
|
412 | } |
||
413 | 4 | if ($this->isReference()) { |
|
414 | 1 | parent::dieOnCircularReference($stk, $p); |
|
415 | } else { |
||
416 | 4 | foreach ($this->selectorsList as $fileSelector) { |
|
417 | 4 | if ($fileSelector instanceof DataType) { |
|
418 | 4 | static::pushAndInvokeCircularReferenceCheck($fileSelector, $stk, $p); |
|
419 | } |
||
420 | } |
||
421 | 4 | foreach ($this->additionalPatterns as $ps) { |
|
422 | static::pushAndInvokeCircularReferenceCheck($ps, $stk, $p); |
||
423 | } |
||
424 | 4 | $this->setChecked(true); |
|
425 | } |
||
426 | 4 | } |
|
427 | |||
428 | /** |
||
429 | * Performs the check for circular references and returns the |
||
430 | * referenced FileSet. |
||
431 | * |
||
432 | * @param Project $p |
||
433 | * |
||
434 | * @throws BuildException |
||
435 | * |
||
436 | * @return FileSet |
||
437 | */ |
||
438 | 1 | public function getRef(Project $p) |
|
439 | { |
||
440 | 1 | return $this->getCheckedRef(__CLASS__, $this->getDataTypeName()); |
|
441 | } |
||
442 | |||
443 | // SelectorContainer methods |
||
444 | |||
445 | /** |
||
446 | * Indicates whether there are any selectors here. |
||
447 | * |
||
448 | * @return boolean Whether any selectors are in this container |
||
449 | */ |
||
450 | public function hasSelectors() |
||
451 | { |
||
452 | if ($this->isReference() && $this->getProject() !== null) { |
||
453 | return $this->getRef($this->getProject())->hasSelectors(); |
||
454 | } |
||
455 | $stk[] = $this; |
||
0 ignored issues
–
show
Comprehensibility
Best Practice
introduced
by
Loading history...
|
|||
456 | $this->dieOnCircularReference($stk, $this->getProject()); |
||
457 | |||
458 | return !empty($this->selectorsList); |
||
459 | } |
||
460 | |||
461 | /** |
||
462 | * Indicates whether there are any patterns here. |
||
463 | * |
||
464 | * @return boolean Whether any patterns are in this container. |
||
465 | */ |
||
466 | public function hasPatterns() |
||
467 | { |
||
468 | if ($this->isReference() && $this->getProject() !== null) { |
||
469 | return $this->getRef($this->getProject())->hasPatterns(); |
||
470 | } |
||
471 | $stk[] = $this; |
||
472 | $this->dieOnCircularReference($stk, $this->getProject()); |
||
473 | |||
474 | if ($this->defaultPatterns->hasPatterns()) { |
||
475 | return true; |
||
476 | } |
||
477 | |||
478 | for ($i = 0, $size = count($this->additionalPatterns); $i < $size; $i++) { |
||
479 | $ps = $this->additionalPatterns[$i]; |
||
480 | if ($ps->hasPatterns()) { |
||
481 | return true; |
||
482 | } |
||
483 | } |
||
484 | |||
485 | return false; |
||
486 | } |
||
487 | |||
488 | /** |
||
489 | * Gives the count of the number of selectors in this container |
||
490 | * |
||
491 | * @throws Exception |
||
492 | * @return int The number of selectors in this container |
||
493 | */ |
||
494 | public function count() |
||
495 | { |
||
496 | if ($this->isReference() && $this->getProject() !== null) { |
||
497 | try { |
||
498 | return $this->getRef($this->getProject())->count(); |
||
499 | } catch (Exception $e) { |
||
500 | throw $e; |
||
501 | } |
||
502 | } |
||
503 | |||
504 | return count($this->selectorsList); |
||
505 | } |
||
506 | |||
507 | /** |
||
508 | * Returns the set of selectors as an array. |
||
509 | * |
||
510 | * @param Project $p |
||
511 | * @throws BuildException |
||
512 | * @return array of selectors in this container |
||
513 | */ |
||
514 | 99 | public function getSelectors(Project $p) |
|
515 | { |
||
516 | 99 | if ($this->isReference()) { |
|
517 | return $this->getRef($p)->getSelectors($p); |
||
518 | } |
||
519 | |||
520 | // *copy* selectors |
||
521 | 99 | $result = []; |
|
522 | 99 | for ($i = 0, $size = count($this->selectorsList); $i < $size; $i++) { |
|
523 | 4 | $result[] = clone $this->selectorsList[$i]; |
|
524 | } |
||
525 | |||
526 | 99 | return $result; |
|
527 | } |
||
528 | |||
529 | /** |
||
530 | * Returns an array for accessing the set of selectors. |
||
531 | * |
||
532 | * @return array The array of selectors |
||
533 | */ |
||
534 | public function selectorElements() |
||
535 | { |
||
536 | if ($this->isReference() && $this->getProject() !== null) { |
||
537 | return $this->getRef($this->getProject())->selectorElements(); |
||
538 | } |
||
539 | |||
540 | return $this->selectorsList; |
||
541 | } |
||
542 | |||
543 | /** |
||
544 | * Add a new selector into this container. |
||
545 | * |
||
546 | * @param FileSelector $selector new selector to add |
||
547 | * |
||
548 | * @throws BuildException |
||
549 | * |
||
550 | * @return void |
||
551 | */ |
||
552 | 7 | public function appendSelector(FileSelector $selector) |
|
553 | { |
||
554 | 7 | if ($this->isReference()) { |
|
555 | throw $this->noChildrenAllowed(); |
||
556 | } |
||
557 | 7 | $this->selectorsList[] = $selector; |
|
558 | 7 | $this->directoryScanner = null; |
|
559 | 7 | $this->setChecked(false); |
|
560 | 7 | } |
|
561 | |||
562 | /** |
||
563 | * @param array ...$options |
||
564 | * @return ArrayIterator |
||
565 | */ |
||
566 | 12 | public function getIterator(...$options): \ArrayIterator |
|
567 | { |
||
568 | 12 | if ($this->isReference()) { |
|
569 | return $this->getRef($this->getProject())->getIterator($options); |
||
570 | } |
||
571 | 12 | return new ArrayIterator($this->getFiles($options)); |
|
572 | } |
||
573 | |||
574 | abstract protected function getFiles(...$options); |
||
575 | |||
576 | 1 | public function __toString() |
|
577 | { |
||
578 | try { |
||
579 | 1 | if ($this->isReference()) { |
|
580 | return (string) $this->getRef($this->getProject()); |
||
581 | } |
||
582 | 1 | $stk[] = $this; |
|
583 | 1 | $this->dieOnCircularReference($stk, $this->getProject()); |
|
584 | 1 | $ds = $this->getDirectoryScanner($this->getProject()); |
|
585 | 1 | $files = $ds->getIncludedFiles(); |
|
586 | 1 | $result = implode(';', $files); |
|
587 | } catch (BuildException $e) { |
||
588 | $result = ''; |
||
589 | } |
||
590 | |||
591 | 1 | return $result; |
|
592 | } |
||
593 | } |
||
594 |