opt
/
alt
/
php72
/
usr
/
share
/
pear
/
PEAR
/
Go to Home Directory
+
Upload
Create File
root@0UT1S:~$
Execute
By Order of Mr.0UT1S
[DIR] ..
N/A
[DIR] ChannelFile
N/A
[DIR] Command
N/A
[DIR] Downloader
N/A
[DIR] Frontend
N/A
[DIR] Installer
N/A
[DIR] PackageFile
N/A
[DIR] REST
N/A
[DIR] Task
N/A
[DIR] Validator
N/A
Builder.php
18.50 KB
Rename
Delete
ChannelFile.php
49.65 KB
Rename
Delete
Command.php
12.14 KB
Rename
Delete
Common.php
25.85 KB
Rename
Delete
Config.php
67.53 KB
Rename
Delete
Dependency2.php
49.26 KB
Rename
Delete
DependencyDB.php
23.75 KB
Rename
Delete
Downloader.php
64.46 KB
Rename
Delete
ErrorStack.php
33.01 KB
Rename
Delete
Exception.php
13.61 KB
Rename
Delete
Frontend.php
6.49 KB
Rename
Delete
Installer.php
68.45 KB
Rename
Delete
PackageFile.php
15.47 KB
Rename
Delete
Packager.php
7.53 KB
Rename
Delete
Proxy.php
5.48 KB
Rename
Delete
REST.php
16.32 KB
Rename
Delete
Registry.php
74.18 KB
Rename
Delete
RunTest.php
35.40 KB
Rename
Delete
Validate.php
21.49 KB
Rename
Delete
XMLParser.php
6.75 KB
Rename
Delete
<?php /** * PEAR_Installer * * PHP versions 4 and 5 * * @category pear * @package PEAR * @author Stig Bakken <ssb@php.net> * @author Tomas V.V. Cox <cox@idecnet.com> * @author Martin Jansen <mj@php.net> * @author Greg Beaver <cellog@php.net> * @copyright 1997-2009 The Authors * @license http://opensource.org/licenses/bsd-license.php New BSD License * @link http://pear.php.net/package/PEAR * @since File available since Release 0.1 */ /** * Used for installation groups in package.xml 2.0 and platform exceptions */ require_once 'OS/Guess.php'; require_once 'PEAR/Downloader.php'; define('PEAR_INSTALLER_NOBINARY', -240); /** * Administration class used to install PEAR packages and maintain the * installed package database. * * @category pear * @package PEAR * @author Stig Bakken <ssb@php.net> * @author Tomas V.V. Cox <cox@idecnet.com> * @author Martin Jansen <mj@php.net> * @author Greg Beaver <cellog@php.net> * @copyright 1997-2009 The Authors * @license http://opensource.org/licenses/bsd-license.php New BSD License * @version Release: 1.10.16 * @link http://pear.php.net/package/PEAR * @since Class available since Release 0.1 */ class PEAR_Installer extends PEAR_Downloader { // {{{ properties /** name of the package directory, for example Foo-1.0 * @var string */ var $pkgdir; /** directory where PHP code files go * @var string */ var $phpdir; /** directory where PHP extension files go * @var string */ var $extdir; /** directory where documentation goes * @var string */ var $docdir; /** installation root directory (ala PHP's INSTALL_ROOT or * automake's DESTDIR * @var string */ var $installroot = ''; /** debug level * @var int */ var $debug = 1; /** temporary directory * @var string */ var $tmpdir; /** * PEAR_Registry object used by the installer * @var PEAR_Registry */ var $registry; /** * array of PEAR_Downloader_Packages * @var array */ var $_downloadedPackages; /** List of file transactions queued for an install/upgrade/uninstall. * * Format: * array( * 0 => array("rename => array("from-file", "to-file")), * 1 => array("delete" => array("file-to-delete")), * ... * ) * * @var array */ var $file_operations = array(); // }}} // {{{ constructor /** * PEAR_Installer constructor. * * @param object $ui user interface object (instance of PEAR_Frontend_*) * * @access public */ function __construct(&$ui) { parent::__construct($ui, array(), null); $this->setFrontendObject($ui); $this->debug = $this->config->get('verbose'); } function setOptions($options) { $this->_options = $options; } function setConfig(&$config) { $this->config = &$config; $this->_registry = &$config->getRegistry(); } // }}} function _removeBackups($files) { foreach ($files as $path) { $this->addFileOperation('removebackup', array($path)); } } // {{{ _deletePackageFiles() /** * Delete a package's installed files, does not remove empty directories. * * @param string package name * @param string channel name * @param bool if true, then files are backed up first * @return bool TRUE on success, or a PEAR error on failure * @access protected */ function _deletePackageFiles($package, $channel = false, $backup = false) { if (!$channel) { $channel = 'pear.php.net'; } if (!strlen($package)) { return $this->raiseError("No package to uninstall given"); } if (strtolower($package) == 'pear' && $channel == 'pear.php.net') { // to avoid race conditions, include all possible needed files require_once 'PEAR/Task/Common.php'; require_once 'PEAR/Task/Replace.php'; require_once 'PEAR/Task/Unixeol.php'; require_once 'PEAR/Task/Windowseol.php'; require_once 'PEAR/PackageFile/v1.php'; require_once 'PEAR/PackageFile/v2.php'; require_once 'PEAR/PackageFile/Generator/v1.php'; require_once 'PEAR/PackageFile/Generator/v2.php'; } $filelist = $this->_registry->packageInfo($package, 'filelist', $channel); if ($filelist == null) { return $this->raiseError("$channel/$package not installed"); } $ret = array(); foreach ($filelist as $file => $props) { if (empty($props['installed_as'])) { continue; } $path = $props['installed_as']; if ($backup) { $this->addFileOperation('backup', array($path)); $ret[] = $path; } $this->addFileOperation('delete', array($path)); } if ($backup) { return $ret; } return true; } // }}} // {{{ _installFile() /** * @param string filename * @param array attributes from <file> tag in package.xml * @param string path to install the file in * @param array options from command-line * @access private */ function _installFile($file, $atts, $tmp_path, $options) { // {{{ return if this file is meant for another platform static $os; if (!isset($this->_registry)) { $this->_registry = &$this->config->getRegistry(); } if (isset($atts['platform'])) { if (empty($os)) { $os = new OS_Guess(); } if (strlen($atts['platform']) && $atts['platform'][0] == '!') { $negate = true; $platform = substr($atts['platform'], 1); } else { $negate = false; $platform = $atts['platform']; } if ((bool) $os->matchSignature($platform) === $negate) { $this->log(3, "skipped $file (meant for $atts[platform], we are ".$os->getSignature().")"); return PEAR_INSTALLER_SKIPPED; } } // }}} $channel = $this->pkginfo->getChannel(); // {{{ assemble the destination paths switch ($atts['role']) { case 'src': case 'extsrc': $this->source_files++; return; case 'doc': case 'data': case 'test': $dest_dir = $this->config->get($atts['role'] . '_dir', null, $channel) . DIRECTORY_SEPARATOR . $this->pkginfo->getPackage(); unset($atts['baseinstalldir']); break; case 'ext': case 'php': $dest_dir = $this->config->get($atts['role'] . '_dir', null, $channel); break; case 'script': $dest_dir = $this->config->get('bin_dir', null, $channel); break; default: return $this->raiseError("Invalid role `$atts[role]' for file $file"); } $save_destdir = $dest_dir; if (!empty($atts['baseinstalldir'])) { $dest_dir .= DIRECTORY_SEPARATOR . $atts['baseinstalldir']; } if (dirname($file) != '.' && empty($atts['install-as'])) { $dest_dir .= DIRECTORY_SEPARATOR . dirname($file); } if (empty($atts['install-as'])) { $dest_file = $dest_dir . DIRECTORY_SEPARATOR . basename($file); } else { $dest_file = $dest_dir . DIRECTORY_SEPARATOR . $atts['install-as']; } $orig_file = $tmp_path . DIRECTORY_SEPARATOR . $file; // Clean up the DIRECTORY_SEPARATOR mess $ds2 = DIRECTORY_SEPARATOR . DIRECTORY_SEPARATOR; list($dest_file, $orig_file) = preg_replace(array('!\\\\+!', '!/!', "!$ds2+!"), array(DIRECTORY_SEPARATOR, DIRECTORY_SEPARATOR, DIRECTORY_SEPARATOR), array($dest_file, $orig_file)); $final_dest_file = $installed_as = $dest_file; if (isset($this->_options['packagingroot'])) { $installedas_dest_dir = dirname($final_dest_file); $installedas_dest_file = $dest_dir . DIRECTORY_SEPARATOR . '.tmp' . basename($final_dest_file); $final_dest_file = $this->_prependPath($final_dest_file, $this->_options['packagingroot']); } else { $installedas_dest_dir = dirname($final_dest_file); $installedas_dest_file = $installedas_dest_dir . DIRECTORY_SEPARATOR . '.tmp' . basename($final_dest_file); } $dest_dir = dirname($final_dest_file); $dest_file = $dest_dir . DIRECTORY_SEPARATOR . '.tmp' . basename($final_dest_file); if (preg_match('~/\.\.(/|\\z)|^\.\./~', str_replace('\\', '/', $dest_file))) { return $this->raiseError("SECURITY ERROR: file $file (installed to $dest_file) contains parent directory reference ..", PEAR_INSTALLER_FAILED); } // }}} if (empty($this->_options['register-only']) && (!file_exists($dest_dir) || !is_dir($dest_dir))) { if (!$this->mkDirHier($dest_dir)) { return $this->raiseError("failed to mkdir $dest_dir", PEAR_INSTALLER_FAILED); } $this->log(3, "+ mkdir $dest_dir"); } // pretty much nothing happens if we are only registering the install if (empty($this->_options['register-only'])) { if (empty($atts['replacements'])) { if (!file_exists($orig_file)) { return $this->raiseError("file $orig_file does not exist", PEAR_INSTALLER_FAILED); } if (!@copy($orig_file, $dest_file)) { return $this->raiseError( "failed to write $dest_file: " . error_get_last()["message"], PEAR_INSTALLER_FAILED); } $this->log(3, "+ cp $orig_file $dest_file"); if (isset($atts['md5sum'])) { $md5sum = md5_file($dest_file); } } else { // {{{ file with replacements if (!file_exists($orig_file)) { return $this->raiseError("file does not exist", PEAR_INSTALLER_FAILED); } $contents = file_get_contents($orig_file); if ($contents === false) { $contents = ''; } if (isset($atts['md5sum'])) { $md5sum = md5($contents); } $subst_from = $subst_to = array(); foreach ($atts['replacements'] as $a) { $to = ''; if ($a['type'] == 'php-const') { if (preg_match('/^[a-z0-9_]+\\z/i', $a['to'])) { eval("\$to = $a[to];"); } else { if (!isset($options['soft'])) { $this->log(0, "invalid php-const replacement: $a[to]"); } continue; } } elseif ($a['type'] == 'pear-config') { if ($a['to'] == 'master_server') { $chan = $this->_registry->getChannel($channel); if (!PEAR::isError($chan)) { $to = $chan->getServer(); } else { $to = $this->config->get($a['to'], null, $channel); } } else { $to = $this->config->get($a['to'], null, $channel); } if (is_null($to)) { if (!isset($options['soft'])) { $this->log(0, "invalid pear-config replacement: $a[to]"); } continue; } } elseif ($a['type'] == 'package-info') { if ($t = $this->pkginfo->packageInfo($a['to'])) { $to = $t; } else { if (!isset($options['soft'])) { $this->log(0, "invalid package-info replacement: $a[to]"); } continue; } } if (!is_null($to)) { $subst_from[] = $a['from']; $subst_to[] = $to; } } $this->log(3, "doing ".sizeof($subst_from)." substitution(s) for $final_dest_file"); if (sizeof($subst_from)) { $contents = str_replace($subst_from, $subst_to, $contents); } $wp = @fopen($dest_file, "wb"); if (!is_resource($wp)) { return $this->raiseError( "failed to create $dest_file: " . error_get_last()["message"], PEAR_INSTALLER_FAILED); } if (@fwrite($wp, $contents) === false) { return $this->raiseError( "failed writing to $dest_file: " . error_get_last()["message"], PEAR_INSTALLER_FAILED); } fclose($wp); // }}} } // {{{ check the md5 if (isset($md5sum)) { if (strtolower($md5sum) === strtolower($atts['md5sum'])) { $this->log(2, "md5sum ok: $final_dest_file"); } else { if (empty($options['force'])) { // delete the file if (file_exists($dest_file)) { unlink($dest_file); } if (!isset($options['ignore-errors'])) { return $this->raiseError("bad md5sum for file $final_dest_file", PEAR_INSTALLER_FAILED); } if (!isset($options['soft'])) { $this->log(0, "warning : bad md5sum for file $final_dest_file"); } } else { if (!isset($options['soft'])) { $this->log(0, "warning : bad md5sum for file $final_dest_file"); } } } } // }}} // {{{ set file permissions if (!OS_WINDOWS) { if ($atts['role'] == 'script') { $mode = 0777 & ~(int)octdec($this->config->get('umask')); $this->log(3, "+ chmod +x $dest_file"); } else { $mode = 0666 & ~(int)octdec($this->config->get('umask')); } if ($atts['role'] != 'src') { $this->addFileOperation("chmod", array($mode, $dest_file)); if (!@chmod($dest_file, $mode)) { if (!isset($options['soft'])) { $this->log(0, "failed to change mode of $dest_file: " . error_get_last()["message"]); } } } } // }}} if ($atts['role'] == 'src') { rename($dest_file, $final_dest_file); $this->log(2, "renamed source file $dest_file to $final_dest_file"); } else { $this->addFileOperation("rename", array($dest_file, $final_dest_file, $atts['role'] == 'ext')); } } // Store the full path where the file was installed for easy unistall if ($atts['role'] != 'script') { $loc = $this->config->get($atts['role'] . '_dir'); } else { $loc = $this->config->get('bin_dir'); } if ($atts['role'] != 'src') { $this->addFileOperation("installed_as", array($file, $installed_as, $loc, dirname(substr($installedas_dest_file, strlen($loc))))); } //$this->log(2, "installed: $dest_file"); return PEAR_INSTALLER_OK; } // }}} // {{{ _installFile2() /** * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2 * @param string filename * @param array attributes from <file> tag in package.xml * @param string path to install the file in * @param array options from command-line * @access private */ function _installFile2(&$pkg, $file, &$real_atts, $tmp_path, $options) { $atts = $real_atts; if (!isset($this->_registry)) { $this->_registry = &$this->config->getRegistry(); } $channel = $pkg->getChannel(); // {{{ assemble the destination paths if (!in_array($atts['attribs']['role'], PEAR_Installer_Role::getValidRoles($pkg->getPackageType()))) { return $this->raiseError('Invalid role `' . $atts['attribs']['role'] . "' for file $file"); } $role = &PEAR_Installer_Role::factory($pkg, $atts['attribs']['role'], $this->config); $err = $role->setup($this, $pkg, $atts['attribs'], $file); if (PEAR::isError($err)) { return $err; } if (!$role->isInstallable()) { return; } $info = $role->processInstallation($pkg, $atts['attribs'], $file, $tmp_path); if (PEAR::isError($info)) { return $info; } list($save_destdir, $dest_dir, $dest_file, $orig_file) = $info; if (preg_match('~/\.\.(/|\\z)|^\.\./~', str_replace('\\', '/', $dest_file))) { return $this->raiseError("SECURITY ERROR: file $file (installed to $dest_file) contains parent directory reference ..", PEAR_INSTALLER_FAILED); } $final_dest_file = $installed_as = $dest_file; if (isset($this->_options['packagingroot'])) { $final_dest_file = $this->_prependPath($final_dest_file, $this->_options['packagingroot']); } $dest_dir = dirname($final_dest_file); $dest_file = $dest_dir . DIRECTORY_SEPARATOR . '.tmp' . basename($final_dest_file); // }}} if (empty($this->_options['register-only'])) { if (!file_exists($dest_dir) || !is_dir($dest_dir)) { if (!$this->mkDirHier($dest_dir)) { return $this->raiseError("failed to mkdir $dest_dir", PEAR_INSTALLER_FAILED); } $this->log(3, "+ mkdir $dest_dir"); } } $attribs = $atts['attribs']; unset($atts['attribs']); // pretty much nothing happens if we are only registering the install if (empty($this->_options['register-only'])) { if (!count($atts)) { // no tasks if (!file_exists($orig_file)) { return $this->raiseError("file $orig_file does not exist", PEAR_INSTALLER_FAILED); } if (!@copy($orig_file, $dest_file)) { return $this->raiseError( "failed to write $dest_file: " . error_get_last()["message"], PEAR_INSTALLER_FAILED); } $this->log(3, "+ cp $orig_file $dest_file"); if (isset($attribs['md5sum'])) { $md5sum = md5_file($dest_file); } } else { // file with tasks if (!file_exists($orig_file)) { return $this->raiseError("file $orig_file does not exist", PEAR_INSTALLER_FAILED); } $contents = file_get_contents($orig_file); if ($contents === false) { $contents = ''; } if (isset($attribs['md5sum'])) { $md5sum = md5($contents); } foreach ($atts as $tag => $raw) { $tag = str_replace(array($pkg->getTasksNs() . ':', '-'), array('', '_'), $tag); $task = "PEAR_Task_$tag"; $task = new $task($this->config, $this, PEAR_TASK_INSTALL); if (!$task->isScript()) { // scripts are only handled after installation $task->init($raw, $attribs, $pkg->getLastInstalledVersion()); $res = $task->startSession($pkg, $contents, $final_dest_file); if ($res === false) { continue; // skip this file } if (PEAR::isError($res)) { return $res; } $contents = $res; // save changes } $wp = @fopen($dest_file, "wb"); if (!is_resource($wp)) { return $this->raiseError( "failed to create $dest_file: " . error_get_last()["message"], PEAR_INSTALLER_FAILED); } if (fwrite($wp, $contents) === false) { return $this->raiseError( "failed writing to $dest_file: " . error_get_last()["message"], PEAR_INSTALLER_FAILED); } fclose($wp); } } // {{{ check the md5 if (isset($md5sum)) { // Make sure the original md5 sum matches with expected if (strtolower($md5sum) === strtolower($attribs['md5sum'])) { $this->log(2, "md5sum ok: $final_dest_file"); if (isset($contents)) { // set md5 sum based on $content in case any tasks were run. $real_atts['attribs']['md5sum'] = md5($contents); } } else { if (empty($options['force'])) { // delete the file if (file_exists($dest_file)) { unlink($dest_file); } if (!isset($options['ignore-errors'])) { return $this->raiseError("bad md5sum for file $final_dest_file", PEAR_INSTALLER_FAILED); } if (!isset($options['soft'])) { $this->log(0, "warning : bad md5sum for file $final_dest_file"); } } else { if (!isset($options['soft'])) { $this->log(0, "warning : bad md5sum for file $final_dest_file"); } } } } else { $real_atts['attribs']['md5sum'] = md5_file($dest_file); } // }}} // {{{ set file permissions if (!OS_WINDOWS) { if ($role->isExecutable()) { $mode = 0777 & ~(int)octdec($this->config->get('umask')); $this->log(3, "+ chmod +x $dest_file"); } else { $mode = 0666 & ~(int)octdec($this->config->get('umask')); } if ($attribs['role'] != 'src') { $this->addFileOperation("chmod", array($mode, $dest_file)); if (!@chmod($dest_file, $mode)) { if (!isset($options['soft'])) { $this->log(0, "failed to change mode of $dest_file: " . error_get_last()["message"]); } } } } // }}} if ($attribs['role'] == 'src') { rename($dest_file, $final_dest_file); $this->log(2, "renamed source file $dest_file to $final_dest_file"); } else { $this->addFileOperation("rename", array($dest_file, $final_dest_file, $role->isExtension())); } } // Store the full path where the file was installed for easy uninstall if ($attribs['role'] != 'src') { $loc = $this->config->get($role->getLocationConfig(), null, $channel); $this->addFileOperation('installed_as', array($file, $installed_as, $loc, dirname(substr($installed_as, strlen($loc))))); } //$this->log(2, "installed: $dest_file"); return PEAR_INSTALLER_OK; } // }}} // {{{ addFileOperation() /** * Add a file operation to the current file transaction. * * @see startFileTransaction() * @param string $type This can be one of: * - rename: rename a file ($data has 3 values) * - backup: backup an existing file ($data has 1 value) * - removebackup: clean up backups created during install ($data has 1 value) * - chmod: change permissions on a file ($data has 2 values) * - delete: delete a file ($data has 1 value) * - rmdir: delete a directory if empty ($data has 1 value) * - installed_as: mark a file as installed ($data has 4 values). * @param array $data For all file operations, this array must contain the * full path to the file or directory that is being operated on. For * the rename command, the first parameter must be the file to rename, * the second its new name, the third whether this is a PHP extension. * * The installed_as operation contains 4 elements in this order: * 1. Filename as listed in the filelist element from package.xml * 2. Full path to the installed file * 3. Full path from the php_dir configuration variable used in this * installation * 4. Relative path from the php_dir that this file is installed in */ function addFileOperation($type, $data) { if (!is_array($data)) { return $this->raiseError('Internal Error: $data in addFileOperation' . ' must be an array, was ' . gettype($data)); } if ($type == 'chmod') { $octmode = decoct($data[0]); $this->log(3, "adding to transaction: $type $octmode $data[1]"); } else { $this->log(3, "adding to transaction: $type " . implode(" ", $data)); } $this->file_operations[] = array($type, $data); } // }}} // {{{ startFileTransaction() function startFileTransaction($rollback_in_case = false) { if (count($this->file_operations) && $rollback_in_case) { $this->rollbackFileTransaction(); } $this->file_operations = array(); } // }}} // {{{ commitFileTransaction() function commitFileTransaction() { // {{{ first, check permissions and such manually $errors = array(); foreach ($this->file_operations as $key => $tr) { list($type, $data) = $tr; switch ($type) { case 'rename': if (!file_exists($data[0])) { $errors[] = "cannot rename file $data[0], doesn't exist"; } // check that dest dir. is writable if (!is_writable(dirname($data[1]))) { $errors[] = "permission denied ($type): $data[1]"; } break; case 'chmod': // check that file is writable if (!is_writable($data[1])) { $errors[] = "permission denied ($type): $data[1] " . decoct($data[0]); } break; case 'delete': if (!file_exists($data[0])) { $this->log(2, "warning: file $data[0] doesn't exist, can't be deleted"); } // check that directory is writable if (file_exists($data[0])) { if (!is_writable(dirname($data[0]))) { $errors[] = "permission denied ($type): $data[0]"; } else { // make sure the file to be deleted can be opened for writing $fp = false; if (!is_dir($data[0]) && (!is_writable($data[0]) || !($fp = @fopen($data[0], 'a')))) { $errors[] = "permission denied ($type): $data[0]"; } elseif ($fp) { fclose($fp); } } /* Verify we are not deleting a file owned by another package * This can happen when a file moves from package A to B in * an upgrade ala http://pear.php.net/17986 */ $info = array( 'package' => strtolower($this->pkginfo->getName()), 'channel' => strtolower($this->pkginfo->getChannel()), ); $result = $this->_registry->checkFileMap($data[0], $info, '1.1'); if (is_array($result)) { $res = array_diff($result, $info); if (!empty($res)) { $new = $this->_registry->getPackage($result[1], $result[0]); $this->file_operations[$key] = false; $pkginfoName = $this->pkginfo->getName(); $newChannel = $new->getChannel(); $newPackage = $new->getName(); $this->log(3, "file $data[0] was scheduled for removal from $pkginfoName but is owned by $newChannel/$newPackage, removal has been cancelled."); } } } break; } } // }}} $n = count($this->file_operations); $this->log(2, "about to commit $n file operations for " . $this->pkginfo->getName()); $m = count($errors); if ($m > 0) { foreach ($errors as $error) { if (!isset($this->_options['soft'])) { $this->log(1, $error); } } if (!isset($this->_options['ignore-errors'])) { return false; } } $this->_dirtree = array(); // {{{ really commit the transaction foreach ($this->file_operations as $i => $tr) { if (!$tr) { // support removal of non-existing backups continue; } list($type, $data) = $tr; switch ($type) { case 'backup': if (!file_exists($data[0])) { $this->file_operations[$i] = false; break; } if (!@copy($data[0], $data[0] . '.bak')) { $this->log(1, 'Could not copy ' . $data[0] . ' to ' . $data[0] . '.bak ' . error_get_last()["message"]); return false; } $this->log(3, "+ backup $data[0] to $data[0].bak"); break; case 'removebackup': if (file_exists($data[0] . '.bak') && is_writable($data[0] . '.bak')) { unlink($data[0] . '.bak'); $this->log(3, "+ rm backup of $data[0] ($data[0].bak)"); } break; case 'rename': $test = file_exists($data[1]) ? @unlink($data[1]) : null; if (!$test && file_exists($data[1])) { if ($data[2]) { $extra = ', this extension must be installed manually. Rename to "' . basename($data[1]) . '"'; } else { $extra = ''; } if (!isset($this->_options['soft'])) { $this->log(1, 'Could not delete ' . $data[1] . ', cannot rename ' . $data[0] . $extra); } if (!isset($this->_options['ignore-errors'])) { return false; } } // permissions issues with rename - copy() is far superior $perms = @fileperms($data[0]); if (!@copy($data[0], $data[1])) { $this->log(1, 'Could not rename ' . $data[0] . ' to ' . $data[1] . ' ' . error_get_last()["message"]); return false; } // copy over permissions, otherwise they are lost @chmod($data[1], $perms); @unlink($data[0]); $this->log(3, "+ mv $data[0] $data[1]"); break; case 'chmod': if (!@chmod($data[1], $data[0])) { $this->log(1, 'Could not chmod ' . $data[1] . ' to ' . decoct($data[0]) . ' ' . error_get_last()["message"]); return false; } $octmode = decoct($data[0]); $this->log(3, "+ chmod $octmode $data[1]"); break; case 'delete': if (file_exists($data[0])) { if (!@unlink($data[0])) { $this->log(1, 'Could not delete ' . $data[0] . ' ' . error_get_last()["message"]); return false; } $this->log(3, "+ rm $data[0]"); } break; case 'rmdir': if (file_exists($data[0])) { do { $testme = opendir($data[0]); while (false !== ($entry = readdir($testme))) { if ($entry == '.' || $entry == '..') { continue; } closedir($testme); break 2; // this directory is not empty and can't be // deleted } closedir($testme); if (!@rmdir($data[0])) { $this->log(1, 'Could not rmdir ' . $data[0] . ' ' . error_get_last()["message"]); return false; } $this->log(3, "+ rmdir $data[0]"); } while (false); } break; case 'installed_as': $this->pkginfo->setInstalledAs($data[0], $data[1]); if (!isset($this->_dirtree[dirname($data[1])])) { $this->_dirtree[dirname($data[1])] = true; $this->pkginfo->setDirtree(dirname($data[1])); while(!empty($data[3]) && dirname($data[3]) != $data[3] && $data[3] != '/' && $data[3] != '\\') { $this->pkginfo->setDirtree($pp = $this->_prependPath($data[3], $data[2])); $this->_dirtree[$pp] = true; $data[3] = dirname($data[3]); } } break; } } // }}} $this->log(2, "successfully committed $n file operations"); $this->file_operations = array(); return true; } // }}} // {{{ rollbackFileTransaction() function rollbackFileTransaction() { $n = count($this->file_operations); $this->log(2, "rolling back $n file operations"); foreach ($this->file_operations as $tr) { list($type, $data) = $tr; switch ($type) { case 'backup': if (file_exists($data[0] . '.bak')) { if (file_exists($data[0] && is_writable($data[0]))) { unlink($data[0]); } @copy($data[0] . '.bak', $data[0]); $this->log(3, "+ restore $data[0] from $data[0].bak"); } break; case 'removebackup': if (file_exists($data[0] . '.bak') && is_writable($data[0] . '.bak')) { unlink($data[0] . '.bak'); $this->log(3, "+ rm backup of $data[0] ($data[0].bak)"); } break; case 'rename': @unlink($data[0]); $this->log(3, "+ rm $data[0]"); break; case 'mkdir': @rmdir($data[0]); $this->log(3, "+ rmdir $data[0]"); break; case 'chmod': break; case 'delete': break; case 'installed_as': $this->pkginfo->setInstalledAs($data[0], false); break; } } $this->pkginfo->resetDirtree(); $this->file_operations = array(); } // }}} // {{{ mkDirHier($dir) function mkDirHier($dir) { $this->addFileOperation('mkdir', array($dir)); return parent::mkDirHier($dir); } // }}} // {{{ _parsePackageXml() function _parsePackageXml(&$descfile) { // Parse xml file ----------------------------------------------- $pkg = new PEAR_PackageFile($this->config, $this->debug); PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN); $p = &$pkg->fromAnyFile($descfile, PEAR_VALIDATE_INSTALLING); PEAR::staticPopErrorHandling(); if (PEAR::isError($p)) { if (is_array($p->getUserInfo())) { foreach ($p->getUserInfo() as $err) { $loglevel = $err['level'] == 'error' ? 0 : 1; if (!isset($this->_options['soft'])) { $this->log($loglevel, ucfirst($err['level']) . ': ' . $err['message']); } } } return $this->raiseError('Installation failed: invalid package file'); } $descfile = $p->getPackageFile(); return $p; } // }}} /** * Set the list of PEAR_Downloader_Package objects to allow more sane * dependency validation * @param array */ function setDownloadedPackages(&$pkgs) { PEAR::pushErrorHandling(PEAR_ERROR_RETURN); $err = $this->analyzeDependencies($pkgs); PEAR::popErrorHandling(); if (PEAR::isError($err)) { return $err; } $this->_downloadedPackages = &$pkgs; } /** * Set the list of PEAR_Downloader_Package objects to allow more sane * dependency validation * @param array */ function setUninstallPackages(&$pkgs) { $this->_downloadedPackages = &$pkgs; } function getInstallPackages() { return $this->_downloadedPackages; } // {{{ install() /** * Installs the files within the package file specified. * * @param string|PEAR_Downloader_Package $pkgfile path to the package file, * or a pre-initialized packagefile object * @param array $options * recognized options: * - installroot : optional prefix directory for installation * - force : force installation * - register-only : update registry but don't install files * - upgrade : upgrade existing install * - soft : fail silently * - nodeps : ignore dependency conflicts/missing dependencies * - alldeps : install all dependencies * - onlyreqdeps : install only required dependencies * * @return array|PEAR_Error package info if successful */ function install($pkgfile, $options = array()) { $this->_options = $options; $this->_registry = &$this->config->getRegistry(); if (is_object($pkgfile)) { $dlpkg = &$pkgfile; $pkg = $pkgfile->getPackageFile(); $pkgfile = $pkg->getArchiveFile(); $descfile = $pkg->getPackageFile(); } else { $descfile = $pkgfile; $pkg = $this->_parsePackageXml($descfile); if (PEAR::isError($pkg)) { return $pkg; } } $tmpdir = dirname($descfile); if (realpath($descfile) != realpath($pkgfile)) { // Use the temp_dir since $descfile can contain the download dir path $tmpdir = $this->config->get('temp_dir', null, 'pear.php.net'); $tmpdir = System::mktemp('-d -t "' . $tmpdir . '"'); $tar = new Archive_Tar($pkgfile); if (!$tar->extract($tmpdir)) { return $this->raiseError("unable to unpack $pkgfile"); } } $pkgname = $pkg->getName(); $channel = $pkg->getChannel(); if (isset($options['installroot'])) { $this->config->setInstallRoot($options['installroot']); $this->_registry = &$this->config->getRegistry(); $installregistry = &$this->_registry; $this->installroot = ''; // all done automagically now $php_dir = $this->config->get('php_dir', null, $channel); } else { $this->config->setInstallRoot(false); $this->_registry = &$this->config->getRegistry(); if (isset($this->_options['packagingroot'])) { $regdir = $this->_prependPath( $this->config->get('php_dir', null, 'pear.php.net'), $this->_options['packagingroot']); $metadata_dir = $this->config->get('metadata_dir', null, 'pear.php.net'); if ($metadata_dir) { $metadata_dir = $this->_prependPath( $metadata_dir, $this->_options['packagingroot']); } $packrootphp_dir = $this->_prependPath( $this->config->get('php_dir', null, $channel), $this->_options['packagingroot']); $installregistry = new PEAR_Registry($regdir, false, false, $metadata_dir); if (!$installregistry->channelExists($channel, true)) { // we need to fake a channel-discover of this channel $chanobj = $this->_registry->getChannel($channel, true); $installregistry->addChannel($chanobj); } $php_dir = $packrootphp_dir; } else { $installregistry = &$this->_registry; $php_dir = $this->config->get('php_dir', null, $channel); } $this->installroot = ''; } // {{{ checks to do when not in "force" mode if (empty($options['force']) && (file_exists($this->config->get('php_dir')) && is_dir($this->config->get('php_dir')))) { $testp = $channel == 'pear.php.net' ? $pkgname : array($channel, $pkgname); $instfilelist = $pkg->getInstallationFileList(true); if (PEAR::isError($instfilelist)) { return $instfilelist; } // ensure we have the most accurate registry $installregistry->flushFileMap(); $test = $installregistry->checkFileMap($instfilelist, $testp, '1.1'); if (PEAR::isError($test)) { return $test; } if (sizeof($test)) { $pkgs = $this->getInstallPackages(); $found = false; foreach ($pkgs as $param) { if ($pkg->isSubpackageOf($param)) { $found = true; break; } } if ($found) { // subpackages can conflict with earlier versions of parent packages $parentreg = $installregistry->packageInfo($param->getPackage(), null, $param->getChannel()); $tmp = $test; foreach ($tmp as $file => $info) { if (is_array($info)) { if (strtolower($info[1]) == strtolower($param->getPackage()) && strtolower($info[0]) == strtolower($param->getChannel()) ) { if (isset($parentreg['filelist'][$file])) { unset($parentreg['filelist'][$file]); } else{ $pos = strpos($file, '/'); $basedir = substr($file, 0, $pos); $file2 = substr($file, $pos + 1); if (isset($parentreg['filelist'][$file2]['baseinstalldir']) && $parentreg['filelist'][$file2]['baseinstalldir'] === $basedir ) { unset($parentreg['filelist'][$file2]); } } unset($test[$file]); } } else { if (strtolower($param->getChannel()) != 'pear.php.net') { continue; } if (strtolower($info) == strtolower($param->getPackage())) { if (isset($parentreg['filelist'][$file])) { unset($parentreg['filelist'][$file]); } else{ $pos = strpos($file, '/'); $basedir = substr($file, 0, $pos); $file2 = substr($file, $pos + 1); if (isset($parentreg['filelist'][$file2]['baseinstalldir']) && $parentreg['filelist'][$file2]['baseinstalldir'] === $basedir ) { unset($parentreg['filelist'][$file2]); } } unset($test[$file]); } } } $pfk = new PEAR_PackageFile($this->config); $parentpkg = &$pfk->fromArray($parentreg); $installregistry->updatePackage2($parentpkg); } if ($param->getChannel() == 'pecl.php.net' && isset($options['upgrade'])) { $tmp = $test; foreach ($tmp as $file => $info) { if (is_string($info)) { // pear.php.net packages are always stored as strings if (strtolower($info) == strtolower($param->getPackage())) { // upgrading existing package unset($test[$file]); } } } } if (count($test)) { $msg = "$channel/$pkgname: conflicting files found:\n"; $longest = max(array_map("strlen", array_keys($test))); $fmt = "%{$longest}s (%s)\n"; foreach ($test as $file => $info) { if (!is_array($info)) { $info = array('pear.php.net', $info); } $info = $info[0] . '/' . $info[1]; $msg .= sprintf($fmt, $file, $info); } if (!isset($options['ignore-errors'])) { return $this->raiseError($msg); } if (!isset($options['soft'])) { $this->log(0, "WARNING: $msg"); } } } } // }}} $this->startFileTransaction(); $usechannel = $channel; if ($channel == 'pecl.php.net') { $test = $installregistry->packageExists($pkgname, $channel); if (!$test) { $test = $installregistry->packageExists($pkgname, 'pear.php.net'); $usechannel = 'pear.php.net'; } } else { $test = $installregistry->packageExists($pkgname, $channel); } if (empty($options['upgrade']) && empty($options['soft'])) { // checks to do only when installing new packages if (empty($options['force']) && $test) { return $this->raiseError("$channel/$pkgname is already installed"); } } else { // Upgrade if ($test) { $v1 = $installregistry->packageInfo($pkgname, 'version', $usechannel); $v2 = $pkg->getVersion(); $cmp = version_compare("$v1", "$v2", 'gt'); if (empty($options['force']) && !version_compare("$v2", "$v1", 'gt')) { return $this->raiseError("upgrade to a newer version ($v2 is not newer than $v1)"); } } } // Do cleanups for upgrade and install, remove old release's files first if ($test && empty($options['register-only'])) { // when upgrading, remove old release's files first: if (PEAR::isError($err = $this->_deletePackageFiles($pkgname, $usechannel, true))) { if (!isset($options['ignore-errors'])) { return $this->raiseError($err); } if (!isset($options['soft'])) { $this->log(0, 'WARNING: ' . $err->getMessage()); } } else { $backedup = $err; } } // {{{ Copy files to dest dir --------------------------------------- // info from the package it self we want to access from _installFile $this->pkginfo = &$pkg; // used to determine whether we should build any C code $this->source_files = 0; $savechannel = $this->config->get('default_channel'); if (empty($options['register-only']) && !is_dir($php_dir)) { if (PEAR::isError(System::mkdir(array('-p'), $php_dir))) { return $this->raiseError("no installation destination directory '$php_dir'\n"); } } if (substr($pkgfile, -4) != '.xml') { $tmpdir .= DIRECTORY_SEPARATOR . $pkgname . '-' . $pkg->getVersion(); } $this->configSet('default_channel', $channel); // {{{ install files $ver = $pkg->getPackagexmlVersion(); if (version_compare($ver, '2.0', '>=')) { $filelist = $pkg->getInstallationFilelist(); } else { $filelist = $pkg->getFileList(); } if (PEAR::isError($filelist)) { return $filelist; } $p = &$installregistry->getPackage($pkgname, $channel); $dirtree = (empty($options['register-only']) && $p) ? $p->getDirTree() : false; $pkg->resetFilelist(); $pkg->setLastInstalledVersion($installregistry->packageInfo($pkg->getPackage(), 'version', $pkg->getChannel())); foreach ($filelist as $file => $atts) { $this->expectError(PEAR_INSTALLER_FAILED); if ($pkg->getPackagexmlVersion() == '1.0') { $res = $this->_installFile($file, $atts, $tmpdir, $options); } else { $res = $this->_installFile2($pkg, $file, $atts, $tmpdir, $options); } $this->popExpect(); if (PEAR::isError($res)) { if (empty($options['ignore-errors'])) { $this->rollbackFileTransaction(); if ($res->getMessage() == "file does not exist") { $this->raiseError("file $file in package.xml does not exist"); } return $this->raiseError($res); } if (!isset($options['soft'])) { $this->log(0, "Warning: " . $res->getMessage()); } } $real = isset($atts['attribs']) ? $atts['attribs'] : $atts; if ($res == PEAR_INSTALLER_OK && $real['role'] != 'src') { // Register files that were installed $pkg->installedFile($file, $atts); } } // }}} // {{{ compile and install source files if ($this->source_files > 0 && empty($options['nobuild'])) { $configureoptions = empty($options['configureoptions']) ? '' : $options['configureoptions']; if (PEAR::isError($err = $this->_compileSourceFiles($savechannel, $pkg, $configureoptions))) { return $err; } } // }}} if (isset($backedup)) { $this->_removeBackups($backedup); } if (!$this->commitFileTransaction()) { $this->rollbackFileTransaction(); $this->configSet('default_channel', $savechannel); return $this->raiseError("commit failed", PEAR_INSTALLER_FAILED); } // }}} $ret = false; $installphase = 'install'; $oldversion = false; // {{{ Register that the package is installed ----------------------- if (empty($options['upgrade'])) { // if 'force' is used, replace the info in registry $usechannel = $channel; if ($channel == 'pecl.php.net') { $test = $installregistry->packageExists($pkgname, $channel); if (!$test) { $test = $installregistry->packageExists($pkgname, 'pear.php.net'); $usechannel = 'pear.php.net'; } } else { $test = $installregistry->packageExists($pkgname, $channel); } if (!empty($options['force']) && $test) { $oldversion = $installregistry->packageInfo($pkgname, 'version', $usechannel); $installregistry->deletePackage($pkgname, $usechannel); } $ret = $installregistry->addPackage2($pkg); } else { if ($dirtree) { $this->startFileTransaction(); // attempt to delete empty directories uksort($dirtree, array($this, '_sortDirs')); foreach($dirtree as $dir => $notused) { $this->addFileOperation('rmdir', array($dir)); } $this->commitFileTransaction(); } $usechannel = $channel; if ($channel == 'pecl.php.net') { $test = $installregistry->packageExists($pkgname, $channel); if (!$test) { $test = $installregistry->packageExists($pkgname, 'pear.php.net'); $usechannel = 'pear.php.net'; } } else { $test = $installregistry->packageExists($pkgname, $channel); } // new: upgrade installs a package if it isn't installed if (!$test) { $ret = $installregistry->addPackage2($pkg); } else { if ($usechannel != $channel) { $installregistry->deletePackage($pkgname, $usechannel); $ret = $installregistry->addPackage2($pkg); } else { $ret = $installregistry->updatePackage2($pkg); } $installphase = 'upgrade'; } } if (!$ret) { $this->configSet('default_channel', $savechannel); return $this->raiseError("Adding package $channel/$pkgname to registry failed"); } // }}} $this->configSet('default_channel', $savechannel); if (class_exists('PEAR_Task_Common')) { // this is auto-included if any tasks exist if (PEAR_Task_Common::hasPostinstallTasks()) { PEAR_Task_Common::runPostinstallTasks($installphase); } } return $pkg->toArray(true); } // }}} // {{{ _compileSourceFiles() /** * @param string * @param PEAR_PackageFile_v1|PEAR_PackageFile_v2 * @param mixed[] $configureoptions */ function _compileSourceFiles($savechannel, &$filelist, $configureoptions) { require_once 'PEAR/Builder.php'; $this->log(1, "$this->source_files source files, building"); $bob = new PEAR_Builder($configureoptions, $this->ui); $bob->debug = $this->debug; $built = $bob->build($filelist, array(&$this, '_buildCallback')); if (PEAR::isError($built)) { $this->rollbackFileTransaction(); $this->configSet('default_channel', $savechannel); return $built; } $this->log(1, "\nBuild process completed successfully"); foreach ($built as $ext) { $bn = basename($ext['file']); list($_ext_name, $_ext_suff) = explode('.', $bn); if ($_ext_suff == 'so' || $_ext_suff == 'dll') { if (extension_loaded($_ext_name)) { return $this->raiseError("Extension '$_ext_name' already loaded. " . 'Please unload it in your php.ini file ' . 'prior to install or upgrade'); } $role = 'ext'; } else { $role = 'src'; } $dest = $ext['dest']; $packagingroot = ''; if (isset($this->_options['packagingroot'])) { $packagingroot = $this->_options['packagingroot']; } $copyto = $this->_prependPath($dest, $packagingroot); $extra = $copyto != $dest ? " as '$copyto'" : ''; $this->log(1, "Installing '$dest'$extra"); $copydir = dirname($copyto); // pretty much nothing happens if we are only registering the install if (empty($this->_options['register-only'])) { if (!file_exists($copydir) || !is_dir($copydir)) { if (!$this->mkDirHier($copydir)) { return $this->raiseError("failed to mkdir $copydir", PEAR_INSTALLER_FAILED); } $this->log(3, "+ mkdir $copydir"); } if (!@copy($ext['file'], $copyto)) { return $this->raiseError( "failed to write $copyto (" . error_get_last()["message"] . ")", PEAR_INSTALLER_FAILED); } $this->log(3, "+ cp $ext[file] $copyto"); $this->addFileOperation('rename', array($ext['file'], $copyto)); if (!OS_WINDOWS) { $mode = 0666 & ~(int)octdec($this->config->get('umask')); $this->addFileOperation('chmod', array($mode, $copyto)); if (!@chmod($copyto, $mode)) { $this->log(0, "failed to change mode of $copyto (" . error_get_last()["message"] . ")"); } } } $data = array( 'role' => $role, 'name' => $bn, 'installed_as' => $dest, 'php_api' => $ext['php_api'], 'zend_mod_api' => $ext['zend_mod_api'], 'zend_ext_api' => $ext['zend_ext_api'], ); if ($filelist->getPackageXmlVersion() == '1.0') { $filelist->installedFile($bn, $data); } else { $filelist->installedFile($bn, array('attribs' => $data)); } } } // }}} function &getUninstallPackages() { return $this->_downloadedPackages; } // {{{ uninstall() /** * Uninstall a package * * This method removes all files installed by the application, and then * removes any empty directories. * @param string package name * @param array Command-line options. Possibilities include: * * - installroot: base installation dir, if not the default * - register-only : update registry but don't remove files * - nodeps: do not process dependencies of other packages to ensure * uninstallation does not break things */ function uninstall($package, $options = array()) { $installRoot = isset($options['installroot']) ? $options['installroot'] : ''; $this->config->setInstallRoot($installRoot); $this->installroot = ''; $this->_registry = &$this->config->getRegistry(); if (is_object($package)) { $channel = $package->getChannel(); $pkg = $package; $package = $pkg->getPackage(); } else { $pkg = false; $info = $this->_registry->parsePackageName($package, $this->config->get('default_channel')); $channel = $info['channel']; $package = $info['package']; } $savechannel = $this->config->get('default_channel'); $this->configSet('default_channel', $channel); if (!is_object($pkg)) { $pkg = $this->_registry->getPackage($package, $channel); } if (!$pkg) { $this->configSet('default_channel', $savechannel); return $this->raiseError($this->_registry->parsedPackageNameToString( array( 'channel' => $channel, 'package' => $package ), true) . ' not installed'); } if ($pkg->getInstalledBinary()) { // this is just an alias for a binary package return $this->_registry->deletePackage($package, $channel); } $filelist = $pkg->getFilelist(); PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN); if (!class_exists('PEAR_Dependency2')) { require_once 'PEAR/Dependency2.php'; } $depchecker = new PEAR_Dependency2($this->config, $options, array('channel' => $channel, 'package' => $package), PEAR_VALIDATE_UNINSTALLING); $e = $depchecker->validatePackageUninstall($this); PEAR::staticPopErrorHandling(); if (PEAR::isError($e)) { if (!isset($options['ignore-errors'])) { return $this->raiseError($e); } if (!isset($options['soft'])) { $this->log(0, 'WARNING: ' . $e->getMessage()); } } elseif (is_array($e)) { if (!isset($options['soft'])) { $this->log(0, $e[0]); } } $this->pkginfo = &$pkg; // pretty much nothing happens if we are only registering the uninstall if (empty($options['register-only'])) { // {{{ Delete the files $this->startFileTransaction(); PEAR::pushErrorHandling(PEAR_ERROR_RETURN); if (PEAR::isError($err = $this->_deletePackageFiles($package, $channel))) { PEAR::popErrorHandling(); $this->rollbackFileTransaction(); $this->configSet('default_channel', $savechannel); if (!isset($options['ignore-errors'])) { return $this->raiseError($err); } if (!isset($options['soft'])) { $this->log(0, 'WARNING: ' . $err->getMessage()); } } else { PEAR::popErrorHandling(); } if (!$this->commitFileTransaction()) { $this->rollbackFileTransaction(); if (!isset($options['ignore-errors'])) { return $this->raiseError("uninstall failed"); } if (!isset($options['soft'])) { $this->log(0, 'WARNING: uninstall failed'); } } else { $this->startFileTransaction(); $dirtree = $pkg->getDirTree(); if ($dirtree === false) { $this->configSet('default_channel', $savechannel); return $this->_registry->deletePackage($package, $channel); } // attempt to delete empty directories uksort($dirtree, array($this, '_sortDirs')); foreach($dirtree as $dir => $notused) { $this->addFileOperation('rmdir', array($dir)); } if (!$this->commitFileTransaction()) { $this->rollbackFileTransaction(); if (!isset($options['ignore-errors'])) { return $this->raiseError("uninstall failed"); } if (!isset($options['soft'])) { $this->log(0, 'WARNING: uninstall failed'); } } } // }}} } $this->configSet('default_channel', $savechannel); // Register that the package is no longer installed return $this->_registry->deletePackage($package, $channel); } /** * Sort a list of arrays of array(downloaded packagefilename) by dependency. * * It also removes duplicate dependencies * @param array an array of PEAR_PackageFile_v[1/2] objects * @return array|PEAR_Error array of array(packagefilename, package.xml contents) */ function sortPackagesForUninstall(&$packages) { $this->_dependencyDB = &PEAR_DependencyDB::singleton($this->config); if (PEAR::isError($this->_dependencyDB)) { return $this->_dependencyDB; } usort($packages, array(&$this, '_sortUninstall')); } function _sortUninstall($a, $b) { if (!$a->getDeps() && !$b->getDeps()) { return 0; // neither package has dependencies, order is insignificant } if ($a->getDeps() && !$b->getDeps()) { return -1; // $a must be installed after $b because $a has dependencies } if (!$a->getDeps() && $b->getDeps()) { return 1; // $b must be installed after $a because $b has dependencies } // both packages have dependencies if ($this->_dependencyDB->dependsOn($a, $b)) { return -1; } if ($this->_dependencyDB->dependsOn($b, $a)) { return 1; } return 0; } // }}} // {{{ _sortDirs() function _sortDirs($a, $b) { if (strnatcmp($a, $b) == -1) return 1; if (strnatcmp($a, $b) == 1) return -1; return 0; } // }}} // {{{ _buildCallback() function _buildCallback($what, $data) { if (($what == 'cmdoutput' && $this->debug > 1) || ($what == 'output' && $this->debug > 0)) { $this->ui->outputData(rtrim($data), 'build'); } } // }}} }
Save