Хранилища Subversion ant

Редакция

Редакция 69 | Содержимое файла | Сравнить с предыдущей | Последнее изменение | Открыть журнал | RSS

Редакция Автор № строки Строка
69 alex-w 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-2008 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.141 2008/05/13 18:32:29 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-2008 The PHP Group
38
 * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
39
 * @version    Release: 1.7.2
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)',
171
                    ),
172
                'ignore-errors' => array(
173
                    'doc' => 'force install even if there were errors',
174
                    ),
175
                'alldeps' => array(
176
                    'shortopt' => 'a',
177
                    'doc' => 'install all required and optional dependencies',
178
                    ),
179
                'onlyreqdeps' => array(
180
                    'shortopt' => 'o',
181
                    'doc' => 'install all required dependencies',
182
                    ),
183
                'offline' => array(
184
                    'shortopt' => 'O',
185
                    'doc' => 'do not attempt to download any urls or contact channels',
186
                    ),
187
                'pretend' => array(
188
                    'shortopt' => 'p',
189
                    'doc' => 'Only list the packages that would be downloaded',
190
                    ),
191
                ),
192
            'doc' => '<package> ...
193
Upgrades one or more PEAR packages.  See documentation for the
194
"install" command for ways to specify a package.
195
 
196
When upgrading, your package will be updated if the provided new
197
package has a higher version number (use the -f option if you need to
198
upgrade anyway).
199
 
200
More than one package may be specified at once.
201
'),
202
        'upgrade-all' => array(
203
            'summary' => 'Upgrade All Packages',
204
            'function' => 'doUpgradeAll',
205
            'shortcut' => 'ua',
206
            'options' => array(
207
                'nodeps' => array(
208
                    'shortopt' => 'n',
209
                    'doc' => 'ignore dependencies, upgrade anyway',
210
                    ),
211
                'register-only' => array(
212
                    'shortopt' => 'r',
213
                    'doc' => 'do not install files, only register the package as upgraded',
214
                    ),
215
                'nobuild' => array(
216
                    'shortopt' => 'B',
217
                    'doc' => 'don\'t build C extensions',
218
                    ),
219
                'nocompress' => array(
220
                    'shortopt' => 'Z',
221
                    'doc' => 'request uncompressed files when downloading',
222
                    ),
223
                'installroot' => array(
224
                    'shortopt' => 'R',
225
                    'arg' => 'DIR',
226
                    'doc' => 'root directory used when installing files (ala PHP\'s INSTALL_ROOT), use packagingroot for RPM',
227
                    ),
228
                'ignore-errors' => array(
229
                    'doc' => 'force install even if there were errors',
230
                    ),
231
                'loose' => array(
232
                    'doc' => 'do not check for recommended dependency version',
233
                    ),
234
                ),
235
            'doc' => '
236
Upgrades all packages that have a newer release available.  Upgrades are
237
done only if there is a release available of the state specified in
238
"preferred_state" (currently {config preferred_state}), or a state considered
239
more stable.
240
'),
241
        'uninstall' => array(
242
            'summary' => 'Un-install Package',
243
            'function' => 'doUninstall',
244
            'shortcut' => 'un',
245
            'options' => array(
246
                'nodeps' => array(
247
                    'shortopt' => 'n',
248
                    'doc' => 'ignore dependencies, uninstall anyway',
249
                    ),
250
                'register-only' => array(
251
                    'shortopt' => 'r',
252
                    'doc' => 'do not remove files, only register the packages as not installed',
253
                    ),
254
                'installroot' => array(
255
                    'shortopt' => 'R',
256
                    'arg' => 'DIR',
257
                    'doc' => 'root directory used when installing files (ala PHP\'s INSTALL_ROOT)',
258
                    ),
259
                'ignore-errors' => array(
260
                    'doc' => 'force install even if there were errors',
261
                    ),
262
                'offline' => array(
263
                    'shortopt' => 'O',
264
                    'doc' => 'do not attempt to uninstall remotely',
265
                    ),
266
                ),
267
            'doc' => '[channel/]<package> ...
268
Uninstalls one or more PEAR packages.  More than one package may be
269
specified at once.  Prefix with channel name to uninstall from a
270
channel not in your default channel ({config default_channel})
271
'),
272
        'bundle' => array(
273
            'summary' => 'Unpacks a Pecl Package',
274
            'function' => 'doBundle',
275
            'shortcut' => 'bun',
276
            'options' => array(
277
                'destination' => array(
278
                   'shortopt' => 'd',
279
                    'arg' => 'DIR',
280
                    'doc' => 'Optional destination directory for unpacking (defaults to current path or "ext" if exists)',
281
                    ),
282
                'force' => array(
283
                    'shortopt' => 'f',
284
                    'doc' => 'Force the unpacking even if there were errors in the package',
285
                ),
286
            ),
287
            'doc' => '<package>
288
Unpacks a Pecl Package into the selected location. It will download the
289
package if needed.
290
'),
291
        'run-scripts' => array(
292
            'summary' => 'Run Post-Install Scripts bundled with a package',
293
            'function' => 'doRunScripts',
294
            'shortcut' => 'rs',
295
            'options' => array(
296
            ),
297
            'doc' => '<package>
298
Run post-installation scripts in package <package>, if any exist.
299
'),
300
    );
301
 
302
    // }}}
303
    // {{{ constructor
304
 
305
    /**
306
     * PEAR_Command_Install constructor.
307
     *
308
     * @access public
309
     */
310
    function PEAR_Command_Install(&$ui, &$config)
311
    {
312
        parent::PEAR_Command_Common($ui, $config);
313
    }
314
 
315
    // }}}
316
 
317
    /**
318
     * For unit testing purposes
319
     */
320
    function &getDownloader(&$ui, $options, &$config)
321
    {
322
        if (!class_exists('PEAR_Downloader')) {
323
            require_once 'PEAR/Downloader.php';
324
        }
325
        $a = &new PEAR_Downloader($ui, $options, $config);
326
        return $a;
327
    }
328
 
329
    /**
330
     * For unit testing purposes
331
     */
332
    function &getInstaller(&$ui)
333
    {
334
        if (!class_exists('PEAR_Installer')) {
335
            require_once 'PEAR/Installer.php';
336
        }
337
        $a = &new PEAR_Installer($ui);
338
        return $a;
339
    }
340
 
341
    function enableExtension($binaries, $type)
342
    {
343
        if (!($phpini = $this->config->get('php_ini', null, 'pear.php.net'))) {
344
            return PEAR::raiseError('configuration option "php_ini" is not set to php.ini location');
345
        }
346
        $ini = $this->_parseIni($phpini);
347
        if (PEAR::isError($ini)) {
348
            return $ini;
349
        }
350
        $line = 0;
351
        if ($type == 'extsrc' || $type == 'extbin') {
352
            $search = 'extensions';
353
            $enable = 'extension';
354
        } else {
355
            $search = 'zend_extensions';
356
            ob_start();
357
            phpinfo(INFO_GENERAL);
358
            $info = ob_get_contents();
359
            ob_end_clean();
360
            $debug = function_exists('leak') ? '_debug' : '';
361
            $ts = preg_match('Thread Safety.+enabled', $info) ? '_ts' : '';
362
            $enable = 'zend_extension' . $debug . $ts;
363
        }
364
        foreach ($ini[$search] as $line => $extension) {
365
            if (in_array($extension, $binaries, true) || in_array(
366
                  $ini['extension_dir'] . DIRECTORY_SEPARATOR . $extension, $binaries, true)) {
367
                // already enabled - assume if one is, all are
368
                return true;
369
            }
370
        }
371
        if ($line) {
372
            $newini = array_slice($ini['all'], 0, $line);
373
        } else {
374
            $newini = array();
375
        }
376
        foreach ($binaries as $binary) {
377
            if ($ini['extension_dir']) {
378
                $binary = basename($binary);
379
            }
380
            $newini[] = $enable . '="' . $binary . '"' . (OS_UNIX ? "\n" : "\r\n");
381
        }
382
        $newini = array_merge($newini, array_slice($ini['all'], $line));
383
        $fp = @fopen($phpini, 'wb');
384
        if (!$fp) {
385
            return PEAR::raiseError('cannot open php.ini "' . $phpini . '" for writing');
386
        }
387
        foreach ($newini as $line) {
388
            fwrite($fp, $line);
389
        }
390
        fclose($fp);
391
        return true;
392
    }
393
 
394
    function disableExtension($binaries, $type)
395
    {
396
        if (!($phpini = $this->config->get('php_ini', null, 'pear.php.net'))) {
397
            return PEAR::raiseError('configuration option "php_ini" is not set to php.ini location');
398
        }
399
        $ini = $this->_parseIni($phpini);
400
        if (PEAR::isError($ini)) {
401
            return $ini;
402
        }
403
        $line = 0;
404
        if ($type == 'extsrc' || $type == 'extbin') {
405
            $search = 'extensions';
406
            $enable = 'extension';
407
        } else {
408
            $search = 'zend_extensions';
409
            ob_start();
410
            phpinfo(INFO_GENERAL);
411
            $info = ob_get_contents();
412
            ob_end_clean();
413
            $debug = function_exists('leak') ? '_debug' : '';
414
            $ts = preg_match('Thread Safety.+enabled', $info) ? '_ts' : '';
415
            $enable = 'zend_extension' . $debug . $ts;
416
        }
417
        $found = false;
418
        foreach ($ini[$search] as $line => $extension) {
419
            if (in_array($extension, $binaries, true) || in_array(
420
                  $ini['extension_dir'] . DIRECTORY_SEPARATOR . $extension, $binaries, true)) {
421
                $found = true;
422
                break;
423
            }
424
        }
425
        if (!$found) {
426
            // not enabled
427
            return true;
428
        }
429
        $fp = @fopen($phpini, 'wb');
430
        if (!$fp) {
431
            return PEAR::raiseError('cannot open php.ini "' . $phpini . '" for writing');
432
        }
433
        if ($line) {
434
            $newini = array_slice($ini['all'], 0, $line);
435
            // delete the enable line
436
            $newini = array_merge($newini, array_slice($ini['all'], $line + 1));
437
        } else {
438
            $newini = array_slice($ini['all'], 1);
439
        }
440
        foreach ($newini as $line) {
441
            fwrite($fp, $line);
442
        }
443
        fclose($fp);
444
        return true;
445
    }
446
 
447
    function _parseIni($filename)
448
    {
449
        if (file_exists($filename)) {
450
            if (filesize($filename) > 300000) {
451
                return PEAR::raiseError('php.ini "' . $filename . '" is too large, aborting');
452
            }
453
            ob_start();
454
            phpinfo(INFO_GENERAL);
455
            $info = ob_get_contents();
456
            ob_end_clean();
457
            $debug = function_exists('leak') ? '_debug' : '';
458
            $ts = preg_match('/Thread Safety.+enabled/', $info) ? '_ts' : '';
459
            $zend_extension_line = 'zend_extension' . $debug . $ts;
460
            $all = @file($filename);
461
            if (!$all) {
462
                return PEAR::raiseError('php.ini "' . $filename .'" could not be read');
463
            }
464
            $zend_extensions = $extensions = array();
465
            // assume this is right, but pull from the php.ini if it is found
466
            $extension_dir = ini_get('extension_dir');
467
            foreach ($all as $linenum => $line) {
468
                $line = trim($line);
469
                if (!$line) {
470
                    continue;
471
                }
472
                if ($line[0] == ';') {
473
                    continue;
474
                }
475
                if (strtolower(substr($line, 0, 13)) == 'extension_dir') {
476
                    $line = trim(substr($line, 13));
477
                    if ($line[0] == '=') {
478
                        $x = trim(substr($line, 1));
479
                        $x = explode(';', $x);
480
                        $extension_dir = str_replace('"', '', array_shift($x));
481
                        continue;
482
                    }
483
                }
484
                if (strtolower(substr($line, 0, 9)) == 'extension') {
485
                    $line = trim(substr($line, 9));
486
                    if ($line[0] == '=') {
487
                        $x = trim(substr($line, 1));
488
                        $x = explode(';', $x);
489
                        $extensions[$linenum] = str_replace('"', '', array_shift($x));
490
                        continue;
491
                    }
492
                }
493
                if (strtolower(substr($line, 0, strlen($zend_extension_line))) ==
494
                      $zend_extension_line) {
495
                    $line = trim(substr($line, strlen($zend_extension_line)));
496
                    if ($line[0] == '=') {
497
                        $x = trim(substr($line, 1));
498
                        $x = explode(';', $x);
499
                        $zend_extensions[$linenum] = str_replace('"', '', array_shift($x));
500
                        continue;
501
                    }
502
                }
503
            }
504
            return array(
505
                'extensions' => $extensions,
506
                'zend_extensions' => $zend_extensions,
507
                'extension_dir' => $extension_dir,
508
                'all' => $all,
509
            );
510
        } else {
511
            return PEAR::raiseError('php.ini "' . $filename . '" does not exist');
512
        }
513
    }
514
 
515
    // {{{ doInstall()
516
 
517
    function doInstall($command, $options, $params)
518
    {
519
        if (!class_exists('PEAR_PackageFile')) {
520
            require_once 'PEAR/PackageFile.php';
521
        }
522
        if (empty($this->installer)) {
523
            $this->installer = &$this->getInstaller($this->ui);
524
        }
525
        if ($command == 'upgrade' || $command == 'upgrade-all') {
526
            $options['upgrade'] = true;
527
        } else {
528
            $packages = $params;
529
        }
530
        if (isset($options['installroot']) && isset($options['packagingroot'])) {
531
            return $this->raiseError('ERROR: cannot use both --installroot and --packagingroot');
532
        }
533
        $reg = &$this->config->getRegistry();
534
        $instreg = &$reg; // instreg used to check if package is installed
535
        if (isset($options['packagingroot']) && !isset($options['upgrade'])) {
536
            $packrootphp_dir = $this->installer->_prependPath(
537
                $this->config->get('php_dir', null, 'pear.php.net'),
538
                $options['packagingroot']);
539
            $instreg = new PEAR_Registry($packrootphp_dir); // other instreg!
540
 
541
            if ($this->config->get('verbose') > 2) {
542
                $this->ui->outputData('using package root: ' . $options['packagingroot']);
543
            }
544
        }
545
        $abstractpackages = array();
546
        $otherpackages = array();
547
        // parse params
548
        PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
549
        foreach($params as $param) {
550
            if (strpos($param, 'http://') === 0) {
551
                $otherpackages[] = $param;
552
                continue;
553
            }
554
            if (strpos($param, 'channel://') === false && @file_exists($param)) {
555
                if (isset($options['force'])) {
556
                    $otherpackages[] = $param;
557
                    continue;
558
                }
559
                $pkg = new PEAR_PackageFile($this->config);
560
                $pf = $pkg->fromAnyFile($param, PEAR_VALIDATE_DOWNLOADING);
561
                if (PEAR::isError($pf)) {
562
                    $otherpackages[] = $param;
563
                    continue;
564
                }
565
                if ($reg->packageExists($pf->getPackage(), $pf->getChannel()) &&
566
                      version_compare($pf->getVersion(),
567
                      $reg->packageInfo($pf->getPackage(), 'version', $pf->getChannel()),
568
                      '<=')) {
569
                    if ($this->config->get('verbose')) {
570
                        $this->ui->outputData('Ignoring installed package ' .
571
                            $reg->parsedPackageNameToString(
572
                            array('package' => $pf->getPackage(),
573
                                  'channel' => $pf->getChannel()), true));
574
                    }
575
                    continue;
576
                }
577
                $otherpackages[] = $param;
578
                continue;
579
            }
580
            $e = $reg->parsePackageName($param, $this->config->get('default_channel'));
581
            if (PEAR::isError($e)) {
582
                $otherpackages[] = $param;
583
            } else {
584
                $abstractpackages[] = $e;
585
            }
586
        }
587
        PEAR::staticPopErrorHandling();
588
 
589
        // if there are any local package .tgz or remote static url, we can't
590
        // filter.  The filter only works for abstract packages
591
        if (count($abstractpackages) && !isset($options['force'])) {
592
            // when not being forced, only do necessary upgrades/installs
593
            if (isset($options['upgrade'])) {
594
                $abstractpackages = $this->_filterUptodatePackages($abstractpackages,
595
                    $command);
596
            } else {
597
                foreach ($abstractpackages as $i => $package) {
598
                    if (isset($package['group'])) {
599
                        // do not filter out install groups
600
                        continue;
601
                    }
602
                    if ($instreg->packageExists($package['package'], $package['channel'])) {
603
                        if ($this->config->get('verbose')) {
604
                            $this->ui->outputData('Ignoring installed package ' .
605
                                $reg->parsedPackageNameToString($package, true));
606
                        }
607
                        unset($abstractpackages[$i]);
608
                    }
609
                }
610
            }
611
            $abstractpackages =
612
                array_map(array($reg, 'parsedPackageNameToString'), $abstractpackages);
613
        } elseif (count($abstractpackages)) {
614
            $abstractpackages =
615
                array_map(array($reg, 'parsedPackageNameToString'), $abstractpackages);
616
        }
617
 
618
 
619
        $packages = array_merge($abstractpackages, $otherpackages);
620
        if (!count($packages)) {
621
            $this->ui->outputData('Nothing to ' . $command);
622
            return true;
623
        }
624
 
625
        $this->downloader = &$this->getDownloader($this->ui, $options, $this->config);
626
        $errors = array();
627
        $binaries = array();
628
        $downloaded = array();
629
        $downloaded = &$this->downloader->download($packages);
630
        if (PEAR::isError($downloaded)) {
631
            return $this->raiseError($downloaded);
632
        }
633
        $errors = $this->downloader->getErrorMsgs();
634
        if (count($errors)) {
635
            $err = array();
636
            $err['data'] = array();
637
            foreach ($errors as $error) {
638
                $err['data'][] = array($error);
639
            }
640
            $err['headline'] = 'Install Errors';
641
            $this->ui->outputData($err);
642
            if (!count($downloaded)) {
643
                return $this->raiseError("$command failed");
644
            }
645
        }
646
        $data = array(
647
            'headline' => 'Packages that would be Installed'
648
        );
649
        if (isset($options['pretend'])) {
650
            foreach ($downloaded as $package) {
651
                $data['data'][] = array($reg->parsedPackageNameToString($package->getParsedPackage()));
652
            }
653
            $this->ui->outputData($data, 'pretend');
654
            return true;
655
        }
656
        $this->installer->setOptions($options);
657
        $this->installer->sortPackagesForInstall($downloaded);
658
        if (PEAR::isError($err = $this->installer->setDownloadedPackages($downloaded))) {
659
            $this->raiseError($err->getMessage());
660
            return true;
661
        }
662
        $extrainfo = array();
663
        $binaries = array();
664
        foreach ($downloaded as $param) {
665
            PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
666
            $info = $this->installer->install($param, $options);
667
            PEAR::staticPopErrorHandling();
668
            if (PEAR::isError($info)) {
669
                $oldinfo = $info;
670
                $pkg = &$param->getPackageFile();
671
                if ($info->getCode() != PEAR_INSTALLER_NOBINARY) {
672
                    if (!($info = $pkg->installBinary($this->installer))) {
673
                        $this->ui->outputData('ERROR: ' .$oldinfo->getMessage());
674
                        continue;
675
                    }
676
                    // we just installed a different package than requested,
677
                    // let's change the param and info so that the rest of this works
678
                    $param = $info[0];
679
                    $info = $info[1];
680
                }
681
            }
682
            if (is_array($info)) {
683
                if ($param->getPackageType() == 'extsrc' ||
684
                      $param->getPackageType() == 'extbin' ||
685
                      $param->getPackageType() == 'zendextsrc' ||
686
                      $param->getPackageType() == 'zendextbin') {
687
                    $pkg = &$param->getPackageFile();
688
                    if ($instbin = $pkg->getInstalledBinary()) {
689
                        $instpkg = &$instreg->getPackage($instbin, $pkg->getChannel());
690
                    } else {
691
                        $instpkg = &$instreg->getPackage($pkg->getPackage(), $pkg->getChannel());
692
                    }
693
 
694
                    foreach ($instpkg->getFilelist() as $name => $atts) {
695
                        $pinfo = pathinfo($atts['installed_as']);
696
                        if (!isset($pinfo['extension']) ||
697
                              in_array($pinfo['extension'], array('c', 'h'))) {
698
                            continue; // make sure we don't match php_blah.h
699
                        }
700
                        if ((strpos($pinfo['basename'], 'php_') === 0 &&
701
                              $pinfo['extension'] == 'dll') ||
702
                              // most unices
703
                              $pinfo['extension'] == 'so' ||
704
                              // hp-ux
705
                              $pinfo['extension'] == 'sl') {
706
                            $binaries[] = array($atts['installed_as'], $pinfo);
707
                            break;
708
                        }
709
                    }
710
                    if (count($binaries)) {
711
                        foreach ($binaries as $pinfo) {
712
                            PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
713
                            $ret = $this->enableExtension(array($pinfo[0]), $param->getPackageType());
714
                            PEAR::staticPopErrorHandling();
715
                            if (PEAR::isError($ret)) {
716
                                $extrainfo[] = $ret->getMessage();
717
                                if ($param->getPackageType() == 'extsrc' ||
718
                                      $param->getPackageType() == 'extbin') {
719
                                    $exttype = 'extension';
720
                                } else {
721
                                    ob_start();
722
                                    phpinfo(INFO_GENERAL);
723
                                    $info = ob_get_contents();
724
                                    ob_end_clean();
725
                                    $debug = function_exists('leak') ? '_debug' : '';
726
                                    $ts = preg_match('Thread Safety.+enabled', $info) ? '_ts' : '';
727
                                    $exttype = 'zend_extension' . $debug . $ts;
728
                                }
729
                                $extrainfo[] = 'You should add "' . $exttype . '=' .
730
                                    $pinfo[1]['basename'] . '" to php.ini';
731
                            } else {
732
                                $extrainfo[] = 'Extension ' . $instpkg->getProvidesExtension() .
733
                                    ' enabled in php.ini';
734
                            }
735
                        }
736
                    }
737
                }
738
                if ($this->config->get('verbose') > 0) {
739
                    $channel = $param->getChannel();
740
                    $label = $reg->parsedPackageNameToString(
741
                        array(
742
                            'channel' => $channel,
743
                            'package' => $param->getPackage(),
744
                            'version' => $param->getVersion(),
745
                        ));
746
                    $out = array('data' => "$command ok: $label");
747
                    if (isset($info['release_warnings'])) {
748
                        $out['release_warnings'] = $info['release_warnings'];
749
                    }
750
                    $this->ui->outputData($out, $command);
751
                    if (!isset($options['register-only']) && !isset($options['offline'])) {
752
                        if ($this->config->isDefinedLayer('ftp')) {
753
                            PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
754
                            $info = $this->installer->ftpInstall($param);
755
                            PEAR::staticPopErrorHandling();
756
                            if (PEAR::isError($info)) {
757
                                $this->ui->outputData($info->getMessage());
758
                                $this->ui->outputData("remote install failed: $label");
759
                            } else {
760
                                $this->ui->outputData("remote install ok: $label");
761
                            }
762
                        }
763
                    }
764
                }
765
                $deps = $param->getDeps();
766
                if ($deps) {
767
                    if (isset($deps['group'])) {
768
                        $groups = $deps['group'];
769
                        if (!isset($groups[0])) {
770
                            $groups = array($groups);
771
                        }
772
                        foreach ($groups as $group) {
773
                            if ($group['attribs']['name'] == 'default') {
774
                                // default group is always installed, unless the user
775
                                // explicitly chooses to install another group
776
                                continue;
777
                            }
778
                            $extrainfo[] = $param->getPackage() . ': Optional feature ' .
779
                                $group['attribs']['name'] . ' available (' .
780
                                $group['attribs']['hint'] . ')';
781
                        }
782
                        $extrainfo[] = $param->getPackage() .
783
                            ': To install optional features use "pear install ' .
784
                            $reg->parsedPackageNameToString(
785
                                array('package' => $param->getPackage(),
786
                                      'channel' => $param->getChannel()), true) .
787
                                  '#featurename"';
788
                    }
789
                }
790
                $pkg = &$instreg->getPackage($param->getPackage(), $param->getChannel());
791
                // $pkg may be NULL if install is a 'fake' install via --packagingroot
792
                if (is_object($pkg)) {
793
                    $pkg->setConfig($this->config);
794
                    if ($list = $pkg->listPostinstallScripts()) {
795
                        $pn = $reg->parsedPackageNameToString(array('channel' =>
796
                           $param->getChannel(), 'package' => $param->getPackage()), true);
797
                        $extrainfo[] = $pn . ' has post-install scripts:';
798
                        foreach ($list as $file) {
799
                            $extrainfo[] = $file;
800
                        }
801
                        $extrainfo[] = $param->getPackage() .
802
                            ': Use "pear run-scripts ' . $pn . '" to finish setup.';
803
                        $extrainfo[] = 'DO NOT RUN SCRIPTS FROM UNTRUSTED SOURCES';
804
                    }
805
                }
806
            } else {
807
                return $this->raiseError("$command failed");
808
            }
809
        }
810
        if (count($extrainfo)) {
811
            foreach ($extrainfo as $info) {
812
                $this->ui->outputData($info);
813
            }
814
        }
815
        return true;
816
    }
817
 
818
    // }}}
819
    // {{{ doUpgradeAll()
820
 
821
    function doUpgradeAll($command, $options, $params)
822
    {
823
        $reg = &$this->config->getRegistry();
824
        $toUpgrade = array();
825
        foreach ($reg->listChannels() as $channel) {
826
            if ($channel == '__uri') {
827
                continue;
828
            }
829
 
830
            // parse name with channel
831
            foreach ($reg->listPackages($channel) as $name) {
832
                $toUpgrade[] = $reg->parsedPackageNameToString(array(
833
                        'channel' => $channel,
834
                        'package' => $name
835
                    ));
836
            }
837
        }
838
 
839
        $err = $this->doInstall('upgrade-all', $options, $toUpgrade);
840
        if (PEAR::isError($err)) {
841
            $this->ui->outputData($err->getMessage(), $command);
842
        }
843
   }
844
 
845
    // }}}
846
    // {{{ doUninstall()
847
 
848
    function doUninstall($command, $options, $params)
849
    {
850
        if (empty($this->installer)) {
851
            $this->installer = &$this->getInstaller($this->ui);
852
        }
853
        if (isset($options['remoteconfig'])) {
854
            $e = $this->config->readFTPConfigFile($options['remoteconfig']);
855
            if (!PEAR::isError($e)) {
856
                $this->installer->setConfig($this->config);
857
            }
858
        }
859
        if (sizeof($params) < 1) {
860
            return $this->raiseError("Please supply the package(s) you want to uninstall");
861
        }
862
        $reg = &$this->config->getRegistry();
863
        $newparams = array();
864
        $binaries = array();
865
        $badparams = array();
866
        foreach ($params as $pkg) {
867
            $channel = $this->config->get('default_channel');
868
            PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
869
            $parsed = $reg->parsePackageName($pkg, $channel);
870
            PEAR::staticPopErrorHandling();
871
            if (!$parsed || PEAR::isError($parsed)) {
872
                $badparams[] = $pkg;
873
                continue;
874
            }
875
            $package = $parsed['package'];
876
            $channel = $parsed['channel'];
877
            $info = &$reg->getPackage($package, $channel);
878
            if ($info === null &&
879
                 ($channel == 'pear.php.net' || $channel == 'pecl.php.net')) {
880
                // make sure this isn't a package that has flipped from pear to pecl but
881
                // used a package.xml 1.0
882
                $testc = ($channel == 'pear.php.net') ? 'pecl.php.net' : 'pear.php.net';
883
                $info = &$reg->getPackage($package, $testc);
884
                if ($info !== null) {
885
                    $channel = $testc;
886
                }
887
            }
888
            if ($info === null) {
889
                $badparams[] = $pkg;
890
            } else {
891
                $newparams[] = &$info;
892
                // check for binary packages (this is an alias for those packages if so)
893
                if ($installedbinary = $info->getInstalledBinary()) {
894
                    $this->ui->log('adding binary package ' .
895
                        $reg->parsedPackageNameToString(array('channel' => $channel,
896
                            'package' => $installedbinary), true));
897
                    $newparams[] = &$reg->getPackage($installedbinary, $channel);
898
                }
899
                // add the contents of a dependency group to the list of installed packages
900
                if (isset($parsed['group'])) {
901
                    $group = $info->getDependencyGroup($parsed['group']);
902
                    if ($group) {
903
                        $installed = $reg->getInstalledGroup($group);
904
                        if ($installed) {
905
                            foreach ($installed as $i => $p) {
906
                                $newparams[] = &$installed[$i];
907
                            }
908
                        }
909
                    }
910
                }
911
            }
912
        }
913
        $err = $this->installer->sortPackagesForUninstall($newparams);
914
        if (PEAR::isError($err)) {
915
            $this->ui->outputData($err->getMessage(), $command);
916
            return true;
917
        }
918
        $params = $newparams;
919
        // twist this to use it to check on whether dependent packages are also being uninstalled
920
        // for circular dependencies like subpackages
921
        $this->installer->setUninstallPackages($newparams);
922
        $params = array_merge($params, $badparams);
923
        $binaries = array();
924
        foreach ($params as $pkg) {
925
            $this->installer->pushErrorHandling(PEAR_ERROR_RETURN);
926
            if ($err = $this->installer->uninstall($pkg, $options)) {
927
                $this->installer->popErrorHandling();
928
                if (PEAR::isError($err)) {
929
                    $this->ui->outputData($err->getMessage(), $command);
930
                    continue;
931
                }
932
                if ($pkg->getPackageType() == 'extsrc' ||
933
                      $pkg->getPackageType() == 'extbin' ||
934
                      $pkg->getPackageType() == 'zendextsrc' ||
935
                      $pkg->getPackageType() == 'zendextbin') {
936
                    if ($instbin = $pkg->getInstalledBinary()) {
937
                        continue; // this will be uninstalled later
938
                    }
939
 
940
                    foreach ($pkg->getFilelist() as $name => $atts) {
941
                        $pinfo = pathinfo($atts['installed_as']);
942
                        if (!isset($pinfo['extension']) ||
943
                              in_array($pinfo['extension'], array('c', 'h'))) {
944
                            continue; // make sure we don't match php_blah.h
945
                        }
946
                        if ((strpos($pinfo['basename'], 'php_') === 0 &&
947
                              $pinfo['extension'] == 'dll') ||
948
                              // most unices
949
                              $pinfo['extension'] == 'so' ||
950
                              // hp-ux
951
                              $pinfo['extension'] == 'sl') {
952
                            $binaries[] = array($atts['installed_as'], $pinfo);
953
                            break;
954
                        }
955
                    }
956
                    if (count($binaries)) {
957
                        foreach ($binaries as $pinfo) {
958
                            PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
959
                            $ret = $this->disableExtension(array($pinfo[0]), $pkg->getPackageType());
960
                            PEAR::staticPopErrorHandling();
961
                            if (PEAR::isError($ret)) {
962
                                $extrainfo[] = $ret->getMessage();
963
                                if ($pkg->getPackageType() == 'extsrc' ||
964
                                      $pkg->getPackageType() == 'extbin') {
965
                                    $exttype = 'extension';
966
                                } else {
967
                                    ob_start();
968
                                    phpinfo(INFO_GENERAL);
969
                                    $info = ob_get_contents();
970
                                    ob_end_clean();
971
                                    $debug = function_exists('leak') ? '_debug' : '';
972
                                    $ts = preg_match('Thread Safety.+enabled', $info) ? '_ts' : '';
973
                                    $exttype = 'zend_extension' . $debug . $ts;
974
                                }
975
                                $this->ui->outputData('Unable to remove "' . $exttype . '=' .
976
                                    $pinfo[1]['basename'] . '" from php.ini', $command);
977
                            } else {
978
                                $this->ui->outputData('Extension ' . $pkg->getProvidesExtension() .
979
                                    ' disabled in php.ini', $command);
980
                            }
981
                        }
982
                    }
983
                }
984
                $savepkg = $pkg;
985
                if ($this->config->get('verbose') > 0) {
986
                    if (is_object($pkg)) {
987
                        $pkg = $reg->parsedPackageNameToString($pkg);
988
                    }
989
                    $this->ui->outputData("uninstall ok: $pkg", $command);
990
                }
991
                if (!isset($options['offline']) && is_object($savepkg) &&
992
                      defined('PEAR_REMOTEINSTALL_OK')) {
993
                    if ($this->config->isDefinedLayer('ftp')) {
994
                        $this->installer->pushErrorHandling(PEAR_ERROR_RETURN);
995
                        $info = $this->installer->ftpUninstall($savepkg);
996
                        $this->installer->popErrorHandling();
997
                        if (PEAR::isError($info)) {
998
                            $this->ui->outputData($info->getMessage());
999
                            $this->ui->outputData("remote uninstall failed: $pkg");
1000
                        } else {
1001
                            $this->ui->outputData("remote uninstall ok: $pkg");
1002
                        }
1003
                    }
1004
                }
1005
            } else {
1006
                $this->installer->popErrorHandling();
1007
                if (is_object($pkg)) {
1008
                    $pkg = $reg->parsedPackageNameToString($pkg);
1009
                }
1010
                return $this->raiseError("uninstall failed: $pkg");
1011
            }
1012
        }
1013
        return true;
1014
    }
1015
 
1016
    // }}}
1017
 
1018
 
1019
    // }}}
1020
    // {{{ doBundle()
1021
    /*
1022
    (cox) It just downloads and untars the package, does not do
1023
            any check that the PEAR_Installer::_installFile() does.
1024
    */
1025
 
1026
    function doBundle($command, $options, $params)
1027
    {
1028
        $downloader = &$this->getDownloader($this->ui, array('force' => true, 'nodeps' => true,
1029
            'soft' => true, 'downloadonly' => true), $this->config);
1030
        $reg = &$this->config->getRegistry();
1031
        if (sizeof($params) < 1) {
1032
            return $this->raiseError("Please supply the package you want to bundle");
1033
        }
1034
 
1035
        if (isset($options['destination'])) {
1036
            if (!is_dir($options['destination'])) {
1037
                System::mkdir('-p ' . $options['destination']);
1038
            }
1039
            $dest = realpath($options['destination']);
1040
        } else {
1041
            $pwd = getcwd();
1042
            if (is_dir($pwd . DIRECTORY_SEPARATOR . 'ext')) {
1043
                $dest = $pwd . DIRECTORY_SEPARATOR . 'ext';
1044
            } else {
1045
                $dest = $pwd;
1046
            }
1047
        }
1048
        PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
1049
        $err = $downloader->setDownloadDir($dest);
1050
        PEAR::staticPopErrorHandling();
1051
        if (PEAR::isError($err)) {
1052
            return PEAR::raiseError('download directory "' . $dest .
1053
                '" is not writeable.');
1054
        }
1055
        $result = &$downloader->download(array($params[0]));
1056
        if (PEAR::isError($result)) {
1057
            return $result;
1058
        }
1059
        if (!isset($result[0])) {
1060
            return $this->raiseError('unable to unpack ' . $params[0]);
1061
        }
1062
        $pkgfile = &$result[0]->getPackageFile();
1063
        $pkgname = $pkgfile->getName();
1064
        $pkgversion = $pkgfile->getVersion();
1065
 
1066
        // Unpacking -------------------------------------------------
1067
        $dest .= DIRECTORY_SEPARATOR . $pkgname;
1068
        $orig = $pkgname . '-' . $pkgversion;
1069
 
1070
        $tar = &new Archive_Tar($pkgfile->getArchiveFile());
1071
        if (!$tar->extractModify($dest, $orig)) {
1072
            return $this->raiseError('unable to unpack ' . $pkgfile->getArchiveFile());
1073
        }
1074
        $this->ui->outputData("Package ready at '$dest'");
1075
    // }}}
1076
    }
1077
 
1078
    // }}}
1079
 
1080
    function doRunScripts($command, $options, $params)
1081
    {
1082
        if (!isset($params[0])) {
1083
            return $this->raiseError('run-scripts expects 1 parameter: a package name');
1084
        }
1085
        $reg = &$this->config->getRegistry();
1086
        PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
1087
        $parsed = $reg->parsePackageName($params[0], $this->config->get('default_channel'));
1088
        PEAR::staticPopErrorHandling();
1089
        if (PEAR::isError($parsed)) {
1090
            return $this->raiseError($parsed);
1091
        }
1092
        $package = &$reg->getPackage($parsed['package'], $parsed['channel']);
1093
        if (is_object($package)) {
1094
            $package->setConfig($this->config);
1095
            $package->runPostinstallScripts();
1096
        } else {
1097
            return $this->raiseError('Could not retrieve package "' . $params[0] . '" from registry');
1098
        }
1099
        $this->ui->outputData('Install scripts complete', $command);
1100
        return true;
1101
    }
1102
 
1103
    /**
1104
     * Given a list of packages, filter out those ones that are already up to date
1105
     *
1106
     * @param $packages: packages, in parsed array format !
1107
     * @return list of packages that can be upgraded
1108
     */
1109
    function _filterUptodatePackages($packages, $command)
1110
    {
1111
        $reg = &$this->config->getRegistry();
1112
        $latestReleases = array();
1113
 
1114
        $ret = array();
1115
        foreach($packages as $package) {
1116
            if (isset($package['group'])) {
1117
                $ret[] = $package;
1118
                continue;
1119
            }
1120
            $channel = $package['channel'];
1121
            $name = $package['package'];
1122
 
1123
            if (!$reg->packageExists($name, $channel)) {
1124
                $ret[] = $package;
1125
                continue;
1126
            }
1127
            if (!isset($latestReleases[$channel])) {
1128
                // fill in cache for this channel
1129
                $chan = &$reg->getChannel($channel);
1130
                if (PEAR::isError($chan)) {
1131
                    return $this->raiseError($chan);
1132
                }
1133
                if ($chan->supportsREST($this->config->get('preferred_mirror',
1134
                                                           null, $channel)) &&
1135
                      $base = $chan->getBaseURL('REST1.0',
1136
                                                $this->config->get('preferred_mirror',
1137
                                                                   null, $channel)))
1138
                {
1139
                    $dorest = true;
1140
                } else {
1141
                    $dorest = false;
1142
                    $remote = &$this->config->getRemote($this->config);
1143
                }
1144
                PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
1145
                if ($dorest) {
1146
                    $rest = &$this->config->getREST('1.0', array());
1147
                    $installed = array_flip($reg->listPackages($channel));
1148
                    $latest = $rest->listLatestUpgrades($base,
1149
                        $this->config->get('preferred_state', null, $channel), $installed,
1150
                        $channel, $reg);
1151
                } else {
1152
                    $latest = $remote->call("package.listLatestReleases",
1153
                        $this->config->get('preferred_state', null, $channel));
1154
                    unset($remote);
1155
                }
1156
                PEAR::staticPopErrorHandling();
1157
                if (PEAR::isError($latest)) {
1158
                    $this->ui->outputData('Error getting channel info from ' . $channel .
1159
                        ': ' . $latest->getMessage());
1160
                    continue;
1161
                }
1162
 
1163
                $latestReleases[$channel] = array_change_key_case($latest);
1164
            }
1165
 
1166
            // check package for latest release
1167
            if (isset($latestReleases[$channel][strtolower($name)])) {
1168
                // if not set, up to date
1169
                $inst_version = $reg->packageInfo($name, 'version', $channel);
1170
                $channel_version = $latestReleases[$channel][strtolower($name)]['version'];
1171
                if (version_compare($channel_version, $inst_version, "le")) {
1172
                    // installed version is up-to-date
1173
                    continue;
1174
                }
1175
                // maintain BC
1176
                if ($command == 'upgrade-all') {
1177
                    $this->ui->outputData(array('data' => 'Will upgrade ' .
1178
                        $reg->parsedPackageNameToString($package)), $command);
1179
                }
1180
                $ret[] = $package;
1181
            }
1182
        }
1183
 
1184
        return $ret;
1185
    }
1186
 
1187
}
1188
?>