373 lines
11 KiB
PHP
373 lines
11 KiB
PHP
|
<?php
|
||
|
|
||
|
use splitbrain\phpcli\Colors;
|
||
|
|
||
|
/**
|
||
|
* Class cli_plugin_extension
|
||
|
*
|
||
|
* Command Line component for the extension manager
|
||
|
*
|
||
|
* @license GPL2
|
||
|
* @author Andreas Gohr <andi@splitbrain.org>
|
||
|
*/
|
||
|
class cli_plugin_extension extends DokuWiki_CLI_Plugin
|
||
|
{
|
||
|
/** @inheritdoc */
|
||
|
protected function setup(\splitbrain\phpcli\Options $options)
|
||
|
{
|
||
|
// general setup
|
||
|
$options->setHelp(
|
||
|
"Manage plugins and templates for this DokuWiki instance\n\n" .
|
||
|
"Status codes:\n" .
|
||
|
" i - installed\n" .
|
||
|
" b - bundled with DokuWiki\n" .
|
||
|
" g - installed via git\n" .
|
||
|
" d - disabled\n" .
|
||
|
" u - update available\n"
|
||
|
);
|
||
|
|
||
|
// search
|
||
|
$options->registerCommand('search', 'Search for an extension');
|
||
|
$options->registerOption('max', 'Maximum number of results (default 10)', 'm', 'number', 'search');
|
||
|
$options->registerOption('verbose', 'Show detailed extension information', 'v', false, 'search');
|
||
|
$options->registerArgument('query', 'The keyword(s) to search for', true, 'search');
|
||
|
|
||
|
// list
|
||
|
$options->registerCommand('list', 'List installed extensions');
|
||
|
$options->registerOption('verbose', 'Show detailed extension information', 'v', false, 'list');
|
||
|
$options->registerOption('filter', 'Filter by this status', 'f', 'status', 'list');
|
||
|
|
||
|
// upgrade
|
||
|
$options->registerCommand('upgrade', 'Update all installed extensions to their latest versions');
|
||
|
|
||
|
// install
|
||
|
$options->registerCommand('install', 'Install or upgrade extensions');
|
||
|
$options->registerArgument('extensions...', 'One or more extensions to install', true, 'install');
|
||
|
|
||
|
// uninstall
|
||
|
$options->registerCommand('uninstall', 'Uninstall a new extension');
|
||
|
$options->registerArgument('extensions...', 'One or more extensions to install', true, 'uninstall');
|
||
|
|
||
|
// enable
|
||
|
$options->registerCommand('enable', 'Enable installed extensions');
|
||
|
$options->registerArgument('extensions...', 'One or more extensions to enable', true, 'enable');
|
||
|
|
||
|
// disable
|
||
|
$options->registerCommand('disable', 'Disable installed extensions');
|
||
|
$options->registerArgument('extensions...', 'One or more extensions to disable', true, 'disable');
|
||
|
|
||
|
|
||
|
}
|
||
|
|
||
|
/** @inheritdoc */
|
||
|
protected function main(\splitbrain\phpcli\Options $options)
|
||
|
{
|
||
|
/** @var helper_plugin_extension_repository $repo */
|
||
|
$repo = plugin_load('helper', 'extension_repository');
|
||
|
if (!$repo->hasAccess(false)) {
|
||
|
$this->warning('Extension Repository API is not accessible, no remote info available!');
|
||
|
}
|
||
|
|
||
|
switch ($options->getCmd()) {
|
||
|
case 'list':
|
||
|
$ret = $this->cmdList($options->getOpt('verbose'), $options->getOpt('filter', ''));
|
||
|
break;
|
||
|
case 'search':
|
||
|
$ret = $this->cmdSearch(
|
||
|
implode(' ', $options->getArgs()),
|
||
|
$options->getOpt('verbose'),
|
||
|
(int)$options->getOpt('max', 10)
|
||
|
);
|
||
|
break;
|
||
|
case 'install':
|
||
|
$ret = $this->cmdInstall($options->getArgs());
|
||
|
break;
|
||
|
case 'uninstall':
|
||
|
$ret = $this->cmdUnInstall($options->getArgs());
|
||
|
break;
|
||
|
case 'enable':
|
||
|
$ret = $this->cmdEnable(true, $options->getArgs());
|
||
|
break;
|
||
|
case 'disable':
|
||
|
$ret = $this->cmdEnable(false, $options->getArgs());
|
||
|
break;
|
||
|
case 'upgrade':
|
||
|
$ret = $this->cmdUpgrade();
|
||
|
break;
|
||
|
default:
|
||
|
echo $options->help();
|
||
|
$ret = 0;
|
||
|
}
|
||
|
|
||
|
exit($ret);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Upgrade all extensions
|
||
|
*
|
||
|
* @return int
|
||
|
*/
|
||
|
protected function cmdUpgrade()
|
||
|
{
|
||
|
/* @var helper_plugin_extension_extension $ext */
|
||
|
$ext = $this->loadHelper('extension_extension');
|
||
|
$list = $this->getInstalledExtensions();
|
||
|
|
||
|
$ok = 0;
|
||
|
foreach ($list as $extname) {
|
||
|
$ext->setExtension($extname);
|
||
|
$date = $ext->getInstalledVersion();
|
||
|
$avail = $ext->getLastUpdate();
|
||
|
if ($avail && $avail > $date) {
|
||
|
$ok += $this->cmdInstall([$extname]);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return $ok;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Enable or disable one or more extensions
|
||
|
*
|
||
|
* @param bool $set
|
||
|
* @param string[] $extensions
|
||
|
* @return int
|
||
|
*/
|
||
|
protected function cmdEnable($set, $extensions)
|
||
|
{
|
||
|
/* @var helper_plugin_extension_extension $ext */
|
||
|
$ext = $this->loadHelper('extension_extension');
|
||
|
|
||
|
$ok = 0;
|
||
|
foreach ($extensions as $extname) {
|
||
|
$ext->setExtension($extname);
|
||
|
if (!$ext->isInstalled()) {
|
||
|
$this->error(sprintf('Extension %s is not installed', $ext->getID()));
|
||
|
$ok += 1;
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
if ($set) {
|
||
|
$status = $ext->enable();
|
||
|
$msg = 'msg_enabled';
|
||
|
} else {
|
||
|
$status = $ext->disable();
|
||
|
$msg = 'msg_disabled';
|
||
|
}
|
||
|
|
||
|
if ($status !== true) {
|
||
|
$this->error($status);
|
||
|
$ok += 1;
|
||
|
continue;
|
||
|
} else {
|
||
|
$this->success(sprintf($this->getLang($msg), $ext->getID()));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return $ok;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Uninstall one or more extensions
|
||
|
*
|
||
|
* @param string[] $extensions
|
||
|
* @return int
|
||
|
*/
|
||
|
protected function cmdUnInstall($extensions)
|
||
|
{
|
||
|
/* @var helper_plugin_extension_extension $ext */
|
||
|
$ext = $this->loadHelper('extension_extension');
|
||
|
|
||
|
$ok = 0;
|
||
|
foreach ($extensions as $extname) {
|
||
|
$ext->setExtension($extname);
|
||
|
if (!$ext->isInstalled()) {
|
||
|
$this->error(sprintf('Extension %s is not installed', $ext->getID()));
|
||
|
$ok += 1;
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
$status = $ext->uninstall();
|
||
|
if ($status) {
|
||
|
$this->success(sprintf($this->getLang('msg_delete_success'), $ext->getID()));
|
||
|
} else {
|
||
|
$this->error(sprintf($this->getLang('msg_delete_failed'), hsc($ext->getID())));
|
||
|
$ok = 1;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return $ok;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Install one or more extensions
|
||
|
*
|
||
|
* @param string[] $extensions
|
||
|
* @return int
|
||
|
*/
|
||
|
protected function cmdInstall($extensions)
|
||
|
{
|
||
|
/* @var helper_plugin_extension_extension $ext */
|
||
|
$ext = $this->loadHelper('extension_extension');
|
||
|
|
||
|
$ok = 0;
|
||
|
foreach ($extensions as $extname) {
|
||
|
$ext->setExtension($extname);
|
||
|
|
||
|
if (!$ext->getDownloadURL()) {
|
||
|
$ok += 1;
|
||
|
$this->error(
|
||
|
sprintf('Could not find download for %s', $ext->getID())
|
||
|
);
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
try {
|
||
|
$installed = $ext->installOrUpdate();
|
||
|
foreach ($installed as $name => $info) {
|
||
|
$this->success(sprintf(
|
||
|
$this->getLang('msg_' . $info['type'] . '_' . $info['action'] . '_success'),
|
||
|
$info['base'])
|
||
|
);
|
||
|
}
|
||
|
} catch (Exception $e) {
|
||
|
$this->error($e->getMessage());
|
||
|
$ok += 1;
|
||
|
}
|
||
|
}
|
||
|
return $ok;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Search for an extension
|
||
|
*
|
||
|
* @param string $query
|
||
|
* @param bool $showdetails
|
||
|
* @param int $max
|
||
|
* @return int
|
||
|
* @throws \splitbrain\phpcli\Exception
|
||
|
*/
|
||
|
protected function cmdSearch($query, $showdetails, $max)
|
||
|
{
|
||
|
/** @var helper_plugin_extension_repository $repository */
|
||
|
$repository = $this->loadHelper('extension_repository');
|
||
|
$result = $repository->search($query);
|
||
|
if ($max) {
|
||
|
$result = array_slice($result, 0, $max);
|
||
|
}
|
||
|
|
||
|
$this->listExtensions($result, $showdetails);
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @param bool $showdetails
|
||
|
* @param string $filter
|
||
|
* @return int
|
||
|
* @throws \splitbrain\phpcli\Exception
|
||
|
*/
|
||
|
protected function cmdList($showdetails, $filter)
|
||
|
{
|
||
|
$list = $this->getInstalledExtensions();
|
||
|
$this->listExtensions($list, $showdetails, $filter);
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Get all installed extensions
|
||
|
*
|
||
|
* @return array
|
||
|
*/
|
||
|
protected function getInstalledExtensions()
|
||
|
{
|
||
|
/** @var Doku_Plugin_Controller $plugin_controller */
|
||
|
global $plugin_controller;
|
||
|
$pluginlist = $plugin_controller->getList('', true);
|
||
|
$tpllist = glob(DOKU_INC . 'lib/tpl/*', GLOB_ONLYDIR);
|
||
|
$tpllist = array_map(function ($path) {
|
||
|
return 'template:' . basename($path);
|
||
|
}, $tpllist);
|
||
|
$list = array_merge($pluginlist, $tpllist);
|
||
|
sort($list);
|
||
|
return $list;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* List the given extensions
|
||
|
*
|
||
|
* @param string[] $list
|
||
|
* @param bool $details display details
|
||
|
* @param string $filter filter for this status
|
||
|
* @throws \splitbrain\phpcli\Exception
|
||
|
*/
|
||
|
protected function listExtensions($list, $details, $filter = '')
|
||
|
{
|
||
|
/** @var helper_plugin_extension_extension $ext */
|
||
|
$ext = $this->loadHelper('extension_extension');
|
||
|
$tr = new \splitbrain\phpcli\TableFormatter($this->colors);
|
||
|
|
||
|
|
||
|
foreach ($list as $name) {
|
||
|
$ext->setExtension($name);
|
||
|
|
||
|
$status = '';
|
||
|
if ($ext->isInstalled()) {
|
||
|
$date = $ext->getInstalledVersion();
|
||
|
$avail = $ext->getLastUpdate();
|
||
|
$status = 'i';
|
||
|
if ($avail && $avail > $date) {
|
||
|
$vcolor = Colors::C_RED;
|
||
|
$status .= 'u';
|
||
|
} else {
|
||
|
$vcolor = Colors::C_GREEN;
|
||
|
}
|
||
|
if ($ext->isGitControlled()) $status = 'g';
|
||
|
if ($ext->isBundled()) $status = 'b';
|
||
|
if ($ext->isEnabled()) {
|
||
|
$ecolor = Colors::C_BROWN;
|
||
|
} else {
|
||
|
$ecolor = Colors::C_DARKGRAY;
|
||
|
$status .= 'd';
|
||
|
}
|
||
|
} else {
|
||
|
$ecolor = null;
|
||
|
$date = $ext->getLastUpdate();
|
||
|
$vcolor = null;
|
||
|
}
|
||
|
|
||
|
if ($filter && strpos($status, $filter) === false) {
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
echo $tr->format(
|
||
|
[20, 3, 12, '*'],
|
||
|
[
|
||
|
$ext->getID(),
|
||
|
$status,
|
||
|
$date,
|
||
|
strip_tags(sprintf(
|
||
|
$this->getLang('extensionby'),
|
||
|
$ext->getDisplayName(),
|
||
|
$this->colors->wrap($ext->getAuthor(), Colors::C_PURPLE))
|
||
|
)
|
||
|
],
|
||
|
[
|
||
|
$ecolor,
|
||
|
Colors::C_YELLOW,
|
||
|
$vcolor,
|
||
|
null,
|
||
|
]
|
||
|
);
|
||
|
|
||
|
if (!$details) continue;
|
||
|
|
||
|
echo $tr->format(
|
||
|
[5, '*'],
|
||
|
['', $ext->getDescription()],
|
||
|
[null, Colors::C_CYAN]
|
||
|
);
|
||
|
}
|
||
|
}
|
||
|
}
|