/**
  * Reads a source for available packages
  *
  * @param	mixed	$source
  */
 public static function readPackages($source)
 {
     // load source
     self::$source = $source instanceof Source ? $source : new Source($source);
     // verify directory
     if (!is_dir(self::$source->sourceDirectory)) {
         throw new SystemException('Source directory for sourceID ' . self::$source->sourceID . ' is invalid.');
     }
     // clear existing WCFSetup resources
     $sql = "DELETE FROM\tpb" . PB_N . "_setup_resource\r\n\t\t\tWHERE\t\tsourceID = " . self::$source->sourceID;
     WCF::getDB()->sendQuery($sql);
     // read available packages
     self::readDirectories(self::$source->sourceDirectory);
     // break if no packages are available
     if (empty(self::$packages)) {
         $sql = "DELETE FROM\tpb" . PB_N . "_source_package\r\n\t\t\t\tWHERE\t\tsourceID = " . self::$source->sourceID;
         WCF::getDB()->sendQuery($sql);
         // clear cache
         self::registerCache();
         WCF::getCache()->clearResource('packages-' . self::$source->sourceID);
         WCF::getCache()->clear(PB_DIR . 'cache/', 'cache.packages-' . self::$source->sourceID . '.php');
         return;
     }
     $hashes = array();
     $referencedPackages = array();
     $sql = '';
     // update data for available packages
     foreach (self::$packages as $directory => $data) {
         if (!empty($sql)) {
             $sql .= ',';
         }
         $hash = self::getHash(self::$source->sourceID, $data['name'], $directory);
         $sql .= "(" . self::$source->sourceID . ",\r\n\t\t\t\t'" . $hash . "',\r\n\t\t\t\t'" . escapeString($data['name']) . "',\r\n\t\t\t\t'" . escapeString($data['version']) . "',\r\n\t\t\t\t'" . escapeString($directory) . "',\r\n\t\t\t\t'" . escapeString($data['packageType']) . "')";
         // set all required or optional packages
         $referencedPackages[$hash] = self::getReferencedPackages($data);
         // register hash
         $hashes[] = "'" . $hash . "'";
     }
     if (!empty($sql)) {
         // build complete sql query
         $sql = "INSERT INTO\t\tpb" . PB_N . "_source_package\r\n\t\t\t\t\t\t\t(sourceID, hash, packageName, version, directory, packageType)\r\n\t\t\t\tVALUES\t\t\t" . $sql . "\r\n\t\t\t\tON DUPLICATE KEY UPDATE\tversion = VALUES(version),\r\n\t\t\t\t\t\t\tpackageType = VALUES(packageType)";
         // update data
         WCF::getDB()->sendQuery($sql);
         // remove removed packages
         $sql = "DELETE FROM\tpb" . PB_N . "_source_package\r\n\t\t\t\tWHERE\t\thash NOT IN (" . implode(',', $hashes) . ")\r\n\t\t\t\tAND\t\tsourceID = " . self::$source->sourceID;
         WCF::getDB()->sendQuery($sql);
         // remove data for each hash
         $sql = "DELETE FROM\tpb" . PB_N . "_referenced_package\r\n\t\t\t\tWHERE\t\thash IN (" . implode(',', $hashes) . ")\r\n\t\t\t\tAND\t\tsourceID = " . self::$source->sourceID;
         WCF::getDB()->sendQuery($sql);
     }
     // insert referenced packages
     $sql = '';
     foreach ($referencedPackages as $hash => $packages) {
         foreach ($packages as $packageName => $packageData) {
             if (!empty($sql)) {
                 $sql .= ',';
             }
             $sql .= "(" . self::$source->sourceID . ",\r\n\t\t\t\t\t'" . $hash . "',\r\n\t\t\t\t\t'" . escapeString($packageName) . "',\r\n\t\t\t\t\t'" . escapeString($packageData['minversion']) . "',\r\n\t\t\t\t\t'" . escapeString($packageData['file']) . "')";
         }
     }
     if (!empty($sql)) {
         $sql = "INSERT INTO\tpb" . PB_N . "_referenced_package\r\n\t\t\t\t\t\t(sourceID, hash, packageName, minVersion, file)\r\n\t\t\t\tVALUES\t\t" . $sql;
         WCF::getDB()->sendQuery($sql);
     }
     // clear cache
     self::registerCache();
     WCF::getCache()->clearResource('packages-' . self::$source->sourceID);
     WCF::getCache()->clear(PB_DIR . 'cache/', 'cache.packages-' . self::$source->sourceID . '.php');
     WCF::getCache()->clearResource('package-dependency-' . self::$source->sourceID);
     WCF::getCache()->clear(PB_DIR . 'cache/', 'cache.package-dependency-' . self::$source->sourceID . '.php');
     WCF::getCache()->clearResource('wcfsetup-resources');
     WCF::getCache()->clear(PB_DIR . 'cache/', 'cache.wcfsetup-resources.php');
 }