source: branches/version-2_13-dev/data/module/PEAR/Command/Install.php @ 23125

Revision 23125, 49.7 KB checked in by kimoto, 11 years ago (diff)

#2275 PEAR更新
不要なrequire_onceの削除
レガシーなPEARモジュールは使わない
SearchReplace?.phpのパスが間違っているので修正

Line 
1<?php
2/**
3 * PEAR_Command_Install (install, upgrade, upgrade-all, uninstall, bundle, run-scripts commands)
4 *
5 * PHP versions 4 and 5
6 *
7 * @category   pear
8 * @package    PEAR
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 * @version    CVS: $Id: Install.php 313023 2011-07-06 19:17:11Z dufuz $
14 * @link       http://pear.php.net/package/PEAR
15 * @since      File available since Release 0.1
16 */
17
18/**
19 * base class
20 */
21require_once 'PEAR/Command/Common.php';
22
23/**
24 * PEAR commands for installation or deinstallation/upgrading of
25 * packages.
26 *
27 * @category   pear
28 * @package    PEAR
29 * @author     Stig Bakken <ssb@php.net>
30 * @author     Greg Beaver <cellog@php.net>
31 * @copyright  1997-2009 The Authors
32 * @license    http://opensource.org/licenses/bsd-license.php New BSD License
33 * @version    Release: 1.9.4
34 * @link       http://pear.php.net/package/PEAR
35 * @since      Class available since Release 0.1
36 */
37class PEAR_Command_Install extends PEAR_Command_Common
38{
39    // {{{ properties
40
41    var $commands = array(
42        'install' => array(
43            'summary' => 'Install Package',
44            'function' => 'doInstall',
45            'shortcut' => 'i',
46            'options' => array(
47                'force' => array(
48                    'shortopt' => 'f',
49                    'doc' => 'will overwrite newer installed packages',
50                    ),
51                'loose' => array(
52                    'shortopt' => 'l',
53                    'doc' => 'do not check for recommended dependency version',
54                    ),
55                'nodeps' => array(
56                    'shortopt' => 'n',
57                    'doc' => 'ignore dependencies, install anyway',
58                    ),
59                'register-only' => array(
60                    'shortopt' => 'r',
61                    'doc' => 'do not install files, only register the package as installed',
62                    ),
63                'soft' => array(
64                    'shortopt' => 's',
65                    'doc' => 'soft install, fail silently, or upgrade if already installed',
66                    ),
67                'nobuild' => array(
68                    'shortopt' => 'B',
69                    'doc' => 'don\'t build C extensions',
70                    ),
71                'nocompress' => array(
72                    'shortopt' => 'Z',
73                    'doc' => 'request uncompressed files when downloading',
74                    ),
75                'installroot' => array(
76                    'shortopt' => 'R',
77                    'arg' => 'DIR',
78                    'doc' => 'root directory used when installing files (ala PHP\'s INSTALL_ROOT), use packagingroot for RPM',
79                    ),
80                'packagingroot' => array(
81                    'shortopt' => 'P',
82                    'arg' => 'DIR',
83                    'doc' => 'root directory used when packaging files, like RPM packaging',
84                    ),
85                'ignore-errors' => array(
86                    'doc' => 'force install even if there were errors',
87                    ),
88                'alldeps' => array(
89                    'shortopt' => 'a',
90                    'doc' => 'install all required and optional dependencies',
91                    ),
92                'onlyreqdeps' => array(
93                    'shortopt' => 'o',
94                    'doc' => 'install all required dependencies',
95                    ),
96                'offline' => array(
97                    'shortopt' => 'O',
98                    'doc' => 'do not attempt to download any urls or contact channels',
99                    ),
100                'pretend' => array(
101                    'shortopt' => 'p',
102                    'doc' => 'Only list the packages that would be downloaded',
103                    ),
104                ),
105            'doc' => '[channel/]<package> ...
106Installs one or more PEAR packages.  You can specify a package to
107install in four ways:
108
109"Package-1.0.tgz" : installs from a local file
110
111"http://example.com/Package-1.0.tgz" : installs from
112anywhere on the net.
113
114"package.xml" : installs the package described in
115package.xml.  Useful for testing, or for wrapping a PEAR package in
116another package manager such as RPM.
117
118"Package[-version/state][.tar]" : queries your default channel\'s server
119({config master_server}) and downloads the newest package with
120the preferred quality/state ({config preferred_state}).
121
122To retrieve Package version 1.1, use "Package-1.1," to retrieve
123Package state beta, use "Package-beta."  To retrieve an uncompressed
124file, append .tar (make sure there is no file by the same name first)
125
126To download a package from another channel, prefix with the channel name like
127"channel/Package"
128
129More than one package may be specified at once.  It is ok to mix these
130four ways of specifying packages.
131'),
132        'upgrade' => array(
133            'summary' => 'Upgrade Package',
134            'function' => 'doInstall',
135            'shortcut' => 'up',
136            'options' => array(
137                'channel' => array(
138                    'shortopt' => 'c',
139                    'doc' => 'upgrade packages from a specific channel',
140                    'arg' => 'CHAN',
141                    ),
142                'force' => array(
143                    'shortopt' => 'f',
144                    'doc' => 'overwrite newer installed packages',
145                    ),
146                'loose' => array(
147                    'shortopt' => 'l',
148                    'doc' => 'do not check for recommended dependency version',
149                    ),
150                'nodeps' => array(
151                    'shortopt' => 'n',
152                    'doc' => 'ignore dependencies, upgrade anyway',
153                    ),
154                'register-only' => array(
155                    'shortopt' => 'r',
156                    'doc' => 'do not install files, only register the package as upgraded',
157                    ),
158                'nobuild' => array(
159                    'shortopt' => 'B',
160                    'doc' => 'don\'t build C extensions',
161                    ),
162                'nocompress' => array(
163                    'shortopt' => 'Z',
164                    'doc' => 'request uncompressed files when downloading',
165                    ),
166                'installroot' => array(
167                    'shortopt' => 'R',
168                    'arg' => 'DIR',
169                    'doc' => 'root directory used when installing files (ala PHP\'s INSTALL_ROOT)',
170                    ),
171                'ignore-errors' => array(
172                    'doc' => 'force install even if there were errors',
173                    ),
174                'alldeps' => array(
175                    'shortopt' => 'a',
176                    'doc' => 'install all required and optional dependencies',
177                    ),
178                'onlyreqdeps' => array(
179                    'shortopt' => 'o',
180                    'doc' => 'install all required dependencies',
181                    ),
182                'offline' => array(
183                    'shortopt' => 'O',
184                    'doc' => 'do not attempt to download any urls or contact channels',
185                    ),
186                'pretend' => array(
187                    'shortopt' => 'p',
188                    'doc' => 'Only list the packages that would be downloaded',
189                    ),
190                ),
191            'doc' => '<package> ...
192Upgrades one or more PEAR packages.  See documentation for the
193"install" command for ways to specify a package.
194
195When upgrading, your package will be updated if the provided new
196package has a higher version number (use the -f option if you need to
197upgrade anyway).
198
199More than one package may be specified at once.
200'),
201        'upgrade-all' => array(
202            'summary' => 'Upgrade All Packages [Deprecated in favor of calling upgrade with no parameters]',
203            'function' => 'doUpgradeAll',
204            'shortcut' => 'ua',
205            'options' => array(
206                'channel' => array(
207                    'shortopt' => 'c',
208                    'doc' => 'upgrade packages from a specific channel',
209                    'arg' => 'CHAN',
210                    ),
211                'nodeps' => array(
212                    'shortopt' => 'n',
213                    'doc' => 'ignore dependencies, upgrade anyway',
214                    ),
215                'register-only' => array(
216                    'shortopt' => 'r',
217                    'doc' => 'do not install files, only register the package as upgraded',
218                    ),
219                'nobuild' => array(
220                    'shortopt' => 'B',
221                    'doc' => 'don\'t build C extensions',
222                    ),
223                'nocompress' => array(
224                    'shortopt' => 'Z',
225                    'doc' => 'request uncompressed files when downloading',
226                    ),
227                'installroot' => array(
228                    'shortopt' => 'R',
229                    'arg' => 'DIR',
230                    'doc' => 'root directory used when installing files (ala PHP\'s INSTALL_ROOT), use packagingroot for RPM',
231                    ),
232                'ignore-errors' => array(
233                    'doc' => 'force install even if there were errors',
234                    ),
235                'loose' => array(
236                    'doc' => 'do not check for recommended dependency version',
237                    ),
238                ),
239            'doc' => '
240WARNING: This function is deprecated in favor of using the upgrade command with no params
241
242Upgrades all packages that have a newer release available.  Upgrades are
243done only if there is a release available of the state specified in
244"preferred_state" (currently {config preferred_state}), or a state considered
245more stable.
246'),
247        'uninstall' => array(
248            'summary' => 'Un-install Package',
249            'function' => 'doUninstall',
250            'shortcut' => 'un',
251            'options' => array(
252                'nodeps' => array(
253                    'shortopt' => 'n',
254                    'doc' => 'ignore dependencies, uninstall anyway',
255                    ),
256                'register-only' => array(
257                    'shortopt' => 'r',
258                    'doc' => 'do not remove files, only register the packages as not installed',
259                    ),
260                'installroot' => array(
261                    'shortopt' => 'R',
262                    'arg' => 'DIR',
263                    'doc' => 'root directory used when installing files (ala PHP\'s INSTALL_ROOT)',
264                    ),
265                'ignore-errors' => array(
266                    'doc' => 'force install even if there were errors',
267                    ),
268                'offline' => array(
269                    'shortopt' => 'O',
270                    'doc' => 'do not attempt to uninstall remotely',
271                    ),
272                ),
273            'doc' => '[channel/]<package> ...
274Uninstalls one or more PEAR packages.  More than one package may be
275specified at once.  Prefix with channel name to uninstall from a
276channel not in your default channel ({config default_channel})
277'),
278        'bundle' => array(
279            'summary' => 'Unpacks a Pecl Package',
280            'function' => 'doBundle',
281            'shortcut' => 'bun',
282            'options' => array(
283                'destination' => array(
284                   'shortopt' => 'd',
285                    'arg' => 'DIR',
286                    'doc' => 'Optional destination directory for unpacking (defaults to current path or "ext" if exists)',
287                    ),
288                'force' => array(
289                    'shortopt' => 'f',
290                    'doc' => 'Force the unpacking even if there were errors in the package',
291                ),
292            ),
293            'doc' => '<package>
294Unpacks a Pecl Package into the selected location. It will download the
295package if needed.
296'),
297        'run-scripts' => array(
298            'summary' => 'Run Post-Install Scripts bundled with a package',
299            'function' => 'doRunScripts',
300            'shortcut' => 'rs',
301            'options' => array(
302            ),
303            'doc' => '<package>
304Run post-installation scripts in package <package>, if any exist.
305'),
306    );
307
308    // }}}
309    // {{{ constructor
310
311    /**
312     * PEAR_Command_Install constructor.
313     *
314     * @access public
315     */
316    function PEAR_Command_Install(&$ui, &$config)
317    {
318        parent::PEAR_Command_Common($ui, $config);
319    }
320
321    // }}}
322
323    /**
324     * For unit testing purposes
325     */
326    function &getDownloader(&$ui, $options, &$config)
327    {
328        if (!class_exists('PEAR_Downloader')) {
329            require_once 'PEAR/Downloader.php';
330        }
331        $a = &new PEAR_Downloader($ui, $options, $config);
332        return $a;
333    }
334
335    /**
336     * For unit testing purposes
337     */
338    function &getInstaller(&$ui)
339    {
340        if (!class_exists('PEAR_Installer')) {
341            require_once 'PEAR/Installer.php';
342        }
343        $a = &new PEAR_Installer($ui);
344        return $a;
345    }
346
347    function enableExtension($binaries, $type)
348    {
349        if (!($phpini = $this->config->get('php_ini', null, 'pear.php.net'))) {
350            return PEAR::raiseError('configuration option "php_ini" is not set to php.ini location');
351        }
352        $ini = $this->_parseIni($phpini);
353        if (PEAR::isError($ini)) {
354            return $ini;
355        }
356        $line = 0;
357        if ($type == 'extsrc' || $type == 'extbin') {
358            $search = 'extensions';
359            $enable = 'extension';
360        } else {
361            $search = 'zend_extensions';
362            ob_start();
363            phpinfo(INFO_GENERAL);
364            $info = ob_get_contents();
365            ob_end_clean();
366            $debug = function_exists('leak') ? '_debug' : '';
367            $ts = preg_match('/Thread Safety.+enabled/', $info) ? '_ts' : '';
368            $enable = 'zend_extension' . $debug . $ts;
369        }
370        foreach ($ini[$search] as $line => $extension) {
371            if (in_array($extension, $binaries, true) || in_array(
372                  $ini['extension_dir'] . DIRECTORY_SEPARATOR . $extension, $binaries, true)) {
373                // already enabled - assume if one is, all are
374                return true;
375            }
376        }
377        if ($line) {
378            $newini = array_slice($ini['all'], 0, $line);
379        } else {
380            $newini = array();
381        }
382        foreach ($binaries as $binary) {
383            if ($ini['extension_dir']) {
384                $binary = basename($binary);
385            }
386            $newini[] = $enable . '="' . $binary . '"' . (OS_UNIX ? "\n" : "\r\n");
387        }
388        $newini = array_merge($newini, array_slice($ini['all'], $line));
389        $fp = @fopen($phpini, 'wb');
390        if (!$fp) {
391            return PEAR::raiseError('cannot open php.ini "' . $phpini . '" for writing');
392        }
393        foreach ($newini as $line) {
394            fwrite($fp, $line);
395        }
396        fclose($fp);
397        return true;
398    }
399
400    function disableExtension($binaries, $type)
401    {
402        if (!($phpini = $this->config->get('php_ini', null, 'pear.php.net'))) {
403            return PEAR::raiseError('configuration option "php_ini" is not set to php.ini location');
404        }
405        $ini = $this->_parseIni($phpini);
406        if (PEAR::isError($ini)) {
407            return $ini;
408        }
409        $line = 0;
410        if ($type == 'extsrc' || $type == 'extbin') {
411            $search = 'extensions';
412            $enable = 'extension';
413        } else {
414            $search = 'zend_extensions';
415            ob_start();
416            phpinfo(INFO_GENERAL);
417            $info = ob_get_contents();
418            ob_end_clean();
419            $debug = function_exists('leak') ? '_debug' : '';
420            $ts = preg_match('/Thread Safety.+enabled/', $info) ? '_ts' : '';
421            $enable = 'zend_extension' . $debug . $ts;
422        }
423        $found = false;
424        foreach ($ini[$search] as $line => $extension) {
425            if (in_array($extension, $binaries, true) || in_array(
426                  $ini['extension_dir'] . DIRECTORY_SEPARATOR . $extension, $binaries, true)) {
427                $found = true;
428                break;
429            }
430        }
431        if (!$found) {
432            // not enabled
433            return true;
434        }
435        $fp = @fopen($phpini, 'wb');
436        if (!$fp) {
437            return PEAR::raiseError('cannot open php.ini "' . $phpini . '" for writing');
438        }
439        if ($line) {
440            $newini = array_slice($ini['all'], 0, $line);
441            // delete the enable line
442            $newini = array_merge($newini, array_slice($ini['all'], $line + 1));
443        } else {
444            $newini = array_slice($ini['all'], 1);
445        }
446        foreach ($newini as $line) {
447            fwrite($fp, $line);
448        }
449        fclose($fp);
450        return true;
451    }
452
453    function _parseIni($filename)
454    {
455        if (!file_exists($filename)) {
456            return PEAR::raiseError('php.ini "' . $filename . '" does not exist');
457        }
458
459        if (filesize($filename) > 300000) {
460            return PEAR::raiseError('php.ini "' . $filename . '" is too large, aborting');
461        }
462
463        ob_start();
464        phpinfo(INFO_GENERAL);
465        $info = ob_get_contents();
466        ob_end_clean();
467        $debug = function_exists('leak') ? '_debug' : '';
468        $ts = preg_match('/Thread Safety.+enabled/', $info) ? '_ts' : '';
469        $zend_extension_line = 'zend_extension' . $debug . $ts;
470        $all = @file($filename);
471        if (!$all) {
472            return PEAR::raiseError('php.ini "' . $filename .'" could not be read');
473        }
474        $zend_extensions = $extensions = array();
475        // assume this is right, but pull from the php.ini if it is found
476        $extension_dir = ini_get('extension_dir');
477        foreach ($all as $linenum => $line) {
478            $line = trim($line);
479            if (!$line) {
480                continue;
481            }
482            if ($line[0] == ';') {
483                continue;
484            }
485            if (strtolower(substr($line, 0, 13)) == 'extension_dir') {
486                $line = trim(substr($line, 13));
487                if ($line[0] == '=') {
488                    $x = trim(substr($line, 1));
489                    $x = explode(';', $x);
490                    $extension_dir = str_replace('"', '', array_shift($x));
491                    continue;
492                }
493            }
494            if (strtolower(substr($line, 0, 9)) == 'extension') {
495                $line = trim(substr($line, 9));
496                if ($line[0] == '=') {
497                    $x = trim(substr($line, 1));
498                    $x = explode(';', $x);
499                    $extensions[$linenum] = str_replace('"', '', array_shift($x));
500                    continue;
501                }
502            }
503            if (strtolower(substr($line, 0, strlen($zend_extension_line))) ==
504                  $zend_extension_line) {
505                $line = trim(substr($line, strlen($zend_extension_line)));
506                if ($line[0] == '=') {
507                    $x = trim(substr($line, 1));
508                    $x = explode(';', $x);
509                    $zend_extensions[$linenum] = str_replace('"', '', array_shift($x));
510                    continue;
511                }
512            }
513        }
514        return array(
515            'extensions' => $extensions,
516            'zend_extensions' => $zend_extensions,
517            'extension_dir' => $extension_dir,
518            'all' => $all,
519        );
520    }
521
522    // {{{ doInstall()
523
524    function doInstall($command, $options, $params)
525    {
526        if (!class_exists('PEAR_PackageFile')) {
527            require_once 'PEAR/PackageFile.php';
528        }
529
530        if (isset($options['installroot']) && isset($options['packagingroot'])) {
531            return $this->raiseError('ERROR: cannot use both --installroot and --packagingroot');
532        }
533
534        $reg = &$this->config->getRegistry();
535        $channel = isset($options['channel']) ? $options['channel'] : $this->config->get('default_channel');
536        if (!$reg->channelExists($channel)) {
537            return $this->raiseError('Channel "' . $channel . '" does not exist');
538        }
539
540        if (empty($this->installer)) {
541            $this->installer = &$this->getInstaller($this->ui);
542        }
543
544        if ($command == 'upgrade' || $command == 'upgrade-all') {
545            // If people run the upgrade command but pass nothing, emulate a upgrade-all
546            if ($command == 'upgrade' && empty($params)) {
547                return $this->doUpgradeAll($command, $options, $params);
548            }
549            $options['upgrade'] = true;
550        } else {
551            $packages = $params;
552        }
553
554        $instreg = &$reg; // instreg used to check if package is installed
555        if (isset($options['packagingroot']) && !isset($options['upgrade'])) {
556            $packrootphp_dir = $this->installer->_prependPath(
557                $this->config->get('php_dir', null, 'pear.php.net'),
558                $options['packagingroot']);
559            $instreg = new PEAR_Registry($packrootphp_dir); // other instreg!
560
561            if ($this->config->get('verbose') > 2) {
562                $this->ui->outputData('using package root: ' . $options['packagingroot']);
563            }
564        }
565
566        $abstractpackages = $otherpackages = array();
567        // parse params
568        PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
569
570        foreach ($params as $param) {
571            if (strpos($param, 'http://') === 0) {
572                $otherpackages[] = $param;
573                continue;
574            }
575
576            if (strpos($param, 'channel://') === false && @file_exists($param)) {
577                if (isset($options['force'])) {
578                    $otherpackages[] = $param;
579                    continue;
580                }
581
582                $pkg = new PEAR_PackageFile($this->config);
583                $pf  = $pkg->fromAnyFile($param, PEAR_VALIDATE_DOWNLOADING);
584                if (PEAR::isError($pf)) {
585                    $otherpackages[] = $param;
586                    continue;
587                }
588
589                $exists   = $reg->packageExists($pf->getPackage(), $pf->getChannel());
590                $pversion = $reg->packageInfo($pf->getPackage(), 'version', $pf->getChannel());
591                $version_compare = version_compare($pf->getVersion(), $pversion, '<=');
592                if ($exists && $version_compare) {
593                    if ($this->config->get('verbose')) {
594                        $this->ui->outputData('Ignoring installed package ' .
595                            $reg->parsedPackageNameToString(
596                            array('package' => $pf->getPackage(),
597                                  'channel' => $pf->getChannel()), true));
598                    }
599                    continue;
600                }
601                $otherpackages[] = $param;
602                continue;
603            }
604
605            $e = $reg->parsePackageName($param, $channel);
606            if (PEAR::isError($e)) {
607                $otherpackages[] = $param;
608            } else {
609                $abstractpackages[] = $e;
610            }
611        }
612        PEAR::staticPopErrorHandling();
613
614        // if there are any local package .tgz or remote static url, we can't
615        // filter.  The filter only works for abstract packages
616        if (count($abstractpackages) && !isset($options['force'])) {
617            // when not being forced, only do necessary upgrades/installs
618            if (isset($options['upgrade'])) {
619                $abstractpackages = $this->_filterUptodatePackages($abstractpackages, $command);
620            } else {
621                $count = count($abstractpackages);
622                foreach ($abstractpackages as $i => $package) {
623                    if (isset($package['group'])) {
624                        // do not filter out install groups
625                        continue;
626                    }
627
628                    if ($instreg->packageExists($package['package'], $package['channel'])) {
629                        if ($count > 1) {
630                            if ($this->config->get('verbose')) {
631                                $this->ui->outputData('Ignoring installed package ' .
632                                    $reg->parsedPackageNameToString($package, true));
633                            }
634                            unset($abstractpackages[$i]);
635                        } elseif ($count === 1) {
636                            // Lets try to upgrade it since it's already installed
637                            $options['upgrade'] = true;
638                        }
639                    }
640                }
641            }
642            $abstractpackages =
643                array_map(array($reg, 'parsedPackageNameToString'), $abstractpackages);
644        } elseif (count($abstractpackages)) {
645            $abstractpackages =
646                array_map(array($reg, 'parsedPackageNameToString'), $abstractpackages);
647        }
648
649        $packages = array_merge($abstractpackages, $otherpackages);
650        if (!count($packages)) {
651            $c = '';
652            if (isset($options['channel'])){
653                $c .= ' in channel "' . $options['channel'] . '"';
654            }
655            $this->ui->outputData('Nothing to ' . $command . $c);
656            return true;
657        }
658
659        $this->downloader = &$this->getDownloader($this->ui, $options, $this->config);
660        $errors = $downloaded = $binaries = array();
661        $downloaded = &$this->downloader->download($packages);
662        if (PEAR::isError($downloaded)) {
663            return $this->raiseError($downloaded);
664        }
665
666        $errors = $this->downloader->getErrorMsgs();
667        if (count($errors)) {
668            $err = array();
669            $err['data'] = array();
670            foreach ($errors as $error) {
671                if ($error !== null) {
672                    $err['data'][] = array($error);
673                }
674            }
675
676            if (!empty($err['data'])) {
677                $err['headline'] = 'Install Errors';
678                $this->ui->outputData($err);
679            }
680
681            if (!count($downloaded)) {
682                return $this->raiseError("$command failed");
683            }
684        }
685
686        $data = array(
687            'headline' => 'Packages that would be Installed'
688        );
689
690        if (isset($options['pretend'])) {
691            foreach ($downloaded as $package) {
692                $data['data'][] = array($reg->parsedPackageNameToString($package->getParsedPackage()));
693            }
694            $this->ui->outputData($data, 'pretend');
695            return true;
696        }
697
698        $this->installer->setOptions($options);
699        $this->installer->sortPackagesForInstall($downloaded);
700        if (PEAR::isError($err = $this->installer->setDownloadedPackages($downloaded))) {
701            $this->raiseError($err->getMessage());
702            return true;
703        }
704
705        $binaries = $extrainfo = array();
706        foreach ($downloaded as $param) {
707            PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
708            $info = $this->installer->install($param, $options);
709            PEAR::staticPopErrorHandling();
710            if (PEAR::isError($info)) {
711                $oldinfo = $info;
712                $pkg = &$param->getPackageFile();
713                if ($info->getCode() != PEAR_INSTALLER_NOBINARY) {
714                    if (!($info = $pkg->installBinary($this->installer))) {
715                        $this->ui->outputData('ERROR: ' .$oldinfo->getMessage());
716                        continue;
717                    }
718
719                    // we just installed a different package than requested,
720                    // let's change the param and info so that the rest of this works
721                    $param = $info[0];
722                    $info  = $info[1];
723                }
724            }
725
726            if (!is_array($info)) {
727                return $this->raiseError("$command failed");
728            }
729
730            if ($param->getPackageType() == 'extsrc' ||
731                  $param->getPackageType() == 'extbin' ||
732                  $param->getPackageType() == 'zendextsrc' ||
733                  $param->getPackageType() == 'zendextbin'
734            ) {
735                $pkg = &$param->getPackageFile();
736                if ($instbin = $pkg->getInstalledBinary()) {
737                    $instpkg = &$instreg->getPackage($instbin, $pkg->getChannel());
738                } else {
739                    $instpkg = &$instreg->getPackage($pkg->getPackage(), $pkg->getChannel());
740                }
741
742                foreach ($instpkg->getFilelist() as $name => $atts) {
743                    $pinfo = pathinfo($atts['installed_as']);
744                    if (!isset($pinfo['extension']) ||
745                          in_array($pinfo['extension'], array('c', 'h'))
746                    ) {
747                        continue; // make sure we don't match php_blah.h
748                    }
749
750                    if ((strpos($pinfo['basename'], 'php_') === 0 &&
751                          $pinfo['extension'] == 'dll') ||
752                          // most unices
753                          $pinfo['extension'] == 'so' ||
754                          // hp-ux
755                          $pinfo['extension'] == 'sl') {
756                        $binaries[] = array($atts['installed_as'], $pinfo);
757                        break;
758                    }
759                }
760
761                if (count($binaries)) {
762                    foreach ($binaries as $pinfo) {
763                        PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
764                        $ret = $this->enableExtension(array($pinfo[0]), $param->getPackageType());
765                        PEAR::staticPopErrorHandling();
766                        if (PEAR::isError($ret)) {
767                            $extrainfo[] = $ret->getMessage();
768                            if ($param->getPackageType() == 'extsrc' ||
769                                  $param->getPackageType() == 'extbin') {
770                                $exttype = 'extension';
771                            } else {
772                                ob_start();
773                                phpinfo(INFO_GENERAL);
774                                $info = ob_get_contents();
775                                ob_end_clean();
776                                $debug = function_exists('leak') ? '_debug' : '';
777                                $ts = preg_match('/Thread Safety.+enabled/', $info) ? '_ts' : '';
778                                $exttype = 'zend_extension' . $debug . $ts;
779                            }
780                            $extrainfo[] = 'You should add "' . $exttype . '=' .
781                                $pinfo[1]['basename'] . '" to php.ini';
782                        } else {
783                            $extrainfo[] = 'Extension ' . $instpkg->getProvidesExtension() .
784                                ' enabled in php.ini';
785                        }
786                    }
787                }
788            }
789
790            if ($this->config->get('verbose') > 0) {
791                $chan = $param->getChannel();
792                $label = $reg->parsedPackageNameToString(
793                    array(
794                        'channel' => $chan,
795                        'package' => $param->getPackage(),
796                        'version' => $param->getVersion(),
797                    ));
798                $out = array('data' => "$command ok: $label");
799                if (isset($info['release_warnings'])) {
800                    $out['release_warnings'] = $info['release_warnings'];
801                }
802                $this->ui->outputData($out, $command);
803
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");
812                        } else {
813                            $this->ui->outputData("remote install ok: $label");
814                        }
815                    }
816                }
817            }
818
819            $deps = $param->getDeps();
820            if ($deps) {
821                if (isset($deps['group'])) {
822                    $groups = $deps['group'];
823                    if (!isset($groups[0])) {
824                        $groups = array($groups);
825                    }
826
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
831                            continue;
832                        }
833                        $extrainfo[] = $param->getPackage() . ': Optional feature ' .
834                            $group['attribs']['name'] . ' available (' .
835                            $group['attribs']['hint'] . ')';
836                    }
837
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) .
843                              '#featurename"';
844                }
845            }
846
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;
857                    }
858                    $extrainfo[] = $param->getPackage() .
859                        ': Use "pear run-scripts ' . $pn . '" to finish setup.';
860                    $extrainfo[] = 'DO NOT RUN SCRIPTS FROM UNTRUSTED SOURCES';
861                }
862            }
863        }
864
865        if (count($extrainfo)) {
866            foreach ($extrainfo as $info) {
867                $this->ui->outputData($info);
868            }
869        }
870
871        return true;
872    }
873
874    // }}}
875    // {{{ doUpgradeAll()
876
877    function doUpgradeAll($command, $options, $params)
878    {
879        $reg = &$this->config->getRegistry();
880        $upgrade = array();
881
882        if (isset($options['channel'])) {
883            $channels = array($options['channel']);
884        } else {
885            $channels = $reg->listChannels();
886        }
887
888        foreach ($channels as $channel) {
889            if ($channel == '__uri') {
890                continue;
891            }
892
893            // parse name with channel
894            foreach ($reg->listPackages($channel) as $name) {
895                $upgrade[] = $reg->parsedPackageNameToString(array(
896                        'channel' => $channel,
897                        'package' => $name
898                    ));
899            }
900        }
901
902        $err = $this->doInstall($command, $options, $upgrade);
903        if (PEAR::isError($err)) {
904            $this->ui->outputData($err->getMessage(), $command);
905        }
906   }
907
908    // }}}
909    // {{{ doUninstall()
910
911    function doUninstall($command, $options, $params)
912    {
913        if (count($params) < 1) {
914            return $this->raiseError("Please supply the package(s) you want to uninstall");
915        }
916
917        if (empty($this->installer)) {
918            $this->installer = &$this->getInstaller($this->ui);
919        }
920
921        if (isset($options['remoteconfig'])) {
922            $e = $this->config->readFTPConfigFile($options['remoteconfig']);
923            if (!PEAR::isError($e)) {
924                $this->installer->setConfig($this->config);
925            }
926        }
927
928        $reg = &$this->config->getRegistry();
929        $newparams = array();
930        $binaries = 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)) {
938                $badparams[] = $pkg;
939                continue;
940            }
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) {
951                    $channel = $testc;
952                }
953            }
954            if ($info === null) {
955                $badparams[] = $pkg;
956            } else {
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);
964                }
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']);
968                    if ($group) {
969                        $installed = $reg->getInstalledGroup($group);
970                        if ($installed) {
971                            foreach ($installed as $i => $p) {
972                                $newparams[] = &$installed[$i];
973                            }
974                        }
975                    }
976                }
977            }
978        }
979        $err = $this->installer->sortPackagesForUninstall($newparams);
980        if (PEAR::isError($err)) {
981            $this->ui->outputData($err->getMessage(), $command);
982            return true;
983        }
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);
989        $binaries = array();
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);
996                    continue;
997                }
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
1004                    }
1005
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
1011                        }
1012                        if ((strpos($pinfo['basename'], 'php_') === 0 &&
1013                              $pinfo['extension'] == 'dll') ||
1014                              // most unices
1015                              $pinfo['extension'] == 'so' ||
1016                              // hp-ux
1017                              $pinfo['extension'] == 'sl') {
1018                            $binaries[] = array($atts['installed_as'], $pinfo);
1019                            break;
1020                        }
1021                    }
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';
1032                                } else {
1033                                    ob_start();
1034                                    phpinfo(INFO_GENERAL);
1035                                    $info = ob_get_contents();
1036                                    ob_end_clean();
1037                                    $debug = function_exists('leak') ? '_debug' : '';
1038                                    $ts = preg_match('/Thread Safety.+enabled/', $info) ? '_ts' : '';
1039                                    $exttype = 'zend_extension' . $debug . $ts;
1040                                }
1041                                $this->ui->outputData('Unable to remove "' . $exttype . '=' .
1042                                    $pinfo[1]['basename'] . '" from php.ini', $command);
1043                            } else {
1044                                $this->ui->outputData('Extension ' . $pkg->getProvidesExtension() .
1045                                    ' disabled in php.ini', $command);
1046                            }
1047                        }
1048                    }
1049                }
1050                $savepkg = $pkg;
1051                if ($this->config->get('verbose') > 0) {
1052                    if (is_object($pkg)) {
1053                        $pkg = $reg->parsedPackageNameToString($pkg);
1054                    }
1055                    $this->ui->outputData("uninstall ok: $pkg", $command);
1056                }
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");
1066                        } else {
1067                            $this->ui->outputData("remote uninstall ok: $pkg");
1068                        }
1069                    }
1070                }
1071            } else {
1072                $this->installer->popErrorHandling();
1073                if (!is_object($pkg)) {
1074                    return $this->raiseError("uninstall failed: $pkg");
1075                }
1076                $pkg = $reg->parsedPackageNameToString($pkg);
1077            }
1078        }
1079
1080        return true;
1081    }
1082
1083    // }}}
1084
1085
1086    // }}}
1087    // {{{ doBundle()
1088    /*
1089    (cox) It just downloads and untars the package, does not do
1090            any check that the PEAR_Installer::_installFile() does.
1091    */
1092
1093    function doBundle($command, $options, $params)
1094    {
1095        $opts = array(
1096            'force'        => true,
1097            'nodeps'       => true,
1098            'soft'         => true,
1099            'downloadonly' => true
1100        );
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");
1105        }
1106
1107        if (isset($options['destination'])) {
1108            if (!is_dir($options['destination'])) {
1109                System::mkdir('-p ' . $options['destination']);
1110            }
1111            $dest = realpath($options['destination']);
1112        } else {
1113            $pwd  = getcwd();
1114            $dir  = $pwd . DIRECTORY_SEPARATOR . 'ext';
1115            $dest = is_dir($dir) ? $dir : $pwd;
1116        }
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.');
1123        }
1124        $result = &$downloader->download(array($params[0]));
1125        if (PEAR::isError($result)) {
1126            return $result;
1127        }
1128        if (!isset($result[0])) {
1129            return $this->raiseError('unable to unpack ' . $params[0]);
1130        }
1131        $pkgfile = &$result[0]->getPackageFile();
1132        $pkgname = $pkgfile->getName();
1133        $pkgversion = $pkgfile->getVersion();
1134
1135        // Unpacking -------------------------------------------------
1136        $dest .= DIRECTORY_SEPARATOR . $pkgname;
1137        $orig = $pkgname . '-' . $pkgversion;
1138
1139        $tar = &new Archive_Tar($pkgfile->getArchiveFile());
1140        if (!$tar->extractModify($dest, $orig)) {
1141            return $this->raiseError('unable to unpack ' . $pkgfile->getArchiveFile());
1142        }
1143        $this->ui->outputData("Package ready at '$dest'");
1144    // }}}
1145    }
1146
1147    // }}}
1148
1149    function doRunScripts($command, $options, $params)
1150    {
1151        if (!isset($params[0])) {
1152            return $this->raiseError('run-scripts expects 1 parameter: a package name');
1153        }
1154
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);
1161        }
1162
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');
1166        }
1167
1168        $package->setConfig($this->config);
1169        $package->runPostinstallScripts();
1170        $this->ui->outputData('Install scripts complete', $command);
1171        return true;
1172    }
1173
1174    /**
1175     * Given a list of packages, filter out those ones that are already up to date
1176     *
1177     * @param $packages: packages, in parsed array format !
1178     * @return list of packages that can be upgraded
1179     */
1180    function _filterUptodatePackages($packages, $command)
1181    {
1182        $reg = &$this->config->getRegistry();
1183        $latestReleases = array();
1184
1185        $ret = array();
1186        foreach ($packages as $package) {
1187            if (isset($package['group'])) {
1188                $ret[] = $package;
1189                continue;
1190            }
1191
1192            $channel = $package['channel'];
1193            $name    = $package['package'];
1194            if (!$reg->packageExists($name, $channel)) {
1195                $ret[] = $package;
1196                continue;
1197            }
1198
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);
1204                }
1205
1206                $base2 = false;
1207                $preferred_mirror = $this->config->get('preferred_mirror', null, $channel);
1208                if ($chan->supportsREST($preferred_mirror) &&
1209                    (
1210                       //($base2 = $chan->getBaseURL('REST1.4', $preferred_mirror)) ||
1211                       ($base  = $chan->getBaseURL('REST1.0', $preferred_mirror))
1212                    )
1213                ) {
1214                    $dorest = true;
1215                }
1216
1217                PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
1218                if (!isset($package['state'])) {
1219                    $state = $this->config->get('preferred_state', null, $channel);
1220                } else {
1221                    $state = $package['state'];
1222                }
1223
1224                if ($dorest) {
1225                    if ($base2) {
1226                        $rest = &$this->config->getREST('1.4', array());
1227                        $base = $base2;
1228                    } else {
1229                        $rest = &$this->config->getREST('1.0', array());
1230                    }
1231
1232                    $installed = array_flip($reg->listPackages($channel));
1233                    $latest    = $rest->listLatestUpgrades($base, $state, $installed, $channel, $reg);
1234                }
1235
1236                PEAR::staticPopErrorHandling();
1237                if (PEAR::isError($latest)) {
1238                    $this->ui->outputData('Error getting channel info from ' . $channel .
1239                        ': ' . $latest->getMessage());
1240                    continue;
1241                }
1242
1243                $latestReleases[$channel] = array_change_key_case($latest);
1244            }
1245
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
1254                    continue;
1255                }
1256
1257                // maintain BC
1258                if ($command == 'upgrade-all') {
1259                    $this->ui->outputData(array('data' => 'Will upgrade ' .
1260                        $reg->parsedPackageNameToString($package)), $command);
1261                }
1262                $ret[] = $package;
1263            }
1264        }
1265
1266        return $ret;
1267    }
1268}
Note: See TracBrowser for help on using the repository browser.