1
|
|
|
<?php |
2
|
|
|
/* |
3
|
|
|
* This file is part of EC-CUBE |
4
|
|
|
* |
5
|
|
|
* Copyright(c) 2000-2015 LOCKON CO.,LTD. All Rights Reserved. |
6
|
|
|
* |
7
|
|
|
* http://www.lockon.co.jp/ |
8
|
|
|
* |
9
|
|
|
* This program is free software; you can redistribute it and/or |
10
|
|
|
* modify it under the terms of the GNU General Public License |
11
|
|
|
* as published by the Free Software Foundation; either version 2 |
12
|
|
|
* of the License, or (at your option) any later version. |
13
|
|
|
* |
14
|
|
|
* This program is distributed in the hope that it will be useful, |
15
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
16
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
17
|
|
|
* GNU General Public License for more details. |
18
|
|
|
* |
19
|
|
|
* You should have received a copy of the GNU General Public License |
20
|
|
|
* along with this program; if not, write to the Free Software |
21
|
|
|
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. |
22
|
|
|
*/ |
23
|
|
|
namespace Eccube\Service\Composer; |
24
|
|
|
|
25
|
|
|
use Doctrine\ORM\EntityManagerInterface; |
26
|
|
|
use Eccube\Annotation\Service; |
27
|
|
|
|
28
|
|
|
/** |
29
|
|
|
* Class ComposerProcessService |
30
|
|
|
* @package Eccube\Service\Composer |
31
|
|
|
* @Service |
32
|
|
|
*/ |
33
|
|
|
class ComposerProcessService implements ComposerServiceInterface |
34
|
|
|
{ |
35
|
|
|
/** |
36
|
|
|
* @var array config parameter |
37
|
|
|
*/ |
38
|
|
|
protected $appConfig; |
39
|
|
|
|
40
|
|
|
/** |
41
|
|
|
* @var EntityManagerInterface |
42
|
|
|
*/ |
43
|
|
|
protected $entityManager; |
44
|
|
|
|
45
|
|
|
private $workingDir; |
46
|
|
|
private $composerFile; |
47
|
|
|
private $composerSetup; |
48
|
|
|
private $pathPHP; |
49
|
|
|
|
50
|
|
|
/** |
51
|
|
|
* ComposerProcessService constructor. |
52
|
|
|
* |
53
|
|
|
* @param array $appConfig |
54
|
|
|
* @param EntityManagerInterface $entityManager |
55
|
|
|
* @param string $pathPHP |
56
|
|
|
*/ |
57
|
|
|
public function __construct($appConfig, $entityManager, $pathPHP) |
58
|
|
|
{ |
59
|
|
|
$this->appConfig = $appConfig; |
60
|
|
|
$this->entityManager = $entityManager; |
61
|
|
|
$this->pathPHP = $pathPHP; |
62
|
|
|
} |
63
|
|
|
|
64
|
|
|
/** |
65
|
|
|
* This function to install a plugin by composer require |
66
|
|
|
* |
67
|
|
|
* @param string $packageName format "foo/bar foo/bar2:1.0.0" |
68
|
|
|
* @return bool |
69
|
|
|
*/ |
70
|
|
View Code Duplication |
public function execRequire($packageName) |
|
|
|
|
71
|
|
|
{ |
72
|
|
|
set_time_limit(0); |
73
|
|
|
if (false === $this->init()) { |
74
|
|
|
return false; |
75
|
|
|
} |
76
|
|
|
// Build command |
77
|
|
|
$command = $this->pathPHP.' '.$this->composerFile.' require '.$packageName; |
78
|
|
|
$command .= ' --prefer-dist --no-progress --no-suggest --no-scripts --ignore-platform-reqs --profile --no-ansi --no-interaction -d '; |
79
|
|
|
$command .= $this->workingDir.' 2>&1'; |
80
|
|
|
log_info($command); |
81
|
|
|
$this->runCommand($command); |
82
|
|
|
|
83
|
|
|
return true; |
84
|
|
|
} |
85
|
|
|
|
86
|
|
|
/** |
87
|
|
|
* This function to remove a plugin by composer remove |
88
|
|
|
* |
89
|
|
|
* @param string $packageName format "foo/bar foo/bar2" |
90
|
|
|
* @return bool |
91
|
|
|
*/ |
92
|
|
View Code Duplication |
public function execRemove($packageName) |
|
|
|
|
93
|
|
|
{ |
94
|
|
|
set_time_limit(0); |
95
|
|
|
if (false === $this->init()) { |
96
|
|
|
return false; |
97
|
|
|
} |
98
|
|
|
// Build command |
99
|
|
|
$command = $this->pathPHP.' '.$this->composerFile.' remove '.$packageName; |
100
|
|
|
$command .= ' --no-progress --no-scripts --ignore-platform-reqs --profile --no-ansi --no-interaction -d '; |
101
|
|
|
$command .= $this->workingDir.' 2>&1'; |
102
|
|
|
log_info($command); |
103
|
|
|
|
104
|
|
|
// Execute command |
105
|
|
|
$this->runCommand($command); |
106
|
|
|
|
107
|
|
|
return true; |
108
|
|
|
} |
109
|
|
|
|
110
|
|
|
/** |
111
|
|
|
* Run command |
112
|
|
|
* |
113
|
|
|
* @param string $command |
114
|
|
|
* @return void |
115
|
|
|
*/ |
116
|
|
|
public function runCommand($command) |
117
|
|
|
{ |
118
|
|
|
// Execute command |
119
|
|
|
$output = array(); |
120
|
|
|
exec($command, $output); |
121
|
|
|
log_info(PHP_EOL.implode(PHP_EOL, $output).PHP_EOL); |
122
|
|
|
} |
123
|
|
|
|
124
|
|
|
/** |
125
|
|
|
* Set working dir |
126
|
|
|
* @param string $workingDir |
127
|
|
|
*/ |
128
|
|
|
public function setWorkingDir($workingDir) |
129
|
|
|
{ |
130
|
|
|
$this->workingDir = $workingDir; |
131
|
|
|
} |
132
|
|
|
|
133
|
|
|
/** |
134
|
|
|
* Set init |
135
|
|
|
* @return bool |
136
|
|
|
*/ |
137
|
|
|
private function init() |
138
|
|
|
{ |
139
|
|
|
if (!$this->isPhpCommandLine()) { |
140
|
|
|
return false; |
141
|
|
|
} |
142
|
|
|
|
143
|
|
|
if (!$this->isSetCliMemoryLimit()) { |
144
|
|
|
$composerMemory = $this->appConfig['composer_memory_limit']; |
145
|
|
|
if ($this->getCliMemoryLimit() < $composerMemory && $this->getCliMemoryLimit() != -1) { |
146
|
|
|
return false; |
147
|
|
|
} |
148
|
|
|
} |
149
|
|
|
|
150
|
|
|
/** |
151
|
|
|
* Mysql lock in transaction |
152
|
|
|
* @link https://dev.mysql.com/doc/refman/5.7/en/lock-tables.html |
153
|
|
|
* @var EntityManagerInterface $em |
154
|
|
|
*/ |
155
|
|
|
$em = $this->entityManager; |
156
|
|
|
if ($em->getConnection()->isTransactionActive()) { |
157
|
|
|
$em->getConnection()->commit(); |
158
|
|
|
$em->getConnection()->beginTransaction(); |
159
|
|
|
} |
160
|
|
|
|
161
|
|
|
@ini_set('memory_limit', '1536M'); |
|
|
|
|
162
|
|
|
// Config for some environment |
163
|
|
|
putenv('COMPOSER_HOME='.$this->appConfig['plugin_realdir'].'/.composer'); |
164
|
|
|
$this->workingDir = $this->workingDir ? $this->workingDir : $this->appConfig['root_dir']; |
165
|
|
|
$this->setupComposer(); |
166
|
|
|
|
167
|
|
|
return true; |
168
|
|
|
} |
169
|
|
|
|
170
|
|
|
/** |
171
|
|
|
* Check composer file and setup it |
172
|
|
|
*/ |
173
|
|
|
private function setupComposer() |
174
|
|
|
{ |
175
|
|
|
$this->composerFile = $this->workingDir.'/composer.phar'; |
176
|
|
|
$this->composerSetup = $this->workingDir.'/composer-setup.php'; |
177
|
|
|
if (!file_exists($this->composerFile)) { |
178
|
|
|
if (!file_exists($this->composerSetup)) { |
179
|
|
|
$result = copy('https://getcomposer.org/installer', $this->composerSetup); |
180
|
|
|
log_info($this->composerSetup.' : '.$result); |
181
|
|
|
} |
182
|
|
|
$command = $this->pathPHP.' '.$this->composerSetup; |
183
|
|
|
$this->runCommand($command); |
184
|
|
|
|
185
|
|
|
unlink($this->composerSetup); |
186
|
|
|
} |
187
|
|
|
} |
188
|
|
|
|
189
|
|
|
/** |
190
|
|
|
* Get grep memory_limit | Megabyte |
191
|
|
|
* @return int|string |
192
|
|
|
*/ |
193
|
|
|
private function getCliMemoryLimit() |
194
|
|
|
{ |
195
|
|
|
$grepMemory = exec($this->pathPHP.' -i | grep "memory_limit"'); |
196
|
|
|
if ($grepMemory) { |
197
|
|
|
$grepMemory = explode('=>', $grepMemory); |
198
|
|
|
|
199
|
|
|
// -1 unlimited |
200
|
|
|
if (trim($grepMemory[2]) == -1) { |
201
|
|
|
return -1; |
202
|
|
|
} |
203
|
|
|
|
204
|
|
|
$exp = preg_split('#(?<=\d)(?=[a-z])#i', $grepMemory[2]); |
205
|
|
|
$memo = trim($exp[0]); |
206
|
|
|
if ($exp[1] == 'M') { |
207
|
|
|
return $memo; |
208
|
|
|
} else { |
209
|
|
|
if ($exp[1] == 'GB') { |
210
|
|
|
return $memo * 1024; |
211
|
|
|
} else { |
212
|
|
|
return 0; |
213
|
|
|
} |
214
|
|
|
} |
215
|
|
|
} |
216
|
|
|
|
217
|
|
|
return 0; |
218
|
|
|
} |
219
|
|
|
|
220
|
|
|
/** |
221
|
|
|
* Check to set new value grep "memory_limit" |
222
|
|
|
* @return bool |
223
|
|
|
*/ |
224
|
|
|
private function isSetCliMemoryLimit() |
225
|
|
|
{ |
226
|
|
|
$oldMemory = exec($this->pathPHP.' -i | grep "memory_limit"'); |
227
|
|
|
$tmpMem = '1.5GB'; |
228
|
|
|
if ($oldMemory) { |
229
|
|
|
$memory = explode('=>', $oldMemory); |
230
|
|
|
$originGrepMemmory = trim($memory[2]); |
231
|
|
|
|
232
|
|
|
if ($originGrepMemmory == $tmpMem) { |
233
|
|
|
$tmpMem = '1.49GB'; |
234
|
|
|
} |
235
|
|
|
|
236
|
|
|
$newMemory = exec($this->pathPHP.' -d memory_limit='.$tmpMem.' -i | grep "memory_limit"'); |
237
|
|
|
if ($newMemory) { |
238
|
|
|
$newMemory = explode('=>', $newMemory); |
239
|
|
|
$grepNewMemory = trim($newMemory[2]); |
240
|
|
|
if ($grepNewMemory != $originGrepMemmory) { |
241
|
|
|
return true; |
242
|
|
|
} |
243
|
|
|
} |
244
|
|
|
} |
245
|
|
|
|
246
|
|
|
return false; |
247
|
|
|
} |
248
|
|
|
|
249
|
|
|
/** |
250
|
|
|
* Check php command line |
251
|
|
|
* @return bool |
252
|
|
|
*/ |
253
|
|
|
private function isPhpCommandLine() |
254
|
|
|
{ |
255
|
|
|
$php = exec('which php'); |
256
|
|
|
if (null != $php) { |
257
|
|
|
if (strpos(strtolower($php), 'php') !== false) { |
258
|
|
|
return true; |
259
|
|
|
} |
260
|
|
|
} |
261
|
|
|
|
262
|
|
|
return false; |
263
|
|
|
} |
264
|
|
|
|
265
|
|
|
/** |
266
|
|
|
* Get version of composer |
267
|
|
|
* @return null|string |
268
|
|
|
*/ |
269
|
|
|
public function composerVersion() |
|
|
|
|
270
|
|
|
{ |
271
|
|
|
$this->init(); |
272
|
|
|
$command = $this->pathPHP . ' ' . $this->composerFile . ' -V'; |
|
|
|
|
273
|
|
|
return exec($command); |
|
|
|
|
274
|
|
|
} |
275
|
|
|
|
276
|
|
|
/** |
277
|
|
|
* Get mode |
278
|
|
|
* @return mixed|string |
279
|
|
|
*/ |
280
|
|
|
public function getMode() |
281
|
|
|
{ |
282
|
|
|
return 'EXEC'; |
283
|
|
|
} |
284
|
|
|
} |
285
|
|
|
|
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.
You can also find more detailed suggestions in the “Code” section of your repository.