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