/** * Set this packagexml with data from the component. * This is useful in the packager. * * WARNING, this will revert any modifications done to the package.xml file! * * @param Component_2_1 $component * * @return string */ public function setFromComponent(Component_2_1 $component){ // Populate the root attributes for this component package. $this->setType('component'); $this->setName($component->getName()); $this->setVersion($component->getVersion()); $this->setPackager(Core::GetComponent()->getVersion()); // Copy over any provide directives. foreach ($component->getRootDOM()->getElementsByTagName('provide') as $u) { $this->getRootDOM()->appendChild($this->getDOM()->importNode($u)); } $this->setProvide('component', $component->getName(), $component->getVersion()); // Copy over any requires directives. foreach ($component->getRootDOM()->getElementsByTagName('require') as $u) { $this->getRootDOM()->appendChild($this->getDOM()->importNode($u)); } // Copy over any upgrade directives. // This one can be useful for an existing installation to see if this // package can provide a valid upgrade path. foreach ($component->getRootDOM()->getElementsByTagName('upgrade') as $u) { // In this case, I just need the definition itself, I don't also need the contents of that upgrade. $this->setUpgrade($u->getAttribute('from'), $u->getAttribute('to')); } // Tack on description $desc = $component->getRootDOM()->getElementsByTagName('description')->item(0); if ($desc) { $this->setDescription($desc->nodeValue); } }
'file' => 'CHANGELOG', 'md5' => md5_file($dirname . 'CHANGELOG') ); // And the readme file_put_contents($dirname . 'README.md', "# About $componentname @todo Write something about this component. "); $allfiles[] = array( 'file' => 'README.md', 'md5' => md5_file($dirname . 'README.md') ); $componentobject = new Component_2_1($dirname . 'component.xml'); $componentobject->setAuthors( array( array('name' => $packagername, 'email' => $packageremail) ) ); $componentobject->setFiles($allfiles); $componentobject->save(); echo "Created new component " . $componentname . "\n"; if($exists_prior){ echo "If there were files in this directory previously, please run the following to scan them:" . "\n" . "utilities/packager.php -r -c $component" . "\n"; }
/** * Internally used method to notify the rest of the system that a given * component has been loaded and is available. * * Expects all checks to be done already. */ public function _registerComponent(Component_2_1 $c) { $name = str_replace(' ', '-', strtolower($c->getName())); if ($c->hasLibrary()) { $liblist = $c->getLibraryList(); $this->_libraries = array_merge($this->_libraries, $liblist); // Register the include paths if set. foreach ($c->getIncludePaths() as $path) { set_include_path(get_include_path() . PATH_SEPARATOR . $path); } } $this->_scriptlibraries = array_merge($this->_scriptlibraries, $c->getScriptLibraryList()); if ($c->hasModule()) $this->_modules[$name] = $c->getVersionInstalled(); $this->_classes = array_merge($this->_classes, $c->getClassList()); $this->_viewClasses = array_merge($this->_viewClasses, $c->getViewClassList()); $this->_widgets = array_merge($this->_widgets, $c->getWidgetList()); $this->_components[$name] = $c; // Permissions were not enabled prior to 2.1, so the legacy components do not have the function. if($c instanceof Component_2_1){ $this->_permissions = array_merge($this->_permissions, $c->getPermissions()); ksort($this->_permissions); // Register this component's user authdrivers, if any. $auths = $c->getUserAuthDrivers(); foreach($auths as $name => $class){ \Core\User\Helper::$AuthDrivers[$name] = $class; } } // All models get a control link registered automatically :) $models = $c->getModelList(); foreach($models as $class => $file){ if(!HookHandler::GetHook('/core/controllinks/' . $class)){ $h = new Hook('/core/controllinks/' . $class); $h->returnType = Hook::RETURN_TYPE_ARRAY; $h->description = 'Automatic hook for control links on the ' . $class . ' object. Attach onto this hook if you want to add a custom link anytime this object\'s control is displayed.'; } } $licenser = $c->getLicenseData(); if($licenser && defined('SERVER_ID') && class_exists('\\Core\\Licenser')){ // This will contain a url key and the features. $url = $licenser['url']; $comp = $c->getKeyName(); foreach($licenser['features'] as $key){ \Core\Licenser::RegisterFeature($key, $url, $comp); } } // Lastly, mark this component as available! $c->_setReady(true); }
public static function RebuildPackages() { $dir = \Core\Filestore\Factory::Directory(\ConfigHandler::Get('/package_repository/base_directory')); $coredir = $dir->getPath() . 'core/'; $componentdir = $dir->getPath() . 'components/'; $themedir = $dir->getPath() . 'themes/'; $tmpdir = \Core\Filestore\Factory::Directory('tmp/exports/'); $gpg = new Core\GPG\GPG(); $keysfound = []; $addedpackages = 0; $failedpackages = 0; $skippedpackages = 0; $ls = $dir->ls('asc', true); \Core\CLI\CLI::PrintProgressBar(0); $totalPackages = sizeof($ls); $percentEach = 100 / $totalPackages; $currentPercent = 0; // Ensure that the necessary temp directory exists. $tmpdir->mkdir(); foreach ($ls as $file) { /** @var \Core\Filestore\File $file */ $fullpath = $file->getFilename(); $relpath = substr($file->getFilename(), strlen($dir->getPath())); $tmpdirpath = $tmpdir->getPath(); // Drop the .asc extension. $basename = $file->getBasename(true); // Tarball of the temporary package $tgz = \Core\Filestore\Factory::File($tmpdirpath . $basename); $output = []; // I need to 1) retrieve and 2) verify the key for this package. try { $signature = $gpg->verifyFileSignature($fullpath); } catch (\Exception $e) { trigger_error($fullpath . ' was not able to be verified as authentic, (probably because the GPG public key was not available)'); $failedpackages++; continue; } // decode and untar it in a temp directory to get the package.xml file. exec('gpg --homedir "' . GPG_HOMEDIR . '" -q -d "' . $fullpath . '" > "' . $tgz->getFilename() . '" 2>/dev/null', $output, $ret); if ($ret) { trigger_error('Decryption of file ' . $fullpath . ' failed!'); $failedpackages++; continue; } // Extract the package.xml metafile, this is critical! exec('tar -xzf "' . $tgz->getFilename() . '" -C "' . $tmpdirpath . '" ./package.xml', $output, $ret); if ($ret) { trigger_error('Unable to extract package.xml from' . $tgz->getFilename()); unlink($tmpdirpath . $basename); $failedpackages++; continue; } // Read in that package file and append it to the repo xml. $package = new PackageXML($tmpdirpath . 'package.xml'); $package->getRootDOM()->setAttribute('key', $signature->keyID); $package->setFileLocation($relpath); // Core has a few differences than most components. if ($package->getKeyName() == 'core') { $pkgName = 'Core Plus'; $chngName = 'Core Plus'; $type = 'core'; $chngDepth = 3; $chngFile = './data/core/CHANGELOG'; $xmlFile = './data/core/component.xml'; } else { $pkgName = $package->getName(); $chngName = ($package->getType() == 'theme' ? 'Theme/' : '') . $package->getName(); $type = $package->getType(); $chngDepth = 2; $chngFile = './data/CHANGELOG'; $xmlFile = './data/' . ($package->getType() == 'theme' ? 'theme.xml' : 'component.xml'); } // Lookup this package in the database or create if it doesn't exist. $model = PackageRepositoryPackageModel::Find(['type = ' . $package->getType(), 'key = ' . $package->getKeyName(), 'version = ' . $package->getVersion()], 1); if (!$model) { $model = new PackageRepositoryPackageModel(); $model->set('type', $type); $model->set('key', $package->getKeyName()); $model->set('version', $package->getVersion()); } // Set the data provided by the package.xml file. $model->set('name', $pkgName); $model->set('gpg_key', $package->getKey()); $model->set('packager', $package->getPackager()); $model->set('file', $relpath); $model->set('description', $package->getDescription()); $model->set('requires', $package->getRequires()); $model->set('provides', $package->getProvides()); $model->set('upgrades', $package->getUpgrades()); unlink($tmpdirpath . 'package.xml'); // Extract out the CHANGELOG file, this is not so critical. // I need strip-components=2 to drop off the "." and "data" prefixes. exec('tar -xzf "' . $tgz->getFilename() . '" -C "' . $tmpdirpath . '" --strip-components=' . $chngDepth . ' ' . $chngFile, $output, $ret); // If there is a CHANGELOG, parse that too! if (file_exists($tmpdirpath . 'CHANGELOG')) { try { $ch = new Core\Utilities\Changelog\Parser($chngName, $tmpdirpath . 'CHANGELOG'); $ch->parse(); // Get the version for this iteration. $chsec = $ch->getSection($model->get('version')); $model->set('packager_name', $chsec->getPackagerName()); $model->set('packager_email', $chsec->getPackagerEmail()); $model->set('datetime_released', $chsec->getReleasedDateUTC()); $model->set('changelog', $chsec->fetchAsHTML(null)); } catch (Exception $e) { // meh, we just won't have a changelog. } finally { if (file_exists($tmpdirpath . 'CHANGELOG')) { // Cleanup unlink($tmpdirpath . 'CHANGELOG'); } } } // Retrieve out the screenshots from this component. exec('tar -xzf "' . $tgz->getFilename() . '" -O ' . $xmlFile . ' > "' . $tmpdirpath . 'comp.xml"', $output, $ret); if (file_exists($tmpdirpath . 'comp.xml')) { try { $images = []; $c = new Component_2_1($tmpdirpath . 'comp.xml'); $screens = $c->getScreenshots(); if (sizeof($screens)) { foreach ($screens as $s) { // Extract out this screen and save it to the filesystem. $archivedFile = dirname($xmlFile) . '/' . $s; $localFile = \Core\Filestore\Factory::File('public/packagerepo-screens/' . $model->get('type') . '-' . $model->get('key') . '-' . $model->get('version') . '/' . basename($s)); // Write something into the file so that it exists on the filesystem. $localFile->putContents(''); // And now tar can extract directly to that destination! exec('tar -xzf "' . $tgz->getFilename() . '" -O ' . $archivedFile . ' > "' . $localFile->getFilename() . '"', $output, $ret); if (!$ret) { // Return code should be 0 on a successful write. $images[] = $localFile->getFilename(false); } } } $model->set('screenshots', $images); } catch (Exception $e) { // meh, we just won't have images.. } finally { if (file_exists($tmpdirpath . 'comp.xml')) { // Cleanup unlink($tmpdirpath . 'comp.xml'); } } } if ($model->changed()) { $model->save(true); $addedpackages++; } else { $skippedpackages++; } // But I can still cleanup! $tgz->delete(); $currentPercent += $percentEach; \Core\CLI\CLI::PrintProgressBar($currentPercent); } // Commit everything! PackageRepositoryPackageModel::CommitSaves(); return ['updated' => $addedpackages, 'skipped' => $skippedpackages, 'failed' => $failedpackages]; }