Updated PEAR and PEAR packages.
[timetracker.git] / WEB-INF / lib / pear / PEAR / Command / Registry.php
1 <?php
2 /**
3  * PEAR_Command_Registry (list, list-files, shell-test, info commands)
4  *
5  * PHP versions 4 and 5
6  *
7  * @category   pear
8  * @package    PEAR
9  * @author     Stig Bakken <ssb@php.net>
10  * @author     Greg Beaver <cellog@php.net>
11  * @copyright  1997-2009 The Authors
12  * @license    http://opensource.org/licenses/bsd-license.php New BSD License
13  * @link       http://pear.php.net/package/PEAR
14  * @since      File available since Release 0.1
15  */
16
17 /**
18  * base class
19  */
20 require_once 'PEAR/Command/Common.php';
21
22 /**
23  * PEAR commands for registry manipulation
24  *
25  * @category   pear
26  * @package    PEAR
27  * @author     Stig Bakken <ssb@php.net>
28  * @author     Greg Beaver <cellog@php.net>
29  * @copyright  1997-2009 The Authors
30  * @license    http://opensource.org/licenses/bsd-license.php New BSD License
31  * @version    Release: 1.10.1
32  * @link       http://pear.php.net/package/PEAR
33  * @since      Class available since Release 0.1
34  */
35 class PEAR_Command_Registry extends PEAR_Command_Common
36 {
37     var $commands = array(
38         'list' => array(
39             'summary' => 'List Installed Packages In The Default Channel',
40             'function' => 'doList',
41             'shortcut' => 'l',
42             'options' => array(
43                 'channel' => array(
44                     'shortopt' => 'c',
45                     'doc' => 'list installed packages from this channel',
46                     'arg' => 'CHAN',
47                     ),
48                 'allchannels' => array(
49                     'shortopt' => 'a',
50                     'doc' => 'list installed packages from all channels',
51                     ),
52                 'channelinfo' => array(
53                     'shortopt' => 'i',
54                     'doc' => 'output fully channel-aware data, even on failure',
55                     ),
56                 ),
57             'doc' => '<package>
58 If invoked without parameters, this command lists the PEAR packages
59 installed in your php_dir ({config php_dir}).  With a parameter, it
60 lists the files in a package.
61 ',
62             ),
63         'list-files' => array(
64             'summary' => 'List Files In Installed Package',
65             'function' => 'doFileList',
66             'shortcut' => 'fl',
67             'options' => array(),
68             'doc' => '<package>
69 List the files in an installed package.
70 '
71             ),
72         'shell-test' => array(
73             'summary' => 'Shell Script Test',
74             'function' => 'doShellTest',
75             'shortcut' => 'st',
76             'options' => array(),
77             'doc' => '<package> [[relation] version]
78 Tests if a package is installed in the system. Will exit(1) if it is not.
79    <relation>   The version comparison operator. One of:
80                 <, lt, <=, le, >, gt, >=, ge, ==, =, eq, !=, <>, ne
81    <version>    The version to compare with
82 '),
83         'info' => array(
84             'summary'  => 'Display information about a package',
85             'function' => 'doInfo',
86             'shortcut' => 'in',
87             'options'  => array(),
88             'doc'      => '<package>
89 Displays information about a package. The package argument may be a
90 local package file, an URL to a package file, or the name of an
91 installed package.'
92             )
93         );
94
95     /**
96      * PEAR_Command_Registry constructor.
97      *
98      * @access public
99      */
100     function __construct(&$ui, &$config)
101     {
102         parent::__construct($ui, $config);
103     }
104
105     function _sortinfo($a, $b)
106     {
107         $apackage = isset($a['package']) ? $a['package'] : $a['name'];
108         $bpackage = isset($b['package']) ? $b['package'] : $b['name'];
109         return strcmp($apackage, $bpackage);
110     }
111
112     function doList($command, $options, $params)
113     {
114         $reg = &$this->config->getRegistry();
115         $channelinfo = isset($options['channelinfo']);
116         if (isset($options['allchannels']) && !$channelinfo) {
117             return $this->doListAll($command, array(), $params);
118         }
119
120         if (isset($options['allchannels']) && $channelinfo) {
121             // allchannels with $channelinfo
122             unset($options['allchannels']);
123             $channels = $reg->getChannels();
124             $errors = array();
125             PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
126             foreach ($channels as $channel) {
127                 $options['channel'] = $channel->getName();
128                 $ret = $this->doList($command, $options, $params);
129
130                 if (PEAR::isError($ret)) {
131                     $errors[] = $ret;
132                 }
133             }
134
135             PEAR::staticPopErrorHandling();
136             if (count($errors)) {
137                 // for now, only give first error
138                 return PEAR::raiseError($errors[0]);
139             }
140
141             return true;
142         }
143
144         if (count($params) === 1) {
145             return $this->doFileList($command, $options, $params);
146         }
147
148         if (isset($options['channel'])) {
149             if (!$reg->channelExists($options['channel'])) {
150                 return $this->raiseError('Channel "' . $options['channel'] .'" does not exist');
151             }
152
153             $channel = $reg->channelName($options['channel']);
154         } else {
155             $channel = $this->config->get('default_channel');
156         }
157
158         $installed = $reg->packageInfo(null, null, $channel);
159         usort($installed, array(&$this, '_sortinfo'));
160
161         $data = array(
162             'caption' => 'Installed packages, channel ' .
163                 $channel . ':',
164             'border' => true,
165             'headline' => array('Package', 'Version', 'State'),
166             'channel' => $channel,
167             );
168         if ($channelinfo) {
169             $data['headline'] = array('Channel', 'Package', 'Version', 'State');
170         }
171
172         if (count($installed) && !isset($data['data'])) {
173             $data['data'] = array();
174         }
175
176         foreach ($installed as $package) {
177             $pobj = $reg->getPackage(isset($package['package']) ?
178                                         $package['package'] : $package['name'], $channel);
179             if ($channelinfo) {
180                 $packageinfo = array($pobj->getChannel(), $pobj->getPackage(), $pobj->getVersion(),
181                                     $pobj->getState() ? $pobj->getState() : null);
182             } else {
183                 $packageinfo = array($pobj->getPackage(), $pobj->getVersion(),
184                                     $pobj->getState() ? $pobj->getState() : null);
185             }
186             $data['data'][] = $packageinfo;
187         }
188
189         if (count($installed) === 0) {
190             if (!$channelinfo) {
191                 $data = '(no packages installed from channel ' . $channel . ')';
192             } else {
193                 $data = array(
194                     'caption' => 'Installed packages, channel ' .
195                         $channel . ':',
196                     'border' => true,
197                     'channel' => $channel,
198                     'data' => array(array('(no packages installed)')),
199                 );
200             }
201         }
202
203         $this->ui->outputData($data, $command);
204         return true;
205     }
206
207     function doListAll($command, $options, $params)
208     {
209         // This duplicate code is deprecated over
210         // list --channelinfo, which gives identical
211         // output for list and list --allchannels.
212         $reg = &$this->config->getRegistry();
213         $installed = $reg->packageInfo(null, null, null);
214         foreach ($installed as $channel => $packages) {
215             usort($packages, array($this, '_sortinfo'));
216             $data = array(
217                 'caption'  => 'Installed packages, channel ' . $channel . ':',
218                 'border'   => true,
219                 'headline' => array('Package', 'Version', 'State'),
220                 'channel'  => $channel
221             );
222
223             foreach ($packages as $package) {
224                 $p = isset($package['package']) ? $package['package'] : $package['name'];
225                 $pobj = $reg->getPackage($p, $channel);
226                 $data['data'][] = array($pobj->getPackage(), $pobj->getVersion(),
227                                         $pobj->getState() ? $pobj->getState() : null);
228             }
229
230             // Adds a blank line after each section
231             $data['data'][] = array();
232
233             if (count($packages) === 0) {
234                 $data = array(
235                     'caption' => 'Installed packages, channel ' . $channel . ':',
236                     'border' => true,
237                     'data' => array(array('(no packages installed)'), array()),
238                     'channel' => $channel
239                     );
240             }
241             $this->ui->outputData($data, $command);
242         }
243         return true;
244     }
245
246     function doFileList($command, $options, $params)
247     {
248         if (count($params) !== 1) {
249             return $this->raiseError('list-files expects 1 parameter');
250         }
251
252         $reg = &$this->config->getRegistry();
253         $fp = false;
254         if (!is_dir($params[0]) && (file_exists($params[0]) || $fp = @fopen($params[0], 'r'))) {
255             if ($fp) {
256                 fclose($fp);
257             }
258
259             if (!class_exists('PEAR_PackageFile')) {
260                 require_once 'PEAR/PackageFile.php';
261             }
262
263             $pkg = new PEAR_PackageFile($this->config, $this->_debug);
264             PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
265             $info = &$pkg->fromAnyFile($params[0], PEAR_VALIDATE_NORMAL);
266             PEAR::staticPopErrorHandling();
267             $headings = array('Package File', 'Install Path');
268             $installed = false;
269         } else {
270             PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
271             $parsed = $reg->parsePackageName($params[0], $this->config->get('default_channel'));
272             PEAR::staticPopErrorHandling();
273             if (PEAR::isError($parsed)) {
274                 return $this->raiseError($parsed);
275             }
276
277             $info = &$reg->getPackage($parsed['package'], $parsed['channel']);
278             $headings = array('Type', 'Install Path');
279             $installed = true;
280         }
281
282         if (PEAR::isError($info)) {
283             return $this->raiseError($info);
284         }
285
286         if ($info === null) {
287             return $this->raiseError("`$params[0]' not installed");
288         }
289
290         $list = ($info->getPackagexmlVersion() == '1.0' || $installed) ?
291             $info->getFilelist() : $info->getContents();
292         if ($installed) {
293             $caption = 'Installed Files For ' . $params[0];
294         } else {
295             $caption = 'Contents of ' . basename($params[0]);
296         }
297
298         $data = array(
299             'caption' => $caption,
300             'border' => true,
301             'headline' => $headings);
302         if ($info->getPackagexmlVersion() == '1.0' || $installed) {
303             foreach ($list as $file => $att) {
304                 if ($installed) {
305                     if (empty($att['installed_as'])) {
306                         continue;
307                     }
308                     $data['data'][] = array($att['role'], $att['installed_as']);
309                 } else {
310                     if (isset($att['baseinstalldir']) && !in_array($att['role'],
311                           array('test', 'data', 'doc'))) {
312                         $dest = $att['baseinstalldir'] . DIRECTORY_SEPARATOR .
313                             $file;
314                     } else {
315                         $dest = $file;
316                     }
317                     switch ($att['role']) {
318                         case 'test':
319                         case 'data':
320                         case 'doc':
321                             $role = $att['role'];
322                             if ($role == 'test') {
323                                 $role .= 's';
324                             }
325                             $dest = $this->config->get($role . '_dir') . DIRECTORY_SEPARATOR .
326                                 $info->getPackage() . DIRECTORY_SEPARATOR . $dest;
327                             break;
328                         case 'php':
329                         default:
330                             $dest = $this->config->get('php_dir') . DIRECTORY_SEPARATOR .
331                                 $dest;
332                     }
333                     $ds2 = DIRECTORY_SEPARATOR . DIRECTORY_SEPARATOR;
334                     $dest = preg_replace(array('!\\\\+!', '!/!', "!$ds2+!"),
335                                                     array(DIRECTORY_SEPARATOR,
336                                                           DIRECTORY_SEPARATOR,
337                                                           DIRECTORY_SEPARATOR),
338                                                     $dest);
339                     $file = preg_replace('!/+!', '/', $file);
340                     $data['data'][] = array($file, $dest);
341                 }
342             }
343         } else { // package.xml 2.0, not installed
344             if (!isset($list['dir']['file'][0])) {
345                 $list['dir']['file'] = array($list['dir']['file']);
346             }
347
348             foreach ($list['dir']['file'] as $att) {
349                 $att = $att['attribs'];
350                 $file = $att['name'];
351                 $role = &PEAR_Installer_Role::factory($info, $att['role'], $this->config);
352                 $role->setup($this, $info, $att, $file);
353                 if (!$role->isInstallable()) {
354                     $dest = '(not installable)';
355                 } else {
356                     $dest = $role->processInstallation($info, $att, $file, '');
357                     if (PEAR::isError($dest)) {
358                         $dest = '(Unknown role "' . $att['role'] . ')';
359                     } else {
360                         list(,, $dest) = $dest;
361                     }
362                 }
363                 $data['data'][] = array($file, $dest);
364             }
365         }
366
367         $this->ui->outputData($data, $command);
368         return true;
369     }
370
371     function doShellTest($command, $options, $params)
372     {
373         if (count($params) < 1) {
374             return PEAR::raiseError('ERROR, usage: pear shell-test packagename [[relation] version]');
375         }
376
377         PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
378         $reg = &$this->config->getRegistry();
379         $info = $reg->parsePackageName($params[0], $this->config->get('default_channel'));
380         if (PEAR::isError($info)) {
381             exit(1); // invalid package name
382         }
383
384         $package = $info['package'];
385         $channel = $info['channel'];
386         // "pear shell-test Foo"
387         if (!$reg->packageExists($package, $channel)) {
388             if ($channel == 'pecl.php.net') {
389                 if ($reg->packageExists($package, 'pear.php.net')) {
390                     $channel = 'pear.php.net'; // magically change channels for extensions
391                 }
392             }
393         }
394
395         if (count($params) === 1) {
396             if (!$reg->packageExists($package, $channel)) {
397                 exit(1);
398             }
399             // "pear shell-test Foo 1.0"
400         } elseif (count($params) === 2) {
401             $v = $reg->packageInfo($package, 'version', $channel);
402             if (!$v || !version_compare("$v", "{$params[1]}", "ge")) {
403                 exit(1);
404             }
405             // "pear shell-test Foo ge 1.0"
406         } elseif (count($params) === 3) {
407             $v = $reg->packageInfo($package, 'version', $channel);
408             if (!$v || !version_compare("$v", "{$params[2]}", $params[1])) {
409                 exit(1);
410             }
411         } else {
412             PEAR::staticPopErrorHandling();
413             $this->raiseError("$command: expects 1 to 3 parameters");
414             exit(1);
415         }
416     }
417
418     function doInfo($command, $options, $params)
419     {
420         if (count($params) !== 1) {
421             return $this->raiseError('pear info expects 1 parameter');
422         }
423
424         $info = $fp = false;
425         $reg = &$this->config->getRegistry();
426         if (is_file($params[0]) && !is_dir($params[0]) &&
427             (file_exists($params[0]) || $fp = @fopen($params[0], 'r'))
428         ) {
429             if ($fp) {
430                 fclose($fp);
431             }
432
433             if (!class_exists('PEAR_PackageFile')) {
434                 require_once 'PEAR/PackageFile.php';
435             }
436
437             $pkg = new PEAR_PackageFile($this->config, $this->_debug);
438             PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
439             $obj = &$pkg->fromAnyFile($params[0], PEAR_VALIDATE_NORMAL);
440             PEAR::staticPopErrorHandling();
441             if (PEAR::isError($obj)) {
442                 $uinfo = $obj->getUserInfo();
443                 if (is_array($uinfo)) {
444                     foreach ($uinfo as $message) {
445                         if (is_array($message)) {
446                             $message = $message['message'];
447                         }
448                         $this->ui->outputData($message);
449                     }
450                 }
451
452                 return $this->raiseError($obj);
453             }
454
455             if ($obj->getPackagexmlVersion() != '1.0') {
456                 return $this->_doInfo2($command, $options, $params, $obj, false);
457             }
458
459             $info = $obj->toArray();
460         } else {
461             $parsed = $reg->parsePackageName($params[0], $this->config->get('default_channel'));
462             if (PEAR::isError($parsed)) {
463                 return $this->raiseError($parsed);
464             }
465
466             $package = $parsed['package'];
467             $channel = $parsed['channel'];
468             $info = $reg->packageInfo($package, null, $channel);
469             if (isset($info['old'])) {
470                 $obj = $reg->getPackage($package, $channel);
471                 return $this->_doInfo2($command, $options, $params, $obj, true);
472             }
473         }
474
475         if (PEAR::isError($info)) {
476             return $info;
477         }
478
479         if (empty($info)) {
480             $this->raiseError("No information found for `$params[0]'");
481             return;
482         }
483
484         unset($info['filelist']);
485         unset($info['dirtree']);
486         unset($info['changelog']);
487         if (isset($info['xsdversion'])) {
488             $info['package.xml version'] = $info['xsdversion'];
489             unset($info['xsdversion']);
490         }
491
492         if (isset($info['packagerversion'])) {
493             $info['packaged with PEAR version'] = $info['packagerversion'];
494             unset($info['packagerversion']);
495         }
496
497         $keys = array_keys($info);
498         $longtext = array('description', 'summary');
499         foreach ($keys as $key) {
500             if (is_array($info[$key])) {
501                 switch ($key) {
502                     case 'maintainers': {
503                         $i = 0;
504                         $mstr = '';
505                         foreach ($info[$key] as $m) {
506                             if ($i++ > 0) {
507                                 $mstr .= "\n";
508                             }
509                             $mstr .= $m['name'] . " <";
510                             if (isset($m['email'])) {
511                                 $mstr .= $m['email'];
512                             } else {
513                                 $mstr .= $m['handle'] . '@php.net';
514                             }
515                             $mstr .= "> ($m[role])";
516                         }
517                         $info[$key] = $mstr;
518                         break;
519                     }
520                     case 'release_deps': {
521                         $i = 0;
522                         $dstr = '';
523                         foreach ($info[$key] as $d) {
524                             if (isset($this->_deps_rel_trans[$d['rel']])) {
525                                 $rel = $this->_deps_rel_trans[$d['rel']];
526                             } else {
527                                 $rel = $d['rel'];
528                             }
529                             if (isset($this->_deps_type_trans[$d['type']])) {
530                                 $type = ucfirst($this->_deps_type_trans[$d['type']]);
531                             } else {
532                                 $type = $d['type'];
533                             }
534                             if (isset($d['name'])) {
535                                 $name = $d['name'] . ' ';
536                             } else {
537                                 $name = '';
538                             }
539                             if (isset($d['version'])) {
540                                 $version = $d['version'] . ' ';
541                             } else {
542                                 $version = '';
543                             }
544                             if (isset($d['optional']) && $d['optional'] == 'yes') {
545                                 $optional = ' (optional)';
546                             } else {
547                                 $optional = '';
548                             }
549                             $dstr .= "$type $name$rel $version$optional\n";
550                         }
551                         $info[$key] = $dstr;
552                         break;
553                     }
554                     case 'provides' : {
555                         $debug = $this->config->get('verbose');
556                         if ($debug < 2) {
557                             $pstr = 'Classes: ';
558                         } else {
559                             $pstr = '';
560                         }
561                         $i = 0;
562                         foreach ($info[$key] as $p) {
563                             if ($debug < 2 && $p['type'] != "class") {
564                                 continue;
565                             }
566                             // Only print classes when verbosity mode is < 2
567                             if ($debug < 2) {
568                                 if ($i++ > 0) {
569                                     $pstr .= ", ";
570                                 }
571                                 $pstr .= $p['name'];
572                             } else {
573                                 if ($i++ > 0) {
574                                     $pstr .= "\n";
575                                 }
576                                 $pstr .= ucfirst($p['type']) . " " . $p['name'];
577                                 if (isset($p['explicit']) && $p['explicit'] == 1) {
578                                     $pstr .= " (explicit)";
579                                 }
580                             }
581                         }
582                         $info[$key] = $pstr;
583                         break;
584                     }
585                     case 'configure_options' : {
586                         foreach ($info[$key] as $i => $p) {
587                             $info[$key][$i] = array_map(null, array_keys($p), array_values($p));
588                             $info[$key][$i] = array_map(create_function('$a',
589                                 'return join(" = ",$a);'), $info[$key][$i]);
590                             $info[$key][$i] = implode(', ', $info[$key][$i]);
591                         }
592                         $info[$key] = implode("\n", $info[$key]);
593                         break;
594                     }
595                     default: {
596                         $info[$key] = implode(", ", $info[$key]);
597                         break;
598                     }
599                 }
600             }
601
602             if ($key == '_lastmodified') {
603                 $hdate = date('Y-m-d', $info[$key]);
604                 unset($info[$key]);
605                 $info['Last Modified'] = $hdate;
606             } elseif ($key == '_lastversion') {
607                 $info['Previous Installed Version'] = $info[$key] ? $info[$key] : '- None -';
608                 unset($info[$key]);
609             } else {
610                 $info[$key] = trim($info[$key]);
611                 if (in_array($key, $longtext)) {
612                     $info[$key] = preg_replace('/  +/', ' ', $info[$key]);
613                 }
614             }
615         }
616
617         $caption = 'About ' . $info['package'] . '-' . $info['version'];
618         $data = array(
619             'caption' => $caption,
620             'border' => true);
621         foreach ($info as $key => $value) {
622             $key = ucwords(trim(str_replace('_', ' ', $key)));
623             $data['data'][] = array($key, $value);
624         }
625         $data['raw'] = $info;
626
627         $this->ui->outputData($data, 'package-info');
628     }
629
630     /**
631      * @access private
632      */
633     function _doInfo2($command, $options, $params, &$obj, $installed)
634     {
635         $reg = &$this->config->getRegistry();
636         $caption = 'About ' . $obj->getChannel() . '/' .$obj->getPackage() . '-' .
637             $obj->getVersion();
638         $data = array(
639             'caption' => $caption,
640             'border' => true);
641         switch ($obj->getPackageType()) {
642             case 'php' :
643                 $release = 'PEAR-style PHP-based Package';
644             break;
645             case 'extsrc' :
646                 $release = 'PECL-style PHP extension (source code)';
647             break;
648             case 'zendextsrc' :
649                 $release = 'PECL-style Zend extension (source code)';
650             break;
651             case 'extbin' :
652                 $release = 'PECL-style PHP extension (binary)';
653             break;
654             case 'zendextbin' :
655                 $release = 'PECL-style Zend extension (binary)';
656             break;
657             case 'bundle' :
658                 $release = 'Package bundle (collection of packages)';
659             break;
660         }
661         $extends = $obj->getExtends();
662         $extends = $extends ?
663             $obj->getPackage() . ' (extends ' . $extends . ')' : $obj->getPackage();
664         if ($src = $obj->getSourcePackage()) {
665             $extends .= ' (source package ' . $src['channel'] . '/' . $src['package'] . ')';
666         }
667
668         $info = array(
669             'Release Type' => $release,
670             'Name' => $extends,
671             'Channel' => $obj->getChannel(),
672             'Summary' => preg_replace('/  +/', ' ', $obj->getSummary()),
673             'Description' => preg_replace('/  +/', ' ', $obj->getDescription()),
674             );
675         $info['Maintainers'] = '';
676         foreach (array('lead', 'developer', 'contributor', 'helper') as $role) {
677             $leads = $obj->{"get{$role}s"}();
678             if (!$leads) {
679                 continue;
680             }
681
682             if (isset($leads['active'])) {
683                 $leads = array($leads);
684             }
685
686             foreach ($leads as $lead) {
687                 if (!empty($info['Maintainers'])) {
688                     $info['Maintainers'] .= "\n";
689                 }
690
691                 $active = $lead['active'] == 'no' ? ', inactive' : '';
692                 $info['Maintainers'] .= $lead['name'] . ' <';
693                 $info['Maintainers'] .= $lead['email'] . "> ($role$active)";
694             }
695         }
696
697         $info['Release Date'] = $obj->getDate();
698         if ($time = $obj->getTime()) {
699             $info['Release Date'] .= ' ' . $time;
700         }
701
702         $info['Release Version'] = $obj->getVersion() . ' (' . $obj->getState() . ')';
703         $info['API Version'] = $obj->getVersion('api') . ' (' . $obj->getState('api') . ')';
704         $info['License'] = $obj->getLicense();
705         $uri = $obj->getLicenseLocation();
706         if ($uri) {
707             if (isset($uri['uri'])) {
708                 $info['License'] .= ' (' . $uri['uri'] . ')';
709             } else {
710                 $extra = $obj->getInstalledLocation($info['filesource']);
711                 if ($extra) {
712                     $info['License'] .= ' (' . $uri['filesource'] . ')';
713                 }
714             }
715         }
716
717         $info['Release Notes'] = $obj->getNotes();
718         if ($compat = $obj->getCompatible()) {
719             if (!isset($compat[0])) {
720                 $compat = array($compat);
721             }
722
723             $info['Compatible with'] = '';
724             foreach ($compat as $package) {
725                 $info['Compatible with'] .= $package['channel'] . '/' . $package['name'] .
726                     "\nVersions >= " . $package['min'] . ', <= ' . $package['max'];
727                 if (isset($package['exclude'])) {
728                     if (is_array($package['exclude'])) {
729                         $package['exclude'] = implode(', ', $package['exclude']);
730                     }
731
732                     if (!isset($info['Not Compatible with'])) {
733                         $info['Not Compatible with'] = '';
734                     } else {
735                         $info['Not Compatible with'] .= "\n";
736                     }
737                     $info['Not Compatible with'] .= $package['channel'] . '/' .
738                         $package['name'] . "\nVersions " . $package['exclude'];
739                 }
740             }
741         }
742
743         $usesrole = $obj->getUsesrole();
744         if ($usesrole) {
745             if (!isset($usesrole[0])) {
746                 $usesrole = array($usesrole);
747             }
748
749             foreach ($usesrole as $roledata) {
750                 if (isset($info['Uses Custom Roles'])) {
751                     $info['Uses Custom Roles'] .= "\n";
752                 } else {
753                     $info['Uses Custom Roles'] = '';
754                 }
755
756                 if (isset($roledata['package'])) {
757                     $rolepackage = $reg->parsedPackageNameToString($roledata, true);
758                 } else {
759                     $rolepackage = $roledata['uri'];
760                 }
761                 $info['Uses Custom Roles'] .= $roledata['role'] . ' (' . $rolepackage . ')';
762             }
763         }
764
765         $usestask = $obj->getUsestask();
766         if ($usestask) {
767             if (!isset($usestask[0])) {
768                 $usestask = array($usestask);
769             }
770
771             foreach ($usestask as $taskdata) {
772                 if (isset($info['Uses Custom Tasks'])) {
773                     $info['Uses Custom Tasks'] .= "\n";
774                 } else {
775                     $info['Uses Custom Tasks'] = '';
776                 }
777
778                 if (isset($taskdata['package'])) {
779                     $taskpackage = $reg->parsedPackageNameToString($taskdata, true);
780                 } else {
781                     $taskpackage = $taskdata['uri'];
782                 }
783                 $info['Uses Custom Tasks'] .= $taskdata['task'] . ' (' . $taskpackage . ')';
784             }
785         }
786
787         $deps = $obj->getDependencies();
788         $info['Required Dependencies'] = 'PHP version ' . $deps['required']['php']['min'];
789         if (isset($deps['required']['php']['max'])) {
790             $info['Required Dependencies'] .= '-' . $deps['required']['php']['max'] . "\n";
791         } else {
792             $info['Required Dependencies'] .= "\n";
793         }
794
795         if (isset($deps['required']['php']['exclude'])) {
796             if (!isset($info['Not Compatible with'])) {
797                 $info['Not Compatible with'] = '';
798             } else {
799                 $info['Not Compatible with'] .= "\n";
800             }
801
802             if (is_array($deps['required']['php']['exclude'])) {
803                 $deps['required']['php']['exclude'] =
804                     implode(', ', $deps['required']['php']['exclude']);
805             }
806             $info['Not Compatible with'] .= "PHP versions\n  " .
807                 $deps['required']['php']['exclude'];
808         }
809
810         $info['Required Dependencies'] .= 'PEAR installer version';
811         if (isset($deps['required']['pearinstaller']['max'])) {
812             $info['Required Dependencies'] .= 's ' .
813                 $deps['required']['pearinstaller']['min'] . '-' .
814                 $deps['required']['pearinstaller']['max'];
815         } else {
816             $info['Required Dependencies'] .= ' ' .
817                 $deps['required']['pearinstaller']['min'] . ' or newer';
818         }
819
820         if (isset($deps['required']['pearinstaller']['exclude'])) {
821             if (!isset($info['Not Compatible with'])) {
822                 $info['Not Compatible with'] = '';
823             } else {
824                 $info['Not Compatible with'] .= "\n";
825             }
826
827             if (is_array($deps['required']['pearinstaller']['exclude'])) {
828                 $deps['required']['pearinstaller']['exclude'] =
829                     implode(', ', $deps['required']['pearinstaller']['exclude']);
830             }
831             $info['Not Compatible with'] .= "PEAR installer\n  Versions " .
832                 $deps['required']['pearinstaller']['exclude'];
833         }
834
835         foreach (array('Package', 'Extension') as $type) {
836             $index = strtolower($type);
837             if (isset($deps['required'][$index])) {
838                 if (isset($deps['required'][$index]['name'])) {
839                     $deps['required'][$index] = array($deps['required'][$index]);
840                 }
841
842                 foreach ($deps['required'][$index] as $package) {
843                     if (isset($package['conflicts'])) {
844                         $infoindex = 'Not Compatible with';
845                         if (!isset($info['Not Compatible with'])) {
846                             $info['Not Compatible with'] = '';
847                         } else {
848                             $info['Not Compatible with'] .= "\n";
849                         }
850                     } else {
851                         $infoindex = 'Required Dependencies';
852                         $info[$infoindex] .= "\n";
853                     }
854
855                     if ($index == 'extension') {
856                         $name = $package['name'];
857                     } else {
858                         if (isset($package['channel'])) {
859                             $name = $package['channel'] . '/' . $package['name'];
860                         } else {
861                             $name = '__uri/' . $package['name'] . ' (static URI)';
862                         }
863                     }
864
865                     $info[$infoindex] .= "$type $name";
866                     if (isset($package['uri'])) {
867                         $info[$infoindex] .= "\n  Download URI: $package[uri]";
868                         continue;
869                     }
870
871                     if (isset($package['max']) && isset($package['min'])) {
872                         $info[$infoindex] .= " \n  Versions " .
873                             $package['min'] . '-' . $package['max'];
874                     } elseif (isset($package['min'])) {
875                         $info[$infoindex] .= " \n  Version " .
876                             $package['min'] . ' or newer';
877                     } elseif (isset($package['max'])) {
878                         $info[$infoindex] .= " \n  Version " .
879                             $package['max'] . ' or older';
880                     }
881
882                     if (isset($package['recommended'])) {
883                         $info[$infoindex] .= "\n  Recommended version: $package[recommended]";
884                     }
885
886                     if (isset($package['exclude'])) {
887                         if (!isset($info['Not Compatible with'])) {
888                             $info['Not Compatible with'] = '';
889                         } else {
890                             $info['Not Compatible with'] .= "\n";
891                         }
892
893                         if (is_array($package['exclude'])) {
894                             $package['exclude'] = implode(', ', $package['exclude']);
895                         }
896
897                         $package['package'] = $package['name']; // for parsedPackageNameToString
898                          if (isset($package['conflicts'])) {
899                             $info['Not Compatible with'] .= '=> except ';
900                         }
901                        $info['Not Compatible with'] .= 'Package ' .
902                             $reg->parsedPackageNameToString($package, true);
903                         $info['Not Compatible with'] .= "\n  Versions " . $package['exclude'];
904                     }
905                 }
906             }
907         }
908
909         if (isset($deps['required']['os'])) {
910             if (isset($deps['required']['os']['name'])) {
911                 $dep['required']['os']['name'] = array($dep['required']['os']['name']);
912             }
913
914             foreach ($dep['required']['os'] as $os) {
915                 if (isset($os['conflicts']) && $os['conflicts'] == 'yes') {
916                     if (!isset($info['Not Compatible with'])) {
917                         $info['Not Compatible with'] = '';
918                     } else {
919                         $info['Not Compatible with'] .= "\n";
920                     }
921                     $info['Not Compatible with'] .= "$os[name] Operating System";
922                 } else {
923                     $info['Required Dependencies'] .= "\n";
924                     $info['Required Dependencies'] .= "$os[name] Operating System";
925                 }
926             }
927         }
928
929         if (isset($deps['required']['arch'])) {
930             if (isset($deps['required']['arch']['pattern'])) {
931                 $dep['required']['arch']['pattern'] = array($dep['required']['os']['pattern']);
932             }
933
934             foreach ($dep['required']['arch'] as $os) {
935                 if (isset($os['conflicts']) && $os['conflicts'] == 'yes') {
936                     if (!isset($info['Not Compatible with'])) {
937                         $info['Not Compatible with'] = '';
938                     } else {
939                         $info['Not Compatible with'] .= "\n";
940                     }
941                     $info['Not Compatible with'] .= "OS/Arch matching pattern '/$os[pattern]/'";
942                 } else {
943                     $info['Required Dependencies'] .= "\n";
944                     $info['Required Dependencies'] .= "OS/Arch matching pattern '/$os[pattern]/'";
945                 }
946             }
947         }
948
949         if (isset($deps['optional'])) {
950             foreach (array('Package', 'Extension') as $type) {
951                 $index = strtolower($type);
952                 if (isset($deps['optional'][$index])) {
953                     if (isset($deps['optional'][$index]['name'])) {
954                         $deps['optional'][$index] = array($deps['optional'][$index]);
955                     }
956
957                     foreach ($deps['optional'][$index] as $package) {
958                         if (isset($package['conflicts']) && $package['conflicts'] == 'yes') {
959                             $infoindex = 'Not Compatible with';
960                             if (!isset($info['Not Compatible with'])) {
961                                 $info['Not Compatible with'] = '';
962                             } else {
963                                 $info['Not Compatible with'] .= "\n";
964                             }
965                         } else {
966                             $infoindex = 'Optional Dependencies';
967                             if (!isset($info['Optional Dependencies'])) {
968                                 $info['Optional Dependencies'] = '';
969                             } else {
970                                 $info['Optional Dependencies'] .= "\n";
971                             }
972                         }
973
974                         if ($index == 'extension') {
975                             $name = $package['name'];
976                         } else {
977                             if (isset($package['channel'])) {
978                                 $name = $package['channel'] . '/' . $package['name'];
979                             } else {
980                                 $name = '__uri/' . $package['name'] . ' (static URI)';
981                             }
982                         }
983
984                         $info[$infoindex] .= "$type $name";
985                         if (isset($package['uri'])) {
986                             $info[$infoindex] .= "\n  Download URI: $package[uri]";
987                             continue;
988                         }
989
990                         if ($infoindex == 'Not Compatible with') {
991                             // conflicts is only used to say that all versions conflict
992                             continue;
993                         }
994
995                         if (isset($package['max']) && isset($package['min'])) {
996                             $info[$infoindex] .= " \n  Versions " .
997                                 $package['min'] . '-' . $package['max'];
998                         } elseif (isset($package['min'])) {
999                             $info[$infoindex] .= " \n  Version " .
1000                                 $package['min'] . ' or newer';
1001                         } elseif (isset($package['max'])) {
1002                             $info[$infoindex] .= " \n  Version " .
1003                                 $package['min'] . ' or older';
1004                         }
1005
1006                         if (isset($package['recommended'])) {
1007                             $info[$infoindex] .= "\n  Recommended version: $package[recommended]";
1008                         }
1009
1010                         if (isset($package['exclude'])) {
1011                             if (!isset($info['Not Compatible with'])) {
1012                                 $info['Not Compatible with'] = '';
1013                             } else {
1014                                 $info['Not Compatible with'] .= "\n";
1015                             }
1016
1017                             if (is_array($package['exclude'])) {
1018                                 $package['exclude'] = implode(', ', $package['exclude']);
1019                             }
1020
1021                             $info['Not Compatible with'] .= "Package $package\n  Versions " .
1022                                 $package['exclude'];
1023                         }
1024                     }
1025                 }
1026             }
1027         }
1028
1029         if (isset($deps['group'])) {
1030             if (!isset($deps['group'][0])) {
1031                 $deps['group'] = array($deps['group']);
1032             }
1033
1034             foreach ($deps['group'] as $group) {
1035                 $info['Dependency Group ' . $group['attribs']['name']] = $group['attribs']['hint'];
1036                 $groupindex = $group['attribs']['name'] . ' Contents';
1037                 $info[$groupindex] = '';
1038                 foreach (array('Package', 'Extension') as $type) {
1039                     $index = strtolower($type);
1040                     if (isset($group[$index])) {
1041                         if (isset($group[$index]['name'])) {
1042                             $group[$index] = array($group[$index]);
1043                         }
1044
1045                         foreach ($group[$index] as $package) {
1046                             if (!empty($info[$groupindex])) {
1047                                 $info[$groupindex] .= "\n";
1048                             }
1049
1050                             if ($index == 'extension') {
1051                                 $name = $package['name'];
1052                             } else {
1053                                 if (isset($package['channel'])) {
1054                                     $name = $package['channel'] . '/' . $package['name'];
1055                                 } else {
1056                                     $name = '__uri/' . $package['name'] . ' (static URI)';
1057                                 }
1058                             }
1059
1060                             if (isset($package['uri'])) {
1061                                 if (isset($package['conflicts']) && $package['conflicts'] == 'yes') {
1062                                     $info[$groupindex] .= "Not Compatible with $type $name";
1063                                 } else {
1064                                     $info[$groupindex] .= "$type $name";
1065                                 }
1066
1067                                 $info[$groupindex] .= "\n  Download URI: $package[uri]";
1068                                 continue;
1069                             }
1070
1071                             if (isset($package['conflicts']) && $package['conflicts'] == 'yes') {
1072                                 $info[$groupindex] .= "Not Compatible with $type $name";
1073                                 continue;
1074                             }
1075
1076                             $info[$groupindex] .= "$type $name";
1077                             if (isset($package['max']) && isset($package['min'])) {
1078                                 $info[$groupindex] .= " \n  Versions " .
1079                                     $package['min'] . '-' . $package['max'];
1080                             } elseif (isset($package['min'])) {
1081                                 $info[$groupindex] .= " \n  Version " .
1082                                     $package['min'] . ' or newer';
1083                             } elseif (isset($package['max'])) {
1084                                 $info[$groupindex] .= " \n  Version " .
1085                                     $package['min'] . ' or older';
1086                             }
1087
1088                             if (isset($package['recommended'])) {
1089                                 $info[$groupindex] .= "\n  Recommended version: $package[recommended]";
1090                             }
1091
1092                             if (isset($package['exclude'])) {
1093                                 if (!isset($info['Not Compatible with'])) {
1094                                     $info['Not Compatible with'] = '';
1095                                 } else {
1096                                     $info[$groupindex] .= "Not Compatible with\n";
1097                                 }
1098
1099                                 if (is_array($package['exclude'])) {
1100                                     $package['exclude'] = implode(', ', $package['exclude']);
1101                                 }
1102                                 $info[$groupindex] .= "  Package $package\n  Versions " .
1103                                     $package['exclude'];
1104                             }
1105                         }
1106                     }
1107                 }
1108             }
1109         }
1110
1111         if ($obj->getPackageType() == 'bundle') {
1112             $info['Bundled Packages'] = '';
1113             foreach ($obj->getBundledPackages() as $package) {
1114                 if (!empty($info['Bundled Packages'])) {
1115                     $info['Bundled Packages'] .= "\n";
1116                 }
1117
1118                 if (isset($package['uri'])) {
1119                     $info['Bundled Packages'] .= '__uri/' . $package['name'];
1120                     $info['Bundled Packages'] .= "\n  (URI: $package[uri]";
1121                 } else {
1122                     $info['Bundled Packages'] .= $package['channel'] . '/' . $package['name'];
1123                 }
1124             }
1125         }
1126
1127         $info['package.xml version'] = '2.0';
1128         if ($installed) {
1129             if ($obj->getLastModified()) {
1130                 $info['Last Modified'] = date('Y-m-d H:i', $obj->getLastModified());
1131             }
1132
1133             $v = $obj->getLastInstalledVersion();
1134             $info['Previous Installed Version'] = $v ? $v : '- None -';
1135         }
1136
1137         foreach ($info as $key => $value) {
1138             $data['data'][] = array($key, $value);
1139         }
1140
1141         $data['raw'] = $obj->getArray(); // no validation needed
1142         $this->ui->outputData($data, 'package-info');
1143     }
1144 }