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