Subversion Repositories Applications.gtt

Rev

Rev 94 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
94 jpm 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
 * LICENSE: This source file is subject to version 3.0 of the PHP license
8
 * that is available through the world-wide-web at the following URI:
9
 * http://www.php.net/license/3_0.txt.  If you did not receive a copy of
10
 * the PHP License and are unable to obtain it through the web, please
11
 * send a note to license@php.net so we can mail you a copy immediately.
12
 *
13
 * @category   pear
14
 * @package    PEAR
15
 * @author     Stig Bakken <ssb@php.net>
16
 * @author     Greg Beaver <cellog@php.net>
17
 * @copyright  1997-2006 The PHP Group
18
 * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
19
 * @version    CVS: $Id: Install.php,v 1.122 2007/02/13 04:30:05 cellog Exp $
20
 * @link       http://pear.php.net/package/PEAR
21
 * @since      File available since Release 0.1
22
 */
23
 
24
/**
25
 * base class
26
 */
27
require_once 'PEAR/Command/Common.php';
28
 
29
/**
30
 * PEAR commands for installation or deinstallation/upgrading of
31
 * packages.
32
 *
33
 * @category   pear
34
 * @package    PEAR
35
 * @author     Stig Bakken <ssb@php.net>
36
 * @author     Greg Beaver <cellog@php.net>
37
 * @copyright  1997-2006 The PHP Group
38
 * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
39
 * @version    Release: 1.5.1
40
 * @link       http://pear.php.net/package/PEAR
41
 * @since      Class available since Release 0.1
42
 */
43
class PEAR_Command_Install extends PEAR_Command_Common
44
{
45
    // {{{ properties
46
 
47
    var $commands = array(
48
        'install' => array(
49
            'summary' => 'Install Package',
50
            'function' => 'doInstall',
51
            'shortcut' => 'i',
52
            'options' => array(
53
                'force' => array(
54
                    'shortopt' => 'f',
55
                    'doc' => 'will overwrite newer installed packages',
56
                    ),
57
                'loose' => array(
58
                    'shortopt' => 'l',
59
                    'doc' => 'do not check for recommended dependency version',
60
                    ),
61
                'nodeps' => array(
62
                    'shortopt' => 'n',
63
                    'doc' => 'ignore dependencies, install anyway',
64
                    ),
65
                'register-only' => array(
66
                    'shortopt' => 'r',
67
                    'doc' => 'do not install files, only register the package as installed',
68
                    ),
69
                'soft' => array(
70
                    'shortopt' => 's',
71
                    'doc' => 'soft install, fail silently, or upgrade if already installed',
72
                    ),
73
                'nobuild' => array(
74
                    'shortopt' => 'B',
75
                    'doc' => 'don\'t build C extensions',
76
                    ),
77
                'nocompress' => array(
78
                    'shortopt' => 'Z',
79
                    'doc' => 'request uncompressed files when downloading',
80
                    ),
81
                'installroot' => array(
82
                    'shortopt' => 'R',
83
                    'arg' => 'DIR',
84
                    'doc' => 'root directory used when installing files (ala PHP\'s INSTALL_ROOT), use packagingroot for RPM',
85
                    ),
86
                'packagingroot' => array(
87
                    'shortopt' => 'P',
88
                    'arg' => 'DIR',
89
                    'doc' => 'root directory used when packaging files, like RPM packaging',
90
                    ),
91
                'ignore-errors' => array(
92
                    'doc' => 'force install even if there were errors',
93
                    ),
94
                'alldeps' => array(
95
                    'shortopt' => 'a',
96
                    'doc' => 'install all required and optional dependencies',
97
                    ),
98
                'onlyreqdeps' => array(
99
                    'shortopt' => 'o',
100
                    'doc' => 'install all required dependencies',
101
                    ),
102
                'offline' => array(
103
                    'shortopt' => 'O',
104
                    'doc' => 'do not attempt to download any urls or contact channels',
105
                    ),
106
                'pretend' => array(
107
                    'shortopt' => 'p',
108
                    'doc' => 'Only list the packages that would be downloaded',
109
                    ),
110
                ),
111
            'doc' => '[channel/]<package> ...
112
Installs one or more PEAR packages.  You can specify a package to
113
install in four ways:
114
 
115
"Package-1.0.tgz" : installs from a local file
116
 
117
"http://example.com/Package-1.0.tgz" : installs from
118
anywhere on the net.
119
 
120
"package.xml" : installs the package described in
121
package.xml.  Useful for testing, or for wrapping a PEAR package in
122
another package manager such as RPM.
123
 
124
"Package[-version/state][.tar]" : queries your default channel\'s server
125
({config master_server}) and downloads the newest package with
126
the preferred quality/state ({config preferred_state}).
127
 
128
To retrieve Package version 1.1, use "Package-1.1," to retrieve
129
Package state beta, use "Package-beta."  To retrieve an uncompressed
130
file, append .tar (make sure there is no file by the same name first)
131
 
132
To download a package from another channel, prefix with the channel name like
133
"channel/Package"
134
 
135
More than one package may be specified at once.  It is ok to mix these
136
four ways of specifying packages.
137
'),
138
        'upgrade' => array(
139
            'summary' => 'Upgrade Package',
140
            'function' => 'doInstall',
141
            'shortcut' => 'up',
142
            'options' => array(
143
                'force' => array(
144
                    'shortopt' => 'f',
145
                    'doc' => 'overwrite newer installed packages',
146
                    ),
147
                'loose' => array(
148
                    'shortopt' => 'l',
149
                    'doc' => 'do not check for recommended dependency version',
150
                    ),
151
                'nodeps' => array(
152
                    'shortopt' => 'n',
153
                    'doc' => 'ignore dependencies, upgrade anyway',
154
                    ),
155
                'register-only' => array(
156
                    'shortopt' => 'r',
157
                    'doc' => 'do not install files, only register the package as upgraded',
158
                    ),
159
                'nobuild' => array(
160
                    'shortopt' => 'B',
161
                    'doc' => 'don\'t build C extensions',
162
                    ),
163
                'nocompress' => array(
164
                    'shortopt' => 'Z',
165
                    'doc' => 'request uncompressed files when downloading',
166
                    ),
167
                'installroot' => array(
168
                    'shortopt' => 'R',
169
                    'arg' => 'DIR',
170
                    'doc' => 'root directory used when installing files (ala PHP\'s INSTALL_ROOT), use packagingroot for RPM',
171
                    ),
172
                'packagingroot' => array(
173
                    'shortopt' => 'P',
174
                    'arg' => 'DIR',
175
                    'doc' => 'root directory used when packaging files, like RPM packaging',
176
                    ),
177
                'ignore-errors' => array(
178
                    'doc' => 'force install even if there were errors',
179
                    ),
180
                'alldeps' => array(
181
                    'shortopt' => 'a',
182
                    'doc' => 'install all required and optional dependencies',
183
                    ),
184
                'onlyreqdeps' => array(
185
                    'shortopt' => 'o',
186
                    'doc' => 'install all required dependencies',
187
                    ),
188
                'offline' => array(
189
                    'shortopt' => 'O',
190
                    'doc' => 'do not attempt to download any urls or contact channels',
191
                    ),
192
                'pretend' => array(
193
                    'shortopt' => 'p',
194
                    'doc' => 'Only list the packages that would be downloaded',
195
                    ),
196
                ),
197
            'doc' => '<package> ...
198
Upgrades one or more PEAR packages.  See documentation for the
199
"install" command for ways to specify a package.
200
 
201
When upgrading, your package will be updated if the provided new
202
package has a higher version number (use the -f option if you need to
203
upgrade anyway).
204
 
205
More than one package may be specified at once.
206
'),
207
        'upgrade-all' => array(
208
            'summary' => 'Upgrade All Packages',
209
            'function' => 'doInstall',
210
            'shortcut' => 'ua',
211
            'options' => array(
212
                'nodeps' => array(
213
                    'shortopt' => 'n',
214
                    'doc' => 'ignore dependencies, upgrade anyway',
215
                    ),
216
                'register-only' => array(
217
                    'shortopt' => 'r',
218
                    'doc' => 'do not install files, only register the package as upgraded',
219
                    ),
220
                'nobuild' => array(
221
                    'shortopt' => 'B',
222
                    'doc' => 'don\'t build C extensions',
223
                    ),
224
                'nocompress' => array(
225
                    'shortopt' => 'Z',
226
                    'doc' => 'request uncompressed files when downloading',
227
                    ),
228
                'installroot' => array(
229
                    'shortopt' => 'R',
230
                    'arg' => 'DIR',
231
                    'doc' => 'root directory used when installing files (ala PHP\'s INSTALL_ROOT), use packagingroot for RPM',
232
                    ),
233
                'ignore-errors' => array(
234
                    'doc' => 'force install even if there were errors',
235
                    ),
236
                'loose' => array(
237
                    'doc' => 'do not check for recommended dependency version',
238
                    ),
239
                ),
240
            'doc' => '
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
244
more stable.
245
'),
246
        'uninstall' => array(
247
            'summary' => 'Un-install Package',
248
            'function' => 'doUninstall',
249
            'shortcut' => 'un',
250
            'options' => array(
251
                'nodeps' => array(
252
                    'shortopt' => 'n',
253
                    'doc' => 'ignore dependencies, uninstall anyway',
254
                    ),
255
                'register-only' => array(
256
                    'shortopt' => 'r',
257
                    'doc' => 'do not remove files, only register the packages as not installed',
258
                    ),
259
                'installroot' => array(
260
                    'shortopt' => 'R',
261
                    'arg' => 'DIR',
262
                    'doc' => 'root directory used when installing files (ala PHP\'s INSTALL_ROOT)',
263
                    ),
264
                'ignore-errors' => array(
265
                    'doc' => 'force install even if there were errors',
266
                    ),
267
                'offline' => array(
268
                    'shortopt' => 'O',
269
                    'doc' => 'do not attempt to uninstall remotely',
270
                    ),
271
                ),
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})
276
'),
277
        'bundle' => array(
278
            'summary' => 'Unpacks a Pecl Package',
279
            'function' => 'doBundle',
280
            'shortcut' => 'bun',
281
            'options' => array(
282
                'destination' => array(
283
                   'shortopt' => 'd',
284
                    'arg' => 'DIR',
285
                    'doc' => 'Optional destination directory for unpacking (defaults to current path or "ext" if exists)',
286
                    ),
287
                'force' => array(
288
                    'shortopt' => 'f',
289
                    'doc' => 'Force the unpacking even if there were errors in the package',
290
                ),
291
            ),
292
            'doc' => '<package>
293
Unpacks a Pecl Package into the selected location. It will download the
294
package if needed.
295
'),
296
        'run-scripts' => array(
297
            'summary' => 'Run Post-Install Scripts bundled with a package',
298
            'function' => 'doRunScripts',
299
            'shortcut' => 'rs',
300
            'options' => array(
301
            ),
302
            'doc' => '<package>
303
Run post-installation scripts in package <package>, if any exist.
304
'),
305
    );
306
 
307
    // }}}
308
    // {{{ constructor
309
 
310
    /**
311
     * PEAR_Command_Install constructor.
312
     *
313
     * @access public
314
     */
315
    function PEAR_Command_Install(&$ui, &$config)
316
    {
317
        parent::PEAR_Command_Common($ui, $config);
318
    }
319
 
320
    // }}}
321
 
322
    /**
323
     * For unit testing purposes
324
     */
325
    function &getDownloader(&$ui, $options, &$config)
326
    {
327
        if (!class_exists('PEAR_Downloader')) {
328
            require_once 'PEAR/Downloader.php';
329
        }
330
        $a = &new PEAR_Downloader($ui, $options, $config);
331
        return $a;
332
    }
333
 
334
    /**
335
     * For unit testing purposes
336
     */
337
    function &getInstaller(&$ui)
338
    {
339
        if (!class_exists('PEAR_Installer')) {
340
            require_once 'PEAR/Installer.php';
341
        }
342
        $a = &new PEAR_Installer($ui);
343
        return $a;
344
    }
345
 
346
    function enableExtension($binaries, $type)
347
    {
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');
350
        }
351
        $ini = $this->_parseIni($phpini);
352
        if (PEAR::isError($ini)) {
353
            return $ini;
354
        }
355
        $fp = @fopen($phpini, 'wb');
356
        if (!$fp) {
357
            return PEAR::raiseError('cannot open php.ini "' . $phpini . '" for writing');
358
        }
359
        $line = 0;
360
        if ($type == 'extsrc' || $type == 'extbin') {
361
            $search = 'extensions';
362
            $enable = 'extension';
363
        } else {
364
            $search = 'zend_extensions';
365
            ob_start();
366
            phpinfo(INFO_GENERAL);
367
            $info = ob_get_contents();
368
            ob_end_clean();
369
            $debug = function_exists('leak') ? '_debug' : '';
370
            $ts = preg_match('Thread Safety.+enabled', $info) ? '_ts' : '';
371
            $enable = 'zend_extension' . $debug . $ts;
372
        }
373
        foreach ($ini[$search] as $line => $extension) {
374
            if (in_array($extension, $binaries, true) || in_array(
375
                  $ini['extension_dir'] . DIRECTORY_SEPARATOR . $extension, $binaries, true)) {
376
                // already enabled - assume if one is, all are
377
                return true;
378
            }
379
        }
380
        if ($line) {
381
            $newini = array_slice($ini['all'], 0, $line);
382
        } else {
383
            $newini = array();
384
        }
385
        foreach ($binaries as $binary) {
386
            if ($ini['extension_dir']) {
387
                $binary = basename($binary);
388
            }
389
            $newini[] = $enable . '="' . $binary . '"' . (OS_UNIX ? "\n" : "\r\n");
390
        }
391
        $newini = array_merge($newini, array_slice($ini['all'], $line));
392
        foreach ($newini as $line) {
393
            fwrite($fp, $line);
394
        }
395
        fclose($fp);
396
        return true;
397
    }
398
 
399
    function disableExtension($binaries, $type)
400
    {
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');
403
        }
404
        $ini = $this->_parseIni($phpini);
405
        if (PEAR::isError($ini)) {
406
            return $ini;
407
        }
408
        $line = 0;
409
        if ($type == 'extsrc' || $type == 'extbin') {
410
            $search = 'extensions';
411
            $enable = 'extension';
412
        } else {
413
            $search = 'zend_extensions';
414
            ob_start();
415
            phpinfo(INFO_GENERAL);
416
            $info = ob_get_contents();
417
            ob_end_clean();
418
            $debug = function_exists('leak') ? '_debug' : '';
419
            $ts = preg_match('Thread Safety.+enabled', $info) ? '_ts' : '';
420
            $enable = 'zend_extension' . $debug . $ts;
421
        }
422
        $found = false;
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)) {
426
                $found = true;
427
                break;
428
            }
429
        }
430
        if (!$found) {
431
            // not enabled
432
            return true;
433
        }
434
        $fp = @fopen($phpini, 'wb');
435
        if (!$fp) {
436
            return PEAR::raiseError('cannot open php.ini "' . $phpini . '" for writing');
437
        }
438
        if ($line) {
439
            $newini = array_slice($ini['all'], 0, $line);
440
            // delete the enable line
441
            $newini = array_merge($newini, array_slice($ini['all'], $line + 1));
442
        } else {
443
            $newini = array_slice($ini['all'], 1);
444
        }
445
        foreach ($newini as $line) {
446
            fwrite($fp, $line);
447
        }
448
        fclose($fp);
449
        return true;
450
    }
451
 
452
    function _parseIni($filename)
453
    {
454
        if (file_exists($filename)) {
455
            if (filesize($filename) > 300000) {
456
                return PEAR::raiseError('php.ini "' . $filename . '" is too large, aborting');
457
            }
458
            ob_start();
459
            phpinfo(INFO_GENERAL);
460
            $info = ob_get_contents();
461
            ob_end_clean();
462
            $debug = function_exists('leak') ? '_debug' : '';
463
            $ts = preg_match('/Thread Safety.+enabled/', $info) ? '_ts' : '';
464
            $zend_extension_line = 'zend_extension' . $debug . $ts;
465
            $all = @file($filename);
466
            if (!$all) {
467
                return PEAR::raiseError('php.ini "' . $filename .'" could not be read');
468
            }
469
            $zend_extensions = $extensions = array();
470
            // assume this is right, but pull from the php.ini if it is found
471
            $extension_dir = ini_get('extension_dir');
472
            foreach ($all as $linenum => $line) {
473
                $line = trim($line);
474
                if (!$line) {
475
                    continue;
476
                }
477
                if ($line[0] == ';') {
478
                    continue;
479
                }
480
                if (strtolower(substr($line, 0, 13)) == 'extension_dir') {
481
                    $line = trim(substr($line, 13));
482
                    if ($line[0] == '=') {
483
                        $x = trim(substr($line, 1));
484
                        $x = explode(';', $x);
485
                        $extension_dir = str_replace('"', '', array_shift($x));
486
                        continue;
487
                    }
488
                }
489
                if (strtolower(substr($line, 0, 9)) == 'extension') {
490
                    $line = trim(substr($line, 9));
491
                    if ($line[0] == '=') {
492
                        $x = trim(substr($line, 1));
493
                        $x = explode(';', $x);
494
                        $extensions[$linenum] = str_replace('"', '', array_shift($x));
495
                        continue;
496
                    }
497
                }
498
                if (strtolower(substr($line, 0, strlen($zend_extension_line))) ==
499
                      $zend_extension_line) {
500
                    $line = trim(substr($line, strlen($zend_extension_line)));
501
                    if ($line[0] == '=') {
502
                        $x = trim(substr($line, 1));
503
                        $x = explode(';', $x);
504
                        $zend_extensions[$linenum] = str_replace('"', '', array_shift($x));
505
                        continue;
506
                    }
507
                }
508
            }
509
            return array(
510
                'extensions' => $extensions,
511
                'zend_extensions' => $zend_extensions,
512
                'extension_dir' => $extension_dir,
513
                'all' => $all,
514
            );
515
        } else {
516
            return PEAR::raiseError('php.ini "' . $filename . '" does not exist');
517
        }
518
    }
519
 
520
    // {{{ doInstall()
521
 
522
    function doInstall($command, $options, $params)
523
    {
524
        if (empty($this->installer)) {
525
            $this->installer = &$this->getInstaller($this->ui);
526
        }
527
        if ($command == 'upgrade') {
528
            $options['upgrade'] = true;
529
        }
530
        if (isset($options['installroot']) && isset($options['packagingroot'])) {
531
            return $this->raiseError('ERROR: cannot use both --installroot and --packagingroot');
532
        }
533
        if (isset($options['packagingroot']) && $this->config->get('verbose') > 2) {
534
            $this->ui->outputData('using package root: ' . $options['packagingroot']);
535
        }
536
        $reg = &$this->config->getRegistry();
537
        if ($command == 'upgrade-all') {
538
            $options['upgrade'] = true;
539
            $reg = &$this->config->getRegistry();
540
            $savechannel = $this->config->get('default_channel');
541
            $params = array();
542
            foreach ($reg->listChannels() as $channel) {
543
                if ($channel == '__uri') {
544
                    continue;
545
                }
546
                $this->config->set('default_channel', $channel);
547
                $chan = &$reg->getChannel($channel);
548
                if (PEAR::isError($chan)) {
549
                    return $this->raiseError($chan);
550
                }
551
                if ($chan->supportsREST($this->config->get('preferred_mirror')) &&
552
                      $base = $chan->getBaseURL('REST1.0', $this->config->get('preferred_mirror'))) {
553
                    $dorest = true;
554
                    unset($remote);
555
                } else {
556
                    $dorest = false;
557
                    $remote = &$this->config->getRemote($this->config);
558
                }
559
                $state = $this->config->get('preferred_state');
560
                $installed = array_flip($reg->listPackages($channel));
561
                PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
562
                if ($dorest) {
563
                    $rest = &$this->config->getREST('1.0', array());
564
                    $latest = $rest->listLatestUpgrades($base, $state, $installed, $channel, $reg);
565
                } else {
566
                    if (empty($state) || $state == 'any') {
567
                        $latest = $remote->call("package.listLatestReleases");
568
                    } else {
569
                        $latest = $remote->call("package.listLatestReleases", $state);
570
                    }
571
                }
572
                PEAR::staticPopErrorHandling();
573
                if (PEAR::isError($latest) || !is_array($latest)) {
574
                    continue;
575
                }
576
                foreach ($latest as $package => $info) {
577
                    $package = strtolower($package);
578
                    if (!isset($installed[$package])) {
579
                        // skip packages we don't have installed
580
                        continue;
581
                    }
582
                    $inst_version = $reg->packageInfo($package, 'version', $channel);
583
                    if (version_compare("$info[version]", "$inst_version", "le")) {
584
                        // installed version is up-to-date
585
                        continue;
586
                    }
587
                    $params[] = $a = $reg->parsedPackageNameToString(array('package' => $package,
588
                        'channel' => $channel));
589
                    $this->ui->outputData(array('data' => "Will upgrade $a"), $command);
590
                }
591
            }
592
            $this->config->set('default_channel', $savechannel);
593
        }
594
        $this->downloader = &$this->getDownloader($this->ui, $options, $this->config);
595
        $errors = array();
596
        $downloaded = array();
597
        $downloaded = &$this->downloader->download($params);
598
        if (PEAR::isError($downloaded)) {
599
            return $this->raiseError($downloaded);
600
        }
601
        $errors = $this->downloader->getErrorMsgs();
602
        if (count($errors)) {
603
            $err['data'] = array();
604
            foreach ($errors as $error) {
605
                $err['data'][] = array($error);
606
            }
607
            $err['headline'] = 'Install Errors';
608
            $this->ui->outputData($err);
609
            if (!count($downloaded)) {
610
                return $this->raiseError("$command failed");
611
            }
612
        }
613
        $data = array(
614
            'headline' => 'Packages that would be Installed'
615
        );
616
        if (isset($options['pretend'])) {
617
            foreach ($downloaded as $package) {
618
                $data['data'][] = array($reg->parsedPackageNameToString($package->getParsedPackage()));
619
            }
620
            $this->ui->outputData($data, 'pretend');
621
            return true;
622
        }
623
        $this->installer->setOptions($options);
624
        $this->installer->sortPackagesForInstall($downloaded);
625
        if (PEAR::isError($err = $this->installer->setDownloadedPackages($downloaded))) {
626
            $this->raiseError($err->getMessage());
627
            return true;
628
        }
629
        $extrainfo = array();
630
        if (isset($options['packagingroot'])) {
631
            $packrootphp_dir = $this->installer->_prependPath(
632
                $this->config->get('php_dir', null, 'pear.php.net'),
633
                $options['packagingroot']);
634
            $instreg = new PEAR_Registry($packrootphp_dir);
635
        } else {
636
            $instreg = $reg;
637
        }
638
        foreach ($downloaded as $param) {
639
            PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
640
            $info = $this->installer->install($param, $options);
641
            PEAR::staticPopErrorHandling();
642
            if (PEAR::isError($info)) {
643
                $oldinfo = $info;
644
                $pkg = &$param->getPackageFile();
645
                if ($info->getCode() != PEAR_INSTALLER_NOBINARY) {
646
                    if (!($info = $pkg->installBinary($this->installer))) {
647
                        $this->ui->outputData('ERROR: ' .$oldinfo->getMessage());
648
                        continue;
649
                    }
650
                    // we just installed a different package than requested,
651
                    // let's change the param and info so that the rest of this works
652
                    $param = $info[0];
653
                    $info = $info[1];
654
                }
655
            }
656
            if (is_array($info)) {
657
                if ($param->getPackageType() == 'extsrc' ||
658
                      $param->getPackageType() == 'extbin' ||
659
                      $param->getPackageType() == 'zendextsrc' ||
660
                      $param->getPackageType() == 'zendextbin') {
661
                    $pkg = &$param->getPackageFile();
662
                    if ($instbin = $pkg->getInstalledBinary()) {
663
                        $instpkg = &$instreg->getPackage($instbin, $pkg->getChannel());
664
                    } else {
665
                        $instpkg = &$instreg->getPackage($pkg->getPackage(), $pkg->getChannel());
666
                    }
667
                    foreach ($instpkg->getFilelist() as $name => $atts) {
668
                        $pinfo = pathinfo($atts['installed_as']);
669
                        if (!isset($pinfo['extension']) ||
670
                              in_array($pinfo['extension'], array('c', 'h'))) {
671
                            continue; // make sure we don't match php_blah.h
672
                        }
673
                        if ((strpos($pinfo['basename'], 'php_') === 0 &&
674
                              $pinfo['extension'] == 'dll') ||
675
                              // most unices
676
                              $pinfo['extension'] == 'so' ||
677
                              // hp-ux
678
                              $pinfo['extension'] == 'sl') {
679
                            $binaries[] = array($atts['installed_as'], $pinfo);
680
                            break;
681
                        }
682
                    }
683
                    foreach ($binaries as $pinfo) {
684
                        PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
685
                        $ret = $this->enableExtension(array($pinfo[0]), $param->getPackageType());
686
                        PEAR::staticPopErrorHandling();
687
                        if (PEAR::isError($ret)) {
688
                            $extrainfo[] = $ret->getMessage();
689
                            if ($param->getPackageType() == 'extsrc' ||
690
                                  $param->getPackageType() == 'extbin') {
691
                                $exttype = 'extension';
692
                            } else {
693
                                ob_start();
694
                                phpinfo(INFO_GENERAL);
695
                                $info = ob_get_contents();
696
                                ob_end_clean();
697
                                $debug = function_exists('leak') ? '_debug' : '';
698
                                $ts = preg_match('Thread Safety.+enabled', $info) ? '_ts' : '';
699
                                $exttype = 'zend_extension' . $debug . $ts;
700
                            }
701
                            $extrainfo[] = 'You should add "' . $exttype . '=' .
702
                                $pinfo[1]['basename'] . '" to php.ini';
703
                        } else {
704
                            $extrainfo[] = 'Extension ' . $instpkg->getProvidesExtension() .
705
                                ' enabled in php.ini';
706
                        }
707
                    }
708
                }
709
                if ($this->config->get('verbose') > 0) {
710
                    $channel = $param->getChannel();
711
                    $label = $reg->parsedPackageNameToString(
712
                        array(
713
                            'channel' => $channel,
714
                            'package' => $param->getPackage(),
715
                            'version' => $param->getVersion(),
716
                        ));
717
                    $out = array('data' => "$command ok: $label");
718
                    if (isset($info['release_warnings'])) {
719
                        $out['release_warnings'] = $info['release_warnings'];
720
                    }
721
                    $this->ui->outputData($out, $command);
722
                    if (!isset($options['register-only']) && !isset($options['offline'])) {
723
                        if ($this->config->isDefinedLayer('ftp')) {
724
                            PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
725
                            $info = $this->installer->ftpInstall($param);
726
                            PEAR::staticPopErrorHandling();
727
                            if (PEAR::isError($info)) {
728
                                $this->ui->outputData($info->getMessage());
729
                                $this->ui->outputData("remote install failed: $label");
730
                            } else {
731
                                $this->ui->outputData("remote install ok: $label");
732
                            }
733
                        }
734
                    }
735
                }
736
                $deps = $param->getDeps();
737
                if ($deps) {
738
                    if (isset($deps['group'])) {
739
                        $groups = $deps['group'];
740
                        if (!isset($groups[0])) {
741
                            $groups = array($groups);
742
                        }
743
                        foreach ($groups as $group) {
744
                            if ($group['attribs']['name'] == 'default') {
745
                                // default group is always installed, unless the user
746
                                // explicitly chooses to install another group
747
                                continue;
748
                            }
749
                            $this->ui->outputData($param->getPackage() . ': Optional feature ' .
750
                                $group['attribs']['name'] . ' available (' .
751
                                $group['attribs']['hint'] . ')');
752
                        }
753
                        $extrainfo[] = 'To install use "pear install ' .
754
                            $reg->parsedPackageNameToString(
755
                                array('package' => $param->getPackage(),
756
                                      'channel' => $param->getChannel()), true) .
757
                                  '#featurename"';
758
                    }
759
                }
760
                if (isset($options['installroot'])) {
761
                    $reg = &$this->config->getRegistry();
762
                }
763
                if (isset($options['packagingroot'])) {
764
                    $instreg = new PEAR_Registry($packrootphp_dir);
765
                } else {
766
                    $instreg = $reg;
767
                }
768
                $pkg = &$instreg->getPackage($param->getPackage(), $param->getChannel());
769
                // $pkg may be NULL if install is a 'fake' install via --packagingroot
770
                if (is_object($pkg)) {
771
                    $pkg->setConfig($this->config);
772
                    if ($list = $pkg->listPostinstallScripts()) {
773
                        $pn = $reg->parsedPackageNameToString(array('channel' =>
774
                           $param->getChannel(), 'package' => $param->getPackage()), true);
775
                        $extrainfo[] = $pn . ' has post-install scripts:';
776
                        foreach ($list as $file) {
777
                            $extrainfo[] = $file;
778
                        }
779
                        $extrainfo[] = 'Use "pear run-scripts ' . $pn . '" to run';
780
                        $extrainfo[] = 'DO NOT RUN SCRIPTS FROM UNTRUSTED SOURCES';
781
                    }
782
                }
783
            } else {
784
                return $this->raiseError("$command failed");
785
            }
786
        }
787
        if (count($extrainfo)) {
788
            foreach ($extrainfo as $info) {
789
                $this->ui->outputData($info);
790
            }
791
        }
792
        return true;
793
    }
794
 
795
    // }}}
796
    // {{{ doUninstall()
797
 
798
    function doUninstall($command, $options, $params)
799
    {
800
        if (empty($this->installer)) {
801
            $this->installer = &$this->getInstaller($this->ui);
802
        }
803
        if (isset($options['remoteconfig'])) {
804
            $e = $this->config->readFTPConfigFile($options['remoteconfig']);
805
            if (!PEAR::isError($e)) {
806
                $this->installer->setConfig($this->config);
807
            }
808
        }
809
        if (sizeof($params) < 1) {
810
            return $this->raiseError("Please supply the package(s) you want to uninstall");
811
        }
812
        $reg = &$this->config->getRegistry();
813
        $newparams = array();
814
        $badparams = array();
815
        foreach ($params as $pkg) {
816
            $channel = $this->config->get('default_channel');
817
            PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
818
            $parsed = $reg->parsePackageName($pkg, $channel);
819
            PEAR::staticPopErrorHandling();
820
            if (!$parsed || PEAR::isError($parsed)) {
821
                $badparams[] = $pkg;
822
                continue;
823
            }
824
            $package = $parsed['package'];
825
            $channel = $parsed['channel'];
826
            $info = &$reg->getPackage($package, $channel);
827
            if ($info === null &&
828
                 ($channel == 'pear.php.net' || $channel == 'pecl.php.net')) {
829
                // make sure this isn't a package that has flipped from pear to pecl but
830
                // used a package.xml 1.0
831
                $testc = ($channel == 'pear.php.net') ? 'pecl.php.net' : 'pear.php.net';
832
                $info = &$reg->getPackage($package, $testc);
833
                if ($info !== null) {
834
                    $channel = $testc;
835
                }
836
            }
837
            if ($info === null) {
838
                $badparams[] = $pkg;
839
            } else {
840
                $newparams[] = &$info;
841
                // check for binary packages (this is an alias for those packages if so)
842
                if ($installedbinary = $info->getInstalledBinary()) {
843
                    $this->ui->log('adding binary package ' .
844
                        $reg->parsedPackageNameToString(array('channel' => $channel,
845
                            'package' => $installedbinary), true));
846
                    $newparams[] = &$reg->getPackage($installedbinary, $channel);
847
                }
848
                // add the contents of a dependency group to the list of installed packages
849
                if (isset($parsed['group'])) {
850
                    $group = $info->getDependencyGroup($parsed['group']);
851
                    if ($group) {
852
                        $installed = &$reg->getInstalledGroup($group);
853
                        if ($installed) {
854
                            foreach ($installed as $i => $p) {
855
                                $newparams[] = &$installed[$i];
856
                            }
857
                        }
858
                    }
859
                }
860
            }
861
        }
862
        $err = $this->installer->sortPackagesForUninstall($newparams);
863
        if (PEAR::isError($err)) {
864
            $this->ui->outputData($err->getMessage(), $command);
865
            return true;
866
        }
867
        $params = $newparams;
868
        // twist this to use it to check on whether dependent packages are also being uninstalled
869
        // for circular dependencies like subpackages
870
        $this->installer->setUninstallPackages($newparams);
871
        $params = array_merge($params, $badparams);
872
        foreach ($params as $pkg) {
873
            $this->installer->pushErrorHandling(PEAR_ERROR_RETURN);
874
            if ($err = $this->installer->uninstall($pkg, $options)) {
875
                $this->installer->popErrorHandling();
876
                if (PEAR::isError($err)) {
877
                    $this->ui->outputData($err->getMessage(), $command);
878
                    continue;
879
                }
880
                if ($pkg->getPackageType() == 'extsrc' ||
881
                      $pkg->getPackageType() == 'extbin' ||
882
                      $pkg->getPackageType() == 'zendextsrc' ||
883
                      $pkg->getPackageType() == 'zendextbin') {
884
                    if ($instbin = $pkg->getInstalledBinary()) {
885
                        continue; // this will be uninstalled later
886
                    }
887
                    foreach ($pkg->getFilelist() as $name => $atts) {
888
                        $pinfo = pathinfo($atts['installed_as']);
889
                        if (!isset($pinfo['extension']) ||
890
                              in_array($pinfo['extension'], array('c', 'h'))) {
891
                            continue; // make sure we don't match php_blah.h
892
                        }
893
                        if ((strpos($pinfo['basename'], 'php_') === 0 &&
894
                              $pinfo['extension'] == 'dll') ||
895
                              // most unices
896
                              $pinfo['extension'] == 'so' ||
897
                              // hp-ux
898
                              $pinfo['extension'] == 'sl') {
899
                            $binaries[] = array($atts['installed_as'], $pinfo);
900
                            break;
901
                        }
902
                    }
903
                    foreach ($binaries as $pinfo) {
904
                        PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
905
                        $ret = $this->disableExtension(array($pinfo[0]), $pkg->getPackageType());
906
                        PEAR::staticPopErrorHandling();
907
                        if (PEAR::isError($ret)) {
908
                            $extrainfo[] = $ret->getMessage();
909
                            if ($pkg->getPackageType() == 'extsrc' ||
910
                                  $pkg->getPackageType() == 'extbin') {
911
                                $exttype = 'extension';
912
                            } else {
913
                                ob_start();
914
                                phpinfo(INFO_GENERAL);
915
                                $info = ob_get_contents();
916
                                ob_end_clean();
917
                                $debug = function_exists('leak') ? '_debug' : '';
918
                                $ts = preg_match('Thread Safety.+enabled', $info) ? '_ts' : '';
919
                                $exttype = 'zend_extension' . $debug . $ts;
920
                            }
921
                            $this->ui->outputData('Unable to remove "' . $exttype . '=' .
922
                                $pinfo[1]['basename'] . '" from php.ini', $command);
923
                        } else {
924
                            $this->ui->outputData('Extension ' . $pkg->getProvidesExtension() .
925
                                ' disabled in php.ini', $command);
926
                        }
927
                    }
928
                }
929
                $savepkg = $pkg;
930
                if ($this->config->get('verbose') > 0) {
931
                    if (is_object($pkg)) {
932
                        $pkg = $reg->parsedPackageNameToString($pkg);
933
                    }
934
                    $this->ui->outputData("uninstall ok: $pkg", $command);
935
                }
936
                if (!isset($options['offline']) && is_object($savepkg) &&
937
                      defined('PEAR_REMOTEINSTALL_OK')) {
938
                    if ($this->config->isDefinedLayer('ftp')) {
939
                        $this->installer->pushErrorHandling(PEAR_ERROR_RETURN);
940
                        $info = $this->installer->ftpUninstall($savepkg);
941
                        $this->installer->popErrorHandling();
942
                        if (PEAR::isError($info)) {
943
                            $this->ui->outputData($info->getMessage());
944
                            $this->ui->outputData("remote uninstall failed: $pkg");
945
                        } else {
946
                            $this->ui->outputData("remote uninstall ok: $pkg");
947
                        }
948
                    }
949
                }
950
            } else {
951
                $this->installer->popErrorHandling();
952
                if (is_object($pkg)) {
953
                    $pkg = $reg->parsedPackageNameToString($pkg);
954
                }
955
                return $this->raiseError("uninstall failed: $pkg");
956
            }
957
        }
958
        return true;
959
    }
960
 
961
    // }}}
962
 
963
 
964
    // }}}
965
    // {{{ doBundle()
966
    /*
967
    (cox) It just downloads and untars the package, does not do
968
            any check that the PEAR_Installer::_installFile() does.
969
    */
970
 
971
    function doBundle($command, $options, $params)
972
    {
973
        $downloader = &$this->getDownloader($this->ui, array('force' => true, 'nodeps' => true,
974
            'soft' => true, 'downloadonly' => true), $this->config);
975
        $reg = &$this->config->getRegistry();
976
        if (sizeof($params) < 1) {
977
            return $this->raiseError("Please supply the package you want to bundle");
978
        }
979
 
980
        if (isset($options['destination'])) {
981
            if (!is_dir($options['destination'])) {
982
                System::mkdir('-p ' . $options['destination']);
983
            }
984
            $dest = realpath($options['destination']);
985
        } else {
986
            $pwd = getcwd();
987
            if (is_dir($pwd . DIRECTORY_SEPARATOR . 'ext')) {
988
                $dest = $pwd . DIRECTORY_SEPARATOR . 'ext';
989
            } else {
990
                $dest = $pwd;
991
            }
992
        }
993
        $downloader->setDownloadDir($dest);
994
        $result = &$downloader->download(array($params[0]));
995
        if (PEAR::isError($result)) {
996
            return $result;
997
        }
998
        $pkgfile = &$result[0]->getPackageFile();
999
        $pkgname = $pkgfile->getName();
1000
        $pkgversion = $pkgfile->getVersion();
1001
 
1002
        // Unpacking -------------------------------------------------
1003
        $dest .= DIRECTORY_SEPARATOR . $pkgname;
1004
        $orig = $pkgname . '-' . $pkgversion;
1005
 
1006
        $tar = &new Archive_Tar($pkgfile->getArchiveFile());
1007
        if (!$tar->extractModify($dest, $orig)) {
1008
            return $this->raiseError('unable to unpack ' . $pkgfile->getArchiveFile());
1009
        }
1010
        $this->ui->outputData("Package ready at '$dest'");
1011
    // }}}
1012
    }
1013
 
1014
    // }}}
1015
 
1016
    function doRunScripts($command, $options, $params)
1017
    {
1018
        if (!isset($params[0])) {
1019
            return $this->raiseError('run-scripts expects 1 parameter: a package name');
1020
        }
1021
        $reg = &$this->config->getRegistry();
1022
        PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
1023
        $parsed = $reg->parsePackageName($params[0], $this->config->get('default_channel'));
1024
        PEAR::staticPopErrorHandling();
1025
        if (PEAR::isError($parsed)) {
1026
            return $this->raiseError($parsed);
1027
        }
1028
        $package = &$reg->getPackage($parsed['package'], $parsed['channel']);
1029
        if (is_object($package)) {
1030
            $package->setConfig($this->config);
1031
            $package->runPostinstallScripts();
1032
        } else {
1033
            return $this->raiseError('Could not retrieve package "' . $params[0] . '" from registry');
1034
        }
1035
        $this->ui->outputData('Install scripts complete', $command);
1036
        return true;
1037
    }
1038
}
1039
?>