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.4
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 return $this->raiseError('ERROR: ' .$oldinfo->getMessage());
723 // we just installed a different package than requested,
724 // let's change the param and info so that the rest of this works
730 if (!is_array($info)) {
731 return $this->raiseError("$command failed");
734 if ($param->getPackageType() == 'extsrc' ||
735 $param->getPackageType() == 'extbin' ||
736 $param->getPackageType() == 'zendextsrc' ||
737 $param->getPackageType() == 'zendextbin'
739 $pkg = &$param->getPackageFile();
740 if ($instbin = $pkg->getInstalledBinary()) {
741 $instpkg = &$instreg->getPackage($instbin, $pkg->getChannel());
743 $instpkg = &$instreg->getPackage($pkg->getPackage(), $pkg->getChannel());
746 foreach ($instpkg->getFilelist() as $name => $atts) {
747 $pinfo = pathinfo($atts['installed_as']);
748 if (!isset($pinfo['extension']) ||
749 in_array($pinfo['extension'], array('c', 'h'))
751 continue; // make sure we don't match php_blah.h
754 if ((strpos($pinfo['basename'], 'php_') === 0 &&
755 $pinfo['extension'] == 'dll') ||
757 $pinfo['extension'] == 'so' ||
759 $pinfo['extension'] == 'sl') {
760 $binaries[] = array($atts['installed_as'], $pinfo);
765 if (count($binaries)) {
766 foreach ($binaries as $pinfo) {
767 PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
768 $ret = $this->enableExtension(array($pinfo[0]), $param->getPackageType());
769 PEAR::staticPopErrorHandling();
770 if (PEAR::isError($ret)) {
771 $extrainfo[] = $ret->getMessage();
772 if ($param->getPackageType() == 'extsrc' ||
773 $param->getPackageType() == 'extbin') {
774 $exttype = 'extension';
775 $extpath = $pinfo[1]['basename'];
777 $exttype = 'zend_extension';
778 $extpath = $atts['installed_as'];
780 $extrainfo[] = 'You should add "' . $exttype . '=' .
781 $extpath . '" to php.ini';
783 $extrainfo[] = 'Extension ' . $instpkg->getProvidesExtension() .
784 ' enabled in php.ini';
790 if ($this->config->get('verbose') > 0) {
791 $chan = $param->getChannel();
792 $label = $reg->parsedPackageNameToString(
795 'package' => $param->getPackage(),
796 'version' => $param->getVersion(),
798 $out = array('data' => "$command ok: $label");
799 if (isset($info['release_warnings'])) {
800 $out['release_warnings'] = $info['release_warnings'];
802 $this->ui->outputData($out, $command);
804 if (!isset($options['register-only']) && !isset($options['offline'])) {
805 if ($this->config->isDefinedLayer('ftp')) {
806 PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
807 $info = $this->installer->ftpInstall($param);
808 PEAR::staticPopErrorHandling();
809 if (PEAR::isError($info)) {
810 $this->ui->outputData($info->getMessage());
811 $this->ui->outputData("remote install failed: $label");
813 $this->ui->outputData("remote install ok: $label");
819 $deps = $param->getDeps();
821 if (isset($deps['group'])) {
822 $groups = $deps['group'];
823 if (!isset($groups[0])) {
824 $groups = array($groups);
827 foreach ($groups as $group) {
828 if ($group['attribs']['name'] == 'default') {
829 // default group is always installed, unless the user
830 // explicitly chooses to install another group
833 $extrainfo[] = $param->getPackage() . ': Optional feature ' .
834 $group['attribs']['name'] . ' available (' .
835 $group['attribs']['hint'] . ')';
838 $extrainfo[] = $param->getPackage() .
839 ': To install optional features use "pear install ' .
840 $reg->parsedPackageNameToString(
841 array('package' => $param->getPackage(),
842 'channel' => $param->getChannel()), true) .
847 $pkg = &$instreg->getPackage($param->getPackage(), $param->getChannel());
848 // $pkg may be NULL if install is a 'fake' install via --packagingroot
849 if (is_object($pkg)) {
850 $pkg->setConfig($this->config);
851 if ($list = $pkg->listPostinstallScripts()) {
852 $pn = $reg->parsedPackageNameToString(array('channel' =>
853 $param->getChannel(), 'package' => $param->getPackage()), true);
854 $extrainfo[] = $pn . ' has post-install scripts:';
855 foreach ($list as $file) {
856 $extrainfo[] = $file;
858 $extrainfo[] = $param->getPackage() .
859 ': Use "pear run-scripts ' . $pn . '" to finish setup.';
860 $extrainfo[] = 'DO NOT RUN SCRIPTS FROM UNTRUSTED SOURCES';
865 if (count($extrainfo)) {
866 foreach ($extrainfo as $info) {
867 $this->ui->outputData($info);
875 // {{{ doUpgradeAll()
877 function doUpgradeAll($command, $options, $params)
879 $reg = &$this->config->getRegistry();
882 if (isset($options['channel'])) {
883 $channels = array($options['channel']);
885 $channels = $reg->listChannels();
888 foreach ($channels as $channel) {
889 if ($channel == '__uri') {
893 // parse name with channel
894 foreach ($reg->listPackages($channel) as $name) {
895 $upgrade[] = $reg->parsedPackageNameToString(array(
896 'channel' => $channel,
902 $err = $this->doInstall($command, $options, $upgrade);
903 if (PEAR::isError($err)) {
904 $this->ui->outputData($err->getMessage(), $command);
911 function doUninstall($command, $options, $params)
913 if (count($params) < 1) {
914 return $this->raiseError("Please supply the package(s) you want to uninstall");
917 if (empty($this->installer)) {
918 $this->installer = &$this->getInstaller($this->ui);
921 if (isset($options['remoteconfig'])) {
922 $e = $this->config->readFTPConfigFile($options['remoteconfig']);
923 if (!PEAR::isError($e)) {
924 $this->installer->setConfig($this->config);
928 $reg = &$this->config->getRegistry();
929 $newparams = array();
931 $badparams = array();
932 foreach ($params as $pkg) {
933 $channel = $this->config->get('default_channel');
934 PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
935 $parsed = $reg->parsePackageName($pkg, $channel);
936 PEAR::staticPopErrorHandling();
937 if (!$parsed || PEAR::isError($parsed)) {
941 $package = $parsed['package'];
942 $channel = $parsed['channel'];
943 $info = &$reg->getPackage($package, $channel);
944 if ($info === null &&
945 ($channel == 'pear.php.net' || $channel == 'pecl.php.net')) {
946 // make sure this isn't a package that has flipped from pear to pecl but
947 // used a package.xml 1.0
948 $testc = ($channel == 'pear.php.net') ? 'pecl.php.net' : 'pear.php.net';
949 $info = &$reg->getPackage($package, $testc);
950 if ($info !== null) {
954 if ($info === null) {
957 $newparams[] = &$info;
958 // check for binary packages (this is an alias for those packages if so)
959 if ($installedbinary = $info->getInstalledBinary()) {
960 $this->ui->log('adding binary package ' .
961 $reg->parsedPackageNameToString(array('channel' => $channel,
962 'package' => $installedbinary), true));
963 $newparams[] = &$reg->getPackage($installedbinary, $channel);
965 // add the contents of a dependency group to the list of installed packages
966 if (isset($parsed['group'])) {
967 $group = $info->getDependencyGroup($parsed['group']);
969 $installed = $reg->getInstalledGroup($group);
971 foreach ($installed as $i => $p) {
972 $newparams[] = &$installed[$i];
979 $err = $this->installer->sortPackagesForUninstall($newparams);
980 if (PEAR::isError($err)) {
981 $this->ui->outputData($err->getMessage(), $command);
984 $params = $newparams;
985 // twist this to use it to check on whether dependent packages are also being uninstalled
986 // for circular dependencies like subpackages
987 $this->installer->setUninstallPackages($newparams);
988 $params = array_merge($params, $badparams);
990 foreach ($params as $pkg) {
991 $this->installer->pushErrorHandling(PEAR_ERROR_RETURN);
992 if ($err = $this->installer->uninstall($pkg, $options)) {
993 $this->installer->popErrorHandling();
994 if (PEAR::isError($err)) {
995 $this->ui->outputData($err->getMessage(), $command);
998 if ($pkg->getPackageType() == 'extsrc' ||
999 $pkg->getPackageType() == 'extbin' ||
1000 $pkg->getPackageType() == 'zendextsrc' ||
1001 $pkg->getPackageType() == 'zendextbin') {
1002 if ($instbin = $pkg->getInstalledBinary()) {
1003 continue; // this will be uninstalled later
1006 foreach ($pkg->getFilelist() as $name => $atts) {
1007 $pinfo = pathinfo($atts['installed_as']);
1008 if (!isset($pinfo['extension']) ||
1009 in_array($pinfo['extension'], array('c', 'h'))) {
1010 continue; // make sure we don't match php_blah.h
1012 if ((strpos($pinfo['basename'], 'php_') === 0 &&
1013 $pinfo['extension'] == 'dll') ||
1015 $pinfo['extension'] == 'so' ||
1017 $pinfo['extension'] == 'sl') {
1018 $binaries[] = array($atts['installed_as'], $pinfo);
1022 if (count($binaries)) {
1023 foreach ($binaries as $pinfo) {
1024 PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
1025 $ret = $this->disableExtension(array($pinfo[0]), $pkg->getPackageType());
1026 PEAR::staticPopErrorHandling();
1027 if (PEAR::isError($ret)) {
1028 $extrainfo[] = $ret->getMessage();
1029 if ($pkg->getPackageType() == 'extsrc' ||
1030 $pkg->getPackageType() == 'extbin') {
1031 $exttype = 'extension';
1034 phpinfo(INFO_GENERAL);
1035 $info = ob_get_contents();
1037 $debug = function_exists('leak') ? '_debug' : '';
1038 $ts = preg_match('/Thread Safety.+enabled/', $info) ? '_ts' : '';
1039 $exttype = 'zend_extension' . $debug . $ts;
1041 $this->ui->outputData('Unable to remove "' . $exttype . '=' .
1042 $pinfo[1]['basename'] . '" from php.ini', $command);
1044 $this->ui->outputData('Extension ' . $pkg->getProvidesExtension() .
1045 ' disabled in php.ini', $command);
1051 if ($this->config->get('verbose') > 0) {
1052 if (is_object($pkg)) {
1053 $pkg = $reg->parsedPackageNameToString($pkg);
1055 $this->ui->outputData("uninstall ok: $pkg", $command);
1057 if (!isset($options['offline']) && is_object($savepkg) &&
1058 defined('PEAR_REMOTEINSTALL_OK')) {
1059 if ($this->config->isDefinedLayer('ftp')) {
1060 $this->installer->pushErrorHandling(PEAR_ERROR_RETURN);
1061 $info = $this->installer->ftpUninstall($savepkg);
1062 $this->installer->popErrorHandling();
1063 if (PEAR::isError($info)) {
1064 $this->ui->outputData($info->getMessage());
1065 $this->ui->outputData("remote uninstall failed: $pkg");
1067 $this->ui->outputData("remote uninstall ok: $pkg");
1072 $this->installer->popErrorHandling();
1073 if (!is_object($pkg)) {
1074 return $this->raiseError("uninstall failed: $pkg");
1076 $pkg = $reg->parsedPackageNameToString($pkg);
1089 (cox) It just downloads and untars the package, does not do
1090 any check that the PEAR_Installer::_installFile() does.
1093 function doBundle($command, $options, $params)
1099 'downloadonly' => true
1101 $downloader = &$this->getDownloader($this->ui, $opts, $this->config);
1102 $reg = &$this->config->getRegistry();
1103 if (count($params) < 1) {
1104 return $this->raiseError("Please supply the package you want to bundle");
1107 if (isset($options['destination'])) {
1108 if (!is_dir($options['destination'])) {
1109 System::mkdir('-p ' . $options['destination']);
1111 $dest = realpath($options['destination']);
1114 $dir = $pwd . DIRECTORY_SEPARATOR . 'ext';
1115 $dest = is_dir($dir) ? $dir : $pwd;
1117 PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
1118 $err = $downloader->setDownloadDir($dest);
1119 PEAR::staticPopErrorHandling();
1120 if (PEAR::isError($err)) {
1121 return PEAR::raiseError('download directory "' . $dest .
1122 '" is not writeable.');
1124 $result = &$downloader->download(array($params[0]));
1125 if (PEAR::isError($result)) {
1128 if (!isset($result[0])) {
1129 return $this->raiseError('unable to unpack ' . $params[0]);
1131 $pkgfile = &$result[0]->getPackageFile();
1132 $pkgname = $pkgfile->getName();
1133 $pkgversion = $pkgfile->getVersion();
1135 // Unpacking -------------------------------------------------
1136 $dest .= DIRECTORY_SEPARATOR . $pkgname;
1137 $orig = $pkgname . '-' . $pkgversion;
1139 $tar = new Archive_Tar($pkgfile->getArchiveFile());
1140 if (!$tar->extractModify($dest, $orig)) {
1141 return $this->raiseError('unable to unpack ' . $pkgfile->getArchiveFile());
1143 $this->ui->outputData("Package ready at '$dest'");
1149 function doRunScripts($command, $options, $params)
1151 if (!isset($params[0])) {
1152 return $this->raiseError('run-scripts expects 1 parameter: a package name');
1155 $reg = &$this->config->getRegistry();
1156 PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
1157 $parsed = $reg->parsePackageName($params[0], $this->config->get('default_channel'));
1158 PEAR::staticPopErrorHandling();
1159 if (PEAR::isError($parsed)) {
1160 return $this->raiseError($parsed);
1163 $package = &$reg->getPackage($parsed['package'], $parsed['channel']);
1164 if (!is_object($package)) {
1165 return $this->raiseError('Could not retrieve package "' . $params[0] . '" from registry');
1168 $package->setConfig($this->config);
1169 $package->runPostinstallScripts();
1170 $this->ui->outputData('Install scripts complete', $command);
1175 * Given a list of packages, filter out those ones that are already up to date
1177 * @param $packages: packages, in parsed array format !
1178 * @return list of packages that can be upgraded
1180 function _filterUptodatePackages($packages, $command)
1182 $reg = &$this->config->getRegistry();
1183 $latestReleases = array();
1186 foreach ($packages as $package) {
1187 if (isset($package['group'])) {
1192 $channel = $package['channel'];
1193 $name = $package['package'];
1194 if (!$reg->packageExists($name, $channel)) {
1199 if (!isset($latestReleases[$channel])) {
1200 // fill in cache for this channel
1201 $chan = $reg->getChannel($channel);
1202 if (PEAR::isError($chan)) {
1203 return $this->raiseError($chan);
1207 $preferred_mirror = $this->config->get('preferred_mirror', null, $channel);
1208 if ($chan->supportsREST($preferred_mirror) &&
1210 //($base2 = $chan->getBaseURL('REST1.4', $preferred_mirror)) ||
1211 ($base = $chan->getBaseURL('REST1.0', $preferred_mirror))
1217 PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
1218 if (!isset($package['state'])) {
1219 $state = $this->config->get('preferred_state', null, $channel);
1221 $state = $package['state'];
1226 $rest = &$this->config->getREST('1.4', array());
1229 $rest = &$this->config->getREST('1.0', array());
1232 $installed = array_flip($reg->listPackages($channel));
1233 $latest = $rest->listLatestUpgrades($base, $state, $installed, $channel, $reg);
1236 PEAR::staticPopErrorHandling();
1237 if (PEAR::isError($latest)) {
1238 $this->ui->outputData('Error getting channel info from ' . $channel .
1239 ': ' . $latest->getMessage());
1243 $latestReleases[$channel] = array_change_key_case($latest);
1246 // check package for latest release
1247 $name_lower = strtolower($name);
1248 if (isset($latestReleases[$channel][$name_lower])) {
1249 // if not set, up to date
1250 $inst_version = $reg->packageInfo($name, 'version', $channel);
1251 $channel_version = $latestReleases[$channel][$name_lower]['version'];
1252 if (version_compare($channel_version, $inst_version, 'le')) {
1253 // installed version is up-to-date
1258 if ($command == 'upgrade-all') {
1259 $this->ui->outputData(array('data' => 'Will upgrade ' .
1260 $reg->parsedPackageNameToString($package)), $command);