Issues (16)

Branch: analysis-2ZGKmg

src/Step/StaticFiles/Copy.php (1 issue)

Labels
Severity
1
<?php
2
3
/**
4
 * This file is part of Cecil.
5
 *
6
 * (c) Arnaud Ligny <[email protected]>
7
 *
8
 * For the full copyright and license information, please view the LICENSE
9
 * file that was distributed with this source code.
10
 */
11
12
declare(strict_types=1);
13
14
namespace Cecil\Step\StaticFiles;
15
16
use Cecil\Exception\RuntimeException;
17
use Cecil\Step\AbstractStep;
18
use Cecil\Util;
19
use Symfony\Component\Finder\Finder;
20
21
/**
22
 * Copy static files step.
23
 *
24
 * This step is responsible for copying static files from the source directories
25
 * (like `static/` and `assets/`) to the output directory. It handles both files
26
 * and directories, allowing for exclusions based on the configuration. It also
27
 * supports copying files from theme-specific directories if themes are configured.
28
 * The step can be run in a dry-run mode where no actual file operations are performed,
29
 * but the intended actions are still logged.
30
 */
31
class Copy extends AbstractStep
32
{
33
    protected $count = 0;
34
35
    /**
36
     * {@inheritdoc}
37
     */
38
    public function getName(): string
39
    {
40
        return 'Copying static';
41
    }
42
43
    /**
44
     * {@inheritdoc}
45
     */
46
    public function init(array $options): void
47
    {
48
        if ($options['dry-run']) {
49
            return;
50
        }
51
52
        // reset output directory only if it's not partial rendering
53
        if (empty($options['render-subset'])) {
54
            Util\File::getFS()->remove($this->config->getOutputPath());
55
            Util\File::getFS()->mkdir($this->config->getOutputPath());
56
        }
57
58
        $this->canProcess = true;
59
    }
60
61
    /**
62
     * {@inheritdoc}
63
     */
64
    public function process(): void
65
    {
66
        $target = (string) $this->config->get('static.target');
67
        $exclude = (array) $this->config->get('static.exclude');
68
69
        // copying assets in debug mode (for source maps)
70
        if ($this->builder->isDebug() && $this->config->isEnabled('assets.compile.sourcemap')) {
71
            // copying content of '<theme>/assets/' dir if exists
72
            if ($this->config->hasTheme()) {
73
                $themes = array_reverse($this->config->getTheme());
74
                foreach ($themes as $theme) {
75
                    $this->copy($this->config->getThemeDirPath($theme, 'assets'));
76
                }
77
            }
78
            // copying content of 'assets/' dir if exists
79
            $this->copy($this->config->getAssetsPath());
80
            // cancel exclusion for static files (see below)
81
            $exclude = [];
82
        }
83
84
        // copying content of '<theme>/static/' dir if exists
85
        if ($this->config->hasTheme()) {
86
            $themes = array_reverse($this->config->getTheme());
87
            foreach ($themes as $theme) {
88
                $this->copy($this->config->getThemeDirPath($theme, 'static'), $target, $exclude);
89
            }
90
        }
91
92
        // copying content of 'static/' dir if exists
93
        $this->copy($this->config->getStaticPath(), $target, $exclude);
94
95
        // copying mounts
96
        if ($this->config->get('static.mounts')) {
97
            foreach ((array) $this->config->get('static.mounts') as $source => $destination) {
98
                $this->copy(Util::joinFile($this->config->getStaticPath(), (string) $source), (string) $destination);
99
            }
100
        }
101
102
        if ($this->count === 0) {
103
            $this->builder->getLogger()->info('Nothing to copy');
104
105
            return;
106
        }
107
        $this->builder->getLogger()->info('Files copied', ['progress' => [$this->count, $this->count]]);
108
    }
109
110
    /**
111
     * Copying a file or files in a directory from $from (if exists) to $to (relative to output path).
112
     * Exclude files or directories with $exclude array.
113
     */
114
    protected function copy(string $from, ?string $to = null, ?array $exclude = null): void
115
    {
116
        try {
117
            if (Util\File::getFS()->exists($from)) {
118
                // copy a file
119
                if (is_file($from)) {
120
                    Util\File::getFS()->copy($from, Util::joinFile($this->config->getOutputPath(), $to), true);
0 ignored issues
show
It seems like $to can also be of type null; however, parameter $path of Cecil\Util::joinFile() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

120
                    Util\File::getFS()->copy($from, Util::joinFile($this->config->getOutputPath(), /** @scrutinizer ignore-type */ $to), true);
Loading history...
121
122
                    return;
123
                }
124
                // copy a directory
125
                $finder = Finder::create()
126
                    ->files()
127
                    ->in($from)
128
                    ->ignoreDotFiles(false);
129
                // exclude files or directories
130
                if (\is_array($exclude)) {
131
                    $finder->notPath($exclude);
132
                    $finder->notName($exclude);
133
                }
134
                $this->count += $finder->count();
135
                Util\File::getFS()->mirror(
136
                    $from,
137
                    Util::joinFile($this->config->getOutputPath(), $to ?? ''),
138
                    $finder,
139
                    ['override' => true]
140
                );
141
            }
142
        } catch (\Exception $e) {
143
            throw new RuntimeException(\sprintf('Error during static files copy: %s', $e->getMessage()));
144
        }
145
    }
146
}
147