Completed
Push — master ( 9a3147...33bee6 )
by Webysther
02:43
created

Clean::removeAll()   A

Complexity

Conditions 3
Paths 4

Size

Total Lines 12
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 12

Importance

Changes 0
Metric Value
cc 3
eloc 6
nc 4
nop 1
dl 0
loc 12
ccs 0
cts 7
cp 0
crap 12
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 Packagist Mirror.
7
 *
8
 * For the full license information, please view the LICENSE.md
9
 * file that was distributed with this source code.
10
 */
11
12
namespace Webs\Mirror\Command;
13
14
use Symfony\Component\Console\Input\InputInterface;
15
use Symfony\Component\Console\Input\InputOption;
16
use Symfony\Component\Console\Output\OutputInterface;
17
use stdClass;
18
19
/**
20
 * Clean mirror outdated files.
21
 *
22
 * @author Webysther Nunes <[email protected]>
23
 */
24
class Clean extends Base
25
{
26
    /**
27
     * @var array
28
     */
29
    protected $changed = [];
30
31
    /**
32
     * @var array
33
     */
34
    protected $removed = [];
35
36
    /**
37
     * @var bool
38
     */
39
    protected $isScrub = false;
40
41
    /**
42
     * {@inheritdoc}
43
     */
44
    public function __construct($name = '')
45
    {
46
        parent::__construct('clean');
47
        $this->setDescription(
48
            'Clean outdated files of mirror'
49
        );
50
    }
51
52
    /**
53
     * Console params configuration.
54
     */
55
    protected function configure():void
56
    {
57
        parent::configure();
58
        $this->addOption(
59
            'scrub',
60
            null,
61
            InputOption::VALUE_NONE,
62
            'Check all directories for old files, use only to check all disk'
63
        );
64
    }
65
66
    /**
67
     * {@inheritdoc}
68
     */
69
    public function execute(InputInterface $input, OutputInterface $output):int
70
    {
71
        $this->initialize($input, $output);
72
        $this->bootstrap();
73
74
        if ($input->hasOption('scrub') && $input->getOption('scrub')) {
75
            $this->isScrub = true;
76
        }
77
78
        $this->flushProviders();
79
        $this->flushPackages();
80
81
        if (!count($this->changed)) {
82
            $output->writeln('<info>Nothing to clean</>');
83
        }
84
85
        return $this->getExitCode();
86
    }
87
88
    /**
89
     * @return void
90
     */
91
    public function bootstrap():void
92
    {
93
        $this->progressBar->setConsole($this->input, $this->output);
94
        $this->package->setConsole($this->input, $this->output);
95
        $this->package->setHttp($this->http);
96
        $this->package->setFilesystem($this->filesystem);
97
        $this->provider->setConsole($this->input, $this->output);
98
        $this->provider->setHttp($this->http);
99
        $this->provider->setFilesystem($this->filesystem);
100
    }
101
102
    /**
103
     * Flush old cached files of providers.
104
     *
105
     * @return Clean
106
     */
107
    protected function flushProviders():Clean
108
    {
109
        if (!$this->filesystem->hasFile(self::MAIN)){
110
            return $this;
111
        }
112
113
        $providers = json_decode($this->filesystem->read(self::MAIN));
114
        $includes = array_keys($this->provider->normalize($providers));
115
116
        $this->initialized = $this->filesystem->hasFile(self::INIT);
117
118
        foreach ($includes as $uri) {
119
            $pattern = $this->filesystem->getGzName($this->shortname($uri));
120
            $glob = $this->filesystem->glob($pattern);
121
122
            $this->output->writeln(
123
                'Check old file of <info>'.
124
                $pattern.
125
                '</>'
126
            );
127
128
            // If not have one file or not scrumbbing
129
            if (!(count($glob) > 1 || $this->isScrub)) {
130
                continue;
131
            }
132
133
            $this->changed[] = $uri;
134
            $uri = $this->filesystem->getFullPath($this->filesystem->getGzName($uri));
135
            $diff = array_diff($glob, [$uri]);
136
            $this->removeAll($diff)->showRemoved();
137
        }
138
139
        return $this;
140
    }
141
142
    /**
143
     * Flush old cached files of packages.
144
     *
145
     * @return bool True if work, false otherside
146
     */
147
    protected function flushPackages():bool
148
    {
149
        $increment = 0;
150
151
        foreach ($this->changed as $uri) {
152
            $providers = json_decode($this->filesystem->read($uri));
153
            $list = $this->package->normalize($providers->providers);
154
155
            $this->output->writeln(
156
                '['.++$increment.'/'.count($this->changed).'] '.
157
                'Check old packages for provider '.
158
                '<info>'.$this->shortname($uri).'</>'
159
            );
160
            $this->progressBar->start(count($list));
161
            $this->flushPackage(array_keys($list));
162
            $this->progressBar->end();
163
            $this->showRemoved();
164
        }
165
166
        return true;
167
    }
168
169
    /**
170
     * Flush from one provider.
171
     *
172
     * @param array $list List of packages
173
     */
174
    protected function flushPackage(array $list):void
175
    {
176
        $packages = $this->package->getDownloaded();
177
178
        foreach ($list as $uri) {
179
            $this->progressBar->progress();
180
181
            if ($this->canSkipPackage($uri, $packages)) {
182
                continue;
183
            }
184
185
            $gzName = $this->filesystem->getGzName($uri);
186
            $pattern = $this->shortname($gzName);
187
            $glob = $this->filesystem->glob($pattern);
188
189
            // If only have the file dont exist old files
190
            if (count($glob) < 2) {
191
                continue;
192
            }
193
194
            // Remove current value
195
            $fullPath = $this->filesystem->getFullPath($gzName);
196
            $diff = array_diff($glob, [$fullPath]);
197
            $this->removeAll($diff);
198
        }
199
    }
200
201
    /**
202
     * @param string $uri
203
     * @param array  $packages
204
     * @return bool
205
     */
206
    protected function canSkipPackage(string $uri, array $packages):bool
207
    {
208
        if ($this->initialized) {
209
            return true;
210
        }
211
212
        $folder = dirname($uri);
213
214
        // This uri was changed by last download?
215
        if (count($packages) && !in_array($uri, $packages)) {
216
            return true;
217
        }
218
219
        // If only have the file and link dont exist old files
220
        if ($this->filesystem->getCount($folder) < 3) {
221
            return true;
222
        }
223
224
        return false;
225
    }
226
227
    /**
228
     * Remove all files
229
     *
230
     * @param  array  $files
231
     * @return Clean
232
     */
233
    protected function removeAll(array $files):Clean
234
    {
235
        foreach ($files as $file) {
236
            $this->filesystem->delete($file);
237
        }
238
239
        $this->removed = [];
240
        if ($this->isVerbose()) {
241
            $this->removed = $files;
242
        }
243
244
        return $this;
245
    }
246
247
    /**
248
     * Show packages removed.
249
     *
250
     * @return Clean
251
     */
252
    protected function showRemoved():Clean
253
    {
254
        $base = getenv('PUBLIC_DIR').DIRECTORY_SEPARATOR;
255
256
        foreach ($this->removed as $file) {
257
            $file = str_replace($base, '', $file);
258
            $this->output->writeln(
259
                'File <fg=blue;>'.$file.'</> was removed!'
260
            );
261
        }
262
263
        $this->removed = [];
264
265
        return $this;
266
    }
267
}
268