Mercurial > hg > rc1
comparison vendor/roundcube/plugin-installer/src/Roundcube/Composer/PluginInstaller.php @ 0:1e000243b222
vanilla 1.3.3 distro, I hope
author | Charlie Root |
---|---|
date | Thu, 04 Jan 2018 15:50:29 -0500 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:1e000243b222 |
---|---|
1 <?php | |
2 | |
3 namespace Roundcube\Composer; | |
4 | |
5 use Composer\Installer\LibraryInstaller; | |
6 use Composer\Package\Version\VersionParser; | |
7 use Composer\Semver\Constraint\Constraint; | |
8 use Composer\Package\PackageInterface; | |
9 use Composer\Repository\InstalledRepositoryInterface; | |
10 use Composer\Util\ProcessExecutor; | |
11 | |
12 /** | |
13 * @category Plugins | |
14 * @package PluginInstaller | |
15 * @author Till Klampaeckel <till@php.net> | |
16 * @author Thomas Bruederli <thomas@roundcube.net> | |
17 * @license GPL-3.0+ | |
18 * @version GIT: <git_id> | |
19 * @link http://github.com/roundcube/plugin-installer | |
20 */ | |
21 class PluginInstaller extends LibraryInstaller | |
22 { | |
23 const INSTALLER_TYPE = 'roundcube-plugin'; | |
24 | |
25 /** | |
26 * {@inheritDoc} | |
27 */ | |
28 public function getInstallPath(PackageInterface $package) | |
29 { | |
30 static $vendorDir; | |
31 if ($vendorDir === null) { | |
32 $vendorDir = $this->getVendorDir(); | |
33 } | |
34 | |
35 return sprintf('%s/%s', $vendorDir, $this->getPluginName($package)); | |
36 } | |
37 | |
38 /** | |
39 * {@inheritDoc} | |
40 */ | |
41 public function install(InstalledRepositoryInterface $repo, PackageInterface $package) | |
42 { | |
43 $this->rcubeVersionCheck($package); | |
44 parent::install($repo, $package); | |
45 | |
46 // post-install: activate plugin in Roundcube config | |
47 $config_file = $this->rcubeConfigFile(); | |
48 $plugin_name = $this->getPluginName($package); | |
49 $plugin_dir = $this->getVendorDir() . DIRECTORY_SEPARATOR . $plugin_name; | |
50 $extra = $package->getExtra(); | |
51 $plugin_name = $this->getPluginName($package); | |
52 | |
53 if (is_writeable($config_file) && php_sapi_name() == 'cli') { | |
54 $answer = $this->io->askConfirmation("Do you want to activate the plugin $plugin_name? [N|y] ", false); | |
55 if (true === $answer) { | |
56 $this->rcubeAlterConfig($plugin_name, true); | |
57 } | |
58 } | |
59 | |
60 // copy config.inc.php.dist -> config.inc.php | |
61 if (is_file($plugin_dir . DIRECTORY_SEPARATOR . 'config.inc.php.dist') && !is_file($plugin_dir . DIRECTORY_SEPARATOR . 'config.inc.php') && is_writeable($plugin_dir)) { | |
62 $this->io->write("<info>Creating plugin config file</info>"); | |
63 copy($plugin_dir . DIRECTORY_SEPARATOR . 'config.inc.php.dist', $plugin_dir . DIRECTORY_SEPARATOR . 'config.inc.php'); | |
64 } | |
65 | |
66 // initialize database schema | |
67 if (!empty($extra['roundcube']['sql-dir'])) { | |
68 if ($sqldir = realpath($plugin_dir . DIRECTORY_SEPARATOR . $extra['roundcube']['sql-dir'])) { | |
69 $this->io->write("<info>Running database initialization script for $plugin_name</info>"); | |
70 system(getcwd() . "/vendor/bin/rcubeinitdb.sh --package=$plugin_name --dir=$sqldir"); | |
71 } | |
72 } | |
73 | |
74 // run post-install script | |
75 if (!empty($extra['roundcube']['post-install-script'])) { | |
76 $this->rcubeRunScript($extra['roundcube']['post-install-script'], $package); | |
77 } | |
78 } | |
79 | |
80 /** | |
81 * {@inheritDoc} | |
82 */ | |
83 public function update(InstalledRepositoryInterface $repo, PackageInterface $initial, PackageInterface $target) | |
84 { | |
85 $this->rcubeVersionCheck($target); | |
86 parent::update($repo, $initial, $target); | |
87 | |
88 $extra = $target->getExtra(); | |
89 | |
90 // trigger updatedb.sh | |
91 if (!empty($extra['roundcube']['sql-dir'])) { | |
92 $plugin_name = $this->getPluginName($target); | |
93 $plugin_dir = $this->getVendorDir() . DIRECTORY_SEPARATOR . $plugin_name; | |
94 | |
95 if ($sqldir = realpath($plugin_dir . DIRECTORY_SEPARATOR . $extra['roundcube']['sql-dir'])) { | |
96 $this->io->write("<info>Updating database schema for $plugin_name</info>"); | |
97 system(getcwd() . "/bin/updatedb.sh --package=$plugin_name --dir=$sqldir", $res); | |
98 } | |
99 } | |
100 | |
101 // run post-update script | |
102 if (!empty($extra['roundcube']['post-update-script'])) { | |
103 $this->rcubeRunScript($extra['roundcube']['post-update-script'], $target); | |
104 } | |
105 } | |
106 | |
107 /** | |
108 * {@inheritDoc} | |
109 */ | |
110 public function uninstall(InstalledRepositoryInterface $repo, PackageInterface $package) | |
111 { | |
112 parent::uninstall($repo, $package); | |
113 | |
114 // post-uninstall: deactivate plugin | |
115 $plugin_name = $this->getPluginName($package); | |
116 $this->rcubeAlterConfig($plugin_name, false); | |
117 | |
118 // run post-uninstall script | |
119 $extra = $package->getExtra(); | |
120 if (!empty($extra['roundcube']['post-uninstall-script'])) { | |
121 $this->rcubeRunScript($extra['roundcube']['post-uninstall-script'], $package); | |
122 } | |
123 } | |
124 | |
125 /** | |
126 * {@inheritDoc} | |
127 */ | |
128 public function supports($packageType) | |
129 { | |
130 return $packageType === self::INSTALLER_TYPE; | |
131 } | |
132 | |
133 /** | |
134 * Setup vendor directory to one of these two: | |
135 * ./plugins | |
136 * | |
137 * @return string | |
138 */ | |
139 public function getVendorDir() | |
140 { | |
141 $pluginDir = getcwd(); | |
142 $pluginDir .= '/plugins'; | |
143 | |
144 return $pluginDir; | |
145 } | |
146 | |
147 /** | |
148 * Extract the (valid) plugin name from the package object | |
149 */ | |
150 private function getPluginName(PackageInterface $package) | |
151 { | |
152 @list($vendor, $pluginName) = explode('/', $package->getPrettyName()); | |
153 | |
154 return strtr($pluginName, '-', '_'); | |
155 } | |
156 | |
157 /** | |
158 * Check version requirements from the "extra" block of a package | |
159 * against the local Roundcube version | |
160 */ | |
161 private function rcubeVersionCheck($package) | |
162 { | |
163 $parser = new VersionParser; | |
164 | |
165 // read rcube version from iniset | |
166 $rootdir = getcwd(); | |
167 $iniset = @file_get_contents($rootdir . '/program/include/iniset.php'); | |
168 if (preg_match('/define\(.RCMAIL_VERSION.,\s*.([0-9.]+[a-z-]*)?/', $iniset, $m)) { | |
169 $rcubeVersion = $parser->normalize(str_replace('-git', '.999', $m[1])); | |
170 } else { | |
171 throw new \Exception("Unable to find a Roundcube installation in $rootdir"); | |
172 } | |
173 | |
174 $extra = $package->getExtra(); | |
175 | |
176 if (!empty($extra['roundcube'])) { | |
177 foreach (array('min-version' => '>=', 'max-version' => '<=') as $key => $operator) { | |
178 if (!empty($extra['roundcube'][$key])) { | |
179 $version = $parser->normalize(str_replace('-git', '.999', $extra['roundcube'][$key])); | |
180 $constraint = new Constraint($operator, $version); | |
181 if (!$constraint->versionCompare($rcubeVersion, $version, $operator)) { | |
182 throw new \Exception("Version check failed! " . $package->getName() . " requires Roundcube version $operator $version, $rcubeVersion was detected."); | |
183 } | |
184 } | |
185 } | |
186 } | |
187 } | |
188 | |
189 /** | |
190 * Add or remove the given plugin to the list of active plugins in the Roundcube config. | |
191 */ | |
192 private function rcubeAlterConfig($plugin_name, $add) | |
193 { | |
194 $config_file = $this->rcubeConfigFile(); | |
195 @include($config_file); | |
196 $success = false; | |
197 $varname = '$config'; | |
198 | |
199 if (empty($config) && !empty($rcmail_config)) { | |
200 $config = $rcmail_config; | |
201 $varname = '$rcmail_config'; | |
202 } | |
203 | |
204 if (is_array($config) && is_writeable($config_file)) { | |
205 $config_templ = @file_get_contents($config_file) ?: ''; | |
206 $config_plugins = !empty($config['plugins']) ? ((array) $config['plugins']) : array(); | |
207 $active_plugins = $config_plugins; | |
208 | |
209 if ($add && !in_array($plugin_name, $active_plugins)) { | |
210 $active_plugins[] = $plugin_name; | |
211 } elseif (!$add && ($i = array_search($plugin_name, $active_plugins)) !== false) { | |
212 unset($active_plugins[$i]); | |
213 } | |
214 | |
215 if ($active_plugins != $config_plugins) { | |
216 $count = 0; | |
217 $var_export = "array(\n\t'" . join("',\n\t'", $active_plugins) . "',\n);"; | |
218 $new_config = preg_replace( | |
219 "/(\\$varname\['plugins'\])\s+=\s+(.+);/Uims", | |
220 "\\1 = " . $var_export, | |
221 $config_templ, -1, $count); | |
222 | |
223 // 'plugins' option does not exist yet, add it... | |
224 if (!$count) { | |
225 $var_txt = "\n{$varname}['plugins'] = $var_export;\n"; | |
226 $new_config = str_replace('?>', $var_txt . '?>', $config_templ, $count); | |
227 | |
228 if (!$count) { | |
229 $new_config = $config_templ . $var_txt; | |
230 } | |
231 } | |
232 | |
233 $success = file_put_contents($config_file, $new_config); | |
234 } | |
235 } | |
236 | |
237 if ($success && php_sapi_name() == 'cli') { | |
238 $this->io->write("<info>Updated local config at $config_file</info>"); | |
239 } | |
240 | |
241 return $success; | |
242 } | |
243 | |
244 /** | |
245 * Helper method to get an absolute path to the local Roundcube config file | |
246 */ | |
247 private function rcubeConfigFile() | |
248 { | |
249 return realpath(getcwd() . '/config/config.inc.php'); | |
250 } | |
251 | |
252 /** | |
253 * Run the given script file | |
254 */ | |
255 private function rcubeRunScript($script, PackageInterface $package) | |
256 { | |
257 $plugin_name = $this->getPluginName($package); | |
258 $plugin_dir = $this->getVendorDir() . DIRECTORY_SEPARATOR . $plugin_name; | |
259 | |
260 // check for executable shell script | |
261 if (($scriptfile = realpath($plugin_dir . DIRECTORY_SEPARATOR . $script)) && is_executable($scriptfile)) { | |
262 $script = $scriptfile; | |
263 } | |
264 | |
265 // run PHP script in Roundcube context | |
266 if ($scriptfile && preg_match('/\.php$/', $scriptfile)) { | |
267 $incdir = realpath(getcwd() . '/program/include'); | |
268 include_once($incdir . '/iniset.php'); | |
269 include($scriptfile); | |
270 } | |
271 // attempt to execute the given string as shell commands | |
272 else { | |
273 $process = new ProcessExecutor($this->io); | |
274 $exitCode = $process->execute($script, null, $plugin_dir); | |
275 if ($exitCode !== 0) { | |
276 throw new \RuntimeException('Error executing script: '. $process->getErrorOutput(), $exitCode); | |
277 } | |
278 } | |
279 } | |
280 } |