3 * PEAR_Command_Install (install, upgrade, upgrade-all, uninstall, bundle, run-scripts commands)
9 * @author Stig Bakken <ssb@php.net>
10 * @author Greg Beaver <cellog@php.net>
11 * @copyright 1997-2009 The Authors
12 * @license http://opensource.org/licenses/bsd-license.php New BSD License
13 * @link http://pear.php.net/package/PEAR
14 * @since File available since Release 0.1
20 require_once 'PEAR/Command/Common.php';
23 * PEAR commands for installation or deinstallation/upgrading of
28 * @author Stig Bakken <ssb@php.net>
29 * @author Greg Beaver <cellog@php.net>
30 * @copyright 1997-2009 The Authors
31 * @license http://opensource.org/licenses/bsd-license.php New BSD License
32 * @version Release: 1.10.1
33 * @link http://pear.php.net/package/PEAR
34 * @since Class available since Release 0.1
36 class PEAR_Command_Install extends PEAR_Command_Common
40 var $commands = array(
42 'summary' => 'Install Package',
43 'function' => 'doInstall',
48 'doc' => 'will overwrite newer installed packages',
52 'doc' => 'do not check for recommended dependency version',
56 'doc' => 'ignore dependencies, install anyway',
58 'register-only' => array(
60 'doc' => 'do not install files, only register the package as installed',
64 'doc' => 'soft install, fail silently, or upgrade if already installed',
68 'doc' => 'don\'t build C extensions',
70 'nocompress' => array(
72 'doc' => 'request uncompressed files when downloading',
74 'installroot' => array(
77 'doc' => 'root directory used when installing files (ala PHP\'s INSTALL_ROOT), use packagingroot for RPM',
79 'packagingroot' => array(
82 'doc' => 'root directory used when packaging files, like RPM packaging',
84 'ignore-errors' => array(
85 'doc' => 'force install even if there were errors',
89 'doc' => 'install all required and optional dependencies',
91 'onlyreqdeps' => array(
93 'doc' => 'install all required dependencies',
97 'doc' => 'do not attempt to download any urls or contact channels',
101 'doc' => 'Only list the packages that would be downloaded',
104 'doc' => '[channel/]<package> ...
105 Installs one or more PEAR packages. You can specify a package to
106 install in four ways:
108 "Package-1.0.tgz" : installs from a local file
110 "http://example.com/Package-1.0.tgz" : installs from
113 "package.xml" : installs the package described in
114 package.xml. Useful for testing, or for wrapping a PEAR package in
115 another package manager such as RPM.
117 "Package[-version/state][.tar]" : queries your default channel\'s server
118 ({config master_server}) and downloads the newest package with
119 the preferred quality/state ({config preferred_state}).
121 To retrieve Package version 1.1, use "Package-1.1," to retrieve
122 Package state beta, use "Package-beta." To retrieve an uncompressed
123 file, append .tar (make sure there is no file by the same name first)
125 To download a package from another channel, prefix with the channel name like
128 More than one package may be specified at once. It is ok to mix these
129 four ways of specifying packages.
132 'summary' => 'Upgrade Package',
133 'function' => 'doInstall',
138 'doc' => 'upgrade packages from a specific channel',
143 'doc' => 'overwrite newer installed packages',
147 'doc' => 'do not check for recommended dependency version',
151 'doc' => 'ignore dependencies, upgrade anyway',
153 'register-only' => array(
155 'doc' => 'do not install files, only register the package as upgraded',
159 'doc' => 'don\'t build C extensions',
161 'nocompress' => array(
163 'doc' => 'request uncompressed files when downloading',
165 'installroot' => array(
168 'doc' => 'root directory used when installing files (ala PHP\'s INSTALL_ROOT)',
170 'ignore-errors' => array(
171 'doc' => 'force install even if there were errors',
175 'doc' => 'install all required and optional dependencies',
177 'onlyreqdeps' => array(
179 'doc' => 'install all required dependencies',
183 'doc' => 'do not attempt to download any urls or contact channels',
187 'doc' => 'Only list the packages that would be downloaded',
190 'doc' => '<package> ...
191 Upgrades one or more PEAR packages. See documentation for the
192 "install" command for ways to specify a package.
194 When upgrading, your package will be updated if the provided new
195 package has a higher version number (use the -f option if you need to
198 More than one package may be specified at once.
200 'upgrade-all' => array(
201 'summary' => 'Upgrade All Packages [Deprecated in favor of calling upgrade with no parameters]',
202 'function' => 'doUpgradeAll',
207 'doc' => 'upgrade packages from a specific channel',
212 'doc' => 'ignore dependencies, upgrade anyway',
214 'register-only' => array(
216 'doc' => 'do not install files, only register the package as upgraded',
220 'doc' => 'don\'t build C extensions',
222 'nocompress' => array(
224 'doc' => 'request uncompressed files when downloading',
226 'installroot' => array(
229 'doc' => 'root directory used when installing files (ala PHP\'s INSTALL_ROOT), use packagingroot for RPM',
231 'ignore-errors' => array(
232 'doc' => 'force install even if there were errors',
235 'doc' => 'do not check for recommended dependency version',
239 WARNING: This function is deprecated in favor of using the upgrade command with no params
241 Upgrades all packages that have a newer release available. Upgrades are
242 done only if there is a release available of the state specified in
243 "preferred_state" (currently {config preferred_state}), or a state considered
246 'uninstall' => array(
247 'summary' => 'Un-install Package',
248 'function' => 'doUninstall',
253 'doc' => 'ignore dependencies, uninstall anyway',
255 'register-only' => array(
257 'doc' => 'do not remove files, only register the packages as not installed',
259 'installroot' => array(
262 'doc' => 'root directory used when installing files (ala PHP\'s INSTALL_ROOT)',
264 'ignore-errors' => array(
265 'doc' => 'force install even if there were errors',
269 'doc' => 'do not attempt to uninstall remotely',
272 'doc' => '[channel/]<package> ...
273 Uninstalls one or more PEAR packages. More than one package may be
274 specified at once. Prefix with channel name to uninstall from a
275 channel not in your default channel ({config default_channel})
278 'summary' => 'Unpacks a Pecl Package',
279 'function' => 'doBundle',
282 'destination' => array(
285 'doc' => 'Optional destination directory for unpacking (defaults to current path or "ext" if exists)',
289 'doc' => 'Force the unpacking even if there were errors in the package',
293 Unpacks a Pecl Package into the selected location. It will download the
296 'run-scripts' => array(
297 'summary' => 'Run Post-Install Scripts bundled with a package',
298 'function' => 'doRunScripts',
303 Run post-installation scripts in package <package>, if any exist.
311 * PEAR_Command_Install constructor.
315 function __construct(&$ui, &$config)
317 parent::__construct($ui, $config);
323 * For unit testing purposes
325 function &getDownloader(&$ui, $options, &$config)
327 if (!class_exists('PEAR_Downloader')) {
328 require_once 'PEAR/Downloader.php';
330 $a = new PEAR_Downloader($ui, $options, $config);
335 * For unit testing purposes
337 function &getInstaller(&$ui)
339 if (!class_exists('PEAR_Installer')) {
340 require_once 'PEAR/Installer.php';
342 $a = new PEAR_Installer($ui);
346 function enableExtension($binaries, $type)
348 if (!($phpini = $this->config->get('php_ini', null, 'pear.php.net'))) {
349 return PEAR::raiseError('configuration option "php_ini" is not set to php.ini location');
351 $ini = $this->_parseIni($phpini);
352 if (PEAR::isError($ini)) {
356 if ($type == 'extsrc' || $type == 'extbin') {
357 $search = 'extensions';
358 $enable = 'extension';
360 $search = 'zend_extensions';
362 phpinfo(INFO_GENERAL);
363 $info = ob_get_contents();
365 $debug = function_exists('leak') ? '_debug' : '';
366 $ts = preg_match('/Thread Safety.+enabled/', $info) ? '_ts' : '';
367 $enable = 'zend_extension' . $debug . $ts;
369 foreach ($ini[$search] as $line => $extension) {
370 if (in_array($extension, $binaries, true) || in_array(
371 $ini['extension_dir'] . DIRECTORY_SEPARATOR . $extension, $binaries, true)) {
372 // already enabled - assume if one is, all are
377 $newini = array_slice($ini['all'], 0, $line);
381 foreach ($binaries as $binary) {
382 if ($ini['extension_dir']) {
383 $binary = basename($binary);
385 $newini[] = $enable . '="' . $binary . '"' . (OS_UNIX ? "\n" : "\r\n");
387 $newini = array_merge($newini, array_slice($ini['all'], $line));
388 $fp = @fopen($phpini, 'wb');
390 return PEAR::raiseError('cannot open php.ini "' . $phpini . '" for writing');
392 foreach ($newini as $line) {
399 function disableExtension($binaries, $type)
401 if (!($phpini = $this->config->get('php_ini', null, 'pear.php.net'))) {
402 return PEAR::raiseError('configuration option "php_ini" is not set to php.ini location');
404 $ini = $this->_parseIni($phpini);
405 if (PEAR::isError($ini)) {
409 if ($type == 'extsrc' || $type == 'extbin') {
410 $search = 'extensions';
411 $enable = 'extension';
413 $search = 'zend_extensions';
415 phpinfo(INFO_GENERAL);
416 $info = ob_get_contents();
418 $debug = function_exists('leak') ? '_debug' : '';
419 $ts = preg_match('/Thread Safety.+enabled/', $info) ? '_ts' : '';
420 $enable = 'zend_extension' . $debug . $ts;
423 foreach ($ini[$search] as $line => $extension) {
424 if (in_array($extension, $binaries, true) || in_array(
425 $ini['extension_dir'] . DIRECTORY_SEPARATOR . $extension, $binaries, true)) {
434 $fp = @fopen($phpini, 'wb');
436 return PEAR::raiseError('cannot open php.ini "' . $phpini . '" for writing');
439 $newini = array_slice($ini['all'], 0, $line);
440 // delete the enable line
441 $newini = array_merge($newini, array_slice($ini['all'], $line + 1));
443 $newini = array_slice($ini['all'], 1);
445 foreach ($newini as $line) {
452 function _parseIni($filename)
454 if (!file_exists($filename)) {
455 return PEAR::raiseError('php.ini "' . $filename . '" does not exist');
458 if (filesize($filename) > 300000) {
459 return PEAR::raiseError('php.ini "' . $filename . '" is too large, aborting');
463 phpinfo(INFO_GENERAL);
464 $info = ob_get_contents();
466 $debug = function_exists('leak') ? '_debug' : '';
467 $ts = preg_match('/Thread Safety.+enabled/', $info) ? '_ts' : '';
468 $zend_extension_line = 'zend_extension' . $debug . $ts;
469 $all = @file($filename);
470 if ($all === false) {
471 return PEAR::raiseError('php.ini "' . $filename .'" could not be read');
473 $zend_extensions = $extensions = array();
474 // assume this is right, but pull from the php.ini if it is found
475 $extension_dir = ini_get('extension_dir');
476 foreach ($all as $linenum => $line) {
481 if ($line[0] == ';') {
484 if (strtolower(substr($line, 0, 13)) == 'extension_dir') {
485 $line = trim(substr($line, 13));
486 if ($line[0] == '=') {
487 $x = trim(substr($line, 1));
488 $x = explode(';', $x);
489 $extension_dir = str_replace('"', '', array_shift($x));
493 if (strtolower(substr($line, 0, 9)) == 'extension') {
494 $line = trim(substr($line, 9));
495 if ($line[0] == '=') {
496 $x = trim(substr($line, 1));
497 $x = explode(';', $x);
498 $extensions[$linenum] = str_replace('"', '', array_shift($x));
502 if (strtolower(substr($line, 0, strlen($zend_extension_line))) ==
503 $zend_extension_line) {
504 $line = trim(substr($line, strlen($zend_extension_line)));
505 if ($line[0] == '=') {
506 $x = trim(substr($line, 1));
507 $x = explode(';', $x);
508 $zend_extensions[$linenum] = str_replace('"', '', array_shift($x));
514 'extensions' => $extensions,
515 'zend_extensions' => $zend_extensions,
516 'extension_dir' => $extension_dir,
523 function doInstall($command, $options, $params)
525 if (!class_exists('PEAR_PackageFile')) {
526 require_once 'PEAR/PackageFile.php';
529 if (isset($options['installroot']) && isset($options['packagingroot'])) {
530 return $this->raiseError('ERROR: cannot use both --installroot and --packagingroot');
533 $reg = &$this->config->getRegistry();
534 $channel = isset($options['channel']) ? $options['channel'] : $this->config->get('default_channel');
535 if (!$reg->channelExists($channel)) {
536 return $this->raiseError('Channel "' . $channel . '" does not exist');
539 if (empty($this->installer)) {
540 $this->installer = &$this->getInstaller($this->ui);
543 if ($command == 'upgrade' || $command == 'upgrade-all') {
544 // If people run the upgrade command but pass nothing, emulate a upgrade-all
545 if ($command == 'upgrade' && empty($params)) {
546 return $this->doUpgradeAll($command, $options, $params);
548 $options['upgrade'] = true;
553 $instreg = &$reg; // instreg used to check if package is installed
554 if (isset($options['packagingroot']) && !isset($options['upgrade'])) {
555 $packrootphp_dir = $this->installer->_prependPath(
556 $this->config->get('php_dir', null, 'pear.php.net'),
557 $options['packagingroot']);
558 $metadata_dir = $this->config->get('metadata_dir', null, 'pear.php.net');
560 $metadata_dir = $this->installer->_prependPath(
562 $options['packagingroot']);
564 $instreg = new PEAR_Registry($packrootphp_dir, false, false, $metadata_dir); // other instreg!
566 if ($this->config->get('verbose') > 2) {
567 $this->ui->outputData('using package root: ' . $options['packagingroot']);
571 $abstractpackages = $otherpackages = array();
573 PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
575 foreach ($params as $param) {
576 if (strpos($param, 'http://') === 0) {
577 $otherpackages[] = $param;
581 if (strpos($param, 'channel://') === false && @file_exists($param)) {
582 if (isset($options['force'])) {
583 $otherpackages[] = $param;
587 $pkg = new PEAR_PackageFile($this->config);
588 $pf = $pkg->fromAnyFile($param, PEAR_VALIDATE_DOWNLOADING);
589 if (PEAR::isError($pf)) {
590 $otherpackages[] = $param;
594 $exists = $reg->packageExists($pf->getPackage(), $pf->getChannel());
595 $pversion = $reg->packageInfo($pf->getPackage(), 'version', $pf->getChannel());
596 $version_compare = version_compare($pf->getVersion(), $pversion, '<=');
597 if ($exists && $version_compare) {
598 if ($this->config->get('verbose')) {
599 $this->ui->outputData('Ignoring installed package ' .
600 $reg->parsedPackageNameToString(
601 array('package' => $pf->getPackage(),
602 'channel' => $pf->getChannel()), true));
606 $otherpackages[] = $param;
610 $e = $reg->parsePackageName($param, $channel);
611 if (PEAR::isError($e)) {
612 $otherpackages[] = $param;
614 $abstractpackages[] = $e;
617 PEAR::staticPopErrorHandling();
619 // if there are any local package .tgz or remote static url, we can't
620 // filter. The filter only works for abstract packages
621 if (count($abstractpackages) && !isset($options['force'])) {
622 // when not being forced, only do necessary upgrades/installs
623 if (isset($options['upgrade'])) {
624 $abstractpackages = $this->_filterUptodatePackages($abstractpackages, $command);
626 $count = count($abstractpackages);
627 foreach ($abstractpackages as $i => $package) {
628 if (isset($package['group'])) {
629 // do not filter out install groups
633 if ($instreg->packageExists($package['package'], $package['channel'])) {
635 if ($this->config->get('verbose')) {
636 $this->ui->outputData('Ignoring installed package ' .
637 $reg->parsedPackageNameToString($package, true));
639 unset($abstractpackages[$i]);
640 } elseif ($count === 1) {
641 // Lets try to upgrade it since it's already installed
642 $options['upgrade'] = true;
648 array_map(array($reg, 'parsedPackageNameToString'), $abstractpackages);
649 } elseif (count($abstractpackages)) {
651 array_map(array($reg, 'parsedPackageNameToString'), $abstractpackages);
654 $packages = array_merge($abstractpackages, $otherpackages);
655 if (!count($packages)) {
657 if (isset($options['channel'])){
658 $c .= ' in channel "' . $options['channel'] . '"';
660 $this->ui->outputData('Nothing to ' . $command . $c);
664 $this->downloader = &$this->getDownloader($this->ui, $options, $this->config);
665 $errors = $downloaded = $binaries = array();
666 $downloaded = &$this->downloader->download($packages);
667 if (PEAR::isError($downloaded)) {
668 return $this->raiseError($downloaded);
671 $errors = $this->downloader->getErrorMsgs();
672 if (count($errors)) {
674 $err['data'] = array();
675 foreach ($errors as $error) {
676 if ($error !== null) {
677 $err['data'][] = array($error);
681 if (!empty($err['data'])) {
682 $err['headline'] = 'Install Errors';
683 $this->ui->outputData($err);
686 if (!count($downloaded)) {
687 return $this->raiseError("$command failed");
692 'headline' => 'Packages that would be Installed'
695 if (isset($options['pretend'])) {
696 foreach ($downloaded as $package) {
697 $data['data'][] = array($reg->parsedPackageNameToString($package->getParsedPackage()));
699 $this->ui->outputData($data, 'pretend');
703 $this->installer->setOptions($options);
704 $this->installer->sortPackagesForInstall($downloaded);
705 if (PEAR::isError($err = $this->installer->setDownloadedPackages($downloaded))) {
706 $this->raiseError($err->getMessage());
710 $binaries = $extrainfo = array();
711 foreach ($downloaded as $param) {
712 PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
713 $info = $this->installer->install($param, $options);
714 PEAR::staticPopErrorHandling();
715 if (PEAR::isError($info)) {
717 $pkg = &$param->getPackageFile();
718 if ($info->getCode() != PEAR_INSTALLER_NOBINARY) {
719 if (!($info = $pkg->installBinary($this->installer))) {
720 $this->ui->outputData('ERROR: ' .$oldinfo->getMessage());
724 // we just installed a different package than requested,
725 // let's change the param and info so that the rest of this works
731 if (!is_array($info)) {
732 return $this->raiseError("$command failed");
735 if ($param->getPackageType() == 'extsrc' ||
736 $param->getPackageType() == 'extbin' ||
737 $param->getPackageType() == 'zendextsrc' ||
738 $param->getPackageType() == 'zendextbin'
740 $pkg = &$param->getPackageFile();
741 if ($instbin = $pkg->getInstalledBinary()) {
742 $instpkg = &$instreg->getPackage($instbin, $pkg->getChannel());
744 $instpkg = &$instreg->getPackage($pkg->getPackage(), $pkg->getChannel());
747 foreach ($instpkg->getFilelist() as $name => $atts) {
748 $pinfo = pathinfo($atts['installed_as']);
749 if (!isset($pinfo['extension']) ||
750 in_array($pinfo['extension'], array('c', 'h'))
752 continue; // make sure we don't match php_blah.h
755 if ((strpos($pinfo['basename'], 'php_') === 0 &&
756 $pinfo['extension'] == 'dll') ||
758 $pinfo['extension'] == 'so' ||
760 $pinfo['extension'] == 'sl') {
761 $binaries[] = array($atts['installed_as'], $pinfo);
766 if (count($binaries)) {
767 foreach ($binaries as $pinfo) {
768 PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
769 $ret = $this->enableExtension(array($pinfo[0]), $param->getPackageType());
770 PEAR::staticPopErrorHandling();
771 if (PEAR::isError($ret)) {
772 $extrainfo[] = $ret->getMessage();
773 if ($param->getPackageType() == 'extsrc' ||
774 $param->getPackageType() == 'extbin') {
775 $exttype = 'extension';
776 $extpath = $pinfo[1]['basename'];
778 $exttype = 'zend_extension';
779 $extpath = $atts['installed_as'];
781 $extrainfo[] = 'You should add "' . $exttype . '=' .
782 $extpath . '" to php.ini';
784 $extrainfo[] = 'Extension ' . $instpkg->getProvidesExtension() .
785 ' enabled in php.ini';
791 if ($this->config->get('verbose') > 0) {
792 $chan = $param->getChannel();
793 $label = $reg->parsedPackageNameToString(
796 'package' => $param->getPackage(),
797 'version' => $param->getVersion(),
799 $out = array('data' => "$command ok: $label");
800 if (isset($info['release_warnings'])) {
801 $out['release_warnings'] = $info['release_warnings'];
803 $this->ui->outputData($out, $command);
805 if (!isset($options['register-only']) && !isset($options['offline'])) {
806 if ($this->config->isDefinedLayer('ftp')) {
807 PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
808 $info = $this->installer->ftpInstall($param);
809 PEAR::staticPopErrorHandling();
810 if (PEAR::isError($info)) {
811 $this->ui->outputData($info->getMessage());
812 $this->ui->outputData("remote install failed: $label");
814 $this->ui->outputData("remote install ok: $label");
820 $deps = $param->getDeps();
822 if (isset($deps['group'])) {
823 $groups = $deps['group'];
824 if (!isset($groups[0])) {
825 $groups = array($groups);
828 foreach ($groups as $group) {
829 if ($group['attribs']['name'] == 'default') {
830 // default group is always installed, unless the user
831 // explicitly chooses to install another group
834 $extrainfo[] = $param->getPackage() . ': Optional feature ' .
835 $group['attribs']['name'] . ' available (' .
836 $group['attribs']['hint'] . ')';
839 $extrainfo[] = $param->getPackage() .
840 ': To install optional features use "pear install ' .
841 $reg->parsedPackageNameToString(
842 array('package' => $param->getPackage(),
843 'channel' => $param->getChannel()), true) .
848 $pkg = &$instreg->getPackage($param->getPackage(), $param->getChannel());
849 // $pkg may be NULL if install is a 'fake' install via --packagingroot
850 if (is_object($pkg)) {
851 $pkg->setConfig($this->config);
852 if ($list = $pkg->listPostinstallScripts()) {
853 $pn = $reg->parsedPackageNameToString(array('channel' =>
854 $param->getChannel(), 'package' => $param->getPackage()), true);
855 $extrainfo[] = $pn . ' has post-install scripts:';
856 foreach ($list as $file) {
857 $extrainfo[] = $file;
859 $extrainfo[] = $param->getPackage() .
860 ': Use "pear run-scripts ' . $pn . '" to finish setup.';
861 $extrainfo[] = 'DO NOT RUN SCRIPTS FROM UNTRUSTED SOURCES';
866 if (count($extrainfo)) {
867 foreach ($extrainfo as $info) {
868 $this->ui->outputData($info);
876 // {{{ doUpgradeAll()
878 function doUpgradeAll($command, $options, $params)
880 $reg = &$this->config->getRegistry();
883 if (isset($options['channel'])) {
884 $channels = array($options['channel']);
886 $channels = $reg->listChannels();
889 foreach ($channels as $channel) {
890 if ($channel == '__uri') {
894 // parse name with channel
895 foreach ($reg->listPackages($channel) as $name) {
896 $upgrade[] = $reg->parsedPackageNameToString(array(
897 'channel' => $channel,
903 $err = $this->doInstall($command, $options, $upgrade);
904 if (PEAR::isError($err)) {
905 $this->ui->outputData($err->getMessage(), $command);
912 function doUninstall($command, $options, $params)
914 if (count($params) < 1) {
915 return $this->raiseError("Please supply the package(s) you want to uninstall");
918 if (empty($this->installer)) {
919 $this->installer = &$this->getInstaller($this->ui);
922 if (isset($options['remoteconfig'])) {
923 $e = $this->config->readFTPConfigFile($options['remoteconfig']);
924 if (!PEAR::isError($e)) {
925 $this->installer->setConfig($this->config);
929 $reg = &$this->config->getRegistry();
930 $newparams = array();
932 $badparams = array();
933 foreach ($params as $pkg) {
934 $channel = $this->config->get('default_channel');
935 PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
936 $parsed = $reg->parsePackageName($pkg, $channel);
937 PEAR::staticPopErrorHandling();
938 if (!$parsed || PEAR::isError($parsed)) {
942 $package = $parsed['package'];
943 $channel = $parsed['channel'];
944 $info = &$reg->getPackage($package, $channel);
945 if ($info === null &&
946 ($channel == 'pear.php.net' || $channel == 'pecl.php.net')) {
947 // make sure this isn't a package that has flipped from pear to pecl but
948 // used a package.xml 1.0
949 $testc = ($channel == 'pear.php.net') ? 'pecl.php.net' : 'pear.php.net';
950 $info = &$reg->getPackage($package, $testc);
951 if ($info !== null) {
955 if ($info === null) {
958 $newparams[] = &$info;
959 // check for binary packages (this is an alias for those packages if so)
960 if ($installedbinary = $info->getInstalledBinary()) {
961 $this->ui->log('adding binary package ' .
962 $reg->parsedPackageNameToString(array('channel' => $channel,
963 'package' => $installedbinary), true));
964 $newparams[] = &$reg->getPackage($installedbinary, $channel);
966 // add the contents of a dependency group to the list of installed packages
967 if (isset($parsed['group'])) {
968 $group = $info->getDependencyGroup($parsed['group']);
970 $installed = $reg->getInstalledGroup($group);
972 foreach ($installed as $i => $p) {
973 $newparams[] = &$installed[$i];
980 $err = $this->installer->sortPackagesForUninstall($newparams);
981 if (PEAR::isError($err)) {
982 $this->ui->outputData($err->getMessage(), $command);
985 $params = $newparams;
986 // twist this to use it to check on whether dependent packages are also being uninstalled
987 // for circular dependencies like subpackages
988 $this->installer->setUninstallPackages($newparams);
989 $params = array_merge($params, $badparams);
991 foreach ($params as $pkg) {
992 $this->installer->pushErrorHandling(PEAR_ERROR_RETURN);
993 if ($err = $this->installer->uninstall($pkg, $options)) {
994 $this->installer->popErrorHandling();
995 if (PEAR::isError($err)) {
996 $this->ui->outputData($err->getMessage(), $command);
999 if ($pkg->getPackageType() == 'extsrc' ||
1000 $pkg->getPackageType() == 'extbin' ||
1001 $pkg->getPackageType() == 'zendextsrc' ||
1002 $pkg->getPackageType() == 'zendextbin') {
1003 if ($instbin = $pkg->getInstalledBinary()) {
1004 continue; // this will be uninstalled later
1007 foreach ($pkg->getFilelist() as $name => $atts) {
1008 $pinfo = pathinfo($atts['installed_as']);
1009 if (!isset($pinfo['extension']) ||
1010 in_array($pinfo['extension'], array('c', 'h'))) {
1011 continue; // make sure we don't match php_blah.h
1013 if ((strpos($pinfo['basename'], 'php_') === 0 &&
1014 $pinfo['extension'] == 'dll') ||
1016 $pinfo['extension'] == 'so' ||
1018 $pinfo['extension'] == 'sl') {
1019 $binaries[] = array($atts['installed_as'], $pinfo);
1023 if (count($binaries)) {
1024 foreach ($binaries as $pinfo) {
1025 PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
1026 $ret = $this->disableExtension(array($pinfo[0]), $pkg->getPackageType());
1027 PEAR::staticPopErrorHandling();
1028 if (PEAR::isError($ret)) {
1029 $extrainfo[] = $ret->getMessage();
1030 if ($pkg->getPackageType() == 'extsrc' ||
1031 $pkg->getPackageType() == 'extbin') {
1032 $exttype = 'extension';
1035 phpinfo(INFO_GENERAL);
1036 $info = ob_get_contents();
1038 $debug = function_exists('leak') ? '_debug' : '';
1039 $ts = preg_match('/Thread Safety.+enabled/', $info) ? '_ts' : '';
1040 $exttype = 'zend_extension' . $debug . $ts;
1042 $this->ui->outputData('Unable to remove "' . $exttype . '=' .
1043 $pinfo[1]['basename'] . '" from php.ini', $command);
1045 $this->ui->outputData('Extension ' . $pkg->getProvidesExtension() .
1046 ' disabled in php.ini', $command);
1052 if ($this->config->get('verbose') > 0) {
1053 if (is_object($pkg)) {
1054 $pkg = $reg->parsedPackageNameToString($pkg);
1056 $this->ui->outputData("uninstall ok: $pkg", $command);
1058 if (!isset($options['offline']) && is_object($savepkg) &&
1059 defined('PEAR_REMOTEINSTALL_OK')) {
1060 if ($this->config->isDefinedLayer('ftp')) {
1061 $this->installer->pushErrorHandling(PEAR_ERROR_RETURN);
1062 $info = $this->installer->ftpUninstall($savepkg);
1063 $this->installer->popErrorHandling();
1064 if (PEAR::isError($info)) {
1065 $this->ui->outputData($info->getMessage());
1066 $this->ui->outputData("remote uninstall failed: $pkg");
1068 $this->ui->outputData("remote uninstall ok: $pkg");
1073 $this->installer->popErrorHandling();
1074 if (!is_object($pkg)) {
1075 return $this->raiseError("uninstall failed: $pkg");
1077 $pkg = $reg->parsedPackageNameToString($pkg);
1090 (cox) It just downloads and untars the package, does not do
1091 any check that the PEAR_Installer::_installFile() does.
1094 function doBundle($command, $options, $params)
1100 'downloadonly' => true
1102 $downloader = &$this->getDownloader($this->ui, $opts, $this->config);
1103 $reg = &$this->config->getRegistry();
1104 if (count($params) < 1) {
1105 return $this->raiseError("Please supply the package you want to bundle");
1108 if (isset($options['destination'])) {
1109 if (!is_dir($options['destination'])) {
1110 System::mkdir('-p ' . $options['destination']);
1112 $dest = realpath($options['destination']);
1115 $dir = $pwd . DIRECTORY_SEPARATOR . 'ext';
1116 $dest = is_dir($dir) ? $dir : $pwd;
1118 PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
1119 $err = $downloader->setDownloadDir($dest);
1120 PEAR::staticPopErrorHandling();
1121 if (PEAR::isError($err)) {
1122 return PEAR::raiseError('download directory "' . $dest .
1123 '" is not writeable.');
1125 $result = &$downloader->download(array($params[0]));
1126 if (PEAR::isError($result)) {
1129 if (!isset($result[0])) {
1130 return $this->raiseError('unable to unpack ' . $params[0]);
1132 $pkgfile = &$result[0]->getPackageFile();
1133 $pkgname = $pkgfile->getName();
1134 $pkgversion = $pkgfile->getVersion();
1136 // Unpacking -------------------------------------------------
1137 $dest .= DIRECTORY_SEPARATOR . $pkgname;
1138 $orig = $pkgname . '-' . $pkgversion;
1140 $tar = new Archive_Tar($pkgfile->getArchiveFile());
1141 if (!$tar->extractModify($dest, $orig)) {
1142 return $this->raiseError('unable to unpack ' . $pkgfile->getArchiveFile());
1144 $this->ui->outputData("Package ready at '$dest'");
1150 function doRunScripts($command, $options, $params)
1152 if (!isset($params[0])) {
1153 return $this->raiseError('run-scripts expects 1 parameter: a package name');
1156 $reg = &$this->config->getRegistry();
1157 PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
1158 $parsed = $reg->parsePackageName($params[0], $this->config->get('default_channel'));
1159 PEAR::staticPopErrorHandling();
1160 if (PEAR::isError($parsed)) {
1161 return $this->raiseError($parsed);
1164 $package = &$reg->getPackage($parsed['package'], $parsed['channel']);
1165 if (!is_object($package)) {
1166 return $this->raiseError('Could not retrieve package "' . $params[0] . '" from registry');
1169 $package->setConfig($this->config);
1170 $package->runPostinstallScripts();
1171 $this->ui->outputData('Install scripts complete', $command);
1176 * Given a list of packages, filter out those ones that are already up to date
1178 * @param $packages: packages, in parsed array format !
1179 * @return list of packages that can be upgraded
1181 function _filterUptodatePackages($packages, $command)
1183 $reg = &$this->config->getRegistry();
1184 $latestReleases = array();
1187 foreach ($packages as $package) {
1188 if (isset($package['group'])) {
1193 $channel = $package['channel'];
1194 $name = $package['package'];
1195 if (!$reg->packageExists($name, $channel)) {
1200 if (!isset($latestReleases[$channel])) {
1201 // fill in cache for this channel
1202 $chan = $reg->getChannel($channel);
1203 if (PEAR::isError($chan)) {
1204 return $this->raiseError($chan);
1208 $preferred_mirror = $this->config->get('preferred_mirror', null, $channel);
1209 if ($chan->supportsREST($preferred_mirror) &&
1211 //($base2 = $chan->getBaseURL('REST1.4', $preferred_mirror)) ||
1212 ($base = $chan->getBaseURL('REST1.0', $preferred_mirror))
1218 PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
1219 if (!isset($package['state'])) {
1220 $state = $this->config->get('preferred_state', null, $channel);
1222 $state = $package['state'];
1227 $rest = &$this->config->getREST('1.4', array());
1230 $rest = &$this->config->getREST('1.0', array());
1233 $installed = array_flip($reg->listPackages($channel));
1234 $latest = $rest->listLatestUpgrades($base, $state, $installed, $channel, $reg);
1237 PEAR::staticPopErrorHandling();
1238 if (PEAR::isError($latest)) {
1239 $this->ui->outputData('Error getting channel info from ' . $channel .
1240 ': ' . $latest->getMessage());
1244 $latestReleases[$channel] = array_change_key_case($latest);
1247 // check package for latest release
1248 $name_lower = strtolower($name);
1249 if (isset($latestReleases[$channel][$name_lower])) {
1250 // if not set, up to date
1251 $inst_version = $reg->packageInfo($name, 'version', $channel);
1252 $channel_version = $latestReleases[$channel][$name_lower]['version'];
1253 if (version_compare($channel_version, $inst_version, 'le')) {
1254 // installed version is up-to-date
1259 if ($command == 'upgrade-all') {
1260 $this->ui->outputData(array('data' => 'Will upgrade ' .
1261 $reg->parsedPackageNameToString($package)), $command);