/** * parse a configuration for a PEAR2 installation * * @param string $pearDirectory This can be either a single path, or a * PATH_SEPARATOR-separated list of directories * @param string $userfile */ public function __construct($snapshot, \Pyrus\Config $config = null) { self::constructDefaults(); if (!$config) { $config = \Pyrus\Config::current(); } $this->loadConfigFile($config->location, $snapshot); $this->pearDir = $config->location; }
function isUpgradeable() { if (!isset(\Pyrus\Main::$options['upgrade'])) { // we don't attempt to upgrade a dep unless we're upgrading return false; } $reg = \Pyrus\Config::current()->registry; $version = $reg->info($this->name, $this->channel, 'version'); if (version_compare($this->version['release'], $version, '<=')) { return !isset(\Pyrus\Main::$options['force']); } return true; }
function __construct($coverage, $recursive) { $this->ini_overwrites[] = 'error_reporting=' . E_ALL; if ($coverage) { $this->_options['coverage'] = true; } if ($recursive) { $this->_options['recur'] = true; } $this->windows = substr(PHP_OS, 0, 3) == 'WIN'; $this->_php = \Pyrus\Config::current()->php_bin; $this->xdebug_loaded = extension_loaded('xdebug'); }
function cloneRegistry(Base $registry) { try { $packageiterator = $registry->package; foreach (\Pyrus\Config::current()->channelregistry->listChannels() as $channel) { $packageiterator->setIteratorChannel($channel); foreach ($packageiterator as $package) { if ($this->exists($package->name, $package->channel)) { $old = $this->toPackageFile($package->name, $package->channel); if ($old->date == $package->date && $old->time == $package->time) { continue; } } $this->replace($package); } } } catch (\Exception $e) { throw new Exception('Cannot clone registry', $e); } }
/** * Get/Create a transaction. * * @param string|Pyrus\Installer\Role\Common $path The directory path. * @return Transaction A Pyrus\AtomicFileTransaction\Transaction instance */ public function getTransaction($path) { if ($path instanceof \Pyrus\Installer\Role\Common) { $path = \Pyrus\Config::current()->{$path->getLocationConfig()}; } $path = FS::path((string) $path); if (isset($this->transactions[$path])) { return $this->transactions[$path]; } // Create new transaction object $class = $this->getTransactionClass(); try { $this->transactions[$path] = new $class($path, $this); return $this->transactions[$path]; } catch (\Exception $e) { $errs = new MultiErrors(); $errs->E_ERROR[] = $e; $errs->merge($this->rollbackTransactions()); throw new MultiException('Unable to begin transaction', $errs); } }
function getRelativeLocation(\Pyrus\PackageFileInterface $pkg, \Pyrus\PackageFile\v2Iterator\FileTag $file, $retDir = false) { if ($this->md5 === null) { return parent::getRelativeLocation($pkg, $file, $retDir); } $info = parent::getRelativeLocation($pkg, $file, $retDir); $path = \Pyrus\Config::current()->cfg_dir . DIRECTORY_SEPARATOR; if ($retDir) { $filepath = $info[1]; } else { $filepath = $info; } if (@file_exists($path . $filepath)) { // configuration has already been installed, check for modifications // made by the user $md5 = md5_file($path . $filepath); $newmd5 = $pkg->files[$file->packagedname]['attribs']; if (!isset($newmd5['md5sum'])) { $newmd5 = md5_file($pkg->getFilePath($file->packagedname)); } else { $newmd5 = $newmd5['md5sum']; } // first check to see if the user modified the file // next check to see if the config file changed from the last installed version // if both tests are satisfied, install the new file under another name and display a warning if ($md5 !== $this->md5 && $md5 !== $newmd5) { // configuration has been modified, so save our version as // configfile.new-version $old = $filepath; $filepath .= '.new-' . $pkg->version['release']; \Pyrus\Logger::log(0, "WARNING: configuration file {$old} is being installed as {$filepath}, " . "you should manually merge in changes to the existing configuration file"); } } if ($retDir) { $info[1] = $filepath; } else { $info = $filepath; } return $info; }
function offsetUnset($offset) { $info = Config::current()->channelregistry->parseName($offset); $this->reg->uninstall($info['package'], $info['channel']); }
/** * @param \Pyrus\PackageFile\v2 * @param int */ function validate(\Pyrus\PackageInterface $pf, $state = \Pyrus\Validate::NORMAL) { $this->errors = new \PEAR2\MultiErrors(); if (!$pf->schemaOK) { // this package.xml was created from scratch, not loaded from an existing // package.xml $dom = new \DOMDocument(); libxml_use_internal_errors(true); libxml_clear_errors(); $dom->loadXML($pf); $a = $pf->toArray(); if ($a['package']['attribs']['version'] == '2.1') { $schema = \Pyrus\Main::getDataPath() . '/package-2.1.xsd'; } else { $schema = \Pyrus\Main::getDataPath() . '/package-2.0.xsd'; } // libxml can't process these from within a phar (pity) if (strpos($schema, 'phar://') === 0) { if (!file_exists($temp = \Pyrus\Config::current()->temp_dir . DIRECTORY_SEPARATOR . 'schema')) { mkdir($temp, 0755, true); } $tmpschema = $temp . DIRECTORY_SEPARATOR . basename($schema); copy($schema, $tmpschema); $dom->schemaValidate($tmpschema); } else { $dom->schemaValidate($schema); } $causes = array(); foreach (libxml_get_errors() as $error) { $this->errors->E_ERROR[] = new \Pyrus\PackageFile\Exception("Line " . $error->line . ': ' . $error->message); } if (count($this->errors)) { throw new \Pyrus\PackageFile\Exception('Invalid package.xml, does' . ' not validate against schema', $this->errors); } } $this->_pf = $pf; $this->_curState = $state; $this->_packageInfo = $this->_pf->toArray(); $this->_packageInfo = $this->_packageInfo['package']; if (!isset($this->_packageInfo) || !is_array($this->_packageInfo)) { return false; } $myversion = self::VERSION; if ($myversion === '@PACKAGE_VERSION@') { // we're running from CVS, assume we're 2.0.0 $myversion = '2.0.0'; } $test = $this->_packageInfo; if (isset($test['dependencies']) && isset($test['dependencies']['required']) && isset($test['dependencies']['required']['pearinstaller']) && isset($test['dependencies']['required']['pearinstaller']['min']) && version_compare($myversion, $test['dependencies']['required']['pearinstaller']['min'], '<')) { $this->errors->E_ERROR[] = new \Pyrus\PackageFile\Exception('This package.xml requires PEAR version ' . $test['dependencies']['required']['pearinstaller']['min'] . ' to parse properly, we are version ' . $myversion); } $fail = false; foreach ($pf->contents as $file) { // leverage the hidden iterators to do our validation $name = $file->dir . $file->name; if ($name[0] == '.' && $name[1] == '/') { // name is something like "./doc/whatever.txt" $this->errors->E_ERROR[] = new \Pyrus\Package\Exception('File "' . $name . '" cannot begin with "."'); continue; } if (!$this->_validateRole($file->role)) { if (isset($this->_packageInfo['usesrole'])) { $roles = $this->_packageInfo['usesrole']; if (!isset($roles[0])) { $roles = array($roles); } foreach ($roles as $role) { if ($role['role'] = $file->role) { if (isset($role['uri'])) { $package = $role['uri']; } else { $package = \Pyrus\Config::parsedPackageNameToString(array('package' => $role['package'], 'channel' => $role['channel']), true); } $msg = 'This package contains role "' . $file->role . '" and requires package "' . $package . '" to be used'; $this->errors->E_WARNING[] = new \Pyrus\PackageFile\Exception($msg); } } } $this->errors->E_ERROR[] = new \Pyrus\PackageFile\Exception('File "' . $name . '" has invalid role "' . $file->role . '", should be one of ' . implode(', ', \Pyrus\Installer\Role::getValidRoles($this->_pf->getPackageType()))); } if (count($file->tasks) && $this->_curState != \Pyrus\Validate::DOWNLOADING) { // has tasks $save = $file->getArrayCopy(); foreach ($file->tasks as $task => $value) { if ($tagClass = \Pyrus\Task\Common::getTask($task)) { if (!is_array($value) || !isset($value[0])) { $value = array($value); } foreach ($value as $v) { try { $ret = $tagClass::validateXml($this->_pf, $v, $save['attribs'], $file->name); } catch (\Pyrus\Task\Exception $e) { $this->errors->E_ERROR[] = new \Pyrus\PackageFile\Exception('Invalid task $task', $e); } } } else { if (isset($this->_packageInfo['usestask'])) { $roles = $this->_packageInfo['usestask']; if (!isset($roles[0])) { $roles = array($roles); } foreach ($roles as $role) { if ($role['task'] = $task) { if (isset($role['uri'])) { $package = $role['uri']; } else { $package = \Pyrus\Config::parsedPackageNameToString(array('package' => $role['package'], 'channel' => $role['channel']), true); } $msg = 'This package contains task "' . str_replace($this->_pf->getTasksNs() . ':', '', $task) . '" and requires package "' . $package . '" to be used'; $this->errors->E_WARNING[] = new \Pyrus\PackageFile\Exception($msg); } } } $this->errors->E_ERROR[] = new \Pyrus\PackageFile\Exception('Unknown task "' . $task . '" passed in file <file name="' . $name . '">'); } } } } $this->_validateRelease(); if (count($this->errors->E_ERROR)) { throw new \Pyrus\PackageFile\Exception('Invalid package.xml', $this->errors); } try { $validator = \Pyrus\Config::current()->channelregistry[$this->_pf->channel]->getValidationObject($this->_pf->name); } catch (\Pyrus\Config\Exception $e) { throw new \Pyrus\PackageFile\Exception('Unable to process channel-specific configuration for channel ' . $this->_pf->getChannel(), $e); } catch (\Exception $e) { $valpack = \Pyrus\Config::current()->channelregistry[$this->_pf->channel]->getValidationPackage(); $this->errors->E_ERROR[] = new \Pyrus\PackageFile\Exception('Unknown channel ' . $this->_pf->channel); $this->errors->E_ERROR[] = new \Pyrus\PackageFile\Exception('package "' . $this->_pf->channel . '/' . $this->_pf->name . '" cannot be properly validated without validation package "' . $this->_pf->channel . '/' . $valpack['name'] . '-' . $valpack['version'] . '"'); } try { $validator->setPackageFile($this->_pf); $validator->setChannel(\Pyrus\Config::current()->channelregistry[$this->_pf->channel]); $validator->validate($state); // merge in errors from channel-specific validation $this->errors[] = $validator->getFailures(); } catch (\Exception $e) { $this->errors->E_ERROR[] = $e; } if (count($this->errors->E_ERROR)) { throw new \Pyrus\PackageFile\Exception('Invalid package.xml', $this->errors); } if ($state == \Pyrus\Validate::PACKAGING) { if ($this->_pf->type == 'bundle') { if (!$this->_analyzeBundledPackages()) { throw new \Pyrus\PackageFile\Exception('Invalid package.xml', $this->errors); } } else { if (!$this->_analyzePhpFiles()) { throw new \Pyrus\PackageFile\Exception('Invalid package.xml', $this->errors); } } } return $state; }
ini_set('display_errors', true); // Get the autoloader require __DIR__ . '/../../../autoload.php'; /* $channel = new PEAR2\SimpleChannelServer('pear2.php.net','/Library/WebServer/Documents/pearserver', null, '/Users/bbieber/pyrus', array('saltybeagle','cellog')); if (!@unserialize(file_get_contents('/tmp/categories.inf'))) { $cat = PEAR2_SimpleChannelServer_Categories::create('Name1', 'Description 1', 'Alias1')-> create('Name2', 'Description 2')-> create('Name3', 'Description 3', 'Alias3')-> create('Name4', 'Description 4'); file_put_contents('/tmp/categories.inf', serialize($cat)); } $categories = PEAR2_SimpleChannelServer_Categories::getCategories(); $categories = $channel->listCategories(); foreach($categories as $category) { var_dump($category); } */ $channel = new PEAR2\SimpleChannelServer\Channel('pear2.php.net', 'Brett Bieber\'s PEAR Channel', 'salty'); //$scs = new PEAR2\SimpleChannelServer($channel,'/Library/WebServer/Documents/pearserver','/home/bbieber/pyrus/php'); $scs = new PEAR2\SimpleChannelServer($channel, '/home/cellog/testapache/htdocs', \Pyrus\Config::current()->path); $categories = PEAR2\SimpleChannelServer\Categories::create('Default', 'This is the default category'); $scs->saveChannel(); $scs->saveRelease(new \Pyrus\Package(__DIR__ . '/../package.xml'), 'cellog'); echo 'did it' . PHP_EOL; /* $manager = new PEAR2\SimpleChannelServer\REST\Manager('/Library/WebServer/Documents/pearserver','pear2.php.net','rest/',array('cellog')); var_dump($manager->saveRelease(new \Pyrus\Package(__DIR__ . '/../package.xml'),'cellog')); */
/** @todo Consider simply injecting the Package object as appropriate */ function package($frontend, $args, $options) { $path = getcwd() . DIRECTORY_SEPARATOR; $package = new \Pyrus\Package(null); if (!isset($args['packagexml']) && !file_exists($path . 'package.xml') && !file_exists($path . 'package2.xml')) { throw new \Pyrus\PackageFile\Exception("No package.xml or package2.xml found in " . $path); } if (isset($args['packagexml'])) { $package = new \Pyrus\Package($args['packagexml']); } else { // first try ./package.xml if (file_exists($path . 'package.xml')) { try { $package = new \Pyrus\Package($path . 'package.xml'); } catch (\Pyrus\PackageFile\Exception $e) { if ($e->getCode() != -3) { throw $e; } if (!file_exists($path . 'package2.xml')) { throw $e; } $package = new \Pyrus\Package($path . 'package2.xml'); // now the creator knows to do the magic of package2.xml/package.xml $package->thisIsOldAndCrustyCompatible(); } } // Alternatively; there's only a package2.xml if (file_exists($path . 'package2.xml') && !file_exists($path . 'package.xml')) { $package = new \Pyrus\Package($path . 'package2.xml'); } } if ($package->isNewPackage()) { if (!$options['phar'] && !$options['zip'] && !$options['tar'] && !$options['tgz']) { // try tgz first if (extension_loaded('zlib')) { $options['tgz'] = true; } else { $options['tar'] = true; } } if ($options['phar'] && ini_get('phar.readonly')) { throw new \Pyrus\Developer\Creator\Exception("Cannot create phar archive, pass -dphar.readonly=0"); } } else { if ($options['zip'] || $options['phar']) { echo "Zip and Phar archives can only be created for PEAR2 packages, ignoring\n"; } if (extension_loaded('zlib')) { $options['tgz'] = true; } else { $options['tar'] = true; } } // get openssl cert if set, and password if (\Pyrus\Config::current()->openssl_cert) { if ('yes' == $frontend->ask('Sign package?', array('yes', 'no'), 'yes')) { $cert = \Pyrus\Config::current()->openssl_cert; if (!file_exists($cert)) { throw new \Pyrus\Developer\Creator\Exception('OpenSSL certificate ' . $cert . ' does not exist'); } $releaser = \Pyrus\Config::current()->handle; $maintainers = array(); foreach ($package->maintainer as $maintainer) { $maintainers[] = $maintainer->user; } if (!strlen($releaser)) { throw new \Pyrus\Developer\Creator\Exception('handle configuration variable must be from ' . 'package.xml (one of ' . implode(', ', $maintainers) . ')'); } if (!in_array($releaser, $maintainers)) { throw new \Pyrus\Developer\Creator\Exception('handle configuration variable must be from ' . 'package.xml (one of ' . implode(', ', $maintainers) . ')'); } $passphrase = $frontend->ask('passphrase for OpenSSL PKCS#12 certificate?'); if (!$passphrase) { $passphrase = ''; } } else { $releaser = $cert = null; $passphrase = ''; } } else { $releaser = $cert = null; $passphrase = ''; } $sourcepath = \Pyrus\Main::getSourcePath(); if (0 !== strpos($sourcepath, 'phar://')) { // running from svn, assume we're in a standard package layout with a vendor dir // TODO: Improve this to automatically find latest releases from pear2.php.net $exceptionpath = $autoloadpath = $multierrorspath = realpath($sourcepath . '/../vendor/php') . '/PEAR2'; if (!file_exists($exceptionpath . '/Exception.php')) { throw new \Pyrus\Developer\Creator\Exception('Cannot locate PEAR2/Exception in a local vendor/ dir. ' . 'It is best to install the latest versions of these locally.'); } } else { $exceptionpath = $autoloadpath = $multierrorspath = dirname($sourcepath) . '/PEAR2'; } $extras = array(); $stub = false; if ($options['tgz'] && extension_loaded('zlib')) { $mainfile = $package->name . '-' . $package->version['release'] . '.tgz'; $mainformat = \Phar::TAR; $maincompress = \Phar::GZ; } elseif ($options['tgz']) { $options['tar'] = true; } if ($options['tar']) { if (isset($mainfile)) { $extras[] = array('tar', \Phar::TAR, \Phar::NONE); } else { $mainfile = $package->name . '-' . $package->version['release'] . '.tar'; $mainformat = \Phar::TAR; $maincompress = \Phar::NONE; } } if ($options['phar']) { if (isset($mainfile)) { $extras[] = array('phar', \Phar::PHAR, \Phar::GZ); } else { $mainfile = $package->name . '-' . $package->version['release'] . '.phar'; $mainformat = \Phar::PHAR; $maincompress = \Phar::NONE; } if (!$options['stub'] && file_exists(dirname($package->archivefile) . '/stub.php')) { $stub = file_get_contents(dirname($package->archivefile) . '/stub.php'); } elseif ($options['stub'] && file_exists($options['stub'])) { $stub = file_get_contents($options['stub']); } $stub = str_replace('@PACKAGE_VERSION' . '@', $package->version['release'], $stub); } if ($options['zip']) { if (isset($mainfile)) { $extras[] = array('zip', \Phar::ZIP, \Phar::NONE); } else { $mainfile = $package->name . '-' . $package->version['release'] . '.zip'; $mainformat = \Phar::ZIP; $maincompress = \Phar::NONE; } } if (isset($options['outputfile'])) { $mainfile = $options['outputfile']; } echo "Creating ", $mainfile, "\n"; if (null == $cert) { $cloner = new \Pyrus\Package\Cloner($mainfile); $clone = $extras; $extras = array(); } else { foreach ($extras as $stuff) { echo "Creating ", $package->name, '-', $package->version['release'], '.', $stuff[0], "\n"; } $clone = array(); } $creator = new \Pyrus\Package\Creator(array(new \Pyrus\Developer\Creator\Phar($mainfile, $stub, $mainformat, $maincompress, $extras, $releaser, $package, $cert, $passphrase)), $exceptionpath, $autoloadpath, $multierrorspath); if (!$options['extrasetup'] && file_exists(dirname($package->archivefile) . '/extrasetup.php')) { $options['extrasetup'] = 'extrasetup.php'; } if ($options['extrasetup']) { // encapsulate the extrafiles inside a closure so there is no access to the variables in this function $getinfo = function () use($options, $package) { $file = $options['extrasetup']; if (!file_exists(dirname($package->archivefile) . '/' . $file)) { throw new \Pyrus\Developer\Creator\Exception('extrasetup file must be in the same directory as package.xml'); } include dirname($package->archivefile) . '/' . $file; if (!isset($extrafiles)) { throw new \Pyrus\Developer\Creator\Exception('extrasetup file must set $extrafiles variable to an array of files'); } if (!is_array($extrafiles)) { throw new \Pyrus\Developer\Creator\Exception('extrasetup file must set $extrafiles variable to an array of files'); } foreach ($extrafiles as $path => $file) { if (is_object($file)) { if ($file instanceof \Pyrus\PackageInterface || $file instanceof \Pyrus\PackageFileInterface) { continue; } throw new \Pyrus\Developer\Creator\Exception('extrasetup file object must implement \\Pyrus\\PackageInterface or \\Pyrus\\PackageFileInterface'); } if (!file_exists($file)) { throw new \Pyrus\Developer\Creator\Exception('extrasetup file ' . $file . ' does not exist'); } if (!is_string($path)) { throw new \Pyrus\Developer\Creator\Exception('extrasetup file ' . $file . ' index should be the path to save in the' . ' release'); } } return $extrafiles; }; $extrafiles = $getinfo(); } else { $extrafiles = array(); } $creator->render($package, $extrafiles); if (count($clone)) { foreach ($clone as $extra) { echo "Creating ", $package->name, '-', $package->version['release'], '.', $extra[0], "\n"; $cloner->{'to' . $extra[0]}(); } } echo "done\n"; }
/** * Rebuild the dependency DB by reading registry entries. */ function rebuildDB() { $depdb = array('_version' => $this->_version); if (!$this->hasWriteAccess()) { // allow startup for read-only with older Registry return $depdb; } $reg = \Pyrus\Config::current()->registry; foreach (\Pyrus\Config::current()->channelregistry as $channel) { foreach ($reg->listPackages($channel->name) as $package) { $package = $reg->package[$channel->name . '/' . $package]; $depdb = $this->_setPackageDeps($depdb, $package); } } $this->_writeDepDB($depdb); }
<?php /** * This file generates the pyrus.phar file and PEAR2 package for Pyrus. */ $current = \Pyrus\Config::current(); $config = \Pyrus\Config::singleton(__DIR__ . '/vendor'); $extrafiles = array($config->registry->toPackage('PEAR2_HTTP_Request', 'pear2.php.net'), $config->registry->toPackage('PEAR2_Console_CommandLine', 'pear2.php.net'), $config->registry->toPackage('PEAR2_Exception', 'pear2.php.net'), $config->registry->toPackage('PEAR2_MultiErrors', 'pear2.php.net')); \Pyrus\Config::setCurrent($current->path);
/** * @param array output of {@link parsePackageName()} * @return \Pyrus\Channel\RemotePackage * @access private */ function getRemotePackage($parr) { // getDownloadURL returns an array. On error, it only contains information // on the latest release as array(version, info). On success it contains // array(version, info, download url string) $state = isset($parr['state']) ? $parr['state'] : Config::current()->preferred_state; if (!isset(Config::current()->channelregistry[$parr['channel']])) { throw new Exception('Unknown remote channel: ' . $parr['channel']); } try { $chan = Config::current()->channelregistry[$parr['channel']]; } catch (\Exception $e) { throw new Exception('Cannot retrieve download information ' . 'for remote abstract package ' . $parr['channel'] . '/' . $parr['package'], $e); } $p_mirror = Config::current()->preferred_mirror; $mirror = isset($chan->mirrors[$p_mirror]) ? $chan->mirrors[$p_mirror] : $chan; return $mirror->remotepackage[$parr['package']]; }
/** * Detect any files already installed that would be overwritten by * files inside the package represented by $package */ public function detectFileConflicts(\Pyrus\PackageFileInterface $package) { // construct list of all installed files $filesByPackage = $allfiles = array(); $config = \Pyrus\Config::current(); foreach ($config->channelregistry as $channel) { foreach ($this->listPackages($channel->name) as $packagename) { $files = $this->info($packagename, $channel->name, 'installedfiles'); $newfiles = array(); foreach ($files as $file) { $newfiles[$file['installed_as']] = $file; } $filesByPackage[$channel->name . '/' . $packagename] = $newfiles; $allfiles = array_merge($allfiles, $newfiles); } } // now iterate over each file in the package, and note all the conflicts $roles = array(); foreach (Role::getValidRoles($package->getPackageType()) as $role) { // set up a list of file role => configuration variable // for storing in the registry $roles[$role] = Role::factory($package->getPackageType(), $role); } $ret = array(); foreach ($package->installcontents as $file) { $relativepath = $roles[$file->role]->getRelativeLocation($package, $file); if (!$relativepath) { continue; } $testpath = $config->{$roles[$file->role]->getLocationConfig()} . DIRECTORY_SEPARATOR . $relativepath; if (isset($allfiles[$testpath])) { foreach ($filesByPackage as $pname => $files) { if (isset($files[$testpath])) { $ret[] = array($relativepath => $pname); break; } } } } return $ret; }
protected function getPackage($package) { $releases = array(); if (isset($package['a']) && $package['a']) { $releases = $package['a']['r']; if (!isset($releases[0])) { $releases = array($releases); } foreach ($releases as $i => $release) { if (!isset($release['m'])) { $releases[$i]['m'] = '5.2.0'; } } } $pxml = new RemotePackage($this->parent, $releases); $pxml->channel = $package['p']['c']; $pxml->name = $package['p']['n']; $pxml->license = $package['p']['l']; $pxml->summary = $package['p']['s']; $pxml->description = $package['p']['d']; $reg = \Pyrus\Config::current()->registry; if ($reg->exists($package['p']['n'], $package['p']['c'])) { $pxml->setExplicitState($version = $reg->info($package['p']['n'], $package['p']['c'], 'version')); $found = false; foreach ($pxml as $remoteversion => $rinfo) { if (version_compare($remoteversion, $version, '<=')) { continue; } if (version_compare($rinfo['minimumphp'], phpversion(), '>')) { continue; } // found one, so upgrade is possible if dependencies pass $found = true; break; } // the installed package version satisfies this dependency, don't do anything if ($found) { $pxml->setUpgradeable(); } } else { $pxml->setExplicitState($this->minimumStability); } return $pxml; }
/** * Unlike other tasks, the installed file name is passed in instead of the file contents, * because this task is handled post-installation * @param \Pyrus\PackageInterface * @param string path to the post-install script * @return bool false to skip this file */ function setupPostInstall() { $files = \Pyrus\Config::current()->registry->info($this->pkg->name, $this->pkg->channel, 'installedfiles'); foreach ($files as $path => $info) { if ($info['name'] == $this->_filename) { break; } } Logger::log(0, 'Including external post-installation script "' . $path . '" - any errors are in this script'); include $path; if (class_exists($this->scriptClass) === false) { throw new Exception('init of post-install script class "' . $this->scriptClass . '" failed'); } Logger::log(0, 'Inclusion succeeded'); $this->obj = new $this->scriptClass(); Logger::log(1, 'running post-install script "' . $this->scriptClass . '->init()"'); try { $this->obj->init2($this->pkg, $this->lastVersion); } catch (\Exception $e) { throw new Exception('init of post-install script "' . $this->scriptClass . '->init()" failed', $e); } Logger::log(0, 'init succeeded'); return true; }
/** * Render packages from the creators passed into the constructor. * * This will take any package source and an array mapping internal * path => file name and create new packages in the formats requested. * * All files in package.xml will have the string @PACKAGE_VERSION@ * automatically replaced with the current package's version * @param \Pyrus\Package $package * @param array $extrafiles */ function render(\Pyrus\Package $package, array $extrafiles = array()) { foreach ($this->_creators as $creator) { $creator->init(); } $this->prepend = $prepend = $package->name . '-' . $package->version['release']; if ($package->isNewPackage()) { $packagexml = $prepend . '/.xmlregistry/packages/' . str_replace('/', '!', $package->channel) . '/' . $package->name . '/' . $package->version['release'] . '-info.xml'; } else { if ($package->isOldAndCrustyCompatible()) { $packagexml = 'package2.xml'; $old = file_get_contents('package.xml'); } else { $packagexml = 'package.xml'; } } if (self::VERSION === '@' . 'PACKAGE_VERSION@') { // we're running straight from SVN, so pretend to be 2.0.0 $package->packagerversion = '2.0.0'; } else { $package->packagerversion = self::VERSION; } // get packaging package.xml $packageingstr = (string) new \Pyrus\XMLWriter($package->toArray(true)); foreach ($this->_creators as $creator) { $creator->addFile($packagexml, $packageingstr); } if ($package->isOldAndCrustyCompatible()) { foreach ($this->_creators as $creator) { $creator->addFile('package.xml', $old); } } if ($package->getInternalPackage() instanceof Xml) { // check for package_compatible.xml if ($package->isNewPackage() && file_exists($package->getFilePath('package_compatible.xml'))) { foreach ($this->_creators as $creator) { $creator->addFile('package.xml', file_get_contents($package->getFilePath('package_compatible.xml'))); } } } $packagingloc = \Pyrus\Config::current()->temp_dir . DIRECTORY_SEPARATOR . 'pyrpackage'; if (file_exists($packagingloc)) { \Pyrus\Filesystem::rmrf($packagingloc, false, false); } mkdir($packagingloc, 0777, true); // $packageat is the relative path within the archive // $info is an array of format: // array('attribs' => array('name' => ...)[, 'tasks:blah' ...]) $alreadyPackaged = array(); $globalreplace = array('attribs' => array('from' => '@' . 'PACKAGE_VERSION@', 'to' => 'version', 'type' => 'package-info')); foreach ($package->packagingcontents as $packageat => $info) { $role = \Pyrus\Installer\Role::factory($package->getPackageType(), $info['attribs']['role']); try { $role->packageTimeValidate($package, $info); } catch (\Exception $e) { throw new Creator\Exception('Invalid file ' . $packageat . ': ' . $e->getMessage(), $e); } $packageat = str_replace('\\', '/', $packageat); $packageat = str_replace('//', '/', $packageat); if ($packageat[0] === '/' || strlen($packageat) > 2 && ($packageat[1] === ':' && $packageat[2] == '/')) { throw new Creator\Exception('Invalid path, cannot save a root path ' . $packageat); } if (preg_match('@^\\.\\.?/|/\\.\\.?\\z|/\\.\\./@', $packageat)) { throw new Creator\Exception('Invalid path, cannot use directory ' . 'reference . or .. ' . $packageat); } $alreadyPackaged[$packageat] = true; $packageat = $prepend . '/' . $packageat; $contents = $package->getFileContents($info['attribs']['name'], true); if (!file_exists(dirname($packagingloc . DIRECTORY_SEPARATOR . $packageat))) { mkdir(dirname($packagingloc . DIRECTORY_SEPARATOR . $packageat), 0777, true); } $fp = fopen($packagingloc . DIRECTORY_SEPARATOR . $packageat, 'wb+'); ftruncate($fp, 0); stream_copy_to_stream($contents, $fp); fclose($contents); rewind($fp); if ($package->isNewPackage() && $info['attribs']['role'] == 'php') { if (isset($info['tasks:replace'])) { if (isset($info['tasks:replace'][0])) { $info['tasks:replace'][] = $globalreplace; } else { $info['tasks:replace'] = array($info['tasks:replace'], $globalreplace); } } else { $info['tasks:replace'] = $globalreplace; } } if (isset(\Pyrus\Config::current()->registry->package[$package->channel . '/' . $package->name])) { $version = \Pyrus\Config::current()->registry->info($package->name, $package->channel, 'version'); } else { $version = null; } foreach (new Creator\TaskIterator($info, $package, \Pyrus\Task\Common::PACKAGE, $version) as $task) { // do pre-processing of file contents try { $task->startSession($fp, $packageat); } catch (\Exception $e) { // TODO: handle exceptions } } fclose($fp); } foreach ($this->_creators as $creator) { $creator->addDir($packagingloc); } if ($package->isNewPackage()) { $this->addPEAR2Stuff($alreadyPackaged); } $this->addExtraFiles($extrafiles); foreach ($this->_creators as $creator) { $creator->close(); } \Pyrus\Filesystem::rmrf($packagingloc, false, false); }
function getDependenciesOn($info) { $name = $info->name; $channel = $info->channel; $packages = \Pyrus\Config::current()->registry->getDependentPackages($info->getPackageFileObject()); $ret = array(); foreach ($packages as $package) { $deps = $package->dependencies; foreach (array('package', 'subpackage') as $type) { foreach (array('required', 'optional') as $required) { foreach ($deps[$required]->{$type} as $dep) { if ($dep->channel != $channel || $dep->name != $name) { continue; } $ret[] = $dep; } } } } return $ret; }
/** * Detect any files already installed that would be overwritten by * files inside the package represented by $package */ public function detectFileConflicts(\Pyrus\PackageFileInterface $package) { if (!static::existsRegistry($this->_path)) { throw new \Pyrus\ChannelRegistry\Exception('Error: no existing SQLite3 channel registry for ' . $this->_path); } $database = static::getRegistry($this->_path); $ret = array(); $sql = 'SELECT packages_channel, packages_name FROM files WHERE packagepath = :path ORDER BY packages_channel, packages_name'; $stmt = $database->prepare($sql); // now iterate over each file in the package, and note all the conflicts $roles = array(); foreach (Role::getValidRoles($package->getPackageType()) as $role) { // set up a list of file role => configuration variable // for storing in the registry $roles[$role] = Role::factory($package->getPackageType(), $role); } $ret = array(); $config = Config::current(); foreach ($package->installcontents as $file) { $stmt->reset(); $relativepath = $roles[$file->role]->getRelativeLocation($package, $file); if (!$relativepath) { continue; } $testpath = $config->{$roles[$file->role]->getLocationConfig()} . DIRECTORY_SEPARATOR . $relativepath; $stmt->bindValue(':path', $testpath, SQLITE3_TEXT); $result = $stmt->execute(); while ($res = $result->fetchArray(SQLITE3_ASSOC)) { $pn = $this->info($res['packages_name'], $res['packages_channel'], 'name'); $ret[] = array($relativepath => $res['packages_channel'] . '/' . $pn); } } return $ret; }
/** * validate a downloaded package against installed packages * * @param $pkg downloaded package package.xml object * @param array $params full list of packages to install * @return bool */ function validateDownloadedPackage(\Pyrus\PackageFileInterface $pkg, $params = array()) { $me = $pkg->channel . '/' . $pkg->name; $reg = Config::current()->registry; $deppackages = $reg->getDependentPackages($pkg); $fail = false; if ($deppackages) { $actual = array(); // first, remove packages that will be installed foreach ($deppackages as $package) { foreach ($params as $packd) { if (strtolower($packd->name) == strtolower($package->name) && $packd->channel == $package->channel) { \Pyrus\Logger::log(3, 'skipping installed package check of "' . Config::parsedPackageNameToString(array('channel' => $package->channel, 'package' => $package->name), true) . '", version "' . $packd->version['release'] . '" will be ' . 'downloaded and installed'); continue 2; } } $actual[] = $package; } foreach ($actual as $package) { $checker = new \Pyrus\Dependency\Validator(array('channel' => $package->channel, 'package' => $package->name), $this->_state, $this->errs); foreach ($params as $packd) { $deps = $package->dependencies['required']->package; if (isset($deps[$me])) { $ret = $checker->_validatePackageDownload($deps[$me], array($pkg, $package)); } $deps = $package->dependencies['required']->subpackage; if (isset($deps[$me])) { $ret = $checker->_validatePackageDownload($deps[$me], array($pkg)); } $deps = $package->dependencies['optional']->package; if (isset($deps[$me])) { $ret = $checker->_validatePackageDownload($deps[$me], array($pkg, $package)); } $deps = $package->dependencies['optional']->subpackage; if (isset($deps[$me])) { $ret = $checker->_validatePackageDownload($deps[$me], array($pkg)); } } } } if (count($this->errs->E_ERROR)) { return $this->raiseError('%s cannot be installed, conflicts with installed packages'); } return true; }
function listAll($args, $options) { $reg = \Pyrus\Config::current()->registry; echo "Remote packages for channel ", $args['channel'], ":\n"; if ($options['basic']) { foreach (\Pyrus\Config::current()->channelregistry[$args['channel']]->remotecategories as $category) { echo $category->name, ":\n"; foreach ($category->basiclist as $package) { $installed = $reg->exists($package['package'], $args['channel']) ? ' *' : ' '; echo $installed, $package['package'], ' latest stable: ', $package['stable'], ', latest release: ', $package['latest']['v'], ' (', $package['latest']['s'], ")\n"; } } return; } foreach (\Pyrus\Config::current()->channelregistry[$args['channel']]->remotecategories as $category) { echo $category->name, ":\n"; $pnames = array(); $summaries = array(); $pnameinfo = array(); $versions = array(); try { foreach ($category as $package) { $installed = ' '; if ($package->isUpgradeable()) { $installed = '!'; } elseif ($reg->exists($package->name, $args['channel'])) { $installed = '*'; } $found = false; foreach ($package as $version => $latest) { $found = true; break; } $pnames[] = $package->name; $summaries[] = $package->summary; if (!$found) { $versions[] = '--'; $pnameinfo[$package->name] = array('installed' => $installed, 'summary' => $package->summary, 'latest' => 'n/a'); continue; } $versions[] = $version; $latest['v'] = $version; $pnameinfo[$package->name] = array('installed' => $installed, 'summary' => $package->summary, 'latest' => $latest); } } catch (\Exception $e) { echo "Error: Category has broken REST (", $e->getMessage(), ")\n"; continue; } $widths = array(1, 25, 8, 51); foreach ($pnameinfo as $package => $info) { if (is_string($info['latest'])) { $text = array($info['installed'], $package, $info['latest'], $info['summary']); } else { $text = array($info['installed'], $package, $info['latest']['v'], $info['summary']); } echo $this->wrapMultiColumns($text, $widths) . "\n"; } echo "Key: * = installed, ! = upgrades available\n"; } }
function pyrusRelease($frontend, $args) { $this->getSCS(); if (null !== $frontend) { $chan = \Pyrus\Config::current()->default_channel; \Pyrus\Config::current()->default_channel = $this->channel->name; $args['maintainer'] = \Pyrus\Config::current()->handle; \Pyrus\Config::current()->default_channel = $chan; } $this->scs->saveRelease($args['path'], $args['maintainer']); echo 'Release successfully saved.' . PHP_EOL; }
protected function getMode($mode = null) { if ($mode === null) { return 0777 & ~octdec(\Pyrus\Config::current()->umask); } return $mode & 0777; }
/** * Do a package.xml 1.0 replacement, with additional package-info fields available * * See validateXml() source for the complete list of allowed fields * @param \Pyrus\PackageInterface * @param resource open file pointer, set to the beginning of the file * @param string the eventual final file location (informational only) * @return string|false */ function startSession($fp, $dest) { $contents = stream_get_contents($fp); $subst_from = $subst_to = array(); foreach ($this->_replacements as $a) { $a = $a['attribs']; $to = ''; if ($a['type'] == 'pear-config') { if ($this->installphase == Common::PACKAGE) { return false; } $to = \Pyrus\Config::current()->{$a['to']}; if (is_null($to)) { \Pyrus\Logger::log(0, "{$dest}: invalid pear-config replacement: {$a['to']}"); return false; } } elseif ($a['type'] == 'php-const') { if ($this->installphase == Common::PACKAGE) { return false; } if (defined($a['to'])) { $to = constant($a['to']); } else { \Pyrus\Logger::log(0, "{$dest}: invalid php-const replacement: {$a['to']}"); return false; } } else { if ($t = $this->pkg->{$a['to']}) { if ($a['to'] == 'version') { $t = $t['release']; } $to = $t; } else { \Pyrus\Logger::log(0, "{$dest}: invalid package-info replacement: {$a['to']}"); return false; } } if (!is_null($to)) { $subst_from[] = $a['from']; $subst_to[] = $to; } } \Pyrus\Logger::log(3, "doing " . sizeof($subst_from) . " substitution(s) for {$dest}"); if (sizeof($subst_from)) { $contents = str_replace($subst_from, $subst_to, $contents); } rewind($fp); ftruncate($fp, 0); fwrite($fp, $contents); return true; }
ini_set('display_errors', true); // Get the autoloader require __DIR__ . '/../../../autoload.php'; /* $channel = new Pyrus_SimpleChannelServer('pear2.php.net','/Library/WebServer/Documents/pearserver', null, '/Users/bbieber/pyrus', array('saltybeagle','cellog')); if (!@unserialize(file_get_contents('/tmp/categories.inf'))) { $cat = Pyrus_SimpleChannelServer_Categories::create('Name1', 'Description 1', 'Alias1')-> create('Name2', 'Description 2')-> create('Name3', 'Description 3', 'Alias3')-> create('Name4', 'Description 4'); file_put_contents('/tmp/categories.inf', serialize($cat)); } $categories = Pyrus_SimpleChannelServer_Categories::getCategories(); $categories = $channel->listCategories(); foreach($categories as $category) { var_dump($category); } */ $channel = new Pyrus\SimpleChannelServer\Channel('pear2.php.net', 'Brett Bieber\'s PEAR Channel', 'salty'); //$scs = new Pyrus\SimpleChannelServer\Main($channel,'/Library/WebServer/Documents/pearserver','/home/bbieber/pyrus/php'); $scs = new Pyrus\SimpleChannelServer\Main($channel, '/home/cellog/testapache/htdocs', \Pyrus\Config::current()->location); $categories = Pyrus\SimpleChannelServer\Categories::create('Default', 'This is the default category'); $scs->saveChannel(); $scs->saveRelease(new \Pyrus\Package(dirname(__FILE__) . '/../package.xml'), 'cellog'); echo 'did it' . PHP_EOL; /* $manager = new Pyrus\SimpleChannelServer\REST_Manager('/Library/WebServer/Documents/pearserver','pear2.php.net','rest/',array('cellog')); var_dump($manager->saveRelease(new \Pyrus\Package(dirname(__FILE__) . '/../package.xml'),'cellog')); */
static function registerCustomRole($info) { if (!isset(self::$_roles)) { self::registerRoles(); } self::$_roles[$info['name']] = $info; $roles = self::$_roles; ksort($roles); self::$_roles = $roles; self::getBaseinstallRoles(true); self::getInstallableRoles(true); self::getValidRoles('****', true); if (isset($info['configvar'])) { if (!isset($info['configvar'][0])) { $info['configvar'] = array($info['configvar']); } foreach ($info['configvar'] as $configvar) { if ($configvar['configtype'] == 'system' && in_array($configvar['name'], Config::current()->customsystemvars) || $configvar['configtype'] == 'user' && in_array($configvar['name'], Config::current()->customuservars) || $configvar['configtype'] == 'channel' && in_array($configvar['name'], Config::current()->customchannelvars)) { continue; } $default = $configvar['default']; if (false !== strpos($default, '<?php')) { $tmp = Config::current()->temp_dir . DIRECTORY_SEPARATOR . '.configdefault.php'; if (!file_exists(dirname($tmp))) { mkdir(dirname($tmp), 0755, true); } if (file_put_contents($tmp, $default) === false) { throw new Role\Exception("Cannot create custom role configuration file {$tmp}"); } $getDefault = function () use($tmp) { include $tmp; return $default; }; $default = $getDefault(); } Config::addConfigValue($configvar['name'], $default, $configvar['configtype']); } } }
/** * Check to see if any packages in the list of packages to be installed * satisfy this dependency, and return one if found, otherwise * instantiate a new dependency package object * @return \Pyrus\PackageInterface|NULL */ function retrieve(\Pyrus\PackageFile\v2\Dependencies\Package $info) { if (isset(self::$localPackages[$info->channel . '/' . $info->name]) || $this->childProcessed($info->channel . '/' . $info->name)) { // we can safely ignore this dependency, an explicit local // package is being installed, and we will use it // or the dependency has been previously processed, and we will // simply result in a duplicate return; } $reg = Config::current()->registry; // first check to see if the dependency is installed $canupgrade = false; if (isset($reg->package[$info->channel . '/' . $info->name])) { if (!isset(\Pyrus\Main::$options['upgrade'])) { // we don't attempt to upgrade a dep unless we're upgrading return; } $version = $reg->info($info->name, $info->channel, 'version'); $stability = $reg->info($info->name, $info->channel, 'state'); if ($this->node->isRemote() && $this->node->getExplicitState()) { $installedstability = \Pyrus\Installer::betterStates($stability); $parentstability = \Pyrus\Installer::betterStates($this->node->getExplicitState()); if (count($parentstability) > count($installedstability)) { $stability = $this->node->getExplicitState(); } } else { $installedstability = \Pyrus\Installer::betterStates($stability); $prefstability = \Pyrus\Installer::betterStates(Config::current()->preferred_state); if (count($prefstability) > count($installedstability)) { $stability = Config::current()->preferred_state; } } // see if there are new versions in our stability or better if (isset($info->uri)) { return; } $remote = new \Pyrus\Channel\RemotePackage(Config::current()->channelregistry[$info->channel], $stability); $found = false; foreach ($remote[$info->name] as $remoteversion => $rinfo) { if (version_compare($remoteversion, $version, '<=')) { continue; } if (version_compare($rinfo['minimumphp'], static::getPHPversion(), '>')) { continue; } // found one, so upgrade is possible if dependencies pass $found = true; break; } // the installed package version satisfies this dependency, don't do anything if (!$found) { return; } $canupgrade = true; } if (isset($info->uri)) { $ret = new \Pyrus\Package\Remote($info->uri); // set up the basics $ret->name = $info->name; $ret->uri = $info->uri; $this->addChild($ret); return; } if ($this->node->isRemote() && $this->node->getExplicitState()) { // pass the same explicit state to the child dependency $ret = new \Pyrus\Package\Remote($info->channel . '/' . $info->name . '-' . $this->node->getExplicitState()); if ($canupgrade) { $ret->setUpgradeable(); } $this->addChild($ret); return; } $ret = new \Pyrus\Package\Remote($info->channel . '/' . $info->name); if ($canupgrade) { $ret->setUpgradeable(); } $this->addChild($ret); return; }
/** * Figure out which version is best, and use this, or error out if none work * @param \Pyrus\PackageFile\v2\Dependencies\Package $compositeDep * the composite of all dependencies on this package, as calculated * by {@link \Pyrus\Package\Dependency::getCompositeDependency()} */ function figureOutBestVersion(\Pyrus\PackageFile\v2\Dependencies\Package $compositeDep, $versions = null, \Pyrus\PackageFile\v2\Dependencies\Package $compositeConflictingDep = null) { // set up release list if not done yet $this->rewind(); $ok = \Pyrus\Installer::betterStates($this->minimumStability, true); $v = $this->explicitVersion; $n = $this->channel . '/' . $this->name; $failIfExplicit = function ($versioninfo) use($v, $n) { if ($v && $versioninfo['v'] == $v) { throw new Exception($n . ' Cannot be installed, it does not satisfy ' . 'all dependencies'); } }; foreach ($this->releaseList as $versioninfo) { if (isset(\Pyrus\Main::$options['force'])) { // found one if ($this->versionSet && $versioninfo['v'] != $this->version['release']) { // inform the installer we need to reset dependencies $this->version['release'] = $versioninfo['v']; return true; } $this->version['release'] = $versioninfo['v']; return; } if ($versions && !in_array($versioninfo['v'], $versions)) { continue; } if (!isset(\Pyrus\Main::$options['force']) && isset($versioninfo['m'])) { // minimum PHP version required if (version_compare($versioninfo['m'], $this->getPHPVersion(), '>')) { $failIfExplicit($versioninfo); continue; } } if (!in_array($versioninfo['s'], $ok) && !isset(\Pyrus\Main::$options['force'])) { // release is not stable enough continue; } if ($this->explicitVersion && $versioninfo['v'] != $this->explicitVersion) { continue; } if (!$compositeDep->satisfied($versioninfo['v'])) { $failIfExplicit($versioninfo); continue; } if ($compositeConflictingDep && !$compositeConflictingDep->satisfied($versioninfo['v'])) { $failIfExplicit($versioninfo); continue; } $paranoia = \Pyrus\Main::getParanoiaLevel(); if (!$this->explicitVersion && $paranoia > 1) { // first, we check to see if we are upgrading if (isset(\Pyrus\Main::$options['upgrade'])) { // now we check to see if we are installed if (isset(Config::current()->registry->package[$n])) { $installed = Config::current()->registry->info($this->name, $this->channel, 'apiversion'); $installed = explode('.', $installed); if (count($installed) == 2) { $installed[] = '0'; } if (count($installed) == 1) { $installed[] = '0'; $installed[] = '0'; } if (isset($this->parent->protocols->rest['REST1.3'])) { $api = $this->rest->retrieveCacheFirst($this->parent->protocols->rest['REST1.3']->baseurl . 'r/' . strtolower($this->name) . '/v2.' . $versioninfo['v'] . '.xml', false, false, 'text/xml'); } else { throw new Exception('Channel ' . $this->channel . ' does not support ' . 'a paranoia greater than 1'); } $api = explode('.', $api['a']); if (count($api) == 2) { $api[] = '0'; } if (count($api) == 1) { $api[] = '0'; $api[] = '0'; } if ($paranoia > 4) { $paranoia = 4; } switch ($paranoia) { case 4: if ($installed != $api) { Logger::log(0, 'Skipping ' . $this->channel . '/' . $this->name . ' version ' . $versioninfo['v'] . ', API has changed'); continue 2; } break; case 3: if ($installed[0] == $api[0] && $installed[1] != $api[1]) { Logger::log(0, 'Skipping ' . $this->channel . '/' . $this->name . ' version ' . $versioninfo['v'] . ', API has added' . ' new features'); continue 2; } // break intentionally omitted // break intentionally omitted case 2: if ($installed[0] != $api[0]) { Logger::log(0, 'Skipping ' . $this->channel . '/' . $this->name . ' version ' . $versioninfo['v'] . ', API breaks' . ' backwards compatibility'); continue 2; } break; } } } } // found one if ($this->versionSet && $versioninfo['v'] != $this->version['release']) { // inform the installer we need to reset dependencies $this->version['release'] = $versioninfo['v']; return true; } $this->version['release'] = $versioninfo['v']; return; } throw new Exception('Unable to locate a package release for ' . $this->channel . '/' . $this->name . ' that can satisfy all dependencies'); }
public function info($package, $channel, $field) { if (!$this->exists($package, $channel)) { throw new Exception('Unknown package ' . $channel . '/' . $package); } $pf = $this->toPackageFile($package, $channel); if ($field === null) { return $pf; } if ($field == 'version') { $field = 'release-version'; } if ($field != 'installedfiles' && $field != 'dirtree') { return $pf->{$field}; } $packagefile = $this->_namePath($channel, $package) . '.reg'; if (!$packagefile || !isset($packagefile[0])) { throw new Exception('Cannot find registry for package ' . $channel . '/' . $package); } $packagecontents = file_get_contents($packagefile); $data = @unserialize($packagecontents); if ($data === false) { throw new Exception('Cannot retrieve package file object for package ' . $channel . '/' . $package . ', PEAR 1.x registry file might be corrupt!'); } if ($field == 'dirtree') { $ret = $data['filelist']['dirtree']; usort($ret, 'strnatcasecmp'); return array_reverse($ret); } $configpaths = $roles = array(); $config = \Pyrus\Config::current(); foreach (Role::getValidRoles($pf->getPackageType()) as $role) { // set up a list of file role => configuration variable // for storing in the registry $roles[$role] = Role::factory($pf->getPackageType(), $role); $configpaths[$role] = $config->{$roles[$role]->getLocationConfig()}; } $ret = array(); foreach ($data['filelist'] as $file) { if (!isset($file['installed_as']) || !isset($configpaths[$file['role']])) { continue; } if (0 !== strpos($file['installed_as'], $configpaths[$file['role']])) { // this was installed with a different configuration, so don't guess $file['relativepath'] = basename($file['installed_as']); $file['configpath'] = dirname($file['installed_as']); } else { $file['relativepath'] = substr($file['installed_as'], strlen($configpaths[$file['role']]) + 1); $file['configpath'] = $configpaths[$file['role']]; } $ret[$file['installed_as']] = $file; } return $ret; }
/** * Repair from a previously failed transaction cut off mid-transaction */ public static function repair() { if (static::inTransaction()) { throw new AtomicFileTransaction\RuntimeException('Cannot repair while in a transaction'); } static::$instance = null; $config = Config::current(); $remove = array(); foreach ($config->systemvars as $var) { if (!strpos($var, '_dir')) { continue; } $path = FS::path($config->{$var}); $backuppath = dirname($path) . DIRECTORY_SEPARATOR . '.old-' . basename($path); if (file_exists($backuppath) && is_dir($backuppath)) { if (file_exists($path)) { if (!is_dir($path)) { throw new AtomicFileTransaction\RuntimeException('Repair failed - ' . $var . ' path ' . $path . ' is not a directory. Move this file out of the way and ' . 'try the repair again'); } // this is the new stuff from journal path, so move it out of the way $journalpath = dirname($path) . DIRECTORY_SEPARATOR . '.journal-' . basename($path); $remove[] = $journalpath; rename($path, $journalpath); } // restore backup rename($backuppath, $path); } } foreach ($remove as $path) { FS::rmrf($path); } }