Initial repo created
[timetracker.git] / WEB-INF / lib / pear / PEAR / PackageFile / Generator / v1.php
1 <?php
2 /**
3  * package.xml generation class, package.xml version 1.0
4  *
5  * PHP versions 4 and 5
6  *
7  * @category   pear
8  * @package    PEAR
9  * @author     Greg Beaver <cellog@php.net>
10  * @copyright  1997-2009 The Authors
11  * @license    http://opensource.org/licenses/bsd-license.php New BSD License
12  * @version    CVS: $Id: v1.php 313023 2011-07-06 19:17:11Z dufuz $
13  * @link       http://pear.php.net/package/PEAR
14  * @since      File available since Release 1.4.0a1
15  */
16 /**
17  * needed for PEAR_VALIDATE_* constants
18  */
19 require_once 'PEAR/Validate.php';
20 require_once 'System.php';
21 require_once 'PEAR/PackageFile/v2.php';
22 /**
23  * This class converts a PEAR_PackageFile_v1 object into any output format.
24  *
25  * Supported output formats include array, XML string, and a PEAR_PackageFile_v2
26  * object, for converting package.xml 1.0 into package.xml 2.0 with no sweat.
27  * @category   pear
28  * @package    PEAR
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 1.4.0a1
35  */
36 class PEAR_PackageFile_Generator_v1
37 {
38     /**
39      * @var PEAR_PackageFile_v1
40      */
41     var $_packagefile;
42     function PEAR_PackageFile_Generator_v1(&$packagefile)
43     {
44         $this->_packagefile = &$packagefile;
45     }
46
47     function getPackagerVersion()
48     {
49         return '1.9.4';
50     }
51
52     /**
53      * @param PEAR_Packager
54      * @param bool if true, a .tgz is written, otherwise a .tar is written
55      * @param string|null directory in which to save the .tgz
56      * @return string|PEAR_Error location of package or error object
57      */
58     function toTgz(&$packager, $compress = true, $where = null)
59     {
60         require_once 'Archive/Tar.php';
61         if ($where === null) {
62             if (!($where = System::mktemp(array('-d')))) {
63                 return PEAR::raiseError('PEAR_Packagefile_v1::toTgz: mktemp failed');
64             }
65         } elseif (!@System::mkDir(array('-p', $where))) {
66             return PEAR::raiseError('PEAR_Packagefile_v1::toTgz: "' . $where . '" could' .
67                 ' not be created');
68         }
69         if (file_exists($where . DIRECTORY_SEPARATOR . 'package.xml') &&
70               !is_file($where . DIRECTORY_SEPARATOR . 'package.xml')) {
71             return PEAR::raiseError('PEAR_Packagefile_v1::toTgz: unable to save package.xml as' .
72                 ' "' . $where . DIRECTORY_SEPARATOR . 'package.xml"');
73         }
74         if (!$this->_packagefile->validate(PEAR_VALIDATE_PACKAGING)) {
75             return PEAR::raiseError('PEAR_Packagefile_v1::toTgz: invalid package file');
76         }
77         $pkginfo = $this->_packagefile->getArray();
78         $ext = $compress ? '.tgz' : '.tar';
79         $pkgver = $pkginfo['package'] . '-' . $pkginfo['version'];
80         $dest_package = getcwd() . DIRECTORY_SEPARATOR . $pkgver . $ext;
81         if (file_exists(getcwd() . DIRECTORY_SEPARATOR . $pkgver . $ext) &&
82               !is_file(getcwd() . DIRECTORY_SEPARATOR . $pkgver . $ext)) {
83             return PEAR::raiseError('PEAR_Packagefile_v1::toTgz: cannot create tgz file "' .
84                 getcwd() . DIRECTORY_SEPARATOR . $pkgver . $ext . '"');
85         }
86         if ($pkgfile = $this->_packagefile->getPackageFile()) {
87             $pkgdir = dirname(realpath($pkgfile));
88             $pkgfile = basename($pkgfile);
89         } else {
90             return PEAR::raiseError('PEAR_Packagefile_v1::toTgz: package file object must ' .
91                 'be created from a real file');
92         }
93         // {{{ Create the package file list
94         $filelist = array();
95         $i = 0;
96
97         foreach ($this->_packagefile->getFilelist() as $fname => $atts) {
98             $file = $pkgdir . DIRECTORY_SEPARATOR . $fname;
99             if (!file_exists($file)) {
100                 return PEAR::raiseError("File does not exist: $fname");
101             } else {
102                 $filelist[$i++] = $file;
103                 if (!isset($atts['md5sum'])) {
104                     $this->_packagefile->setFileAttribute($fname, 'md5sum', md5_file($file));
105                 }
106                 $packager->log(2, "Adding file $fname");
107             }
108         }
109         // }}}
110         $packagexml = $this->toPackageFile($where, PEAR_VALIDATE_PACKAGING, 'package.xml', true);
111         if ($packagexml) {
112             $tar =& new Archive_Tar($dest_package, $compress);
113             $tar->setErrorHandling(PEAR_ERROR_RETURN); // XXX Don't print errors
114             // ----- Creates with the package.xml file
115             $ok = $tar->createModify(array($packagexml), '', $where);
116             if (PEAR::isError($ok)) {
117                 return $ok;
118             } elseif (!$ok) {
119                 return PEAR::raiseError('PEAR_Packagefile_v1::toTgz: tarball creation failed');
120             }
121             // ----- Add the content of the package
122             if (!$tar->addModify($filelist, $pkgver, $pkgdir)) {
123                 return PEAR::raiseError('PEAR_Packagefile_v1::toTgz: tarball creation failed');
124             }
125             return $dest_package;
126         }
127     }
128
129     /**
130      * @param string|null directory to place the package.xml in, or null for a temporary dir
131      * @param int one of the PEAR_VALIDATE_* constants
132      * @param string name of the generated file
133      * @param bool if true, then no analysis will be performed on role="php" files
134      * @return string|PEAR_Error path to the created file on success
135      */
136     function toPackageFile($where = null, $state = PEAR_VALIDATE_NORMAL, $name = 'package.xml',
137                            $nofilechecking = false)
138     {
139         if (!$this->_packagefile->validate($state, $nofilechecking)) {
140             return PEAR::raiseError('PEAR_Packagefile_v1::toPackageFile: invalid package.xml',
141                 null, null, null, $this->_packagefile->getValidationWarnings());
142         }
143         if ($where === null) {
144             if (!($where = System::mktemp(array('-d')))) {
145                 return PEAR::raiseError('PEAR_Packagefile_v1::toPackageFile: mktemp failed');
146             }
147         } elseif (!@System::mkDir(array('-p', $where))) {
148             return PEAR::raiseError('PEAR_Packagefile_v1::toPackageFile: "' . $where . '" could' .
149                 ' not be created');
150         }
151         $newpkgfile = $where . DIRECTORY_SEPARATOR . $name;
152         $np = @fopen($newpkgfile, 'wb');
153         if (!$np) {
154             return PEAR::raiseError('PEAR_Packagefile_v1::toPackageFile: unable to save ' .
155                "$name as $newpkgfile");
156         }
157         fwrite($np, $this->toXml($state, true));
158         fclose($np);
159         return $newpkgfile;
160     }
161
162     /**
163      * fix both XML encoding to be UTF8, and replace standard XML entities < > " & '
164      *
165      * @param string $string
166      * @return string
167      * @access private
168      */
169     function _fixXmlEncoding($string)
170     {
171         if (version_compare(phpversion(), '5.0.0', 'lt')) {
172             $string = utf8_encode($string);
173         }
174         return strtr($string, array(
175                                           '&'  => '&amp;',
176                                           '>'  => '&gt;',
177                                           '<'  => '&lt;',
178                                           '"'  => '&quot;',
179                                           '\'' => '&apos;' ));
180     }
181
182     /**
183      * Return an XML document based on the package info (as returned
184      * by the PEAR_Common::infoFrom* methods).
185      *
186      * @return string XML data
187      */
188     function toXml($state = PEAR_VALIDATE_NORMAL, $nofilevalidation = false)
189     {
190         $this->_packagefile->setDate(date('Y-m-d'));
191         if (!$this->_packagefile->validate($state, $nofilevalidation)) {
192             return false;
193         }
194         $pkginfo = $this->_packagefile->getArray();
195         static $maint_map = array(
196             "handle" => "user",
197             "name" => "name",
198             "email" => "email",
199             "role" => "role",
200             );
201         $ret = "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n";
202         $ret .= "<!DOCTYPE package SYSTEM \"http://pear.php.net/dtd/package-1.0\">\n";
203         $ret .= "<package version=\"1.0\" packagerversion=\"1.9.4\">\n" .
204 " <name>$pkginfo[package]</name>";
205         if (isset($pkginfo['extends'])) {
206             $ret .= "\n<extends>$pkginfo[extends]</extends>";
207         }
208         $ret .=
209  "\n <summary>".$this->_fixXmlEncoding($pkginfo['summary'])."</summary>\n" .
210 " <description>".trim($this->_fixXmlEncoding($pkginfo['description']))."\n </description>\n" .
211 " <maintainers>\n";
212         foreach ($pkginfo['maintainers'] as $maint) {
213             $ret .= "  <maintainer>\n";
214             foreach ($maint_map as $idx => $elm) {
215                 $ret .= "   <$elm>";
216                 $ret .= $this->_fixXmlEncoding($maint[$idx]);
217                 $ret .= "</$elm>\n";
218             }
219             $ret .= "  </maintainer>\n";
220         }
221         $ret .= "  </maintainers>\n";
222         $ret .= $this->_makeReleaseXml($pkginfo, false, $state);
223         if (isset($pkginfo['changelog']) && count($pkginfo['changelog']) > 0) {
224             $ret .= " <changelog>\n";
225             foreach ($pkginfo['changelog'] as $oldrelease) {
226                 $ret .= $this->_makeReleaseXml($oldrelease, true);
227             }
228             $ret .= " </changelog>\n";
229         }
230         $ret .= "</package>\n";
231         return $ret;
232     }
233
234     // }}}
235     // {{{ _makeReleaseXml()
236
237     /**
238      * Generate part of an XML description with release information.
239      *
240      * @param array  $pkginfo    array with release information
241      * @param bool   $changelog  whether the result will be in a changelog element
242      *
243      * @return string XML data
244      *
245      * @access private
246      */
247     function _makeReleaseXml($pkginfo, $changelog = false, $state = PEAR_VALIDATE_NORMAL)
248     {
249         // XXX QUOTE ENTITIES IN PCDATA, OR EMBED IN CDATA BLOCKS!!
250         $indent = $changelog ? "  " : "";
251         $ret = "$indent <release>\n";
252         if (!empty($pkginfo['version'])) {
253             $ret .= "$indent  <version>$pkginfo[version]</version>\n";
254         }
255         if (!empty($pkginfo['release_date'])) {
256             $ret .= "$indent  <date>$pkginfo[release_date]</date>\n";
257         }
258         if (!empty($pkginfo['release_license'])) {
259             $ret .= "$indent  <license>$pkginfo[release_license]</license>\n";
260         }
261         if (!empty($pkginfo['release_state'])) {
262             $ret .= "$indent  <state>$pkginfo[release_state]</state>\n";
263         }
264         if (!empty($pkginfo['release_notes'])) {
265             $ret .= "$indent  <notes>".trim($this->_fixXmlEncoding($pkginfo['release_notes']))
266             ."\n$indent  </notes>\n";
267         }
268         if (!empty($pkginfo['release_warnings'])) {
269             $ret .= "$indent  <warnings>".$this->_fixXmlEncoding($pkginfo['release_warnings'])."</warnings>\n";
270         }
271         if (isset($pkginfo['release_deps']) && sizeof($pkginfo['release_deps']) > 0) {
272             $ret .= "$indent  <deps>\n";
273             foreach ($pkginfo['release_deps'] as $dep) {
274                 $ret .= "$indent   <dep type=\"$dep[type]\" rel=\"$dep[rel]\"";
275                 if (isset($dep['version'])) {
276                     $ret .= " version=\"$dep[version]\"";
277                 }
278                 if (isset($dep['optional'])) {
279                     $ret .= " optional=\"$dep[optional]\"";
280                 }
281                 if (isset($dep['name'])) {
282                     $ret .= ">$dep[name]</dep>\n";
283                 } else {
284                     $ret .= "/>\n";
285                 }
286             }
287             $ret .= "$indent  </deps>\n";
288         }
289         if (isset($pkginfo['configure_options'])) {
290             $ret .= "$indent  <configureoptions>\n";
291             foreach ($pkginfo['configure_options'] as $c) {
292                 $ret .= "$indent   <configureoption name=\"".
293                     $this->_fixXmlEncoding($c['name']) . "\"";
294                 if (isset($c['default'])) {
295                     $ret .= " default=\"" . $this->_fixXmlEncoding($c['default']) . "\"";
296                 }
297                 $ret .= " prompt=\"" . $this->_fixXmlEncoding($c['prompt']) . "\"";
298                 $ret .= "/>\n";
299             }
300             $ret .= "$indent  </configureoptions>\n";
301         }
302         if (isset($pkginfo['provides'])) {
303             foreach ($pkginfo['provides'] as $key => $what) {
304                 $ret .= "$indent  <provides type=\"$what[type]\" ";
305                 $ret .= "name=\"$what[name]\" ";
306                 if (isset($what['extends'])) {
307                     $ret .= "extends=\"$what[extends]\" ";
308                 }
309                 $ret .= "/>\n";
310             }
311         }
312         if (isset($pkginfo['filelist'])) {
313             $ret .= "$indent  <filelist>\n";
314             if ($state ^ PEAR_VALIDATE_PACKAGING) {
315                 $ret .= $this->recursiveXmlFilelist($pkginfo['filelist']);
316             } else {
317                 foreach ($pkginfo['filelist'] as $file => $fa) {
318                     if (!isset($fa['role'])) {
319                         $fa['role'] = '';
320                     }
321                     $ret .= "$indent   <file role=\"$fa[role]\"";
322                     if (isset($fa['baseinstalldir'])) {
323                         $ret .= ' baseinstalldir="' .
324                             $this->_fixXmlEncoding($fa['baseinstalldir']) . '"';
325                     }
326                     if (isset($fa['md5sum'])) {
327                         $ret .= " md5sum=\"$fa[md5sum]\"";
328                     }
329                     if (isset($fa['platform'])) {
330                         $ret .= " platform=\"$fa[platform]\"";
331                     }
332                     if (!empty($fa['install-as'])) {
333                         $ret .= ' install-as="' .
334                             $this->_fixXmlEncoding($fa['install-as']) . '"';
335                     }
336                     $ret .= ' name="' . $this->_fixXmlEncoding($file) . '"';
337                     if (empty($fa['replacements'])) {
338                         $ret .= "/>\n";
339                     } else {
340                         $ret .= ">\n";
341                         foreach ($fa['replacements'] as $r) {
342                             $ret .= "$indent    <replace";
343                             foreach ($r as $k => $v) {
344                                 $ret .= " $k=\"" . $this->_fixXmlEncoding($v) .'"';
345                             }
346                             $ret .= "/>\n";
347                         }
348                         $ret .= "$indent   </file>\n";
349                     }
350                 }
351             }
352             $ret .= "$indent  </filelist>\n";
353         }
354         $ret .= "$indent </release>\n";
355         return $ret;
356     }
357
358     /**
359      * @param array
360      * @access protected
361      */
362     function recursiveXmlFilelist($list)
363     {
364         $this->_dirs = array();
365         foreach ($list as $file => $attributes) {
366             $this->_addDir($this->_dirs, explode('/', dirname($file)), $file, $attributes);
367         }
368         return $this->_formatDir($this->_dirs);
369     }
370
371     /**
372      * @param array
373      * @param array
374      * @param string|null
375      * @param array|null
376      * @access private
377      */
378     function _addDir(&$dirs, $dir, $file = null, $attributes = null)
379     {
380         if ($dir == array() || $dir == array('.')) {
381             $dirs['files'][basename($file)] = $attributes;
382             return;
383         }
384         $curdir = array_shift($dir);
385         if (!isset($dirs['dirs'][$curdir])) {
386             $dirs['dirs'][$curdir] = array();
387         }
388         $this->_addDir($dirs['dirs'][$curdir], $dir, $file, $attributes);
389     }
390
391     /**
392      * @param array
393      * @param string
394      * @param string
395      * @access private
396      */
397     function _formatDir($dirs, $indent = '', $curdir = '')
398     {
399         $ret = '';
400         if (!count($dirs)) {
401             return '';
402         }
403         if (isset($dirs['dirs'])) {
404             uksort($dirs['dirs'], 'strnatcasecmp');
405             foreach ($dirs['dirs'] as $dir => $contents) {
406                 $usedir = "$curdir/$dir";
407                 $ret .= "$indent   <dir name=\"$dir\">\n";
408                 $ret .= $this->_formatDir($contents, "$indent ", $usedir);
409                 $ret .= "$indent   </dir> <!-- $usedir -->\n";
410             }
411         }
412         if (isset($dirs['files'])) {
413             uksort($dirs['files'], 'strnatcasecmp');
414             foreach ($dirs['files'] as $file => $attribs) {
415                 $ret .= $this->_formatFile($file, $attribs, $indent);
416             }
417         }
418         return $ret;
419     }
420
421     /**
422      * @param string
423      * @param array
424      * @param string
425      * @access private
426      */
427     function _formatFile($file, $attributes, $indent)
428     {
429         $ret = "$indent   <file role=\"$attributes[role]\"";
430         if (isset($attributes['baseinstalldir'])) {
431             $ret .= ' baseinstalldir="' .
432                 $this->_fixXmlEncoding($attributes['baseinstalldir']) . '"';
433         }
434         if (isset($attributes['md5sum'])) {
435             $ret .= " md5sum=\"$attributes[md5sum]\"";
436         }
437         if (isset($attributes['platform'])) {
438             $ret .= " platform=\"$attributes[platform]\"";
439         }
440         if (!empty($attributes['install-as'])) {
441             $ret .= ' install-as="' .
442                 $this->_fixXmlEncoding($attributes['install-as']) . '"';
443         }
444         $ret .= ' name="' . $this->_fixXmlEncoding($file) . '"';
445         if (empty($attributes['replacements'])) {
446             $ret .= "/>\n";
447         } else {
448             $ret .= ">\n";
449             foreach ($attributes['replacements'] as $r) {
450                 $ret .= "$indent    <replace";
451                 foreach ($r as $k => $v) {
452                     $ret .= " $k=\"" . $this->_fixXmlEncoding($v) .'"';
453                 }
454                 $ret .= "/>\n";
455             }
456             $ret .= "$indent   </file>\n";
457         }
458         return $ret;
459     }
460
461     // {{{ _unIndent()
462
463     /**
464      * Unindent given string (?)
465      *
466      * @param string $str The string that has to be unindented.
467      * @return string
468      * @access private
469      */
470     function _unIndent($str)
471     {
472         // remove leading newlines
473         $str = preg_replace('/^[\r\n]+/', '', $str);
474         // find whitespace at the beginning of the first line
475         $indent_len = strspn($str, " \t");
476         $indent = substr($str, 0, $indent_len);
477         $data = '';
478         // remove the same amount of whitespace from following lines
479         foreach (explode("\n", $str) as $line) {
480             if (substr($line, 0, $indent_len) == $indent) {
481                 $data .= substr($line, $indent_len) . "\n";
482             }
483         }
484         return $data;
485     }
486
487     /**
488      * @return array
489      */
490     function dependenciesToV2()
491     {
492         $arr = array();
493         $this->_convertDependencies2_0($arr);
494         return $arr['dependencies'];
495     }
496
497     /**
498      * Convert a package.xml version 1.0 into version 2.0
499      *
500      * Note that this does a basic conversion, to allow more advanced
501      * features like bundles and multiple releases
502      * @param string the classname to instantiate and return.  This must be
503      *               PEAR_PackageFile_v2 or a descendant
504      * @param boolean if true, only valid, deterministic package.xml 1.0 as defined by the
505      *                strictest parameters will be converted
506      * @return PEAR_PackageFile_v2|PEAR_Error
507      */
508     function &toV2($class = 'PEAR_PackageFile_v2', $strict = false)
509     {
510         if ($strict) {
511             if (!$this->_packagefile->validate()) {
512                 $a = PEAR::raiseError('invalid package.xml version 1.0 cannot be converted' .
513                     ' to version 2.0', null, null, null,
514                     $this->_packagefile->getValidationWarnings(true));
515                 return $a;
516             }
517         }
518
519         $arr = array(
520             'attribs' => array(
521                              'version' => '2.0',
522                              'xmlns' => 'http://pear.php.net/dtd/package-2.0',
523                              'xmlns:tasks' => 'http://pear.php.net/dtd/tasks-1.0',
524                              'xmlns:xsi' => 'http://www.w3.org/2001/XMLSchema-instance',
525                              'xsi:schemaLocation' => "http://pear.php.net/dtd/tasks-1.0\n" .
526 "http://pear.php.net/dtd/tasks-1.0.xsd\n" .
527 "http://pear.php.net/dtd/package-2.0\n" .
528 'http://pear.php.net/dtd/package-2.0.xsd',
529                          ),
530             'name' => $this->_packagefile->getPackage(),
531             'channel' => 'pear.php.net',
532         );
533         $arr['summary'] = $this->_packagefile->getSummary();
534         $arr['description'] = $this->_packagefile->getDescription();
535         $maintainers = $this->_packagefile->getMaintainers();
536         foreach ($maintainers as $maintainer) {
537             if ($maintainer['role'] != 'lead') {
538                 continue;
539             }
540             $new = array(
541                 'name' => $maintainer['name'],
542                 'user' => $maintainer['handle'],
543                 'email' => $maintainer['email'],
544                 'active' => 'yes',
545             );
546             $arr['lead'][] = $new;
547         }
548
549         if (!isset($arr['lead'])) { // some people... you know?
550             $arr['lead'] = array(
551                 'name' => 'unknown',
552                 'user' => 'unknown',
553                 'email' => 'noleadmaintainer@example.com',
554                 'active' => 'no',
555             );
556         }
557
558         if (count($arr['lead']) == 1) {
559             $arr['lead'] = $arr['lead'][0];
560         }
561
562         foreach ($maintainers as $maintainer) {
563             if ($maintainer['role'] == 'lead') {
564                 continue;
565             }
566             $new = array(
567                 'name' => $maintainer['name'],
568                 'user' => $maintainer['handle'],
569                 'email' => $maintainer['email'],
570                 'active' => 'yes',
571             );
572             $arr[$maintainer['role']][] = $new;
573         }
574
575         if (isset($arr['developer']) && count($arr['developer']) == 1) {
576             $arr['developer'] = $arr['developer'][0];
577         }
578
579         if (isset($arr['contributor']) && count($arr['contributor']) == 1) {
580             $arr['contributor'] = $arr['contributor'][0];
581         }
582
583         if (isset($arr['helper']) && count($arr['helper']) == 1) {
584             $arr['helper'] = $arr['helper'][0];
585         }
586
587         $arr['date'] = $this->_packagefile->getDate();
588         $arr['version'] =
589             array(
590                 'release' => $this->_packagefile->getVersion(),
591                 'api' => $this->_packagefile->getVersion(),
592             );
593         $arr['stability'] =
594             array(
595                 'release' => $this->_packagefile->getState(),
596                 'api' => $this->_packagefile->getState(),
597             );
598         $licensemap =
599             array(
600                 'php' => 'http://www.php.net/license',
601                 'php license' => 'http://www.php.net/license',
602                 'lgpl' => 'http://www.gnu.org/copyleft/lesser.html',
603                 'bsd' => 'http://www.opensource.org/licenses/bsd-license.php',
604                 'bsd style' => 'http://www.opensource.org/licenses/bsd-license.php',
605                 'bsd-style' => 'http://www.opensource.org/licenses/bsd-license.php',
606                 'mit' => 'http://www.opensource.org/licenses/mit-license.php',
607                 'gpl' => 'http://www.gnu.org/copyleft/gpl.html',
608                 'apache' => 'http://www.opensource.org/licenses/apache2.0.php'
609             );
610
611         if (isset($licensemap[strtolower($this->_packagefile->getLicense())])) {
612             $arr['license'] = array(
613                 'attribs' => array('uri' =>
614                     $licensemap[strtolower($this->_packagefile->getLicense())]),
615                 '_content' => $this->_packagefile->getLicense()
616                 );
617         } else {
618             // don't use bogus uri
619             $arr['license'] = $this->_packagefile->getLicense();
620         }
621
622         $arr['notes'] = $this->_packagefile->getNotes();
623         $temp = array();
624         $arr['contents'] = $this->_convertFilelist2_0($temp);
625         $this->_convertDependencies2_0($arr);
626         $release = ($this->_packagefile->getConfigureOptions() || $this->_isExtension) ?
627             'extsrcrelease' : 'phprelease';
628         if ($release == 'extsrcrelease') {
629             $arr['channel'] = 'pecl.php.net';
630             $arr['providesextension'] = $arr['name']; // assumption
631         }
632
633         $arr[$release] = array();
634         if ($this->_packagefile->getConfigureOptions()) {
635             $arr[$release]['configureoption'] = $this->_packagefile->getConfigureOptions();
636             foreach ($arr[$release]['configureoption'] as $i => $opt) {
637                 $arr[$release]['configureoption'][$i] = array('attribs' => $opt);
638             }
639             if (count($arr[$release]['configureoption']) == 1) {
640                 $arr[$release]['configureoption'] = $arr[$release]['configureoption'][0];
641             }
642         }
643
644         $this->_convertRelease2_0($arr[$release], $temp);
645         if ($release == 'extsrcrelease' && count($arr[$release]) > 1) {
646             // multiple extsrcrelease tags added in PEAR 1.4.1
647             $arr['dependencies']['required']['pearinstaller']['min'] = '1.4.1';
648         }
649
650         if ($cl = $this->_packagefile->getChangelog()) {
651             foreach ($cl as $release) {
652                 $rel = array();
653                 $rel['version'] =
654                     array(
655                         'release' => $release['version'],
656                         'api' => $release['version'],
657                     );
658                 if (!isset($release['release_state'])) {
659                     $release['release_state'] = 'stable';
660                 }
661
662                 $rel['stability'] =
663                     array(
664                         'release' => $release['release_state'],
665                         'api' => $release['release_state'],
666                     );
667                 if (isset($release['release_date'])) {
668                     $rel['date'] = $release['release_date'];
669                 } else {
670                     $rel['date'] = date('Y-m-d');
671                 }
672
673                 if (isset($release['release_license'])) {
674                     if (isset($licensemap[strtolower($release['release_license'])])) {
675                         $uri = $licensemap[strtolower($release['release_license'])];
676                     } else {
677                         $uri = 'http://www.example.com';
678                     }
679                     $rel['license'] = array(
680                             'attribs' => array('uri' => $uri),
681                             '_content' => $release['release_license']
682                         );
683                 } else {
684                     $rel['license'] = $arr['license'];
685                 }
686
687                 if (!isset($release['release_notes'])) {
688                     $release['release_notes'] = 'no release notes';
689                 }
690
691                 $rel['notes'] = $release['release_notes'];
692                 $arr['changelog']['release'][] = $rel;
693             }
694         }
695
696         $ret = new $class;
697         $ret->setConfig($this->_packagefile->_config);
698         if (isset($this->_packagefile->_logger) && is_object($this->_packagefile->_logger)) {
699             $ret->setLogger($this->_packagefile->_logger);
700         }
701
702         $ret->fromArray($arr);
703         return $ret;
704     }
705
706     /**
707      * @param array
708      * @param bool
709      * @access private
710      */
711     function _convertDependencies2_0(&$release, $internal = false)
712     {
713         $peardep = array('pearinstaller' =>
714             array('min' => '1.4.0b1')); // this is a lot safer
715         $required = $optional = array();
716         $release['dependencies'] = array('required' => array());
717         if ($this->_packagefile->hasDeps()) {
718             foreach ($this->_packagefile->getDeps() as $dep) {
719                 if (!isset($dep['optional']) || $dep['optional'] == 'no') {
720                     $required[] = $dep;
721                 } else {
722                     $optional[] = $dep;
723                 }
724             }
725             foreach (array('required', 'optional') as $arr) {
726                 $deps = array();
727                 foreach ($$arr as $dep) {
728                     // organize deps by dependency type and name
729                     if (!isset($deps[$dep['type']])) {
730                         $deps[$dep['type']] = array();
731                     }
732                     if (isset($dep['name'])) {
733                         $deps[$dep['type']][$dep['name']][] = $dep;
734                     } else {
735                         $deps[$dep['type']][] = $dep;
736                     }
737                 }
738                 do {
739                     if (isset($deps['php'])) {
740                         $php = array();
741                         if (count($deps['php']) > 1) {
742                             $php = $this->_processPhpDeps($deps['php']);
743                         } else {
744                             if (!isset($deps['php'][0])) {
745                                 list($key, $blah) = each ($deps['php']); // stupid buggy versions
746                                 $deps['php'] = array($blah[0]);
747                             }
748                             $php = $this->_processDep($deps['php'][0]);
749                             if (!$php) {
750                                 break; // poor mans throw
751                             }
752                         }
753                         $release['dependencies'][$arr]['php'] = $php;
754                     }
755                 } while (false);
756                 do {
757                     if (isset($deps['pkg'])) {
758                         $pkg = array();
759                         $pkg = $this->_processMultipleDepsName($deps['pkg']);
760                         if (!$pkg) {
761                             break; // poor mans throw
762                         }
763                         $release['dependencies'][$arr]['package'] = $pkg;
764                     }
765                 } while (false);
766                 do {
767                     if (isset($deps['ext'])) {
768                         $pkg = array();
769                         $pkg = $this->_processMultipleDepsName($deps['ext']);
770                         $release['dependencies'][$arr]['extension'] = $pkg;
771                     }
772                 } while (false);
773                 // skip sapi - it's not supported so nobody will have used it
774                 // skip os - it's not supported in 1.0
775             }
776         }
777         if (isset($release['dependencies']['required'])) {
778             $release['dependencies']['required'] =
779                 array_merge($peardep, $release['dependencies']['required']);
780         } else {
781             $release['dependencies']['required'] = $peardep;
782         }
783         if (!isset($release['dependencies']['required']['php'])) {
784             $release['dependencies']['required']['php'] =
785                 array('min' => '4.0.0');
786         }
787         $order = array();
788         $bewm = $release['dependencies']['required'];
789         $order['php'] = $bewm['php'];
790         $order['pearinstaller'] = $bewm['pearinstaller'];
791         isset($bewm['package']) ? $order['package'] = $bewm['package'] :0;
792         isset($bewm['extension']) ? $order['extension'] = $bewm['extension'] :0;
793         $release['dependencies']['required'] = $order;
794     }
795
796     /**
797      * @param array
798      * @access private
799      */
800     function _convertFilelist2_0(&$package)
801     {
802         $ret = array('dir' =>
803                     array(
804                         'attribs' => array('name' => '/'),
805                         'file' => array()
806                         )
807                     );
808         $package['platform'] =
809         $package['install-as'] = array();
810         $this->_isExtension = false;
811         foreach ($this->_packagefile->getFilelist() as $name => $file) {
812             $file['name'] = $name;
813             if (isset($file['role']) && $file['role'] == 'src') {
814                 $this->_isExtension = true;
815             }
816             if (isset($file['replacements'])) {
817                 $repl = $file['replacements'];
818                 unset($file['replacements']);
819             } else {
820                 unset($repl);
821             }
822             if (isset($file['install-as'])) {
823                 $package['install-as'][$name] = $file['install-as'];
824                 unset($file['install-as']);
825             }
826             if (isset($file['platform'])) {
827                 $package['platform'][$name] = $file['platform'];
828                 unset($file['platform']);
829             }
830             $file = array('attribs' => $file);
831             if (isset($repl)) {
832                 foreach ($repl as $replace ) {
833                     $file['tasks:replace'][] = array('attribs' => $replace);
834                 }
835                 if (count($repl) == 1) {
836                     $file['tasks:replace'] = $file['tasks:replace'][0];
837                 }
838             }
839             $ret['dir']['file'][] = $file;
840         }
841         return $ret;
842     }
843
844     /**
845      * Post-process special files with install-as/platform attributes and
846      * make the release tag.
847      *
848      * This complex method follows this work-flow to create the release tags:
849      *
850      * <pre>
851      * - if any install-as/platform exist, create a generic release and fill it with
852      *   o <install as=..> tags for <file name=... install-as=...>
853      *   o <install as=..> tags for <file name=... platform=!... install-as=..>
854      *   o <ignore> tags for <file name=... platform=...>
855      *   o <ignore> tags for <file name=... platform=... install-as=..>
856      * - create a release for each platform encountered and fill with
857      *   o <install as..> tags for <file name=... install-as=...>
858      *   o <install as..> tags for <file name=... platform=this platform install-as=..>
859      *   o <install as..> tags for <file name=... platform=!other platform install-as=..>
860      *   o <ignore> tags for <file name=... platform=!this platform>
861      *   o <ignore> tags for <file name=... platform=other platform>
862      *   o <ignore> tags for <file name=... platform=other platform install-as=..>
863      *   o <ignore> tags for <file name=... platform=!this platform install-as=..>
864      * </pre>
865      *
866      * It does this by accessing the $package parameter, which contains an array with
867      * indices:
868      *
869      *  - platform: mapping of file => OS the file should be installed on
870      *  - install-as: mapping of file => installed name
871      *  - osmap: mapping of OS => list of files that should be installed
872      *    on that OS
873      *  - notosmap: mapping of OS => list of files that should not be
874      *    installed on that OS
875      *
876      * @param array
877      * @param array
878      * @access private
879      */
880     function _convertRelease2_0(&$release, $package)
881     {
882         //- if any install-as/platform exist, create a generic release and fill it with
883         if (count($package['platform']) || count($package['install-as'])) {
884             $generic = array();
885             $genericIgnore = array();
886             foreach ($package['install-as'] as $file => $as) {
887                 //o <install as=..> tags for <file name=... install-as=...>
888                 if (!isset($package['platform'][$file])) {
889                     $generic[] = $file;
890                     continue;
891                 }
892                 //o <install as=..> tags for <file name=... platform=!... install-as=..>
893                 if (isset($package['platform'][$file]) &&
894                       $package['platform'][$file]{0} == '!') {
895                     $generic[] = $file;
896                     continue;
897                 }
898                 //o <ignore> tags for <file name=... platform=... install-as=..>
899                 if (isset($package['platform'][$file]) &&
900                       $package['platform'][$file]{0} != '!') {
901                     $genericIgnore[] = $file;
902                     continue;
903                 }
904             }
905             foreach ($package['platform'] as $file => $platform) {
906                 if (isset($package['install-as'][$file])) {
907                     continue;
908                 }
909                 if ($platform{0} != '!') {
910                     //o <ignore> tags for <file name=... platform=...>
911                     $genericIgnore[] = $file;
912                 }
913             }
914             if (count($package['platform'])) {
915                 $oses = $notplatform = $platform = array();
916                 foreach ($package['platform'] as $file => $os) {
917                     // get a list of oses
918                     if ($os{0} == '!') {
919                         if (isset($oses[substr($os, 1)])) {
920                             continue;
921                         }
922                         $oses[substr($os, 1)] = count($oses);
923                     } else {
924                         if (isset($oses[$os])) {
925                             continue;
926                         }
927                         $oses[$os] = count($oses);
928                     }
929                 }
930                 //- create a release for each platform encountered and fill with
931                 foreach ($oses as $os => $releaseNum) {
932                     $release[$releaseNum]['installconditions']['os']['name'] = $os;
933                     $release[$releaseNum]['filelist'] = array('install' => array(),
934                         'ignore' => array());
935                     foreach ($package['install-as'] as $file => $as) {
936                         //o <install as=..> tags for <file name=... install-as=...>
937                         if (!isset($package['platform'][$file])) {
938                             $release[$releaseNum]['filelist']['install'][] =
939                                 array(
940                                     'attribs' => array(
941                                         'name' => $file,
942                                         'as' => $as,
943                                     ),
944                                 );
945                             continue;
946                         }
947                         //o <install as..> tags for
948                         //  <file name=... platform=this platform install-as=..>
949                         if (isset($package['platform'][$file]) &&
950                               $package['platform'][$file] == $os) {
951                             $release[$releaseNum]['filelist']['install'][] =
952                                 array(
953                                     'attribs' => array(
954                                         'name' => $file,
955                                         'as' => $as,
956                                     ),
957                                 );
958                             continue;
959                         }
960                         //o <install as..> tags for
961                         //  <file name=... platform=!other platform install-as=..>
962                         if (isset($package['platform'][$file]) &&
963                               $package['platform'][$file] != "!$os" &&
964                               $package['platform'][$file]{0} == '!') {
965                             $release[$releaseNum]['filelist']['install'][] =
966                                 array(
967                                     'attribs' => array(
968                                         'name' => $file,
969                                         'as' => $as,
970                                     ),
971                                 );
972                             continue;
973                         }
974                         //o <ignore> tags for
975                         //  <file name=... platform=!this platform install-as=..>
976                         if (isset($package['platform'][$file]) &&
977                               $package['platform'][$file] == "!$os") {
978                             $release[$releaseNum]['filelist']['ignore'][] =
979                                 array(
980                                     'attribs' => array(
981                                         'name' => $file,
982                                     ),
983                                 );
984                             continue;
985                         }
986                         //o <ignore> tags for
987                         //  <file name=... platform=other platform install-as=..>
988                         if (isset($package['platform'][$file]) &&
989                               $package['platform'][$file]{0} != '!' &&
990                               $package['platform'][$file] != $os) {
991                             $release[$releaseNum]['filelist']['ignore'][] =
992                                 array(
993                                     'attribs' => array(
994                                         'name' => $file,
995                                     ),
996                                 );
997                             continue;
998                         }
999                     }
1000                     foreach ($package['platform'] as $file => $platform) {
1001                         if (isset($package['install-as'][$file])) {
1002                             continue;
1003                         }
1004                         //o <ignore> tags for <file name=... platform=!this platform>
1005                         if ($platform == "!$os") {
1006                             $release[$releaseNum]['filelist']['ignore'][] =
1007                                 array(
1008                                     'attribs' => array(
1009                                         'name' => $file,
1010                                     ),
1011                                 );
1012                             continue;
1013                         }
1014                         //o <ignore> tags for <file name=... platform=other platform>
1015                         if ($platform{0} != '!' && $platform != $os) {
1016                             $release[$releaseNum]['filelist']['ignore'][] =
1017                                 array(
1018                                     'attribs' => array(
1019                                         'name' => $file,
1020                                     ),
1021                                 );
1022                         }
1023                     }
1024                     if (!count($release[$releaseNum]['filelist']['install'])) {
1025                         unset($release[$releaseNum]['filelist']['install']);
1026                     }
1027                     if (!count($release[$releaseNum]['filelist']['ignore'])) {
1028                         unset($release[$releaseNum]['filelist']['ignore']);
1029                     }
1030                 }
1031                 if (count($generic) || count($genericIgnore)) {
1032                     $release[count($oses)] = array();
1033                     if (count($generic)) {
1034                         foreach ($generic as $file) {
1035                             if (isset($package['install-as'][$file])) {
1036                                 $installas = $package['install-as'][$file];
1037                             } else {
1038                                 $installas = $file;
1039                             }
1040                             $release[count($oses)]['filelist']['install'][] =
1041                                 array(
1042                                     'attribs' => array(
1043                                         'name' => $file,
1044                                         'as' => $installas,
1045                                     )
1046                                 );
1047                         }
1048                     }
1049                     if (count($genericIgnore)) {
1050                         foreach ($genericIgnore as $file) {
1051                             $release[count($oses)]['filelist']['ignore'][] =
1052                                 array(
1053                                     'attribs' => array(
1054                                         'name' => $file,
1055                                     )
1056                                 );
1057                         }
1058                     }
1059                 }
1060                 // cleanup
1061                 foreach ($release as $i => $rel) {
1062                     if (isset($rel['filelist']['install']) &&
1063                           count($rel['filelist']['install']) == 1) {
1064                         $release[$i]['filelist']['install'] =
1065                             $release[$i]['filelist']['install'][0];
1066                     }
1067                     if (isset($rel['filelist']['ignore']) &&
1068                           count($rel['filelist']['ignore']) == 1) {
1069                         $release[$i]['filelist']['ignore'] =
1070                             $release[$i]['filelist']['ignore'][0];
1071                     }
1072                 }
1073                 if (count($release) == 1) {
1074                     $release = $release[0];
1075                 }
1076             } else {
1077                 // no platform atts, but some install-as atts
1078                 foreach ($package['install-as'] as $file => $value) {
1079                     $release['filelist']['install'][] =
1080                         array(
1081                             'attribs' => array(
1082                                 'name' => $file,
1083                                 'as' => $value
1084                             )
1085                         );
1086                 }
1087                 if (count($release['filelist']['install']) == 1) {
1088                     $release['filelist']['install'] = $release['filelist']['install'][0];
1089                 }
1090             }
1091         }
1092     }
1093
1094     /**
1095      * @param array
1096      * @return array
1097      * @access private
1098      */
1099     function _processDep($dep)
1100     {
1101         if ($dep['type'] == 'php') {
1102             if ($dep['rel'] == 'has') {
1103                 // come on - everyone has php!
1104                 return false;
1105             }
1106         }
1107         $php = array();
1108         if ($dep['type'] != 'php') {
1109             $php['name'] = $dep['name'];
1110             if ($dep['type'] == 'pkg') {
1111                 $php['channel'] = 'pear.php.net';
1112             }
1113         }
1114         switch ($dep['rel']) {
1115             case 'gt' :
1116                 $php['min'] = $dep['version'];
1117                 $php['exclude'] = $dep['version'];
1118             break;
1119             case 'ge' :
1120                 if (!isset($dep['version'])) {
1121                     if ($dep['type'] == 'php') {
1122                         if (isset($dep['name'])) {
1123                             $dep['version'] = $dep['name'];
1124                         }
1125                     }
1126                 }
1127                 $php['min'] = $dep['version'];
1128             break;
1129             case 'lt' :
1130                 $php['max'] = $dep['version'];
1131                 $php['exclude'] = $dep['version'];
1132             break;
1133             case 'le' :
1134                 $php['max'] = $dep['version'];
1135             break;
1136             case 'eq' :
1137                 $php['min'] = $dep['version'];
1138                 $php['max'] = $dep['version'];
1139             break;
1140             case 'ne' :
1141                 $php['exclude'] = $dep['version'];
1142             break;
1143             case 'not' :
1144                 $php['conflicts'] = 'yes';
1145             break;
1146         }
1147         return $php;
1148     }
1149
1150     /**
1151      * @param array
1152      * @return array
1153      */
1154     function _processPhpDeps($deps)
1155     {
1156         $test = array();
1157         foreach ($deps as $dep) {
1158             $test[] = $this->_processDep($dep);
1159         }
1160         $min = array();
1161         $max = array();
1162         foreach ($test as $dep) {
1163             if (!$dep) {
1164                 continue;
1165             }
1166             if (isset($dep['min'])) {
1167                 $min[$dep['min']] = count($min);
1168             }
1169             if (isset($dep['max'])) {
1170                 $max[$dep['max']] = count($max);
1171             }
1172         }
1173         if (count($min) > 0) {
1174             uksort($min, 'version_compare');
1175         }
1176         if (count($max) > 0) {
1177             uksort($max, 'version_compare');
1178         }
1179         if (count($min)) {
1180             // get the highest minimum
1181             $min = array_pop($a = array_flip($min));
1182         } else {
1183             $min = false;
1184         }
1185         if (count($max)) {
1186             // get the lowest maximum
1187             $max = array_shift($a = array_flip($max));
1188         } else {
1189             $max = false;
1190         }
1191         if ($min) {
1192             $php['min'] = $min;
1193         }
1194         if ($max) {
1195             $php['max'] = $max;
1196         }
1197         $exclude = array();
1198         foreach ($test as $dep) {
1199             if (!isset($dep['exclude'])) {
1200                 continue;
1201             }
1202             $exclude[] = $dep['exclude'];
1203         }
1204         if (count($exclude)) {
1205             $php['exclude'] = $exclude;
1206         }
1207         return $php;
1208     }
1209
1210     /**
1211      * process multiple dependencies that have a name, like package deps
1212      * @param array
1213      * @return array
1214      * @access private
1215      */
1216     function _processMultipleDepsName($deps)
1217     {
1218         $ret = $tests = array();
1219         foreach ($deps as $name => $dep) {
1220             foreach ($dep as $d) {
1221                 $tests[$name][] = $this->_processDep($d);
1222             }
1223         }
1224
1225         foreach ($tests as $name => $test) {
1226             $max = $min = $php = array();
1227             $php['name'] = $name;
1228             foreach ($test as $dep) {
1229                 if (!$dep) {
1230                     continue;
1231                 }
1232                 if (isset($dep['channel'])) {
1233                     $php['channel'] = 'pear.php.net';
1234                 }
1235                 if (isset($dep['conflicts']) && $dep['conflicts'] == 'yes') {
1236                     $php['conflicts'] = 'yes';
1237                 }
1238                 if (isset($dep['min'])) {
1239                     $min[$dep['min']] = count($min);
1240                 }
1241                 if (isset($dep['max'])) {
1242                     $max[$dep['max']] = count($max);
1243                 }
1244             }
1245             if (count($min) > 0) {
1246                 uksort($min, 'version_compare');
1247             }
1248             if (count($max) > 0) {
1249                 uksort($max, 'version_compare');
1250             }
1251             if (count($min)) {
1252                 // get the highest minimum
1253                 $min = array_pop($a = array_flip($min));
1254             } else {
1255                 $min = false;
1256             }
1257             if (count($max)) {
1258                 // get the lowest maximum
1259                 $max = array_shift($a = array_flip($max));
1260             } else {
1261                 $max = false;
1262             }
1263             if ($min) {
1264                 $php['min'] = $min;
1265             }
1266             if ($max) {
1267                 $php['max'] = $max;
1268             }
1269             $exclude = array();
1270             foreach ($test as $dep) {
1271                 if (!isset($dep['exclude'])) {
1272                     continue;
1273                 }
1274                 $exclude[] = $dep['exclude'];
1275             }
1276             if (count($exclude)) {
1277                 $php['exclude'] = $exclude;
1278             }
1279             $ret[] = $php;
1280         }
1281         return $ret;
1282     }
1283 }
1284 ?>