diff options
author | Andreas Gohr <andi@splitbrain.org> | 2024-04-17 14:49:08 +0200 |
---|---|---|
committer | Andreas Gohr <andi@splitbrain.org> | 2024-12-04 10:51:13 +0100 |
commit | 160d3688fe2b70ebe88d464cba3417440127a155 (patch) | |
tree | 90b51f13067f59958474dd6e22cfde4bf478b3f0 /lib/plugins/extension | |
parent | 25d28a0105a16bf32f2784e80b3cf268074c8c8a (diff) | |
download | dokuwiki-160d3688fe2b70ebe88d464cba3417440127a155.tar.gz dokuwiki-160d3688fe2b70ebe88d464cba3417440127a155.zip |
Extension Manager: CLI now should completely use new classes
Diffstat (limited to 'lib/plugins/extension')
-rw-r--r-- | lib/plugins/extension/Extension.php | 40 | ||||
-rw-r--r-- | lib/plugins/extension/Installer.php | 35 | ||||
-rw-r--r-- | lib/plugins/extension/Manager.php | 18 | ||||
-rw-r--r-- | lib/plugins/extension/cli.php | 136 | ||||
-rw-r--r-- | lib/plugins/extension/lang/en/lang.php | 7 |
5 files changed, 138 insertions, 98 deletions
diff --git a/lib/plugins/extension/Extension.php b/lib/plugins/extension/Extension.php index baecce194..b2dd9abbd 100644 --- a/lib/plugins/extension/Extension.php +++ b/lib/plugins/extension/Extension.php @@ -406,6 +406,31 @@ class Extension return $plugin_controller->isEnabled($this->base); } + /** + * Has the download URL changed since the last download? + * + * @return bool + */ + public function hasChangedURL() + { + $last = $this->getManager()->getDownloadUrl(); + if(!$last) return false; + return $last !== $this->getDownloadURL(); + } + + /** + * Is an update available for this extension? + * + * @return bool + */ + public function updateAvailable() + { + if($this->isBundled()) return false; // bundled extensions are never updated + $self = $this->getInstalledVersion(); + $remote = $this->getLastUpdate(); + return $self < $remote; + } + // endregion // region Remote Info @@ -544,10 +569,7 @@ class Extension public function installOrUpdate() { $installer = new Installer(true); - $installer->installFromUrl( - $this->getURL(), - $this->getBase(), - ); + $installer->installExtension($this); } /** @@ -568,8 +590,8 @@ class Extension public function enable() { if ($this->isTemplate()) throw new Exception('notimplemented'); - if (!$this->isInstalled()) throw new Exception('notinstalled'); - if ($this->isEnabled()) throw new Exception('alreadyenabled'); + if (!$this->isInstalled()) throw new Exception('error_notinstalled', [$this->getId()]); + if ($this->isEnabled()) throw new Exception('error_alreadyenabled', [$this->getId()]); /* @var PluginController $plugin_controller */ global $plugin_controller; @@ -587,9 +609,9 @@ class Extension public function disable() { if ($this->isTemplate()) throw new Exception('notimplemented'); - if (!$this->isInstalled()) throw new Exception('notinstalled'); - if (!$this->isEnabled()) throw new Exception('alreadydisabled'); - if ($this->isProtected()) throw new Exception('error_disable_protected'); + if (!$this->isInstalled()) throw new Exception('error_notinstalled', [$this->getId()]); + if (!$this->isEnabled()) throw new Exception('error_alreadydisabled', [$this->getId()]); + if ($this->isProtected()) throw new Exception('error_disable_protected', [$this->getId()]); /* @var PluginController $plugin_controller */ global $plugin_controller; diff --git a/lib/plugins/extension/Installer.php b/lib/plugins/extension/Installer.php index 214f53bf0..75e836367 100644 --- a/lib/plugins/extension/Installer.php +++ b/lib/plugins/extension/Installer.php @@ -36,7 +36,6 @@ class Installer public const STATUS_SKIPPED = 'skipped'; public const STATUS_UPDATED = 'updated'; public const STATUS_INSTALLED = 'installed'; - public const STATUS_DELETED = 'deleted'; /** @@ -63,9 +62,9 @@ class Installer } /** - * Install an extension + * Install an extension by ID * - * This will simply call installFromUrl() with the URL from the extension + * This will simply call installExtension after constructing an extension from the ID * * The $skipInstalled parameter should only be used when installing dependencies * @@ -73,11 +72,25 @@ class Installer * @param bool $skipInstalled Ignore the overwrite setting and skip installed extensions * @throws Exception */ - public function installFromId($id, $skipInstalled = false) { + public function installFromId($id, $skipInstalled = false) + { $extension = Extension::createFromId($id); - if($skipInstalled && $extension->isInstalled()) return; + if ($skipInstalled && $extension->isInstalled()) return; + $this->installExtension($extension); + } + + /** + * Install an extension + * + * This will simply call installFromUrl() with the URL from the extension + * + * @param Extension $extension + * @throws Exception + */ + public function installExtension(Extension $extension) + { $url = $extension->getDownloadURL(); - if(!$url) { + if (!$url) { throw new Exception('error_nourl', [$extension->getId()]); } $this->installFromUrl($url); @@ -142,7 +155,7 @@ class Installer foreach ($extensions as $extension) { // check installation status if ($extension->isInstalled()) { - if(!$this->overwrite) { + if (!$this->overwrite) { $this->processed[$extension->getId()] = self::STATUS_SKIPPED; continue; } @@ -184,7 +197,11 @@ class Installer { // FIXME check if dependencies are still needed - if($extension->isProtected()) { + if (!$extension->isInstalled()) { + throw new Exception('error_notinstalled', [$extension->getId()]); + } + + if ($extension->isProtected()) { throw new Exception('error_uninstall_protected', [$extension->getId()]); } @@ -284,7 +301,7 @@ class Installer } /** - * Get the list of processed extensions and the processing status + * Get the list of processed extensions and their status during an installation run * * @return array id => status */ diff --git a/lib/plugins/extension/Manager.php b/lib/plugins/extension/Manager.php index b99b082b4..a4e31905a 100644 --- a/lib/plugins/extension/Manager.php +++ b/lib/plugins/extension/Manager.php @@ -3,7 +3,7 @@ namespace dokuwiki\plugin\extension; /** - * Manages info about installation/deinstallation of extensions + * Manages info about installation of extensions */ class Manager { @@ -54,7 +54,6 @@ class Manager } - /** * Reads the manager.dat file and fills the managerInfo array */ @@ -75,4 +74,19 @@ class Manager return $data; } + + public function getLastUpdate() + { + return $this->data['updated'] ?? $this->data['installed'] ?? ''; + } + + public function getDownloadUrl() + { + return $this->data['downloadurl'] ?? ''; + } + + public function getInstallDate() + { + return $this->data['installed'] ?? ''; + } } diff --git a/lib/plugins/extension/cli.php b/lib/plugins/extension/cli.php index f2d44b553..01bc3b1c8 100644 --- a/lib/plugins/extension/cli.php +++ b/lib/plugins/extension/cli.php @@ -29,14 +29,11 @@ class cli_plugin_extension extends CLIPlugin $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" . - " ☠ - security issue\n" . - " ⚠ - security warning\n" . - " ▽ - update message\n" + " i - installed ☠ - security issue\n" . + " b - bundled with DokuWiki ⚠ - security warning\n" . + " g - installed via git ↯ - update message\n" . + " d - disabled ⮎ - URL changed\n" . + " u - update available\n" ); // search @@ -126,21 +123,12 @@ class cli_plugin_extension extends CLIPlugin */ 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 && !$ext->isBundled()) { - $ok += $this->cmdInstall([$extname]); - } + $local = new Local(); + $extensions = []; + foreach ($local->getExtensions() as $ext) { + if($ext->updateAvailable()) $extensions[] = $ext->getID(); } - - return $ok; + return $this->cmdInstall($extensions); } /** @@ -152,32 +140,23 @@ class cli_plugin_extension extends CLIPlugin */ 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; - continue; - } - - if ($set) { - $status = $ext->enable(); - $msg = 'msg_enabled'; - } else { - $status = $ext->disable(); - $msg = 'msg_disabled'; - } + $ext = Extension::createFromId($extname); - if ($status !== true) { - $this->error($status); + try { + if ($set) { + $ext->enable(); + $msg = 'msg_enabled'; + } else { + $ext->disable(); + $msg = 'msg_disabled'; + } + $this->success(sprintf($this->getLang($msg), $ext->getID())); + } catch (ExtensionException $e) { + $this->error($e->getMessage()); ++$ok; continue; - } else { - $this->success(sprintf($this->getLang($msg), $ext->getID())); } } @@ -192,27 +171,21 @@ class cli_plugin_extension extends CLIPlugin */ protected function cmdUnInstall($extensions) { - /* @var helper_plugin_extension_extension $ext */ - $ext = $this->loadHelper('extension_extension'); + $installer = new Installer(); $ok = 0; foreach ($extensions as $extname) { - $ext->setExtension($extname); - if (!$ext->isInstalled()) { - $this->error(sprintf('Extension %s is not installed', $ext->getID())); - ++$ok; - continue; - } + $ext = Extension::createFromId($extname); - $status = $ext->uninstall(); - if ($status) { + try { + $installer->uninstall($ext); $this->success(sprintf($this->getLang('msg_delete_success'), $ext->getID())); - } else { - $this->error(sprintf($this->getLang('msg_delete_failed'), hsc($ext->getID()))); - $ok = 1; + } catch (ExtensionException $e) { + $this->debug($e->getTraceAsString()); + $this->error($e->getMessage()); + $ok++; // error code is number of failed uninstalls } } - return $ok; } @@ -224,11 +197,10 @@ class cli_plugin_extension extends CLIPlugin */ protected function cmdInstall($extensions) { - - $installer = new Installer(true); - $ok = 0; foreach ($extensions as $extname) { + $installer = new Installer(true); + try { if (preg_match("/^https?:\/\//i", $extname)) { $installer->installFromURL($extname, true); @@ -240,18 +212,17 @@ class cli_plugin_extension extends CLIPlugin $this->error($e->getMessage()); $ok++; // error code is number of failed installs } - } - $processed = $installer->getProcessed(); - foreach($processed as $id => $status){ - if($status == Installer::STATUS_INSTALLED) { - $this->success(sprintf($this->getLang('msg_install_success'), $id)); - } else if($status == Installer::STATUS_UPDATED) { - $this->success(sprintf($this->getLang('msg_update_success'), $id)); + $processed = $installer->getProcessed(); + foreach($processed as $id => $status){ + if($status == Installer::STATUS_INSTALLED) { + $this->success(sprintf($this->getLang('msg_install_success'), $id)); + } else if($status == Installer::STATUS_UPDATED) { + $this->success(sprintf($this->getLang('msg_update_success'), $id)); + } } } - return $ok; } @@ -295,6 +266,7 @@ class cli_plugin_extension extends CLIPlugin * @param bool $details display details * @param string $filter filter for this status * @throws Exception + * @todo break into smaller methods */ protected function listExtensions($list, $details, $filter = '') { @@ -337,10 +309,11 @@ class cli_plugin_extension extends CLIPlugin if ($ext->getSecurityIssue()) $status .= '☠'; if ($ext->getSecurityWarning()) $status .= '⚠'; - if ($ext->getUpdateMessage()) $status .= '▽'; + if ($ext->getUpdateMessage()) $status .= '↯'; + if ($ext->hasChangedURL()) $status .= '⮎'; echo $tr->format( - [20, 3, 12, '*'], + [20, 5, 12, '*'], [ $ext->getID(), $status, @@ -363,31 +336,44 @@ class cli_plugin_extension extends CLIPlugin if (!$details) continue; echo $tr->format( - [5, '*'], + [7, '*'], ['', $ext->getDescription()], [null, Colors::C_CYAN] ); if ($ext->getSecurityWarning()) { echo $tr->format( - [5, '*'], + [7, '*'], ['', '⚠ ' . $ext->getSecurityWarning()], [null, Colors::C_YELLOW] ); } if ($ext->getSecurityIssue()) { echo $tr->format( - [5, '*'], + [7, '*'], ['', '☠ ' . $ext->getSecurityIssue()], [null, Colors::C_LIGHTRED] ); } if ($ext->getUpdateMessage()) { echo $tr->format( - [5, '*'], - ['', '▽ ' . $ext->getUpdateMessage()], + [7, '*'], + ['', '↯ ' . $ext->getUpdateMessage()], [null, Colors::C_LIGHTBLUE] ); } + if ($ext->hasChangedURL()) { + $msg = $this->getLang('url_change'); + $msg = str_replace('<br>',"\n", $msg); + $msg = str_replace('<br/>',"\n", $msg); + $msg = str_replace('<br />',"\n", $msg); + $msg = strip_tags($msg); + + echo $tr->format( + [7, '*'], + ['', '⮎ ' . sprintf($msg, $ext->getDownloadURL(), $ext->getManager()->getDownloadUrl())], + [null, Colors::C_BLUE] + ); + } } } } diff --git a/lib/plugins/extension/lang/en/lang.php b/lib/plugins/extension/lang/en/lang.php index 46af03d43..75e391e22 100644 --- a/lib/plugins/extension/lang/en/lang.php +++ b/lib/plugins/extension/lang/en/lang.php @@ -14,9 +14,6 @@ $lang['tab_search'] = 'Search and Install'; $lang['tab_install'] = 'Manual Install'; $lang['notimplemented'] = 'This feature hasn\'t been implemented yet'; -$lang['notinstalled'] = 'This extension is not installed'; -$lang['alreadyenabled'] = 'This extension has already been enabled'; -$lang['alreadydisabled'] = 'This extension has already been disabled'; $lang['pluginlistsaveerror'] = 'There was an error saving the plugin list'; $lang['unknownauthor'] = 'Unknown author'; $lang['unknownversion'] = 'Unknown version'; @@ -98,6 +95,10 @@ $lang['error_archive_extract'] = 'Could not extract archive %s: %s'; $lang['error_uninstall_protected'] = 'Extension %s is protected and cannot be uninstalled'; $lang['error_disable_protected'] = 'Extension %s is protected and cannot be disabled'; $lang['error_nourl'] = 'No download URL could be found for extension %s'; +$lang['error_notinstalled'] = 'Extension %s is not installed'; +$lang['error_alreadyenabled'] = 'Extension %s has already been enabled'; +$lang['error_alreadydisabled'] = 'Extension %s has already been disabled'; + $lang['noperms'] = 'Extension directory is not writable'; $lang['notplperms'] = 'Template directory is not writable'; |