xref: /dokuwiki/lib/plugins/extension/cli.php (revision ed3520eed10a8224b4bcdc4c401f6ba33f25f202)
1<?php
2
3use splitbrain\phpcli\Colors;
4
5/**
6 * Class cli_plugin_extension
7 *
8 * Command Line component for the extension manager
9 *
10 * @license GPL2
11 * @author Andreas Gohr <andi@splitbrain.org>
12 */
13class cli_plugin_extension extends DokuWiki_CLI_Plugin
14{
15    /** @inheritdoc */
16    protected function setup(\splitbrain\phpcli\Options $options)
17    {
18        // general setup
19        $options->setHelp('Manage plugins and templates for this DokuWiki instance');
20
21        // search
22        $options->registerCommand('search', 'Search for an extension');
23        $options->registerOption('max', 'Maximum number of results (default 10)', 'm', 'number', 'search');
24        $options->registerOption('verbose', 'Show detailed extension information', 'v', false, 'search');
25        $options->registerArgument('query', 'The keyword(s) to search for', true, 'search');
26
27        // list
28        $options->registerCommand('list', 'List installed extensions');
29        $options->registerOption('verbose', 'Show detailed extension information', 'v', false, 'list');
30
31        // upgrade
32        $options->registerCommand('upgrade', 'Update all installed extensions to their latest versions');
33
34        // install
35        $options->registerCommand('install', 'Install or upgrade extensions');
36        $options->registerArgument('extensions...', 'One or more extensions to install', true, 'install');
37
38        // uninstall
39        $options->registerCommand('uninstall', 'Uninstall a new extension');
40        $options->registerArgument('extensions...', 'One or more extensions to install', true, 'uninstall');
41
42        // enable
43        $options->registerCommand('enable', 'Enable installed extensions');
44        $options->registerArgument('extensions...', 'One or more extensions to enable', true, 'enable');
45
46        // disable
47        $options->registerCommand('disable', 'Disable installed extensions');
48        $options->registerArgument('extensions...', 'One or more extensions to disable', true, 'disable');
49
50
51    }
52
53    /** @inheritdoc */
54    protected function main(\splitbrain\phpcli\Options $options)
55    {
56        /** @var helper_plugin_extension_repository $repo */
57        $repo = plugin_load('helper', 'extension_repository');
58        if(!$repo->hasAccess(false)) {
59            $this->warning('Extension Repository API is not accessible, no remote info available!');
60        }
61
62        switch ($options->getCmd()) {
63            case 'list':
64                $ret = $this->cmdList($options->getOpt('verbose'));
65                break;
66            case 'search':
67                $ret = $this->cmdSearch(
68                    implode(' ', $options->getArgs()),
69                    $options->getOpt('verbose'),
70                    (int)$options->getOpt('max', 10)
71                );
72                break;
73            case 'install':
74                $ret = $this->cmdInstall($options->getArgs());
75                break;
76            case 'uninstall':
77                $ret = $this->cmdUnInstall($options->getArgs());
78                break;
79            case 'enable':
80                $ret = $this->cmdEnable(true, $options->getArgs());
81                break;
82            case 'disable':
83                $ret = $this->cmdEnable(false, $options->getArgs());
84                break;
85            case 'upgrade':
86                $ret = $this->cmdUpgrade();
87                break;
88            default:
89                echo $options->help();
90                $ret = 0;
91        }
92
93        exit($ret);
94    }
95
96    /**
97     * Upgrade all extensions
98     *
99     * @return int
100     */
101    protected function cmdUpgrade()
102    {
103        /* @var helper_plugin_extension_extension $ext */
104        $ext = $this->loadHelper('extension_extension');
105        $list = $this->getInstalledExtensions();
106
107        $ok = 0;
108        foreach ($list as $extname) {
109            $ext->setExtension($extname);
110            $date = $ext->getInstalledVersion();
111            $avail = $ext->getLastUpdate();
112            if ($avail && $avail > $date) {
113                $ok += $this->cmdInstall([$extname]);
114            }
115        }
116
117        return $ok;
118    }
119
120    /**
121     * Enable or disable one or more extensions
122     *
123     * @param bool $set
124     * @param string[] $extensions
125     * @return int
126     */
127    protected function cmdEnable($set, $extensions)
128    {
129        /* @var helper_plugin_extension_extension $ext */
130        $ext = $this->loadHelper('extension_extension');
131
132        $ok = 0;
133        foreach ($extensions as $extname) {
134            $ext->setExtension($extname);
135            if (!$ext->isInstalled()) {
136                $this->error(sprintf('Extension %s is not installed', $ext->getID()));
137                $ok += 1;
138                continue;
139            }
140
141            if ($set) {
142                $status = $ext->enable();
143                $msg = 'msg_enabled';
144            } else {
145                $status = $ext->disable();
146                $msg = 'msg_disabled';
147            }
148
149            if ($status !== true) {
150                $this->error($status);
151                $ok += 1;
152                continue;
153            } else {
154                $this->success(sprintf($this->getLang($msg), $ext->getID()));
155            }
156        }
157
158        return $ok;
159    }
160
161    /**
162     * Uninstall one or more extensions
163     *
164     * @param string[] $extensions
165     * @return int
166     */
167    protected function cmdUnInstall($extensions)
168    {
169        /* @var helper_plugin_extension_extension $ext */
170        $ext = $this->loadHelper('extension_extension');
171
172        $ok = 0;
173        foreach ($extensions as $extname) {
174            $ext->setExtension($extname);
175            if (!$ext->isInstalled()) {
176                $this->error(sprintf('Extension %s is not installed', $ext->getID()));
177                $ok += 1;
178                continue;
179            }
180
181            $status = $ext->uninstall();
182            if ($status) {
183                $this->success(sprintf($this->getLang('msg_delete_success'), $ext->getID()));
184            } else {
185                $this->error(sprintf($this->getLang('msg_delete_failed'), hsc($ext->getID())));
186                $ok = 1;
187            }
188        }
189
190        return $ok;
191    }
192
193    /**
194     * Install one or more extensions
195     *
196     * @param string[] $extensions
197     * @return int
198     */
199    protected function cmdInstall($extensions)
200    {
201        /* @var helper_plugin_extension_extension $ext */
202        $ext = $this->loadHelper('extension_extension');
203
204        $ok = 0;
205        foreach ($extensions as $extname) {
206            $ext->setExtension($extname);
207
208            if (!$ext->getDownloadURL()) {
209                $ok += 1;
210                $this->error(
211                    sprintf('Could not find download for %s', $ext->getID())
212                );
213                continue;
214            }
215
216            try {
217                $installed = $ext->installOrUpdate();
218                foreach ($installed as $ext => $info) {
219                    $this->success(sprintf(
220                            $this->getLang('msg_' . $info['type'] . '_' . $info['action'] . '_success'),
221                            $info['base'])
222                    );
223                }
224            } catch (Exception $e) {
225                $this->error($e->getMessage());
226                $ok += 1;
227            }
228        }
229        return $ok;
230    }
231
232    /**
233     * Search for an extension
234     *
235     * @param string $query
236     * @param bool $showdetails
237     * @param int $max
238     * @return int
239     * @throws \splitbrain\phpcli\Exception
240     */
241    protected function cmdSearch($query, $showdetails, $max)
242    {
243        /** @var helper_plugin_extension_repository $repository */
244        $repository = $this->loadHelper('extension_repository');
245        $result = $repository->search($query);
246        if ($max) {
247            $result = array_slice($result, 0, $max);
248        }
249
250        $this->listExtensions($result, $showdetails);
251        return 0;
252    }
253
254    /**
255     * @param bool $showdetails
256     * @return int
257     * @throws \splitbrain\phpcli\Exception
258     */
259    protected function cmdList($showdetails)
260    {
261        $list = $this->getInstalledExtensions();
262        $this->listExtensions($list, $showdetails);
263
264        return 0;
265    }
266
267    /**
268     * Get all installed extensions
269     *
270     * @return array
271     */
272    protected function getInstalledExtensions()
273    {
274        /** @var Doku_Plugin_Controller $plugin_controller */
275        global $plugin_controller;
276        $pluginlist = $plugin_controller->getList('', true);
277        $tpllist = glob(DOKU_INC . 'lib/tpl/*', GLOB_ONLYDIR);
278        $tpllist = array_map(function ($path) {
279            return 'template:' . basename($path);
280        }, $tpllist);
281        $list = array_merge($pluginlist, $tpllist);
282        sort($list);
283        return $list;
284    }
285
286    /**
287     * List the given extensions
288     *
289     * @param string[] $list
290     * @param bool $details display details
291     * @throws \splitbrain\phpcli\Exception
292     */
293    protected function listExtensions($list, $details)
294    {
295        /** @var helper_plugin_extension_extension $ext */
296        $ext = $this->loadHelper('extension_extension');
297        $tr = new \splitbrain\phpcli\TableFormatter($this->colors);
298
299
300        foreach ($list as $name) {
301            $ext->setExtension($name);
302
303            $status = '';
304            if ($ext->isInstalled()) {
305                $date = $ext->getInstalledVersion();
306                $avail = $ext->getLastUpdate();
307                $status = 'i';
308                if ($avail && $avail > $date) {
309                    $color = Colors::C_RED;
310                } else {
311                    $color = Colors::C_GREEN;
312                }
313                if ($ext->isGitControlled()) $status = 'g';
314                if ($ext->isBundled()) $status = 'b';
315                if (!$ext->isEnabled()) $status .= 'd';
316            } else {
317                $date = $ext->getLastUpdate();
318                $color = null;
319            }
320
321
322            echo $tr->format(
323                [20, 3, 12, '*'],
324                [
325                    $ext->getID(),
326                    $status,
327                    $date,
328                    strip_tags(sprintf(
329                            $this->getLang('extensionby'),
330                            $ext->getDisplayName(),
331                            $this->colors->wrap($ext->getAuthor(), Colors::C_PURPLE))
332                    )
333                ],
334                [
335                    Colors::C_BROWN,
336                    Colors::C_YELLOW,
337                    $color,
338                    null,
339                ]
340            );
341
342            if (!$details) continue;
343
344            echo $tr->format(
345                [5, '*'],
346                ['', $ext->getDescription()],
347                [null, Colors::C_CYAN]
348            );
349        }
350    }
351}
352