From d49556513b7ae8060c6451077d2d05d6e7397b13 Mon Sep 17 00:00:00 2001 From: Alexander Ebert Date: Thu, 13 Jul 2017 14:11:55 +0200 Subject: [PATCH] Added 'sync all', improved behavior, fixes See #2331 --- com.woltlab.wcf/option.xml | 8 +- .../acp/templates/devtoolsProjectSync.tpl | 164 +++++++-------- .../Core/Acp/Ui/Devtools/Project/Sync.js | 191 ++++++++++++++++++ .../files/js/WoltLabSuite/Core/Ajax.js | 20 +- .../js/WoltLabSuite/Core/Ajax/Request.js | 57 +++--- .../files/js/WoltLabSuite/Core/Ui/Dialog.js | 2 +- .../DevtoolsProjectSyncPage.class.php} | 6 +- .../project/DevtoolsProject.class.php | 27 +++ .../PackageInstallationPluginAction.class.php | 10 +- .../package/DevtoolsInstaller.class.php | 36 ++++ .../package/DevtoolsPackageArchive.class.php | 23 ++- .../devtools/package/DevtoolsTar.class.php | 70 ++++++- ...olsPackageInstallationDispatcher.class.php | 30 +++ ...DevtoolsPackageInstallationQueue.class.php | 12 ++ .../system/devtools/pip/DevtoolsPip.class.php | 128 +++++++++++- ...mpotentPackageInstallationPlugin.class.php | 13 +- ...roviderPackageInstallationPlugin.class.php | 7 + ...emplatePackageInstallationPlugin.class.php | 7 + ...actMenuPackageInstallationPlugin.class.php | 7 + ...tOptionPackageInstallationPlugin.class.php | 7 + .../BBCodePackageInstallationPlugin.class.php | 7 + .../BoxPackageInstallationPlugin.class.php | 7 + ...dActionPackageInstallationPlugin.class.php | 7 + ...eObjectPackageInstallationPlugin.class.php | 7 + ...CronjobPackageInstallationPlugin.class.php | 7 + ...istenerPackageInstallationPlugin.class.php | 8 + .../FilePackageInstallationPlugin.class.php | 7 + ...anguagePackageInstallationPlugin.class.php | 7 + ...enuItemPackageInstallationPlugin.class.php | 7 + .../MenuPackageInstallationPlugin.class.php | 7 + ...initionPackageInstallationPlugin.class.php | 7 + ...ectTypePackageInstallationPlugin.class.php | 7 + .../PIPPackageInstallationPlugin.class.php | 7 + .../PagePackageInstallationPlugin.class.php | 7 + .../SmileyPackageInstallationPlugin.class.php | 7 + ...istenerPackageInstallationPlugin.class.php | 7 + ...emplatePackageInstallationPlugin.class.php | 7 + ...onEventPackageInstallationPlugin.class.php | 8 + ...ileMenuPackageInstallationPlugin.class.php | 7 + .../lib/system/setup/Installer.class.php | 12 +- wcfsetup/install/lang/de.xml | 8 +- wcfsetup/install/lang/en.xml | 27 +++ 42 files changed, 865 insertions(+), 142 deletions(-) create mode 100644 wcfsetup/install/files/js/WoltLabSuite/Core/Acp/Ui/Devtools/Project/Sync.js rename wcfsetup/install/files/lib/acp/{form/DevtoolsProjectSyncForm.class.php => page/DevtoolsProjectSyncPage.class.php} (91%) create mode 100644 wcfsetup/install/files/lib/system/devtools/package/DevtoolsInstaller.class.php diff --git a/com.woltlab.wcf/option.xml b/com.woltlab.wcf/option.xml index a3aaf39649..ba97bd1150 100644 --- a/com.woltlab.wcf/option.xml +++ b/com.woltlab.wcf/option.xml @@ -21,7 +21,7 @@ module - + module @@ -408,17 +408,17 @@ diff --git a/wcfsetup/install/files/acp/templates/devtoolsProjectSync.tpl b/wcfsetup/install/files/acp/templates/devtoolsProjectSync.tpl index 441289be05..e7750fe0ef 100644 --- a/wcfsetup/install/files/acp/templates/devtoolsProjectSync.tpl +++ b/wcfsetup/install/files/acp/templates/devtoolsProjectSync.tpl @@ -20,98 +20,68 @@ {if $object->validate() === ''}

{lang}wcf.acp.devtools.pip.notice{/lang}

-
-
-
-
-
- - {lang}wcf.acp.devtools.pip.showOnlyMatches.description{/lang} -
-
-
-
- - - - - - - - - - - {foreach from=$object->getPips() item=pip} - {assign var=_isSupported value=$pip->isSupported()} - {assign var=_targets value=$pip->getTargets($object)} - - - - {if $_isSupported} - - +
+
+
+
+ + {lang}wcf.acp.devtools.pip.showOnlyMatches.description{/lang} +
+
+
+
+
{lang}wcf.acp.devtools.pip.pluginName{/lang}{lang}wcf.acp.devtools.pip.defaultFilename{/lang}{lang}wcf.acp.devtools.pip.target{/lang}
{$pip->pluginName}{$pip->getDefaultFilename()} - {hascontent} -
    - {content} - {foreach from=$_targets item=target} -
  • - {/foreach} - {/content} -
- {hascontentelse} - {lang}wcf.acp.devtools.pip.target.noMatches{/lang} - {/hascontent} -
+ + + + + + + + + + {foreach from=$object->getPips() item=pip} + {assign var=_isSupported value=$pip->isSupported()} + {assign var=_targets value=$pip->getTargets($object)} + {assign var=_targetCount value=$_targets|count} + + + + {if $_isSupported} + + {if $_targetCount} + + {else} - + {/if} - - {/foreach} - -
{lang}wcf.acp.devtools.pip.pluginName{/lang}{lang}wcf.acp.devtools.pip.defaultFilename{/lang}{lang}wcf.acp.devtools.pip.target{/lang}
{$pip->pluginName}{$pip->getEffectiveDefaultFilename()}{lang}wcf.acp.devtools.sync.status.idle{/lang}{$pip->getFirstError()} + {lang}wcf.acp.devtools.pip.target.noMatches{/lang} +
-
- - {event name='sections'} - -
- - {@SECURITY_TOKEN_INPUT_TAG} -
-
+ {else} + {$pip->getFirstError()} + {/if} + + {if $_targetCount} + {section name=i loop=$_targets start=1} + + + {lang}wcf.acp.devtools.sync.status.idle{/lang} + + {/section} + {/if} + {/foreach} + + + @@ -119,6 +89,26 @@ #syncPipMatches.jsShowOnlyMatches tbody > tr:not(.jsHasPipTargets) { display: none; } + + #syncPipMatches > table { + /*table-layout: fixed;*/ + } + + #syncPipMatches td:first-child { + width: 300px; + } + + #syncPipMatches td.pipDefaultFilename { + width: 300px; + } + + #syncPipMatches td:last-child { + width: auto; + } + + .syncStatusContainer { + overflow: hidden; + } {else}

{$object->validate()}

diff --git a/wcfsetup/install/files/js/WoltLabSuite/Core/Acp/Ui/Devtools/Project/Sync.js b/wcfsetup/install/files/js/WoltLabSuite/Core/Acp/Ui/Devtools/Project/Sync.js new file mode 100644 index 0000000000..41c6ae1edb --- /dev/null +++ b/wcfsetup/install/files/js/WoltLabSuite/Core/Acp/Ui/Devtools/Project/Sync.js @@ -0,0 +1,191 @@ +define(['Ajax', 'Dictionary', 'Language', 'Ui/Dialog'], function (Ajax, Dictionary, Language, UiDialog) { + "use strict"; + + var _buttons = new Dictionary(); + var _buttonStatus = new Dictionary(); + var _buttonSyncAll = null; + var _container = elById('syncPipMatches'); + var _pips = []; + var _projectId = 0; + var _queue = []; + + return { + init: function (projectId) { + _projectId = projectId; + + + elById('syncShowOnlyMatches').addEventListener('change', function() { + _container.classList.toggle('jsShowOnlyMatches'); + }); + + var knownPips = [], tmpPips = []; + elBySelAll('.jsHasPipTargets:not(.jsSkipTargetDetection)', _container, (function (pip) { + var pluginName = elData(pip, 'plugin-name'); + var targets = []; + + elBySelAll('.jsHasPipTargets[data-plugin-name="' + pluginName + '"] .jsInvokePip', _container, (function(button) { + var target = elData(button, 'target'); + targets.push(target); + + button.addEventListener(WCF_CLICK_EVENT, (function(event) { + event.preventDefault(); + + if (_queue.length > 0) return; + + this._sync(pluginName, target); + }).bind(this)); + + _buttons.set(pluginName + '-' + target, button); + _buttonStatus.set(pluginName + '-' + target, elBySel('.jsHasPipTargets[data-plugin-name="' + pluginName + '"] .jsInvokePipResult[data-target="' + target + '"]', _container)); + }).bind(this)); + + var data = { + dependencies: JSON.parse(elData(pip, 'sync-dependencies')), + pluginName: pluginName, + targets: targets + }; + + if (data.dependencies.length > 0) { + tmpPips.push(data); + } + else { + _pips.push(data); + knownPips.push(pluginName); + } + }).bind(this)); + + var resolvedDependency = false; + while (tmpPips.length > 0) { + resolvedDependency = false; + + var openDependencies, item, length = tmpPips.length; + for (var i = 0; i < length; i++) { + item = tmpPips[i]; + + openDependencies = item.dependencies.filter(function (dependency) { + return (knownPips.indexOf(dependency) === -1); + }); + + if (openDependencies.length === 0) { + knownPips.push(item.pluginName); + _pips.push(item); + tmpPips.splice(i, 1); + + resolvedDependency = true; + break; + } + } + + if (!resolvedDependency) { + // We could not resolve any dependency, either because there is no more pip + // in `tmpPips` or we're facing a circular dependency. In case there are items + // left, we simply append them to the end and hope for the operation to + // complete anyway, despite unmatched dependencies. + tmpPips.forEach(function(pip) { + window.console.warn('Unable to resolve dependencies for', pip); + + _pips.push(pip); + }); + + break; + } + } + + var syncAll = elCreate('li'); + syncAll.innerHTML = ' ' + Language.get('wcf.acp.devtools.sync.syncAll') + ''; + _buttonSyncAll = syncAll.children[0]; + _buttonSyncAll.addEventListener(WCF_CLICK_EVENT, this._syncAll.bind(this)); + + var list = elBySel('.contentHeaderNavigation > ul'); + list.insertBefore(syncAll, list.firstElementChild); + }, + + _sync: function (pluginName, target) { + _buttons.get(pluginName + '-' + target).disabled = true; + _buttonStatus.get(pluginName + '-' + target).innerHTML = ''; + + Ajax.api(this, { + parameters: { + pluginName: pluginName, + target: target + } + }); + }, + + _syncAll: function (event) { + event.preventDefault(); + + if (_buttonSyncAll.classList.contains('disabled')) { + return; + } + + _buttonSyncAll.classList.add('disabled'); + + _queue = []; + _pips.forEach(function(pip) { + pip.targets.forEach(function (target) { + _queue.push([pip.pluginName, target]); + }); + }); + this._syncNext(); + }, + + _syncNext: function () { + if (_queue.length === 0) { + _buttonSyncAll.classList.remove('disabled'); + + // TODO: do stuff + return; + } + + var next = _queue.shift(); + this._sync(next[0], next[1]); + }, + + _ajaxSuccess: function(data) { + _buttons.get(data.returnValues.pluginName + '-' + data.returnValues.target).disabled = false; + _buttonStatus.get(data.returnValues.pluginName + '-' + data.returnValues.target).innerHTML = data.returnValues.timeElapsed; + + this._syncNext(); + }, + + _ajaxFailure: function (data, responseText, xhr, requestData) { + _buttons.get(requestData.parameters.pluginName + '-' + requestData.parameters.target).disabled = false; + + var buttonStatus = _buttonStatus.get(requestData.parameters.pluginName + '-' + requestData.parameters.target); + buttonStatus.innerHTML = '' + Language.get('wcf.acp.devtools.sync.status.failure') + ''; + buttonStatus.children[0].addEventListener(WCF_CLICK_EVENT, (function (event) { + event.preventDefault(); + + UiDialog.open( + this, + Ajax.getRequestObject(this).getErrorHtml(data, xhr) + ); + }).bind(this)); + + _buttonSyncAll.classList.remove('disabled'); + }, + + _ajaxSetup: function () { + return { + data: { + actionName: 'invoke', + className: 'wcf\\data\\package\\installation\\plugin\\PackageInstallationPluginAction', + parameters: { + projectID: _projectId + } + } + } + }, + + _dialogSetup: function() { + return { + id: 'devtoolsProjectSyncPipError', + options: { + title: Language.get('wcf.global.error.title') + }, + source: null + } + } + }; +}); \ No newline at end of file diff --git a/wcfsetup/install/files/js/WoltLabSuite/Core/Ajax.js b/wcfsetup/install/files/js/WoltLabSuite/Core/Ajax.js index 5a8398df5d..15a4947e9b 100644 --- a/wcfsetup/install/files/js/WoltLabSuite/Core/Ajax.js +++ b/wcfsetup/install/files/js/WoltLabSuite/Core/Ajax.js @@ -14,7 +14,7 @@ define(['AjaxRequest', 'Core', 'ObjectMap'], function(AjaxRequest, Core, ObjectM /** * @exports WoltLabSuite/Core/Ajax */ - var Ajax = { + return { /** * Shorthand function to perform a request against the WCF-API with overrides * for success and failure callbacks. @@ -91,9 +91,21 @@ define(['AjaxRequest', 'Core', 'ObjectMap'], function(AjaxRequest, Core, ObjectM } var request = new AjaxRequest(options); - request.sendRequest(); + request.sendRequest(false); + }, + + /** + * Returns the request object used for an earlier call to `api()`. + * + * @param {Object} callbackObject callback object + * @return {AjaxRequest} + */ + getRequestObject: function(callbackObject) { + if (!_requests.has(callbackObject)) { + throw new Error('Expected a previously used callback object, provided object is unknown.'); + } + + return _requests.get(callbackObject); } }; - - return Ajax; }); diff --git a/wcfsetup/install/files/js/WoltLabSuite/Core/Ajax/Request.js b/wcfsetup/install/files/js/WoltLabSuite/Core/Ajax/Request.js index 9e5a23e4de..ef21f39f39 100644 --- a/wcfsetup/install/files/js/WoltLabSuite/Core/Ajax/Request.js +++ b/wcfsetup/install/files/js/WoltLabSuite/Core/Ajax/Request.js @@ -277,29 +277,7 @@ define(['Core', 'Language', 'Dom/ChangeListener', 'Dom/Util', 'Ui/Dialog', 'Wolt } if (options.ignoreError !== true && showError !== false) { - var details = ''; - var message = ''; - - if (data !== null) { - if (data.stacktrace) details = '

Stacktrace:

' + data.stacktrace + '

'; - else if (data.exceptionID) details = '

Exception ID: ' + data.exceptionID + '

'; - - message = data.message; - - data.previous.forEach(function(previous) { - details += '

' + previous.message + '

'; - details += '

Stacktrace

' + previous.stacktrace + '

'; - }); - } - else { - message = xhr.responseText; - } - - if (!message || message === 'undefined') { - return; - } - - var html = '

' + message + '

' + details + '
'; + var html = this.getErrorHtml(data, xhr); if (UiDialog === undefined) UiDialog = require('Ui/Dialog'); UiDialog.openStatic(DomUtil.getUniqueId(), html, { @@ -310,6 +288,39 @@ define(['Core', 'Language', 'Dom/ChangeListener', 'Dom/Util', 'Ui/Dialog', 'Wolt this._finalize(options); }, + /** + * Returns the inner HTML for an error/exception display. + * + * @param {Object} data + * @param {XMLHttpRequest} xhr + * @return {string} + */ + getErrorHtml: function(data, xhr) { + var details = ''; + var message = ''; + + if (data !== null) { + if (data.stacktrace) details = '

Stacktrace:

' + data.stacktrace + '

'; + else if (data.exceptionID) details = '

Exception ID: ' + data.exceptionID + '

'; + + message = data.message; + + data.previous.forEach(function(previous) { + details += '

' + previous.message + '

'; + details += '

Stacktrace

' + previous.stacktrace + '

'; + }); + } + else { + message = xhr.responseText; + } + + if (!message || message === 'undefined') { + return; + } + + return '

' + message + '

' + details + '
'; + }, + /** * Finalizes a request. * diff --git a/wcfsetup/install/files/js/WoltLabSuite/Core/Ui/Dialog.js b/wcfsetup/install/files/js/WoltLabSuite/Core/Ui/Dialog.js index c78433a01d..67f5a060f6 100644 --- a/wcfsetup/install/files/js/WoltLabSuite/Core/Ui/Dialog.js +++ b/wcfsetup/install/files/js/WoltLabSuite/Core/Ui/Dialog.js @@ -134,7 +134,7 @@ define( if (setupData.source === undefined) { var dialogElement = elById(setupData.id); if (dialogElement === null) { - throw new Error("Element id '" + setupData.id + "' is invalid and no source attribute was given."); + throw new Error("Element id '" + setupData.id + "' is invalid and no source attribute was given. If you want to use the `html` argument instead, please add `source: null` to your dialog configuration."); } setupData.source = document.createDocumentFragment(); diff --git a/wcfsetup/install/files/lib/acp/form/DevtoolsProjectSyncForm.class.php b/wcfsetup/install/files/lib/acp/page/DevtoolsProjectSyncPage.class.php similarity index 91% rename from wcfsetup/install/files/lib/acp/form/DevtoolsProjectSyncForm.class.php rename to wcfsetup/install/files/lib/acp/page/DevtoolsProjectSyncPage.class.php index 67149beaab..152702d5f5 100644 --- a/wcfsetup/install/files/lib/acp/form/DevtoolsProjectSyncForm.class.php +++ b/wcfsetup/install/files/lib/acp/page/DevtoolsProjectSyncPage.class.php @@ -1,7 +1,7 @@ - * @package WoltLabSuite\Core\Acp\Form + * @package WoltLabSuite\Core\Acp\Page * @since 3.1 */ -class DevtoolsProjectSyncForm extends AbstractForm { +class DevtoolsProjectSyncPage extends AbstractPage { /** * @inheritDoc */ diff --git a/wcfsetup/install/files/lib/data/devtools/project/DevtoolsProject.class.php b/wcfsetup/install/files/lib/data/devtools/project/DevtoolsProject.class.php index f8e5afc2dd..c8f716e91c 100644 --- a/wcfsetup/install/files/lib/data/devtools/project/DevtoolsProject.class.php +++ b/wcfsetup/install/files/lib/data/devtools/project/DevtoolsProject.class.php @@ -38,6 +38,11 @@ class DevtoolsProject extends DatabaseObject { */ protected $packageArchive; + /** + * Returns a list of decorated PIPs. + * + * @return DevtoolsPip[] + */ public function getPips() { $pipList = new PackageInstallationPluginList(); $pipList->sqlOrderBy = 'pluginName'; @@ -51,6 +56,12 @@ class DevtoolsProject extends DatabaseObject { return $pips; } + /** + * Validates the repository and returns the first error message, or + * an empty string on success. + * + * @return string + */ public function validate() { $errorType = self::validatePath($this->path); if ($errorType !== '') { @@ -60,6 +71,11 @@ class DevtoolsProject extends DatabaseObject { return $this->validatePackageXml(); } + /** + * Returns true if this project appears to be `WoltLab Suite Core`. + * + * @return boolean + */ public function isCore() { if ($this->isCore === null) { $this->isCore = self::pathIsCore($this->path); @@ -68,6 +84,11 @@ class DevtoolsProject extends DatabaseObject { return $this->isCore; } + /** + * Validates the package.xml and checks if the package is already installed. + * + * @return string + */ public function validatePackageXml() { $packageXml = $this->path . ($this->isCore() ? 'com.woltlab.wcf/' : '') . 'package.xml'; $this->packageArchive = new DevtoolsPackageArchive($packageXml); @@ -124,6 +145,12 @@ class DevtoolsProject extends DatabaseObject { return ''; } + /** + * Returns true if the path appears to point to `WoltLab Suite Core`. + * + * @param string $path + * @return boolean + */ public static function pathIsCore($path) { return (is_dir($path . 'com.woltlab.wcf') && file_exists($path . 'com.woltlab.wcf/package.xml')); } diff --git a/wcfsetup/install/files/lib/data/package/installation/plugin/PackageInstallationPluginAction.class.php b/wcfsetup/install/files/lib/data/package/installation/plugin/PackageInstallationPluginAction.class.php index 7c7beabb51..de704dcb5d 100644 --- a/wcfsetup/install/files/lib/data/package/installation/plugin/PackageInstallationPluginAction.class.php +++ b/wcfsetup/install/files/lib/data/package/installation/plugin/PackageInstallationPluginAction.class.php @@ -8,7 +8,6 @@ use wcf\system\devtools\pip\DevtoolsPip; use wcf\system\devtools\pip\IIdempotentPackageInstallationPlugin; use wcf\system\exception\PermissionDeniedException; use wcf\system\exception\UserInputException; -use wcf\system\package\plugin\IPackageInstallationPlugin; use wcf\system\package\SplitNodeException; use wcf\system\search\SearchIndexManager; use wcf\system\version\VersionTracker; @@ -85,6 +84,8 @@ class PackageInstallationPluginAction extends AbstractDatabaseObjectAction { 'value' => $this->devtoolsPip->getInstructionValue($this->project, $this->parameters['target']) ]); + $start = microtime(true); + try { $pip->update(); } @@ -102,5 +103,12 @@ class PackageInstallationPluginAction extends AbstractDatabaseObjectAction { VersionTracker::getInstance()->createStorageTables(); CacheHandler::getInstance()->flushAll(); + + + return [ + 'pluginName' => $this->packageInstallationPlugin->pluginName, + 'target' => $this->parameters['target'], + 'timeElapsed' => WCF::getLanguage()->getDynamicVariable('wcf.acp.devtools.sync.status.success', ['timeElapsed' => round(microtime(true) - $start, 3)]) + ]; } } diff --git a/wcfsetup/install/files/lib/system/devtools/package/DevtoolsInstaller.class.php b/wcfsetup/install/files/lib/system/devtools/package/DevtoolsInstaller.class.php new file mode 100644 index 0000000000..f1a13899d5 --- /dev/null +++ b/wcfsetup/install/files/lib/system/devtools/package/DevtoolsInstaller.class.php @@ -0,0 +1,36 @@ + + * @package WoltLabSuite\Core\System\Devtools\Package + * @since 3.1 + */ +class DevtoolsInstaller extends Installer { + /** + * @var DevtoolsProject + */ + protected $project; + + /** + * @inheritDoc + */ + public function __construct(DevtoolsProject $project, $targetDir, $source, $fileHandler = null, $folder = '') { + $this->project = $project; + + parent::__construct($targetDir, $source, $fileHandler, $folder); + } + + /** + * @inheritDoc + */ + public function getTar($source) { + return $this->project->getPackageArchive()->getTar(); + } +} \ No newline at end of file diff --git a/wcfsetup/install/files/lib/system/devtools/package/DevtoolsPackageArchive.class.php b/wcfsetup/install/files/lib/system/devtools/package/DevtoolsPackageArchive.class.php index 1494becc2f..2a60f8a514 100644 --- a/wcfsetup/install/files/lib/system/devtools/package/DevtoolsPackageArchive.class.php +++ b/wcfsetup/install/files/lib/system/devtools/package/DevtoolsPackageArchive.class.php @@ -3,19 +3,38 @@ namespace wcf\system\devtools\package; use wcf\system\package\PackageArchive; /** - * @method DevtoolsTar getTar() + * Specialized implementation to emulate a regular package installation. + * + * @author Alexander Ebert + * @copyright 2001-2017 WoltLab GmbH + * @license GNU Lesser General Public License + * @package WoltLabSuite\Core\System\Devtools\Package + * @since 3.1 + * + * @method DevtoolsTar getTar() */ class DevtoolsPackageArchive extends PackageArchive { protected $packageXmlPath = ''; - /** @noinspection PhpMissingParentConstructorInspection */ + /** @noinspection PhpMissingParentConstructorInspection @inheritDoc */ public function __construct($packageXmlPath) { $this->packageXmlPath = $packageXmlPath; } + + /** + * @inheritDoc + */ public function openArchive() { $this->tar = new DevtoolsTar(['package.xml' => $this->packageXmlPath]); $this->readPackageInfo(); } + + /** + * @inheritDoc + */ + public function extractTar($filename, $tempPrefix = 'package_') { + return $tempPrefix . $filename . '_dummy'; + } } diff --git a/wcfsetup/install/files/lib/system/devtools/package/DevtoolsTar.class.php b/wcfsetup/install/files/lib/system/devtools/package/DevtoolsTar.class.php index 31fe02184b..50caa3a608 100644 --- a/wcfsetup/install/files/lib/system/devtools/package/DevtoolsTar.class.php +++ b/wcfsetup/install/files/lib/system/devtools/package/DevtoolsTar.class.php @@ -2,22 +2,57 @@ namespace wcf\system\devtools\package; use wcf\system\io\Tar; +/** + * Specialized implementation to emulate a regular package installation. + * + * @author Alexander Ebert + * @copyright 2001-2017 WoltLab GmbH + * @license GNU Lesser General Public License + * @package WoltLabSuite\Core\System\Devtools\Package + * @since 3.1 + */ class DevtoolsTar extends Tar { - protected $files = ''; + /** + * list of virtual files + * @var string[] + */ + protected $files = []; - /** @noinspection PhpMissingParentConstructorInspection */ + /** @noinspection PhpMissingParentConstructorInspection @inheritDoc */ public function __construct(array $files) { $this->files = $files; } + /** + * Resets the internal file list for re-use, because the devtools use + * the same instance over and over to avoid some otherwise awkward + * changes to the code. + */ + public function reset() { + $this->contentList = $this->files = []; + $this->read = false; + } + + /** + * Registers a new file in the virtual file list. + * + * @param string $filename + * @param string $fullPath + */ public function registerFile($filename, $fullPath) { $this->files[$filename] = $fullPath; } + /** + * @inheritDoc + */ public function getIndexByFilename($filename) { return (isset($this->files[$filename]) ? $filename : false); } + /** + * @inheritDoc + */ public function extractToString($index) { if (!isset($this->files[$index])) { throw new \RuntimeException("DevtoolsTar does not permit reading any files except for the explicitly registered ones."); @@ -26,7 +61,38 @@ class DevtoolsTar extends Tar { return file_get_contents($this->files[$index]); } + /** + * @inheritDoc + */ public function extract($index, $destination) { copy($this->files[$index], $destination); } + + /** + * @inheritDoc + */ + public function getContentList() { + if (!$this->read) { + foreach ($this->files as $filename => $fullPath) { + if (strpos($filename, '/') !== false) { + $directory = dirname($filename) . '/'; + if (!isset($this->contentList[$directory])) { + $this->contentList[$directory] = [ + 'filename' => $directory, + 'type' => 'folder' + ]; + } + } + + $this->contentList[$filename] = [ + 'filename' => $filename, + 'type' => 'file' + ]; + } + + $this->read = true; + } + + return $this->contentList; + } } diff --git a/wcfsetup/install/files/lib/system/devtools/pip/DevtoolsPackageInstallationDispatcher.class.php b/wcfsetup/install/files/lib/system/devtools/pip/DevtoolsPackageInstallationDispatcher.class.php index 484f78ed15..8c09c947c9 100644 --- a/wcfsetup/install/files/lib/system/devtools/pip/DevtoolsPackageInstallationDispatcher.class.php +++ b/wcfsetup/install/files/lib/system/devtools/pip/DevtoolsPackageInstallationDispatcher.class.php @@ -1,30 +1,60 @@ + * @package WoltLabSuite\Core\System\Devtools\Pip + * @since 3.1 + */ class DevtoolsPackageInstallationDispatcher extends PackageInstallationDispatcher { /** * @var DevtoolsPackageArchive */ protected $project; + /** + * @inheritDoc + */ public function __construct(DevtoolsProject $project) { parent::__construct(new DevtoolsPackageInstallationQueue($project)); $this->project = $project; } + /** + * @inheritDoc + */ public function getArchive() { return $this->project->getPackageArchive(); } + /** + * @inheritDoc + */ public function getPackageID() { return $this->project->getPackage()->packageID; } + /** + * @inheritDoc + */ public function getPackageName() { return $this->project->getPackage()->getName(); } + + /** + * @inheritDoc + */ + public function extractFiles($targetDir, $sourceArchive, $fileHandler = null) { + /** @noinspection PhpParamsInspection */ + return new DevtoolsInstaller($this->project, $targetDir, $sourceArchive, $fileHandler); + } } diff --git a/wcfsetup/install/files/lib/system/devtools/pip/DevtoolsPackageInstallationQueue.class.php b/wcfsetup/install/files/lib/system/devtools/pip/DevtoolsPackageInstallationQueue.class.php index 6845c88522..31ff90d0b5 100644 --- a/wcfsetup/install/files/lib/system/devtools/pip/DevtoolsPackageInstallationQueue.class.php +++ b/wcfsetup/install/files/lib/system/devtools/pip/DevtoolsPackageInstallationQueue.class.php @@ -4,7 +4,19 @@ use wcf\data\devtools\project\DevtoolsProject; use wcf\data\package\installation\queue\PackageInstallationQueue; use wcf\system\WCF; +/** + * Specialized implementation to emulate a regular package installation. + * + * @author Alexander Ebert + * @copyright 2001-2017 WoltLab GmbH + * @license GNU Lesser General Public License + * @package WoltLabSuite\Core\System\Devtools\Pip + * @since 3.1 + */ class DevtoolsPackageInstallationQueue extends PackageInstallationQueue { + /** + * @inheritDoc + */ public function __construct(DevtoolsProject $project) { parent::__construct(null, [ 'queueID' => 0, diff --git a/wcfsetup/install/files/lib/system/devtools/pip/DevtoolsPip.class.php b/wcfsetup/install/files/lib/system/devtools/pip/DevtoolsPip.class.php index 54e19a1974..9d778ab80c 100644 --- a/wcfsetup/install/files/lib/system/devtools/pip/DevtoolsPip.class.php +++ b/wcfsetup/install/files/lib/system/devtools/pip/DevtoolsPip.class.php @@ -4,8 +4,9 @@ use wcf\data\devtools\project\DevtoolsProject; use wcf\data\package\installation\plugin\PackageInstallationPlugin; use wcf\data\DatabaseObjectDecorator; use wcf\system\application\ApplicationHandler; -use wcf\system\exception\NotImplementedException; use wcf\system\WCF; +use wcf\util\FileUtil; +use wcf\util\JSON; /** * Wrapper class for package installation plugins for use with the sync feature. @@ -52,6 +53,10 @@ class DevtoolsPip extends DatabaseObjectDecorator { return call_user_func([$this->getDecoratedObject()->className, 'getDefaultFilename']); } + public function getEffectiveDefaultFilename() { + return './' . preg_replace('~\.tar$~', '/', $this->getDefaultFilename()); + } + /** * Returns true if the PIP exists, has a default filename and is idempotent. * @@ -61,6 +66,12 @@ class DevtoolsPip extends DatabaseObjectDecorator { return $this->classExists() && $this->getDefaultFilename() && $this->isIdempotent(); } + public function getSyncDependencies($toJson = true) { + $dependencies = call_user_func([$this->getDecoratedObject()->className, 'getSyncDependencies']); + + return ($toJson) ? JSON::encode($dependencies) : $dependencies; + } + /** * Returns the first validation error. * @@ -162,37 +173,132 @@ class DevtoolsPip extends DatabaseObjectDecorator { return $targets; } + /** + * Computes and prepares the instruction value for the provided target file. + * + * @param DevtoolsProject $project + * @param string $target + * @return string + */ public function getInstructionValue(DevtoolsProject $project, $target) { $defaultFilename = $this->getDefaultFilename(); + $pluginName = $this->getDecoratedObject()->pluginName; + $tar = $project->getPackageArchive()->getTar(); + $tar->reset(); if ($project->isCore()) { - switch ($this->getDecoratedObject()->pluginName) { + switch ($pluginName) { case 'acpTemplate': case 'file': case 'template': - throw new NotImplementedException(); - break; + if ($pluginName === 'acpTemplate' || $pluginName === 'template') { + $path = ($pluginName === 'acpTemplate') ? 'wcfsetup/install/files/acp/templates/' : 'com.woltlab.wcf/templates/'; + foreach (glob($project->path . $path . '*.tpl') as $template) { + $tar->registerFile(basename($template), FileUtil::unifyDirSeparator($template)); + } + } + else { + $path = 'wcfsetup/install/files/'; + + $directory = new \RecursiveDirectoryIterator($project->path . $path); + $filter = new \RecursiveCallbackFilterIterator($directory, function ($current) { + /** @var \SplFileInfo $current */ + $filename = $current->getFilename(); + if ($filename[0] === '.') { + // ignore dot files and files/directories starting with a dot + return false; + } + else if ($filename === 'templates') { + // ignores both `templates` and `acp/templates` + return false; + } + + return true; + }); + + $iterator = new \RecursiveIteratorIterator($filter, \RecursiveIteratorIterator::SELF_FIRST); + foreach ($iterator as $value => $item) { + /** @var \SplFileInfo $item */ + $itemPath = $item->getRealPath(); + if (is_dir($itemPath)) continue; + + $tar->registerFile( + FileUtil::getRelativePath($project->path . $path, $item->getPath()) . $item->getFilename(), + $itemPath + ); + } + } + + return $defaultFilename; case 'language': $filename = "wcfsetup/install/lang/{$target}"; - $project->getPackageArchive()->getTar()->registerFile($filename, $project->path . $filename); + $tar->registerFile($filename, $project->path . $filename); return $filename; default: $filename = "com.woltlab.wcf/{$target}"; - $project->getPackageArchive()->getTar()->registerFile($filename, $project->path . $filename); + $tar->registerFile($filename, $project->path . $filename); return $filename; } } else { - if (strpos($defaultFilename, '*') !== false) { - $filename = str_replace('*', $target, $defaultFilename); - $project->getPackageArchive()->getTar()->registerFile($filename, $project->path . $filename); + switch ($pluginName) { + case 'acpTemplate': + case 'file': + case 'template': + if ($pluginName === 'acpTemplate' || $pluginName === 'template') { + $path = ($pluginName === 'acpTemplate') ? 'acptemplates/' : 'templates/'; + foreach (glob($project->path . $path . '*.tpl') as $template) { + $tar->registerFile(basename($template), FileUtil::unifyDirSeparator($template)); + } + } + else { + $path = 'files/'; + + $directory = new \RecursiveDirectoryIterator($project->path . $path); + $filter = new \RecursiveCallbackFilterIterator($directory, function ($current) { + /** @var \SplFileInfo $current */ + $filename = $current->getFilename(); + if ($filename[0] === '.') { + // ignore dot files and files/directories starting with a dot + return false; + } + + return true; + }); + + $iterator = new \RecursiveIteratorIterator($filter, \RecursiveIteratorIterator::SELF_FIRST); + foreach ($iterator as $value => $item) { + /** @var \SplFileInfo $item */ + $itemPath = $item->getRealPath(); + if (is_dir($itemPath)) continue; + + $tar->registerFile( + FileUtil::getRelativePath($project->path . $path, $item->getPath()) . $item->getFilename(), + $itemPath + ); + } + } + + return $defaultFilename; + + default: + if (strpos($defaultFilename, '*') !== false) { + $filename = str_replace('*', $target, $defaultFilename); + $tar->registerFile($filename, $project->path . $filename); + } + else { + $filename = "com.woltlab.wcf/{$target}"; + $tar->registerFile($filename, $project->path . $filename); + } + + return $filename; } + + } - - throw new NotImplementedException(); } } \ No newline at end of file diff --git a/wcfsetup/install/files/lib/system/devtools/pip/IIdempotentPackageInstallationPlugin.class.php b/wcfsetup/install/files/lib/system/devtools/pip/IIdempotentPackageInstallationPlugin.class.php index 9022c096dd..5ad65569fd 100644 --- a/wcfsetup/install/files/lib/system/devtools/pip/IIdempotentPackageInstallationPlugin.class.php +++ b/wcfsetup/install/files/lib/system/devtools/pip/IIdempotentPackageInstallationPlugin.class.php @@ -20,4 +20,15 @@ use wcf\system\package\plugin\IPackageInstallationPlugin; * @package WoltLabSuite\Core\System\Devtools\Pip * @since 3.1 */ -interface IIdempotentPackageInstallationPlugin extends IPackageInstallationPlugin {} +interface IIdempotentPackageInstallationPlugin extends IPackageInstallationPlugin { + /** + * Returns a list of package installation plugins that need to be + * executed prior to a call to this PIP. + * + * This method is only considered for the bulk sync in the developer + * tools and has no impact on the regular installation process. + * + * @return string[] + */ + public static function getSyncDependencies(); +} diff --git a/wcfsetup/install/files/lib/system/package/plugin/ACPSearchProviderPackageInstallationPlugin.class.php b/wcfsetup/install/files/lib/system/package/plugin/ACPSearchProviderPackageInstallationPlugin.class.php index c6b61b31f4..628ce07b4d 100644 --- a/wcfsetup/install/files/lib/system/package/plugin/ACPSearchProviderPackageInstallationPlugin.class.php +++ b/wcfsetup/install/files/lib/system/package/plugin/ACPSearchProviderPackageInstallationPlugin.class.php @@ -86,4 +86,11 @@ class ACPSearchProviderPackageInstallationPlugin extends AbstractXMLPackageInsta public static function getDefaultFilename() { return 'acpSearchProvider.xml'; } + + /** + * @inheritDoc + */ + public static function getSyncDependencies() { + return []; + } } diff --git a/wcfsetup/install/files/lib/system/package/plugin/ACPTemplatePackageInstallationPlugin.class.php b/wcfsetup/install/files/lib/system/package/plugin/ACPTemplatePackageInstallationPlugin.class.php index 34871b5789..a9828f7a4d 100644 --- a/wcfsetup/install/files/lib/system/package/plugin/ACPTemplatePackageInstallationPlugin.class.php +++ b/wcfsetup/install/files/lib/system/package/plugin/ACPTemplatePackageInstallationPlugin.class.php @@ -113,4 +113,11 @@ class ACPTemplatePackageInstallationPlugin extends AbstractPackageInstallationPl return false; } + + /** + * @inheritDoc + */ + public static function getSyncDependencies() { + return []; + } } diff --git a/wcfsetup/install/files/lib/system/package/plugin/AbstractMenuPackageInstallationPlugin.class.php b/wcfsetup/install/files/lib/system/package/plugin/AbstractMenuPackageInstallationPlugin.class.php index 9cf09cda94..324bca4c57 100644 --- a/wcfsetup/install/files/lib/system/package/plugin/AbstractMenuPackageInstallationPlugin.class.php +++ b/wcfsetup/install/files/lib/system/package/plugin/AbstractMenuPackageInstallationPlugin.class.php @@ -88,4 +88,11 @@ abstract class AbstractMenuPackageInstallationPlugin extends AbstractXMLPackageI 'parameters' => $parameters ]; } + + /** + * @inheritDoc + */ + public static function getSyncDependencies() { + return []; + } } diff --git a/wcfsetup/install/files/lib/system/package/plugin/AbstractOptionPackageInstallationPlugin.class.php b/wcfsetup/install/files/lib/system/package/plugin/AbstractOptionPackageInstallationPlugin.class.php index ad9959f770..46e5ee4bb4 100644 --- a/wcfsetup/install/files/lib/system/package/plugin/AbstractOptionPackageInstallationPlugin.class.php +++ b/wcfsetup/install/files/lib/system/package/plugin/AbstractOptionPackageInstallationPlugin.class.php @@ -322,4 +322,11 @@ abstract class AbstractOptionPackageInstallationPlugin extends AbstractXMLPackag * @inheritDoc */ protected function findExistingItem(array $data) { } + + /** + * @inheritDoc + */ + public static function getSyncDependencies() { + return []; + } } diff --git a/wcfsetup/install/files/lib/system/package/plugin/BBCodePackageInstallationPlugin.class.php b/wcfsetup/install/files/lib/system/package/plugin/BBCodePackageInstallationPlugin.class.php index 8f80ceaa62..faf2e3b04a 100644 --- a/wcfsetup/install/files/lib/system/package/plugin/BBCodePackageInstallationPlugin.class.php +++ b/wcfsetup/install/files/lib/system/package/plugin/BBCodePackageInstallationPlugin.class.php @@ -196,4 +196,11 @@ class BBCodePackageInstallationPlugin extends AbstractXMLPackageInstallationPlug public static function getDefaultFilename() { return 'bbcode.xml'; } + + /** + * @inheritDoc + */ + public static function getSyncDependencies() { + return []; + } } diff --git a/wcfsetup/install/files/lib/system/package/plugin/BoxPackageInstallationPlugin.class.php b/wcfsetup/install/files/lib/system/package/plugin/BoxPackageInstallationPlugin.class.php index 5266bc02d8..fc93485d2b 100644 --- a/wcfsetup/install/files/lib/system/package/plugin/BoxPackageInstallationPlugin.class.php +++ b/wcfsetup/install/files/lib/system/package/plugin/BoxPackageInstallationPlugin.class.php @@ -391,4 +391,11 @@ class BoxPackageInstallationPlugin extends AbstractXMLPackageInstallationPlugin } } } + + /** + * @inheritDoc + */ + public static function getSyncDependencies() { + return ['language']; + } } diff --git a/wcfsetup/install/files/lib/system/package/plugin/ClipboardActionPackageInstallationPlugin.class.php b/wcfsetup/install/files/lib/system/package/plugin/ClipboardActionPackageInstallationPlugin.class.php index 1f8bce012b..4a5de19fb1 100644 --- a/wcfsetup/install/files/lib/system/package/plugin/ClipboardActionPackageInstallationPlugin.class.php +++ b/wcfsetup/install/files/lib/system/package/plugin/ClipboardActionPackageInstallationPlugin.class.php @@ -147,4 +147,11 @@ class ClipboardActionPackageInstallationPlugin extends AbstractXMLPackageInstall } } } + + /** + * @inheritDoc + */ + public static function getSyncDependencies() { + return []; + } } diff --git a/wcfsetup/install/files/lib/system/package/plugin/CoreObjectPackageInstallationPlugin.class.php b/wcfsetup/install/files/lib/system/package/plugin/CoreObjectPackageInstallationPlugin.class.php index 1306e68363..f29651f95b 100644 --- a/wcfsetup/install/files/lib/system/package/plugin/CoreObjectPackageInstallationPlugin.class.php +++ b/wcfsetup/install/files/lib/system/package/plugin/CoreObjectPackageInstallationPlugin.class.php @@ -69,4 +69,11 @@ class CoreObjectPackageInstallationPlugin extends AbstractXMLPackageInstallation protected function cleanup() { CoreObjectCacheBuilder::getInstance()->reset(); } + + /** + * @inheritDoc + */ + public static function getSyncDependencies() { + return []; + } } diff --git a/wcfsetup/install/files/lib/system/package/plugin/CronjobPackageInstallationPlugin.class.php b/wcfsetup/install/files/lib/system/package/plugin/CronjobPackageInstallationPlugin.class.php index b83aefd1b4..a3a24f6e89 100644 --- a/wcfsetup/install/files/lib/system/package/plugin/CronjobPackageInstallationPlugin.class.php +++ b/wcfsetup/install/files/lib/system/package/plugin/CronjobPackageInstallationPlugin.class.php @@ -149,4 +149,11 @@ class CronjobPackageInstallationPlugin extends AbstractXMLPackageInstallationPlu $data['nextExec'] = TIME_NOW; } + + /** + * @inheritDoc + */ + public static function getSyncDependencies() { + return []; + } } diff --git a/wcfsetup/install/files/lib/system/package/plugin/EventListenerPackageInstallationPlugin.class.php b/wcfsetup/install/files/lib/system/package/plugin/EventListenerPackageInstallationPlugin.class.php index ee1d778e05..740cd91272 100644 --- a/wcfsetup/install/files/lib/system/package/plugin/EventListenerPackageInstallationPlugin.class.php +++ b/wcfsetup/install/files/lib/system/package/plugin/EventListenerPackageInstallationPlugin.class.php @@ -157,4 +157,12 @@ class EventListenerPackageInstallationPlugin extends AbstractXMLPackageInstallat // clear cache immediately EventListenerCacheBuilder::getInstance()->reset(); } + + /** + * @inheritDoc + */ + public static function getSyncDependencies() { + return []; + } + } diff --git a/wcfsetup/install/files/lib/system/package/plugin/FilePackageInstallationPlugin.class.php b/wcfsetup/install/files/lib/system/package/plugin/FilePackageInstallationPlugin.class.php index a0501a7489..40da096c40 100644 --- a/wcfsetup/install/files/lib/system/package/plugin/FilePackageInstallationPlugin.class.php +++ b/wcfsetup/install/files/lib/system/package/plugin/FilePackageInstallationPlugin.class.php @@ -137,4 +137,11 @@ class FilePackageInstallationPlugin extends AbstractPackageInstallationPlugin im return false; } + + /** + * @inheritDoc + */ + public static function getSyncDependencies() { + return []; + } } diff --git a/wcfsetup/install/files/lib/system/package/plugin/LanguagePackageInstallationPlugin.class.php b/wcfsetup/install/files/lib/system/package/plugin/LanguagePackageInstallationPlugin.class.php index 3813e55ed4..ef9003f34f 100644 --- a/wcfsetup/install/files/lib/system/package/plugin/LanguagePackageInstallationPlugin.class.php +++ b/wcfsetup/install/files/lib/system/package/plugin/LanguagePackageInstallationPlugin.class.php @@ -262,4 +262,11 @@ class LanguagePackageInstallationPlugin extends AbstractXMLPackageInstallationPl public static function isValid(PackageArchive $archive, $instruction) { return true; } + + /** + * @inheritDoc + */ + public static function getSyncDependencies() { + return []; + } } diff --git a/wcfsetup/install/files/lib/system/package/plugin/MenuItemPackageInstallationPlugin.class.php b/wcfsetup/install/files/lib/system/package/plugin/MenuItemPackageInstallationPlugin.class.php index b2e5099c0e..2f6ad07e7d 100644 --- a/wcfsetup/install/files/lib/system/package/plugin/MenuItemPackageInstallationPlugin.class.php +++ b/wcfsetup/install/files/lib/system/package/plugin/MenuItemPackageInstallationPlugin.class.php @@ -203,4 +203,11 @@ class MenuItemPackageInstallationPlugin extends AbstractXMLPackageInstallationPl return (!$row['showOrder']) ? 1 : $row['showOrder'] + 1; } + + /** + * @inheritDoc + */ + public static function getSyncDependencies() { + return ['language']; + } } diff --git a/wcfsetup/install/files/lib/system/package/plugin/MenuPackageInstallationPlugin.class.php b/wcfsetup/install/files/lib/system/package/plugin/MenuPackageInstallationPlugin.class.php index f2f1563a8a..a5d8762705 100644 --- a/wcfsetup/install/files/lib/system/package/plugin/MenuPackageInstallationPlugin.class.php +++ b/wcfsetup/install/files/lib/system/package/plugin/MenuPackageInstallationPlugin.class.php @@ -265,4 +265,11 @@ class MenuPackageInstallationPlugin extends AbstractXMLPackageInstallationPlugin } } } + + /** + * @inheritDoc + */ + public static function getSyncDependencies() { + return ['language']; + } } diff --git a/wcfsetup/install/files/lib/system/package/plugin/ObjectTypeDefinitionPackageInstallationPlugin.class.php b/wcfsetup/install/files/lib/system/package/plugin/ObjectTypeDefinitionPackageInstallationPlugin.class.php index 6fa72676e1..87a33b9952 100644 --- a/wcfsetup/install/files/lib/system/package/plugin/ObjectTypeDefinitionPackageInstallationPlugin.class.php +++ b/wcfsetup/install/files/lib/system/package/plugin/ObjectTypeDefinitionPackageInstallationPlugin.class.php @@ -64,4 +64,11 @@ class ObjectTypeDefinitionPackageInstallationPlugin extends AbstractXMLPackageIn 'parameters' => $parameters ]; } + + /** + * @inheritDoc + */ + public static function getSyncDependencies() { + return []; + } } diff --git a/wcfsetup/install/files/lib/system/package/plugin/ObjectTypePackageInstallationPlugin.class.php b/wcfsetup/install/files/lib/system/package/plugin/ObjectTypePackageInstallationPlugin.class.php index f0597d50d6..527317f395 100644 --- a/wcfsetup/install/files/lib/system/package/plugin/ObjectTypePackageInstallationPlugin.class.php +++ b/wcfsetup/install/files/lib/system/package/plugin/ObjectTypePackageInstallationPlugin.class.php @@ -104,4 +104,11 @@ class ObjectTypePackageInstallationPlugin extends AbstractXMLPackageInstallation 'parameters' => $parameters ]; } + + /** + * @inheritDoc + */ + public static function getSyncDependencies() { + return ['objectTypeDefinition']; + } } diff --git a/wcfsetup/install/files/lib/system/package/plugin/PIPPackageInstallationPlugin.class.php b/wcfsetup/install/files/lib/system/package/plugin/PIPPackageInstallationPlugin.class.php index e033c38159..feef16a0de 100644 --- a/wcfsetup/install/files/lib/system/package/plugin/PIPPackageInstallationPlugin.class.php +++ b/wcfsetup/install/files/lib/system/package/plugin/PIPPackageInstallationPlugin.class.php @@ -76,4 +76,11 @@ class PIPPackageInstallationPlugin extends AbstractXMLPackageInstallationPlugin 'parameters' => $parameters ]; } + + /** + * @inheritDoc + */ + public static function getSyncDependencies() { + return []; + } } diff --git a/wcfsetup/install/files/lib/system/package/plugin/PagePackageInstallationPlugin.class.php b/wcfsetup/install/files/lib/system/package/plugin/PagePackageInstallationPlugin.class.php index 7daf6a3f32..b954e02352 100644 --- a/wcfsetup/install/files/lib/system/package/plugin/PagePackageInstallationPlugin.class.php +++ b/wcfsetup/install/files/lib/system/package/plugin/PagePackageInstallationPlugin.class.php @@ -355,4 +355,11 @@ class PagePackageInstallationPlugin extends AbstractXMLPackageInstallationPlugin } } } + + /** + * @inheritDoc + */ + public static function getSyncDependencies() { + return ['language']; + } } diff --git a/wcfsetup/install/files/lib/system/package/plugin/SmileyPackageInstallationPlugin.class.php b/wcfsetup/install/files/lib/system/package/plugin/SmileyPackageInstallationPlugin.class.php index 596a6cf304..ceb5dae0e6 100644 --- a/wcfsetup/install/files/lib/system/package/plugin/SmileyPackageInstallationPlugin.class.php +++ b/wcfsetup/install/files/lib/system/package/plugin/SmileyPackageInstallationPlugin.class.php @@ -78,4 +78,11 @@ class SmileyPackageInstallationPlugin extends AbstractXMLPackageInstallationPlug 'parameters' => $parameters ]; } + + /** + * @inheritDoc + */ + public static function getSyncDependencies() { + return []; + } } diff --git a/wcfsetup/install/files/lib/system/package/plugin/TemplateListenerPackageInstallationPlugin.class.php b/wcfsetup/install/files/lib/system/package/plugin/TemplateListenerPackageInstallationPlugin.class.php index a3b3d9fcac..151f2cde94 100644 --- a/wcfsetup/install/files/lib/system/package/plugin/TemplateListenerPackageInstallationPlugin.class.php +++ b/wcfsetup/install/files/lib/system/package/plugin/TemplateListenerPackageInstallationPlugin.class.php @@ -98,4 +98,11 @@ class TemplateListenerPackageInstallationPlugin extends AbstractXMLPackageInstal // clear cache immediately TemplateListenerCodeCacheBuilder::getInstance()->reset(); } + + /** + * @inheritDoc + */ + public static function getSyncDependencies() { + return []; + } } diff --git a/wcfsetup/install/files/lib/system/package/plugin/TemplatePackageInstallationPlugin.class.php b/wcfsetup/install/files/lib/system/package/plugin/TemplatePackageInstallationPlugin.class.php index fcf275bfae..61302b2aea 100644 --- a/wcfsetup/install/files/lib/system/package/plugin/TemplatePackageInstallationPlugin.class.php +++ b/wcfsetup/install/files/lib/system/package/plugin/TemplatePackageInstallationPlugin.class.php @@ -115,4 +115,11 @@ class TemplatePackageInstallationPlugin extends AbstractPackageInstallationPlugi return false; } + + /** + * @inheritDoc + */ + public static function getSyncDependencies() { + return []; + } } diff --git a/wcfsetup/install/files/lib/system/package/plugin/UserNotificationEventPackageInstallationPlugin.class.php b/wcfsetup/install/files/lib/system/package/plugin/UserNotificationEventPackageInstallationPlugin.class.php index ec90935e00..ad4934aaf3 100644 --- a/wcfsetup/install/files/lib/system/package/plugin/UserNotificationEventPackageInstallationPlugin.class.php +++ b/wcfsetup/install/files/lib/system/package/plugin/UserNotificationEventPackageInstallationPlugin.class.php @@ -131,6 +131,7 @@ class UserNotificationEventPackageInstallationPlugin extends AbstractXMLPackageI * * @param string $objectType * @return integer + * @throws SystemException */ protected function getObjectTypeID($objectType) { // get object type id @@ -148,4 +149,11 @@ class UserNotificationEventPackageInstallationPlugin extends AbstractXMLPackageI if (empty($row['objectTypeID'])) throw new SystemException("unknown notification object type '".$objectType."' given"); return $row['objectTypeID']; } + + /** + * @inheritDoc + */ + public static function getSyncDependencies() { + return []; + } } diff --git a/wcfsetup/install/files/lib/system/package/plugin/UserProfileMenuPackageInstallationPlugin.class.php b/wcfsetup/install/files/lib/system/package/plugin/UserProfileMenuPackageInstallationPlugin.class.php index 23ba0ca631..cb94b961f6 100644 --- a/wcfsetup/install/files/lib/system/package/plugin/UserProfileMenuPackageInstallationPlugin.class.php +++ b/wcfsetup/install/files/lib/system/package/plugin/UserProfileMenuPackageInstallationPlugin.class.php @@ -81,4 +81,11 @@ class UserProfileMenuPackageInstallationPlugin extends AbstractXMLPackageInstall 'parameters' => $parameters ]; } + + /** + * @inheritDoc + */ + public static function getSyncDependencies() { + return []; + } } diff --git a/wcfsetup/install/files/lib/system/setup/Installer.class.php b/wcfsetup/install/files/lib/system/setup/Installer.class.php index 6e9bb02cd1..a399bac31c 100644 --- a/wcfsetup/install/files/lib/system/setup/Installer.class.php +++ b/wcfsetup/install/files/lib/system/setup/Installer.class.php @@ -118,7 +118,7 @@ class Installer { $this->createTargetDir(); // open source archive - $tar = new Tar($this->source); + $tar = $this->getTar($this->source); // distinct directories and files $directories = []; @@ -173,6 +173,16 @@ class Installer { $tar->close(); } + /** + * Opens a new tar archive. + * + * @param string $source + * @return Tar + */ + protected function getTar($source) { + return new Tar($source); + } + /** * Checks whether the given files overwriting locked existing files. * diff --git a/wcfsetup/install/lang/de.xml b/wcfsetup/install/lang/de.xml index dfeadd24f3..c016a0b1bf 100644 --- a/wcfsetup/install/lang/de.xml +++ b/wcfsetup/install/lang/de.xml @@ -386,6 +386,10 @@ + + + +
@@ -874,7 +878,7 @@ - + @@ -1333,7 +1337,7 @@ GmbH=Gesellschaft mit beschränkter Haftung]]> Eingabefelder und Empfänger individuell konfigurieren.]]> - + diff --git a/wcfsetup/install/lang/en.xml b/wcfsetup/install/lang/en.xml index 5d9b486b2a..8bc1bb061a 100644 --- a/wcfsetup/install/lang/en.xml +++ b/wcfsetup/install/lang/en.xml @@ -353,6 +353,28 @@ + + + + + + + + + + + package.xml will be ignored; This allows the import of PIPs that have no specific instructions provided for them yet. Only the suggested default paths are recognized, with an additional support for application suffixes for .tar-archives (e. g. files_wcf.tar) are supported.]]> + + + + + + + + + + + @@ -838,6 +860,8 @@ + + @@ -1303,6 +1327,9 @@ input fields and recipients to better suit your needs.]]> + + + -- 2.20.1