Passed
Push — master ( a30145...bc128f )
by Webysther
36s
created

Clean::execute()   B

Complexity

Conditions 4
Paths 4

Size

Total Lines 26
Code Lines 15

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 20

Importance

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