Ignore this, these classes are just lying around doing nothing.
namespace wcf\system\package;
use wcf\data\package\Package;
use wcf\system\database\util\PreparedStatementConditionBuilder;
-use wcf\system\exception\SystemException;
+use wcf\system\package\validation\PackageValidationException;
use wcf\system\io\Tar;
use wcf\system\WCF;
use wcf\util\DateUtil;
public function openArchive() {
// check whether archive exists and is a TAR archive
if (!file_exists($this->archive)) {
- throw new SystemException("unable to find package file '".$this->archive."'");
+ throw new PackageValidationException(PackageValidationException::FILE_NOT_FOUND, array('archive' => $this->archive));
}
// open archive and read package information
// search package.xml in package archive
// throw error message if not found
if ($this->tar->getIndexByFilename(self::INFO_FILE) === false) {
- throw new SystemException("package information file '".(self::INFO_FILE)."' not found in '".$this->archive."'");
+ throw new PackageValidationException(PackageValidationException::MISSING_PACKAGE_XML, array('archive' => $this->archive));
}
// extract package.xml, parse XML
$packageName = $package->getAttribute('name');
if (!Package::isValidPackageName($packageName)) {
// package name is not a valid package identifier
- throw new SystemException("'".$packageName."' is not a valid package name.");
+ throw new PackageValidationException(PackageValidationException::INVALID_PACKAGE_NAME, array('packageName' => $packageName));
}
$this->packageInfo['name'] = $packageName;
case 'version':
if (!Package::isValidVersion($element->nodeValue)) {
- throw new SystemException("package version '".$element->nodeValue."' is invalid");
+ throw new PackageValidationException(PackageValidationException::INVALID_PACKAGE_VERSION, array('packageVersion' => $element->nodeValue));
}
$this->packageInfo['version'] = $element->nodeValue;
$elements = $xpath->query('child::ns:requiredpackages/ns:requiredpackage', $package);
foreach ($elements as $element) {
if (!Package::isValidPackageName($element->nodeValue)) {
- throw new SystemException("'".$element->nodeValue."' is not a valid package name.");
+ throw new PackageValidationException(PackageValidationException::INVALID_PACKAGE_NAME, array('packageName' => $element->nodeValue));
}
// read attributes
$elements = $xpath->query('child::ns:optionalpackages/ns:optionalpackage', $package);
foreach ($elements as $element) {
if (!Package::isValidPackageName($element->nodeValue)) {
- throw new SystemException("'".$element->nodeValue."' is not a valid package name.");
+ throw new PackageValidationException(PackageValidationException::INVALID_PACKAGE_NAME, array('packageName' => $element->nodeValue));
}
// read attributes
$elements = $xpath->query('child::ns:excludedpackages/ns:excludedpackage', $package);
foreach ($elements as $element) {
if (!Package::isValidPackageName($element->nodeValue)) {
- throw new SystemException("'".$element->nodeValue."' is not a valid package name.");
+ throw new PackageValidationException(PackageValidationException::INVALID_PACKAGE_NAME, array('packageName' => $element->nodeValue));
}
// read attributes
// search the requested tar archive in our package archive.
// throw error message if not found.
if (($fileIndex = $this->tar->getIndexByFilename($filename)) === false) {
- throw new SystemException("tar archive '".$filename."' not found in '".$this->archive."'.");
+ throw new PackageValidationException(PackageValidationException::FILE_NOT_FOUND, array(
+ 'archive' => $this->archive,
+ 'targetArchive' => $filename
+ ));
}
// requested tar archive was found
--- /dev/null
+<?php
+namespace wcf\system\package\validation;
+use wcf\system\package\PackageArchive;
+use wcf\system\WCF;
+
+/**
+ * Recursively validates the package archive and it's delivered requirements.
+ *
+ * @author Alexander Ebert
+ * @copyright 2001-2014 WoltLab GmbH
+ * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @package com.woltlab.wcf
+ * @subpackage system.package.validation
+ * @category Community Framework
+ */
+class PackageValidationArchive implements \RecursiveIterator {
+ /**
+ * package archive object
+ * @var \wcf\system\package\PackageArchive
+ */
+ protected $archive = null;
+
+ /**
+ * list of direct requirements delivered by this package
+ * @var array<\wcf\system\package\validation\PackageValidationArchive>
+ */
+ protected $children = array();
+
+ /**
+ * exception occured during validation
+ * @var \Exception
+ */
+ protected $exception = null;
+
+ /**
+ * children pointer
+ * @var integer
+ */
+ private $position = 0;
+
+ /**
+ * Creates a new package validation archive instance.
+ *
+ * @param string $archive
+ */
+ public function __construct($archive) {
+ $this->archive = new PackageArchive($archive);
+ }
+
+ /**
+ * Validates this package and it's delivered requirements.
+ *
+ * @return boolean
+ */
+ public function validate() {
+ //
+ // step 1) try to read archive
+ //
+ try {
+ $this->archive->openArchive();
+ }
+ catch (\Exception $e) {
+ $this->exception = $e;
+ }
+
+ //
+ // step 2) traverse requirements
+ //
+ die("<pre>".print_r($this->archive->getOpenRequirements(), true));
+
+ //
+ // step 3) check requirements against virtual package table
+ //
+
+ /* TODO: do something */
+
+ //
+ // step 4) check exclusions
+ //
+
+ /* TODO: do something */
+
+ return true;
+
+ }
+
+ /**
+ * Returns the exception message.
+ *
+ * @return string
+ */
+ public function getExceptionMessage() {
+ if ($this->exception === null) {
+ return '';
+ }
+
+ if ($this->exception instanceof PackageValidationException) {
+ return WCF::getLanguage()->getDynamicVariable('wcf.package.validation.errorCode.' . $this->exception->getCode(), $this->exception->getDetails());
+ }
+
+ return $this->exception->getMessage();
+ }
+
+ /**
+ * @see \Iterator::rewind()
+ */
+ public function rewind() {
+ $this->position = 0;
+ }
+
+ /**
+ * @see \Iterator::valid()
+ */
+ public function valid() {
+ return isset($this->children[$this->position]);
+ }
+
+ /**
+ * @see \Iterator::next()
+ */
+ public function next() {
+ $this->position++;
+ }
+
+ /**
+ * @see \Iterator::current()
+ */
+ public function current() {
+ return $this->children[$this->position];
+ }
+
+ /**
+ * @see \Iterator::key()
+ */
+ public function key() {
+ return $this->position;
+ }
+
+ /**
+ * @see \RecursiveIterator::getChildren()
+ */
+ public function getChildren() {
+ return $this->children[$this->position];
+ }
+
+ /**
+ * @see \RecursiveIterator::hasChildren()
+ */
+ public function hasChildren() {
+ return count($this->children) > 0;
+ }
+}
--- /dev/null
+<?php
+namespace wcf\system\package\validation;
+use wcf\system\exception\SystemException;
+
+/**
+ * Represents exceptions occured during validation of a package archive. This exception
+ * does not cause the details to be logged.
+ *
+ * @author Alexander Ebert
+ * @copyright 2001-2014 WoltLab GmbH
+ * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @package com.woltlab.wcf
+ * @subpackage system.package.validation
+ * @category Community Framework
+ */
+class PackageValidationException extends SystemException {
+ /**
+ * list of additional details for each subtype
+ * @var array<string>
+ */
+ protected $details = array();
+
+ /**
+ * missing archive, expects the detail 'archive' and optionally 'targetArchive' (extracting archive from the archive)
+ * @var integer
+ */
+ const FILE_NOT_FOUND = 1;
+
+ /**
+ * missing package.xml, expects the detail 'archive'
+ * @var integer
+ */
+ const MISSING_PACKAGE_XML = 2;
+
+ /**
+ * package name violates WCF's schema, expects the detail 'packageName'
+ * @var integer
+ */
+ const INVALID_PACKAGE_NAME = 3;
+
+ /**
+ * package version violates WCF's schema, expects the detail 'packageVersion'
+ * @var integer
+ */
+ const INVALID_PACKAGE_VERSION = 4;
+
+ /**
+ * Creates a new PackageArchiveValidationException.
+ *
+ * @param integer $code
+ * @param array<string> $details
+ */
+ public function __construct($code, array $details = array()) {
+ parent::__construct($this->getLegacyMessage(), $code);
+
+ $this->details = $details;
+ }
+
+ /**
+ * Returns exception details.
+ *
+ * @return array<string>
+ */
+ public function getDetails() {
+ return $this->details;
+ }
+
+ /**
+ * Returns legacy error messages to mimic WCF 2.0.x PackageArchive's exceptions.
+ *
+ * @return string
+ */
+ protected function getLegacyMessage() {
+ switch ($this->getCode()) {
+ case self::FILE_NOT_FOUND:
+ if (isset($this->details['targetArchive'])) {
+ return "tar archive '".$this->details['targetArchive']."' not found in '".$this->details['archive']."'.";
+ }
+
+ return "unable to find package file '".$this->details['archive']."'";
+ break;
+
+ case self::MISSING_PACKAGE_XML:
+ return "package information file '".PackageArchive::INFO_FILE."' not found in '".$this->details['archive']."'";
+ break;
+
+ case self::INVALID_PACKAGE_NAME:
+ return "'".$this->details['packageName']."' is not a valid package name.";
+ break;
+
+ case self::INVALID_PACKAGE_VERSION:
+ return "package version '".$this->details['packageVersion']."' is invalid";
+ break;
+ }
+ }
+
+ /**
+ * @see \wcf\system\exception\LoggedException::logError()
+ */
+ protected function logError() {
+ // do not log errors
+ }
+}
--- /dev/null
+<?php
+namespace wcf\system\package\validation;
+use wcf\system\SingletonFactory;
+use wcf\data\package\Package;
+
+/**
+ * Manages recursive validation of package archives.
+ *
+ * @author Alexander Ebert
+ * @copyright 2001-2014 WoltLab GmbH
+ * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @package com.woltlab.wcf
+ * @subpackage system.package.validation
+ * @category Community Framework
+ */
+class PackageValidationManager extends SingletonFactory {
+ /**
+ * package validation archive object
+ * @var \wcf\system\package\validation\PackageValidationArchive
+ */
+ protected $packageValidationArchive = null;
+
+ /**
+ * virtual package list containing package => packageVersion
+ * @var array<string>
+ */
+ protected $virtualPackageList = array();
+
+ /**
+ * Validates given archive for existance and ability to be installed/updated
+ *
+ * @param string $archive
+ * @return boolean
+ */
+ public function validate($archive) {
+ $this->virtualPackageList = array();
+ $this->packageValidationArchive = new PackageValidationArchive($archive);
+
+ return $this->packageValidationArchive->validate();
+ }
+
+ /**
+ * Returns package validation archive object.
+ *
+ * @return \wcf\system\package\validation\PackageValidationArchive
+ */
+ public function getPackageValidationArchive() {
+ return $this->packageValidationArchive;
+ }
+
+ /**
+ * Adds a virtual package with the corresponding version, if the package is already known,
+ * the higher version number will be stored.
+ *
+ * @param string $package
+ * @param string $packageVersion
+ * @return boolean
+ */
+ public function addVirtualPackage($package, $packageVersion) {
+ if (isset($this->virtualPackageList[$package])) {
+ if (Package::compareVersion($packageVersion, $this->virtualPackageList[$package], '<')) {
+ return false;
+ }
+ }
+
+ $this->virtualPackageList[$package] = $packageVersion;
+
+ return true;
+ }
+
+ /**
+ * Returns the version number of a virtual package or null if it doesn't exist.
+ *
+ * @param string $package
+ * @return string
+ */
+ public function geVirtualPackageVersion($package) {
+ if (isset($this->virtualPackageList[$package])) {
+ return $this->virtualPackageList[$package];
+ }
+
+ return null;
+ }
+}