示例#1
0
	/**
	 * Extracts information about this package (parses package.xml).
	 */
	protected function readPackageInfo() {
		// 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."'");
		}
		
		// extract package.xml, parse with SimpleXML
		// and compile an array with XML::getElementTree()
		$xml = new XML();
		try {
			$xml->loadXML(self::INFO_FILE, $this->tar->extractToString(self::INFO_FILE));
		}
		catch (\Exception $e) { // bugfix to avoid file caching problems
			$xml->loadXML(self::INFO_FILE, $this->tar->extractToString(self::INFO_FILE));
		}
		
		// parse xml
		$xpath = $xml->xpath();
		$package = $xpath->query('/ns:package')->item(0);
		
		// package name
		$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.");
		}
		
		$this->packageInfo['name'] = $packageName;
		
		// get package information
		$packageInformation = $xpath->query('./ns:packageinformation', $package)->item(0);
		$elements = $xpath->query('child::*', $packageInformation);
		foreach ($elements as $element) {
			switch ($element->tagName) {
				case 'packagename':
				case 'packagedescription':
				case 'readme':
				case 'license':
					if (!isset($this->packageInfo[$element->tagName])) $this->packageInfo[$element->tagName] = array();
					
					$languageCode = 'default';
					if ($element->hasAttribute('language')) {
						$languageCode = $element->getAttribute('language');
					}
					
					// fix case-sensitive names
					$name = $element->tagName;
					if ($name == 'packagename') $name = 'packageName';
					else if ($name == 'packagedescription') $name = 'packageDescription';
					
					$this->packageInfo[$name][$languageCode] = $element->nodeValue;
				break;
				
				case 'isapplication':
					$this->packageInfo['isApplication'] = intval($element->nodeValue);
				break;
				
				case 'packageurl':
					$this->packageInfo['packageURL'] = $element->nodeValue;
				break;
				
				case 'version':
					if (!Package::isValidVersion($element->nodeValue)) {
						throw new SystemException("package version '".$element->nodeValue."' is invalid");
					}
					
					$this->packageInfo['version'] = $element->nodeValue;
				break;
				
				case 'date':
					DateUtil::validateDate($element->nodeValue);
					
					$this->packageInfo['date'] = strtotime($element->nodeValue);
				break;
			}
		}
		
		// get author information
		$authorInformation = $xpath->query('./ns:authorinformation', $package)->item(0);
		$elements = $xpath->query('child::*', $authorInformation);
		foreach ($elements as $element) {
			$tagName = ($element->tagName == 'authorurl') ? 'authorURL' : $element->tagName;
			$this->authorInfo[$tagName] = $element->nodeValue;
		}
		
		// get required packages
		$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.");
			}
			
			// read attributes
			$data = array('name' => $element->nodeValue);
			$attributes = $xpath->query('attribute::*', $element);
			foreach ($attributes as $attribute) {
				$data[$attribute->name] = $attribute->value;
			}
					
			$this->requirements[$element->nodeValue] = $data;
		}
		
		// get optional packages
		$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.");
			}
			
			// read attributes
			$data = array('name' => $element->nodeValue);
			$attributes = $xpath->query('attribute::*', $element);
			foreach ($attributes as $attribute) {
				$data[$attribute->name] = $attribute->value;
			}
					
			$this->optionals[] = $data;
		}
		
		// get excluded packages
		$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.");
			}
			
			// read attributes
			$data = array('name' => $element->nodeValue);
			$attributes = $xpath->query('attribute::*', $element);
			foreach ($attributes as $attribute) {
				$data[$attribute->name] = $attribute->value;
			}
			
			$this->excludedPackages[] = $data;
		}
		
		// get instructions
		$elements = $xpath->query('./ns:instructions', $package);
		foreach ($elements as $element) {
			$instructionData = array();
			$instructions = $xpath->query('./ns:instruction', $element);
			foreach ($instructions as $instruction) {
				$data = array();
				$attributes = $xpath->query('attribute::*', $instruction);
				foreach ($attributes as $attribute) {
					$data[$attribute->name] = $attribute->value;
				}
				
				$instructionData[] = array(
					'attributes' => $data,
					'pip' => $instruction->getAttribute('type'),
					'value' => $instruction->nodeValue
				);
			}
			
			$fromVersion = $element->getAttribute('fromversion');
			$type = $element->getAttribute('type');
			
			if ($type == 'install') {
				$this->instructions['install'] = $instructionData;
			}
			else {
				$this->instructions['update'][$fromVersion] = $instructionData;
			}
		}
		
		// get php requirements
		$requirements = $xpath->query('./ns:phprequirements', $package);
		foreach ($requirements as $requirement) {
			$elements = $xpath->query('child::*', $requirement);
			foreach ($elements as $element) {
				switch ($element->tagName) {
					case 'version':
						$this->phpRequirements['version'] = $element->nodeValue;
					break;
					
					case 'setting':
						$this->phpRequirements['settings'][$element->getAttribute('name')] = $element->nodeValue;
					break;
					
					case 'extension':
						$this->phpRequirements['extensions'][] = $element->nodeValue;
					break;
					
					case 'function':
						$this->phpRequirements['functions'][] = $element->nodeValue;
					break;
					
					case 'class':
						$this->phpRequirements['classes'][] = $element->nodeValue;
					break;
				}
			}
		}
		
		// add com.woltlab.wcf to package requirements
		if (!isset($this->requirements['com.woltlab.wcf']) && $this->packageInfo['name'] != 'com.woltlab.wcf') {
			$this->requirements['com.woltlab.wcf'] = array('name' => 'com.woltlab.wcf');
		}
		
		if ($this->package != null) {
			$validFromVersion = null;
			foreach ($this->instructions['update'] as $fromVersion => $update) {
				if (Package::checkFromversion($this->package->packageVersion, $fromVersion)) {
					$validFromVersion = $fromVersion;
					break;
				}
			}
			if ($validFromVersion === null) {
				$this->instructions['update'] = array();
			}
			else {
				$this->instructions['update'] = $this->instructions['update'][$validFromVersion];
			}
		}
		
		// set default values
		if (!isset($this->packageInfo['isApplication'])) $this->packageInfo['isApplication'] = 0;
		if (!isset($this->packageInfo['packageURL'])) $this->packageInfo['packageURL'] = '';
	}
 /**
  * Determines intermediate update steps using a backtracking algorithm in case there is no direct upgrade possible.
  * 
  * @param	string		$package		package identifier
  * @param	array		$fromversions		list of all fromversions
  * @param	string		$currentVersion		current package version
  * @param	string		$newVersion		new package version
  * @return	array		list of update steps (old version => new version, old version => new version, ...)
  */
 protected function findShortestUpdateThread($package, $fromversions, $currentVersion, $newVersion)
 {
     if (!isset($fromversions[$newVersion])) {
         throw new SystemException("An update of package " . $package . " from version " . $currentVersion . " to " . $newVersion . " is not supported.");
     }
     // find direct update
     foreach ($fromversions[$newVersion] as $fromversion) {
         if (Package::checkFromversion($currentVersion, $fromversion)) {
             return array($currentVersion => $newVersion);
         }
     }
     // find intermediate update
     $packageVersions = array_keys($fromversions);
     $updateThreadList = array();
     foreach ($fromversions[$newVersion] as $fromversion) {
         $innerUpdateThreadList = array();
         // find matching package versions
         foreach ($packageVersions as $packageVersion) {
             if (Package::checkFromversion($packageVersion, $fromversion) && Package::compareVersion($packageVersion, $currentVersion, '>') && Package::compareVersion($packageVersion, $newVersion, '<')) {
                 $innerUpdateThreadList[] = $this->findShortestUpdateThread($package, $fromversions, $currentVersion, $packageVersion) + array($packageVersion => $newVersion);
             }
         }
         if (!empty($innerUpdateThreadList)) {
             // sort by length
             usort($innerUpdateThreadList, array($this, 'compareUpdateThreadLists'));
             // add to thread list
             $updateThreadList[] = array_shift($innerUpdateThreadList);
         }
     }
     if (empty($updateThreadList)) {
         throw new SystemException("An update of package " . $package . " from version " . $currentVersion . " to " . $newVersion . " is not supported.");
     }
     // sort by length
     usort($updateThreadList, array($this, 'compareUpdateThreadLists'));
     // take shortest
     return array_shift($updateThreadList);
 }
示例#3
0
 /**
  * Filters update instructions.
  */
 protected function filterUpdateInstructions()
 {
     $validFromVersion = null;
     foreach ($this->instructions['update'] as $fromVersion => $update) {
         if (Package::checkFromversion($this->package->packageVersion, $fromVersion)) {
             $validFromVersion = $fromVersion;
             break;
         }
     }
     if ($validFromVersion === null) {
         $this->instructions['update'] = array();
     } else {
         $this->instructions['update'] = $this->instructions['update'][$validFromVersion];
     }
 }