1 | <?php |
||
2 | |||
3 | namespace BringYourOwnIdeas\Maintenance\Tasks; |
||
4 | |||
5 | use BringYourOwnIdeas\Maintenance\Util\ComposerLoader; |
||
6 | use BringYourOwnIdeas\Maintenance\Util\ModuleHealthLoader; |
||
7 | use BringYourOwnIdeas\Maintenance\Util\SupportedAddonsLoader; |
||
8 | use RuntimeException; |
||
9 | use SilverStripe\Control\HTTPRequest; |
||
10 | use SilverStripe\Core\Convert; |
||
11 | use SilverStripe\Core\Environment; |
||
12 | use SilverStripe\ORM\Queries\SQLDelete; |
||
13 | use SilverStripe\ORM\DataObjectSchema; |
||
14 | use BringYourOwnIdeas\Maintenance\Model\Package; |
||
15 | use SilverStripe\Dev\BuildTask; |
||
16 | |||
17 | /** |
||
18 | * Parses a composer lock file in order to cache information about the installation. |
||
19 | */ |
||
20 | class UpdatePackageInfoTask extends BuildTask |
||
21 | { |
||
22 | /** |
||
23 | * {@inheritDoc} |
||
24 | * @var string |
||
25 | */ |
||
26 | private static $segment = 'UpdatePackageInfoTask'; |
||
27 | |||
28 | /** |
||
29 | * A custom memory limit to set for this to increase to (or do nothing if the memory is already set high enough) |
||
30 | * |
||
31 | * @config |
||
32 | * @var string |
||
33 | */ |
||
34 | private static $memory_limit = '256m'; |
||
35 | |||
36 | /** |
||
37 | * @var array Injector configuration |
||
38 | * @config |
||
39 | */ |
||
40 | private static $dependencies = [ |
||
41 | 'ComposerLoader' => '%$BringYourOwnIdeas\\Maintenance\\Util\\ComposerLoader', |
||
42 | 'SupportedAddonsLoader' => '%$BringYourOwnIdeas\\Maintenance\\Util\\SupportedAddonsLoader', |
||
43 | 'ModuleHealthLoader' => '%$BringYourOwnIdeas\\Maintenance\\Util\\ModuleHealthLoader', |
||
44 | ]; |
||
45 | |||
46 | /** |
||
47 | * The "types" of composer libraries that will be processed. Anything without these types will be ignored. |
||
48 | * |
||
49 | * @config |
||
50 | * @var array |
||
51 | */ |
||
52 | private static $allowed_types = [ |
||
53 | 'silverstripe-module', |
||
54 | 'silverstripe-vendormodule', |
||
55 | ]; |
||
56 | |||
57 | /** |
||
58 | * @var ComposerLoader |
||
59 | */ |
||
60 | protected $composerLoader; |
||
61 | |||
62 | /** |
||
63 | * @var SupportedAddonsLoader |
||
64 | */ |
||
65 | protected $supportedAddonsLoader; |
||
66 | |||
67 | /** |
||
68 | * @var ModuleHealthLoader |
||
69 | */ |
||
70 | protected $moduleHealthLoader; |
||
71 | |||
72 | /** |
||
73 | * Fetch the composer loader |
||
74 | * |
||
75 | * @return ComposerLoader |
||
76 | */ |
||
77 | public function getComposerLoader() |
||
78 | { |
||
79 | return $this->composerLoader; |
||
80 | } |
||
81 | |||
82 | /** |
||
83 | * set composer loader - provided for use with Injector {@see Injector} |
||
84 | * |
||
85 | * @param ComposerLoader $composerLoader |
||
86 | * |
||
87 | * @return UpdatePackageInfoTask $this |
||
88 | */ |
||
89 | public function setComposerLoader($composerLoader) |
||
90 | { |
||
91 | $this->composerLoader = $composerLoader; |
||
92 | return $this; |
||
93 | } |
||
94 | |||
95 | /** |
||
96 | * @return SupportedAddonsLoader |
||
97 | */ |
||
98 | public function getSupportedAddonsLoader() |
||
99 | { |
||
100 | return $this->supportedAddonsLoader; |
||
101 | } |
||
102 | |||
103 | /** |
||
104 | * @param SupportedAddonsLoader $supportedAddonsLoader |
||
105 | * @return $this |
||
106 | */ |
||
107 | public function setSupportedAddonsLoader(SupportedAddonsLoader $supportedAddonsLoader) |
||
108 | { |
||
109 | $this->supportedAddonsLoader = $supportedAddonsLoader; |
||
110 | return $this; |
||
111 | } |
||
112 | |||
113 | /** |
||
114 | * @return ModuleHealthLoader |
||
115 | */ |
||
116 | public function getModuleHealthLoader() |
||
117 | { |
||
118 | return $this->moduleHealthLoader; |
||
119 | } |
||
120 | |||
121 | /** |
||
122 | * @param ModuleHealthLoader $moduleHealthLoader |
||
123 | * @return $this |
||
124 | */ |
||
125 | public function setModuleHealthLoader(ModuleHealthLoader $moduleHealthLoader) |
||
126 | { |
||
127 | $this->moduleHealthLoader = $moduleHealthLoader; |
||
128 | return $this; |
||
129 | } |
||
130 | |||
131 | public function getTitle() |
||
132 | { |
||
133 | return _t(__CLASS__ . '.TITLE', 'Refresh installed package info'); |
||
134 | } |
||
135 | |||
136 | public function getDescription() |
||
137 | { |
||
138 | return _t( |
||
139 | __CLASS__ . '.DESCRIPTION', |
||
140 | 'Repopulates installation summary, listing installed modules'. |
||
141 | ' and information associated with each.' |
||
142 | ); |
||
143 | } |
||
144 | |||
145 | /** |
||
146 | * Update database cached information about this site. |
||
147 | * |
||
148 | * @param HTTPRequest $request unused, can be null (must match signature of parent function). |
||
149 | */ |
||
150 | public function run($request) |
||
151 | { |
||
152 | // Loading packages and all their updates can be quite memory intensive. |
||
153 | $memoryLimit = $this->config()->get('memory_limit'); |
||
154 | if ($memoryLimit) { |
||
155 | if (Environment::getMemoryLimitMax() < Convert::memstring2bytes($memoryLimit)) { |
||
156 | Environment::setMemoryLimitMax($memoryLimit); |
||
157 | } |
||
158 | Environment::increaseMemoryLimitTo($memoryLimit); |
||
159 | } |
||
160 | |||
161 | $composerLock = $this->getComposerLoader()->getLock(); |
||
162 | $rawPackages = array_merge($composerLock->packages, (array) $composerLock->{'packages-dev'}); |
||
163 | $packages = $this->getPackageInfo($rawPackages); |
||
164 | |||
165 | // Get "name" from $packages and put into an array |
||
166 | $moduleNames = array_column($packages, 'Name'); |
||
167 | |||
168 | $supportedPackages = $this->getSupportedPackages(); |
||
169 | $moduleHealthInfo = $this->getHealthIndicator($moduleNames); |
||
170 | |||
171 | // Extensions to the process that add data may rely on external services. |
||
172 | // There may be a communication issue between the site and the external service, |
||
173 | // so if there are 'none' we should assume this is untrue and _not_ proceed |
||
174 | // to remove everything. Stale information is better than no information. |
||
175 | if ($packages) { |
||
0 ignored issues
–
show
|
|||
176 | // There is no onBeforeDelete for Package |
||
177 | $table = DataObjectSchema::create()->tableName(Package::class); |
||
178 | SQLDelete::create("\"$table\"")->execute(); |
||
179 | foreach ($packages as $package) { |
||
180 | $packageName = $package['Name']; |
||
181 | if (is_array($supportedPackages)) { |
||
182 | $package['Supported'] = in_array($packageName, $supportedPackages); |
||
183 | } |
||
184 | if (is_array($moduleHealthInfo) && isset($moduleHealthInfo[$packageName])) { |
||
185 | $package['Rating'] = $moduleHealthInfo[$packageName]; |
||
186 | } |
||
187 | Package::create()->update($package)->write(); |
||
188 | } |
||
189 | } |
||
190 | } |
||
191 | |||
192 | /** |
||
193 | * Fetch information about the installed packages. |
||
194 | * |
||
195 | * @param array $packageList list of packages as objects, formatted as one finds in a composer.lock |
||
196 | * |
||
197 | * @return array indexed array of package information, represented as associative arrays. |
||
198 | */ |
||
199 | public function getPackageInfo($packageList) |
||
200 | { |
||
201 | $formatInfo = function ($package) { |
||
202 | // Convert object to array, with Capitalised keys |
||
203 | $package = get_object_vars($package); |
||
204 | return array_combine( |
||
205 | array_map('ucfirst', array_keys($package)), |
||
206 | $package |
||
207 | ); |
||
208 | }; |
||
209 | |||
210 | $packageList = array_map($formatInfo, $packageList); |
||
211 | $this->extend('updatePackageInfo', $packageList); |
||
212 | return $packageList; |
||
213 | } |
||
214 | |||
215 | /** |
||
216 | * Return an array of supported modules as fetched from addons.silverstripe.org. Outputs a message and returns null |
||
217 | * if an error occurs |
||
218 | * |
||
219 | * @return null|array |
||
220 | */ |
||
221 | public function getSupportedPackages() |
||
222 | { |
||
223 | try { |
||
224 | return $this->getSupportedAddonsLoader()->getAddonNames() ?: []; |
||
225 | } catch (RuntimeException $exception) { |
||
226 | echo $exception->getMessage() . PHP_EOL; |
||
227 | } |
||
228 | |||
229 | return null; |
||
230 | } |
||
231 | |||
232 | /** |
||
233 | * Return an array of module health information as fetched from addons.silverstripe.org. Outputs a message and |
||
234 | * returns null if an error occurs |
||
235 | * |
||
236 | * @param string[] $moduleNames |
||
237 | * @return null|array |
||
238 | */ |
||
239 | public function getHealthIndicator(array $moduleNames) |
||
240 | { |
||
241 | try { |
||
242 | return $this->getModuleHealthLoader()->setModuleNames($moduleNames)->getModuleHealthInfo() ?: []; |
||
243 | } catch (RuntimeException $exception) { |
||
244 | echo $exception->getMessage() . PHP_EOL; |
||
245 | } |
||
246 | |||
247 | return null; |
||
248 | } |
||
249 | } |
||
250 |
This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.
Consider making the comparison explicit by using
empty(..)
or! empty(...)
instead.