source: branches/version-2_13-dev/data/module/PEAR/Command/Package.php @ 23125

Revision 23125, 39.3 KB checked in by kimoto, 11 years ago (diff)

#2275 PEAR更新
不要なrequire_onceの削除
レガシーなPEARモジュールは使わない
SearchReplace?.phpのパスが間違っているので修正

Line 
1<?php
2/**
3 * PEAR_Command_Package (package, package-validate, cvsdiff, cvstag, package-dependencies,
4 * sign, makerpm, convert commands)
5 *
6 * PHP versions 4 and 5
7 *
8 * @category   pear
9 * @package    PEAR
10 * @author     Stig Bakken <ssb@php.net>
11 * @author     Martin Jansen <mj@php.net>
12 * @author     Greg Beaver <cellog@php.net>
13 * @copyright  1997-2009 The Authors
14 * @license    http://opensource.org/licenses/bsd-license.php New BSD License
15 * @version    CVS: $Id: Package.php 313024 2011-07-06 19:51:24Z dufuz $
16 * @link       http://pear.php.net/package/PEAR
17 * @since      File available since Release 0.1
18 */
19
20/**
21 * base class
22 */
23require_once 'PEAR/Command/Common.php';
24
25/**
26 * PEAR commands for login/logout
27 *
28 * @category   pear
29 * @package    PEAR
30 * @author     Stig Bakken <ssb@php.net>
31 * @author     Martin Jansen <mj@php.net>
32 * @author     Greg Beaver <cellog@php.net>
33 * @copyright  1997-2009 The Authors
34 * @license    http://opensource.org/licenses/bsd-license.php New BSD License
35 * @version    Release: 1.9.4
36 * @link       http://pear.php.net/package/PEAR
37 * @since      Class available since Release 0.1
38 */
39
40class PEAR_Command_Package extends PEAR_Command_Common
41{
42    var $commands = array(
43        'package' => array(
44            'summary' => 'Build Package',
45            'function' => 'doPackage',
46            'shortcut' => 'p',
47            'options' => array(
48                'nocompress' => array(
49                    'shortopt' => 'Z',
50                    'doc' => 'Do not gzip the package file'
51                    ),
52                'showname' => array(
53                    'shortopt' => 'n',
54                    'doc' => 'Print the name of the packaged file.',
55                    ),
56                ),
57            'doc' => '[descfile] [descfile2]
58Creates a PEAR package from its description file (usually called
59package.xml).  If a second packagefile is passed in, then
60the packager will check to make sure that one is a package.xml
61version 1.0, and the other is a package.xml version 2.0.  The
62package.xml version 1.0 will be saved as "package.xml" in the archive,
63and the other as "package2.xml" in the archive"
64'
65            ),
66        'package-validate' => array(
67            'summary' => 'Validate Package Consistency',
68            'function' => 'doPackageValidate',
69            'shortcut' => 'pv',
70            'options' => array(),
71            'doc' => '
72',
73            ),
74        'cvsdiff' => array(
75            'summary' => 'Run a "cvs diff" for all files in a package',
76            'function' => 'doCvsDiff',
77            'shortcut' => 'cd',
78            'options' => array(
79                'quiet' => array(
80                    'shortopt' => 'q',
81                    'doc' => 'Be quiet',
82                    ),
83                'reallyquiet' => array(
84                    'shortopt' => 'Q',
85                    'doc' => 'Be really quiet',
86                    ),
87                'date' => array(
88                    'shortopt' => 'D',
89                    'doc' => 'Diff against revision of DATE',
90                    'arg' => 'DATE',
91                    ),
92                'release' => array(
93                    'shortopt' => 'R',
94                    'doc' => 'Diff against tag for package release REL',
95                    'arg' => 'REL',
96                    ),
97                'revision' => array(
98                    'shortopt' => 'r',
99                    'doc' => 'Diff against revision REV',
100                    'arg' => 'REV',
101                    ),
102                'context' => array(
103                    'shortopt' => 'c',
104                    'doc' => 'Generate context diff',
105                    ),
106                'unified' => array(
107                    'shortopt' => 'u',
108                    'doc' => 'Generate unified diff',
109                    ),
110                'ignore-case' => array(
111                    'shortopt' => 'i',
112                    'doc' => 'Ignore case, consider upper- and lower-case letters equivalent',
113                    ),
114                'ignore-whitespace' => array(
115                    'shortopt' => 'b',
116                    'doc' => 'Ignore changes in amount of white space',
117                    ),
118                'ignore-blank-lines' => array(
119                    'shortopt' => 'B',
120                    'doc' => 'Ignore changes that insert or delete blank lines',
121                    ),
122                'brief' => array(
123                    'doc' => 'Report only whether the files differ, no details',
124                    ),
125                'dry-run' => array(
126                    'shortopt' => 'n',
127                    'doc' => 'Don\'t do anything, just pretend',
128                    ),
129                ),
130            'doc' => '<package.xml>
131Compares all the files in a package.  Without any options, this
132command will compare the current code with the last checked-in code.
133Using the -r or -R option you may compare the current code with that
134of a specific release.
135',
136            ),
137         'svntag' => array(
138             'summary' => 'Set SVN Release Tag',
139             'function' => 'doSvnTag',
140             'shortcut' => 'sv',
141             'options' => array(
142                 'quiet' => array(
143                     'shortopt' => 'q',
144                     'doc' => 'Be quiet',
145                     ),
146                 'slide' => array(
147                     'shortopt' => 'F',
148                     'doc' => 'Move (slide) tag if it exists',
149                     ),
150                 'delete' => array(
151                     'shortopt' => 'd',
152                     'doc' => 'Remove tag',
153                     ),
154                 'dry-run' => array(
155                     'shortopt' => 'n',
156                     'doc' => 'Don\'t do anything, just pretend',
157                     ),
158                 ),
159             'doc' => '<package.xml> [files...]
160 Sets a SVN tag on all files in a package.  Use this command after you have
161 packaged a distribution tarball with the "package" command to tag what
162 revisions of what files were in that release.  If need to fix something
163 after running svntag once, but before the tarball is released to the public,
164 use the "slide" option to move the release tag.
165
166 to include files (such as a second package.xml, or tests not included in the
167 release), pass them as additional parameters.
168 ',
169             ),
170        'cvstag' => array(
171            'summary' => 'Set CVS Release Tag',
172            'function' => 'doCvsTag',
173            'shortcut' => 'ct',
174            'options' => array(
175                'quiet' => array(
176                    'shortopt' => 'q',
177                    'doc' => 'Be quiet',
178                    ),
179                'reallyquiet' => array(
180                    'shortopt' => 'Q',
181                    'doc' => 'Be really quiet',
182                    ),
183                'slide' => array(
184                    'shortopt' => 'F',
185                    'doc' => 'Move (slide) tag if it exists',
186                    ),
187                'delete' => array(
188                    'shortopt' => 'd',
189                    'doc' => 'Remove tag',
190                    ),
191                'dry-run' => array(
192                    'shortopt' => 'n',
193                    'doc' => 'Don\'t do anything, just pretend',
194                    ),
195                ),
196            'doc' => '<package.xml> [files...]
197Sets a CVS tag on all files in a package.  Use this command after you have
198packaged a distribution tarball with the "package" command to tag what
199revisions of what files were in that release.  If need to fix something
200after running cvstag once, but before the tarball is released to the public,
201use the "slide" option to move the release tag.
202
203to include files (such as a second package.xml, or tests not included in the
204release), pass them as additional parameters.
205',
206            ),
207        'package-dependencies' => array(
208            'summary' => 'Show package dependencies',
209            'function' => 'doPackageDependencies',
210            'shortcut' => 'pd',
211            'options' => array(),
212            'doc' => '<package-file> or <package.xml> or <install-package-name>
213List all dependencies the package has.
214Can take a tgz / tar file, package.xml or a package name of an installed package.'
215            ),
216        'sign' => array(
217            'summary' => 'Sign a package distribution file',
218            'function' => 'doSign',
219            'shortcut' => 'si',
220            'options' => array(
221                'verbose' => array(
222                    'shortopt' => 'v',
223                    'doc' => 'Display GnuPG output',
224                    ),
225            ),
226            'doc' => '<package-file>
227Signs a package distribution (.tar or .tgz) file with GnuPG.',
228            ),
229        'makerpm' => array(
230            'summary' => 'Builds an RPM spec file from a PEAR package',
231            'function' => 'doMakeRPM',
232            'shortcut' => 'rpm',
233            'options' => array(
234                'spec-template' => array(
235                    'shortopt' => 't',
236                    'arg' => 'FILE',
237                    'doc' => 'Use FILE as RPM spec file template'
238                    ),
239                'rpm-pkgname' => array(
240                    'shortopt' => 'p',
241                    'arg' => 'FORMAT',
242                    'doc' => 'Use FORMAT as format string for RPM package name, %s is replaced
243by the PEAR package name, defaults to "PEAR::%s".',
244                    ),
245                ),
246            'doc' => '<package-file>
247
248Creates an RPM .spec file for wrapping a PEAR package inside an RPM
249package.  Intended to be used from the SPECS directory, with the PEAR
250package tarball in the SOURCES directory:
251
252$ pear makerpm ../SOURCES/Net_Socket-1.0.tgz
253Wrote RPM spec file PEAR::Net_Geo-1.0.spec
254$ rpm -bb PEAR::Net_Socket-1.0.spec
255...
256Wrote: /usr/src/redhat/RPMS/i386/PEAR::Net_Socket-1.0-1.i386.rpm
257',
258            ),
259        'convert' => array(
260            'summary' => 'Convert a package.xml 1.0 to package.xml 2.0 format',
261            'function' => 'doConvert',
262            'shortcut' => 'c2',
263            'options' => array(
264                'flat' => array(
265                    'shortopt' => 'f',
266                    'doc' => 'do not beautify the filelist.',
267                    ),
268                ),
269            'doc' => '[descfile] [descfile2]
270Converts a package.xml in 1.0 format into a package.xml
271in 2.0 format.  The new file will be named package2.xml by default,
272and package.xml will be used as the old file by default.
273This is not the most intelligent conversion, and should only be
274used for automated conversion or learning the format.
275'
276            ),
277        );
278
279    var $output;
280
281    /**
282     * PEAR_Command_Package constructor.
283     *
284     * @access public
285     */
286    function PEAR_Command_Package(&$ui, &$config)
287    {
288        parent::PEAR_Command_Common($ui, $config);
289    }
290
291    function _displayValidationResults($err, $warn, $strict = false)
292    {
293        foreach ($err as $e) {
294            $this->output .= "Error: $e\n";
295        }
296        foreach ($warn as $w) {
297            $this->output .= "Warning: $w\n";
298        }
299        $this->output .= sprintf('Validation: %d error(s), %d warning(s)'."\n",
300                                       sizeof($err), sizeof($warn));
301        if ($strict && count($err) > 0) {
302            $this->output .= "Fix these errors and try again.";
303            return false;
304        }
305        return true;
306    }
307
308    function &getPackager()
309    {
310        if (!class_exists('PEAR_Packager')) {
311            require_once 'PEAR/Packager.php';
312        }
313        $a = &new PEAR_Packager;
314        return $a;
315    }
316
317    function &getPackageFile($config, $debug = false)
318    {
319        if (!class_exists('PEAR_Common')) {
320            require_once 'PEAR/Common.php';
321        }
322        if (!class_exists('PEAR_PackageFile')) {
323            require_once 'PEAR/PackageFile.php';
324        }
325        $a = &new PEAR_PackageFile($config, $debug);
326        $common = new PEAR_Common;
327        $common->ui = $this->ui;
328        $a->setLogger($common);
329        return $a;
330    }
331
332    function doPackage($command, $options, $params)
333    {
334        $this->output = '';
335        $pkginfofile = isset($params[0]) ? $params[0] : 'package.xml';
336        $pkg2 = isset($params[1]) ? $params[1] : null;
337        if (!$pkg2 && !isset($params[0]) && file_exists('package2.xml')) {
338            $pkg2 = 'package2.xml';
339        }
340
341        $packager = &$this->getPackager();
342        $compress = empty($options['nocompress']) ? true : false;
343        $result   = $packager->package($pkginfofile, $compress, $pkg2);
344        if (PEAR::isError($result)) {
345            return $this->raiseError($result);
346        }
347
348        // Don't want output, only the package file name just created
349        if (isset($options['showname'])) {
350            $this->output = $result;
351        }
352
353        if ($this->output) {
354            $this->ui->outputData($this->output, $command);
355        }
356
357        return true;
358    }
359
360    function doPackageValidate($command, $options, $params)
361    {
362        $this->output = '';
363        if (count($params) < 1) {
364            $params[0] = 'package.xml';
365        }
366
367        $obj = &$this->getPackageFile($this->config, $this->_debug);
368        $obj->rawReturn();
369        PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
370        $info = $obj->fromTgzFile($params[0], PEAR_VALIDATE_NORMAL);
371        if (PEAR::isError($info)) {
372            $info = $obj->fromPackageFile($params[0], PEAR_VALIDATE_NORMAL);
373        } else {
374            $archive = $info->getArchiveFile();
375            $tar = &new Archive_Tar($archive);
376            $tar->extract(dirname($info->getPackageFile()));
377            $info->setPackageFile(dirname($info->getPackageFile()) . DIRECTORY_SEPARATOR .
378                $info->getPackage() . '-' . $info->getVersion() . DIRECTORY_SEPARATOR .
379                basename($info->getPackageFile()));
380        }
381
382        PEAR::staticPopErrorHandling();
383        if (PEAR::isError($info)) {
384            return $this->raiseError($info);
385        }
386
387        $valid = false;
388        if ($info->getPackagexmlVersion() == '2.0') {
389            if ($valid = $info->validate(PEAR_VALIDATE_NORMAL)) {
390                $info->flattenFileList();
391                $valid = $info->validate(PEAR_VALIDATE_PACKAGING);
392            }
393        } else {
394            $valid = $info->validate(PEAR_VALIDATE_PACKAGING);
395        }
396
397        $err = $warn = array();
398        if ($errors = $info->getValidationWarnings()) {
399            foreach ($errors as $error) {
400                if ($error['level'] == 'warning') {
401                    $warn[] = $error['message'];
402                } else {
403                    $err[] = $error['message'];
404                }
405            }
406        }
407
408        $this->_displayValidationResults($err, $warn);
409        $this->ui->outputData($this->output, $command);
410        return true;
411    }
412
413    function doSvnTag($command, $options, $params)
414    {
415        $this->output = '';
416        $_cmd = $command;
417        if (count($params) < 1) {
418            $help = $this->getHelp($command);
419            return $this->raiseError("$command: missing parameter: $help[0]");
420        }
421
422        $packageFile = realpath($params[0]);
423        $dir = dirname($packageFile);
424        $dir = substr($dir, strrpos($dir, DIRECTORY_SEPARATOR) + 1);
425        $obj  = &$this->getPackageFile($this->config, $this->_debug);
426        $info = $obj->fromAnyFile($packageFile, PEAR_VALIDATE_NORMAL);
427        if (PEAR::isError($info)) {
428            return $this->raiseError($info);
429        }
430
431        $err = $warn = array();
432        if (!$info->validate()) {
433            foreach ($info->getValidationWarnings() as $error) {
434                if ($error['level'] == 'warning') {
435                    $warn[] = $error['message'];
436                } else {
437                    $err[] = $error['message'];
438                }
439            }
440        }
441
442        if (!$this->_displayValidationResults($err, $warn, true)) {
443            $this->ui->outputData($this->output, $command);
444            return $this->raiseError('SVN tag failed');
445        }
446
447        $version    = $info->getVersion();
448        $package    = $info->getName();
449        $svntag     = "$package-$version";
450
451        if (isset($options['delete'])) {
452            return $this->_svnRemoveTag($version, $package, $svntag, $packageFile, $options);
453        }
454
455        $path = $this->_svnFindPath($packageFile);
456
457        // Check if there are any modified files
458        $fp = popen('svn st --xml ' . dirname($packageFile), "r");
459        $out = '';
460        while ($line = fgets($fp, 1024)) {
461            $out .= rtrim($line)."\n";
462        }
463        pclose($fp);
464
465        if (!isset($options['quiet']) && strpos($out, 'item="modified"')) {
466            $params = array(array(
467                'name' => 'modified',
468                'type' => 'yesno',
469                'default' => 'no',
470                'prompt' => 'You have files in your SVN checkout (' . $path['from']  . ') that have been modified but not commited, do you still want to tag ' . $version . '?',
471            ));
472            $answers = $this->ui->confirmDialog($params);
473
474            if (!in_array($answers['modified'], array('y', 'yes', 'on', '1'))) {
475                return true;
476            }
477        }
478
479        if (isset($options['slide'])) {
480            $this->_svnRemoveTag($version, $package, $svntag, $packageFile, $options);
481        }
482
483        // Check if tag already exists
484        $releaseTag = $path['local']['base'] . 'tags' . DIRECTORY_SEPARATOR . $svntag;
485        $existsCommand = 'svn ls ' . $path['base'] . 'tags/';
486
487        $fp = popen($existsCommand, "r");
488        $out = '';
489        while ($line = fgets($fp, 1024)) {
490            $out .= rtrim($line)."\n";
491        }
492        pclose($fp);
493
494        if (in_array($svntag . DIRECTORY_SEPARATOR, explode("\n", $out))) {
495            $this->ui->outputData($this->output, $command);
496            return $this->raiseError('SVN tag ' . $svntag . ' for ' . $package . ' already exists.');
497        } elseif (file_exists($path['local']['base'] . 'tags') === false) {
498            return $this->raiseError('Can not locate the tags directory at ' . $path['local']['base'] . 'tags');
499        } elseif (is_writeable($path['local']['base'] . 'tags') === false) {
500            return $this->raiseError('Can not write to the tag directory at ' . $path['local']['base'] . 'tags');
501        } else {
502            $makeCommand = 'svn mkdir ' . $releaseTag;
503            $this->output .= "+ $makeCommand\n";
504            if (empty($options['dry-run'])) {
505                // We need to create the tag dir.
506                $fp = popen($makeCommand, "r");
507                $out = '';
508                while ($line = fgets($fp, 1024)) {
509                    $out .= rtrim($line)."\n";
510                }
511                pclose($fp);
512                $this->output .= "$out\n";
513            }
514        }
515
516        $command = 'svn';
517        if (isset($options['quiet'])) {
518            $command .= ' -q';
519        }
520
521        $command .= ' copy --parents ';
522
523        $dir   = dirname($packageFile);
524        $dir   = substr($dir, strrpos($dir, DIRECTORY_SEPARATOR) + 1);
525        $files = array_keys($info->getFilelist());
526        if (!in_array(basename($packageFile), $files)) {
527            $files[] = basename($packageFile);
528        }
529
530        array_shift($params);
531        if (count($params)) {
532            // add in additional files to be tagged (package files and such)
533            $files = array_merge($files, $params);
534        }
535
536        $commands = array();
537        foreach ($files as $file) {
538            if (!file_exists($file)) {
539                $file = $dir . DIRECTORY_SEPARATOR . $file;
540            }
541            $commands[] = $command . ' ' . escapeshellarg($file) . ' ' .
542                          escapeshellarg($releaseTag . DIRECTORY_SEPARATOR . $file);
543        }
544
545        $this->output .= implode("\n", $commands) . "\n";
546        if (empty($options['dry-run'])) {
547            foreach ($commands as $command) {
548                $fp = popen($command, "r");
549                while ($line = fgets($fp, 1024)) {
550                    $this->output .= rtrim($line)."\n";
551                }
552                pclose($fp);
553            }
554        }
555
556        $command = 'svn ci -m "Tagging the ' . $version  . ' release" ' . $releaseTag . "\n";
557        $this->output .= "+ $command\n";
558        if (empty($options['dry-run'])) {
559            $fp = popen($command, "r");
560            while ($line = fgets($fp, 1024)) {
561                $this->output .= rtrim($line)."\n";
562            }
563            pclose($fp);
564        }
565
566        $this->ui->outputData($this->output, $_cmd);
567        return true;
568    }
569
570    function _svnFindPath($file)
571    {
572        $xml = '';
573        $command = "svn info --xml $file";
574        $fp = popen($command, "r");
575        while ($line = fgets($fp, 1024)) {
576            $xml .= rtrim($line)."\n";
577        }
578        pclose($fp);
579        $url_tag = strpos($xml, '<url>');
580        $url = substr($xml, $url_tag + 5, strpos($xml, '</url>', $url_tag + 5) - ($url_tag + 5));
581
582        $path = array();
583        $path['from'] = substr($url, 0, strrpos($url, '/'));
584        $path['base'] = substr($path['from'], 0, strrpos($path['from'], '/') + 1);
585
586        // Figure out the local paths - see http://pear.php.net/bugs/17463
587        $pos = strpos($file, DIRECTORY_SEPARATOR . 'trunk' . DIRECTORY_SEPARATOR);
588        if ($pos === false) {
589            $pos = strpos($file, DIRECTORY_SEPARATOR . 'branches' . DIRECTORY_SEPARATOR);
590        }
591        $path['local']['base'] = substr($file, 0, $pos + 1);
592
593        return $path;
594    }
595
596    function _svnRemoveTag($version, $package, $tag, $packageFile, $options)
597    {
598        $command = 'svn';
599
600        if (isset($options['quiet'])) {
601            $command .= ' -q';
602        }
603
604        $command .= ' remove';
605        $command .= ' -m "Removing tag for the ' . $version  . ' release."';
606
607        $path = $this->_svnFindPath($packageFile);
608        $command .= ' ' . $path['base'] . 'tags/' . $tag;
609
610
611        if ($this->config->get('verbose') > 1) {
612            $this->output .= "+ $command\n";
613        }
614
615        $this->output .= "+ $command\n";
616        if (empty($options['dry-run'])) {
617            $fp = popen($command, "r");
618            while ($line = fgets($fp, 1024)) {
619                $this->output .= rtrim($line)."\n";
620            }
621            pclose($fp);
622        }
623
624        $this->ui->outputData($this->output, $command);
625        return true;
626    }
627
628    function doCvsTag($command, $options, $params)
629    {
630        $this->output = '';
631        $_cmd = $command;
632        if (count($params) < 1) {
633            $help = $this->getHelp($command);
634            return $this->raiseError("$command: missing parameter: $help[0]");
635        }
636
637        $packageFile = realpath($params[0]);
638        $obj  = &$this->getPackageFile($this->config, $this->_debug);
639        $info = $obj->fromAnyFile($packageFile, PEAR_VALIDATE_NORMAL);
640        if (PEAR::isError($info)) {
641            return $this->raiseError($info);
642        }
643
644        $err = $warn = array();
645        if (!$info->validate()) {
646            foreach ($info->getValidationWarnings() as $error) {
647                if ($error['level'] == 'warning') {
648                    $warn[] = $error['message'];
649                } else {
650                    $err[] = $error['message'];
651                }
652            }
653        }
654
655        if (!$this->_displayValidationResults($err, $warn, true)) {
656            $this->ui->outputData($this->output, $command);
657            return $this->raiseError('CVS tag failed');
658        }
659
660        $version    = $info->getVersion();
661        $cvsversion = preg_replace('/[^a-z0-9]/i', '_', $version);
662        $cvstag     = "RELEASE_$cvsversion";
663        $files      = array_keys($info->getFilelist());
664        $command = 'cvs';
665        if (isset($options['quiet'])) {
666            $command .= ' -q';
667        }
668
669        if (isset($options['reallyquiet'])) {
670            $command .= ' -Q';
671        }
672
673        $command .= ' tag';
674        if (isset($options['slide'])) {
675            $command .= ' -F';
676        }
677
678        if (isset($options['delete'])) {
679            $command .= ' -d';
680        }
681
682        $command .= ' ' . $cvstag . ' ' . escapeshellarg($params[0]);
683        array_shift($params);
684        if (count($params)) {
685            // add in additional files to be tagged
686            $files = array_merge($files, $params);
687        }
688
689        $dir = dirname($packageFile);
690        $dir = substr($dir, strrpos($dir, '/') + 1);
691        foreach ($files as $file) {
692            if (!file_exists($file)) {
693                $file = $dir . DIRECTORY_SEPARATOR . $file;
694            }
695            $command .= ' ' . escapeshellarg($file);
696        }
697
698        if ($this->config->get('verbose') > 1) {
699            $this->output .= "+ $command\n";
700        }
701
702        $this->output .= "+ $command\n";
703        if (empty($options['dry-run'])) {
704            $fp = popen($command, "r");
705            while ($line = fgets($fp, 1024)) {
706                $this->output .= rtrim($line)."\n";
707            }
708            pclose($fp);
709        }
710
711        $this->ui->outputData($this->output, $_cmd);
712        return true;
713    }
714
715    function doCvsDiff($command, $options, $params)
716    {
717        $this->output = '';
718        if (sizeof($params) < 1) {
719            $help = $this->getHelp($command);
720            return $this->raiseError("$command: missing parameter: $help[0]");
721        }
722
723        $file = realpath($params[0]);
724        $obj  = &$this->getPackageFile($this->config, $this->_debug);
725        $info = $obj->fromAnyFile($file, PEAR_VALIDATE_NORMAL);
726        if (PEAR::isError($info)) {
727            return $this->raiseError($info);
728        }
729
730        $err = $warn = array();
731        if (!$info->validate()) {
732            foreach ($info->getValidationWarnings() as $error) {
733                if ($error['level'] == 'warning') {
734                    $warn[] = $error['message'];
735                } else {
736                    $err[] = $error['message'];
737                }
738            }
739        }
740
741        if (!$this->_displayValidationResults($err, $warn, true)) {
742            $this->ui->outputData($this->output, $command);
743            return $this->raiseError('CVS diff failed');
744        }
745
746        $info1 = $info->getFilelist();
747        $files = $info1;
748        $cmd = "cvs";
749        if (isset($options['quiet'])) {
750            $cmd .= ' -q';
751            unset($options['quiet']);
752        }
753
754        if (isset($options['reallyquiet'])) {
755            $cmd .= ' -Q';
756            unset($options['reallyquiet']);
757        }
758
759        if (isset($options['release'])) {
760            $cvsversion = preg_replace('/[^a-z0-9]/i', '_', $options['release']);
761            $cvstag = "RELEASE_$cvsversion";
762            $options['revision'] = $cvstag;
763            unset($options['release']);
764        }
765
766        $execute = true;
767        if (isset($options['dry-run'])) {
768            $execute = false;
769            unset($options['dry-run']);
770        }
771
772        $cmd .= ' diff';
773        // the rest of the options are passed right on to "cvs diff"
774        foreach ($options as $option => $optarg) {
775            $arg = $short = false;
776            if (isset($this->commands[$command]['options'][$option])) {
777                $arg = $this->commands[$command]['options'][$option]['arg'];
778                $short = $this->commands[$command]['options'][$option]['shortopt'];
779            }
780            $cmd .= $short ? " -$short" : " --$option";
781            if ($arg && $optarg) {
782                $cmd .= ($short ? '' : '=') . escapeshellarg($optarg);
783            }
784        }
785
786        foreach ($files as $file) {
787            $cmd .= ' ' . escapeshellarg($file['name']);
788        }
789
790        if ($this->config->get('verbose') > 1) {
791            $this->output .= "+ $cmd\n";
792        }
793
794        if ($execute) {
795            $fp = popen($cmd, "r");
796            while ($line = fgets($fp, 1024)) {
797                $this->output .= rtrim($line)."\n";
798            }
799            pclose($fp);
800        }
801
802        $this->ui->outputData($this->output, $command);
803        return true;
804    }
805
806    function doPackageDependencies($command, $options, $params)
807    {
808        // $params[0] -> the PEAR package to list its information
809        if (count($params) !== 1) {
810            return $this->raiseError("bad parameter(s), try \"help $command\"");
811        }
812
813        $obj = &$this->getPackageFile($this->config, $this->_debug);
814        if (is_file($params[0]) || strpos($params[0], '.xml') > 0) {
815           $info = $obj->fromAnyFile($params[0], PEAR_VALIDATE_NORMAL);
816        } else {
817            $reg  = $this->config->getRegistry();
818            $info = $obj->fromArray($reg->packageInfo($params[0]));
819        }
820
821        if (PEAR::isError($info)) {
822            return $this->raiseError($info);
823        }
824
825        $deps = $info->getDeps();
826        if (is_array($deps)) {
827            if ($info->getPackagexmlVersion() == '1.0') {
828                $data = array(
829                    'caption' => 'Dependencies for pear/' . $info->getPackage(),
830                    'border' => true,
831                    'headline' => array("Required?", "Type", "Name", "Relation", "Version"),
832                    );
833
834                foreach ($deps as $d) {
835                    if (isset($d['optional'])) {
836                        if ($d['optional'] == 'yes') {
837                            $req = 'No';
838                        } else {
839                            $req = 'Yes';
840                        }
841                    } else {
842                        $req = 'Yes';
843                    }
844
845                    if (isset($this->_deps_rel_trans[$d['rel']])) {
846                        $rel = $this->_deps_rel_trans[$d['rel']];
847                    } else {
848                        $rel = $d['rel'];
849                    }
850
851                    if (isset($this->_deps_type_trans[$d['type']])) {
852                        $type = ucfirst($this->_deps_type_trans[$d['type']]);
853                    } else {
854                        $type = $d['type'];
855                    }
856
857                    if (isset($d['name'])) {
858                        $name = $d['name'];
859                    } else {
860                        $name = '';
861                    }
862
863                    if (isset($d['version'])) {
864                        $version = $d['version'];
865                    } else {
866                        $version = '';
867                    }
868
869                    $data['data'][] = array($req, $type, $name, $rel, $version);
870                }
871            } else { // package.xml 2.0 dependencies display
872                require_once 'PEAR/Dependency2.php';
873                $deps = $info->getDependencies();
874                $reg = &$this->config->getRegistry();
875                if (is_array($deps)) {
876                    $d = new PEAR_Dependency2($this->config, array(), '');
877                    $data = array(
878                        'caption' => 'Dependencies for ' . $info->getPackage(),
879                        'border' => true,
880                        'headline' => array("Required?", "Type", "Name", 'Versioning', 'Group'),
881                        );
882                    foreach ($deps as $type => $subd) {
883                        $req = ($type == 'required') ? 'Yes' : 'No';
884                        if ($type == 'group') {
885                            $group = $subd['attribs']['name'];
886                        } else {
887                            $group = '';
888                        }
889
890                        if (!isset($subd[0])) {
891                            $subd = array($subd);
892                        }
893
894                        foreach ($subd as $groupa) {
895                            foreach ($groupa as $deptype => $depinfo) {
896                                if ($deptype == 'attribs') {
897                                    continue;
898                                }
899
900                                if ($deptype == 'pearinstaller') {
901                                    $deptype = 'pear Installer';
902                                }
903
904                                if (!isset($depinfo[0])) {
905                                    $depinfo = array($depinfo);
906                                }
907
908                                foreach ($depinfo as $inf) {
909                                    $name = '';
910                                    if (isset($inf['channel'])) {
911                                        $alias = $reg->channelAlias($inf['channel']);
912                                        if (!$alias) {
913                                            $alias = '(channel?) ' .$inf['channel'];
914                                        }
915                                        $name = $alias . '/';
916
917                                    }
918                                    if (isset($inf['name'])) {
919                                        $name .= $inf['name'];
920                                    } elseif (isset($inf['pattern'])) {
921                                        $name .= $inf['pattern'];
922                                    } else {
923                                        $name .= '';
924                                    }
925
926                                    if (isset($inf['uri'])) {
927                                        $name .= ' [' . $inf['uri'] .  ']';
928                                    }
929
930                                    if (isset($inf['conflicts'])) {
931                                        $ver = 'conflicts';
932                                    } else {
933                                        $ver = $d->_getExtraString($inf);
934                                    }
935
936                                    $data['data'][] = array($req, ucfirst($deptype), $name,
937                                        $ver, $group);
938                                }
939                            }
940                        }
941                    }
942                }
943            }
944
945            $this->ui->outputData($data, $command);
946            return true;
947        }
948
949        // Fallback
950        $this->ui->outputData("This package does not have any dependencies.", $command);
951    }
952
953    function doSign($command, $options, $params)
954    {
955        // should move most of this code into PEAR_Packager
956        // so it'll be easy to implement "pear package --sign"
957        if (count($params) !== 1) {
958            return $this->raiseError("bad parameter(s), try \"help $command\"");
959        }
960
961        require_once 'System.php';
962        require_once 'Archive/Tar.php';
963
964        if (!file_exists($params[0])) {
965            return $this->raiseError("file does not exist: $params[0]");
966        }
967
968        $obj = $this->getPackageFile($this->config, $this->_debug);
969        $info = $obj->fromTgzFile($params[0], PEAR_VALIDATE_NORMAL);
970        if (PEAR::isError($info)) {
971            return $this->raiseError($info);
972        }
973
974        $tar = new Archive_Tar($params[0]);
975
976        $tmpdir = $this->config->get('temp_dir');
977        $tmpdir = System::mktemp(' -t "' . $tmpdir . '" -d pearsign');
978        if (!$tar->extractList('package2.xml package.xml package.sig', $tmpdir)) {
979            return $this->raiseError("failed to extract tar file");
980        }
981
982        if (file_exists("$tmpdir/package.sig")) {
983            return $this->raiseError("package already signed");
984        }
985
986        $packagexml = 'package.xml';
987        if (file_exists("$tmpdir/package2.xml")) {
988            $packagexml = 'package2.xml';
989        }
990
991        if (file_exists("$tmpdir/package.sig")) {
992            unlink("$tmpdir/package.sig");
993        }
994
995        if (!file_exists("$tmpdir/$packagexml")) {
996            return $this->raiseError("Extracted file $tmpdir/$packagexml not found.");
997        }
998
999        $input = $this->ui->userDialog($command,
1000                                       array('GnuPG Passphrase'),
1001                                       array('password'));
1002        if (!isset($input[0])) {
1003            //use empty passphrase
1004            $input[0] = '';
1005        }
1006
1007        $devnull = (isset($options['verbose'])) ? '' : ' 2>/dev/null';
1008        $gpg = popen("gpg --batch --passphrase-fd 0 --armor --detach-sign --output $tmpdir/package.sig $tmpdir/$packagexml" . $devnull, "w");
1009        if (!$gpg) {
1010            return $this->raiseError("gpg command failed");
1011        }
1012
1013        fwrite($gpg, "$input[0]\n");
1014        if (pclose($gpg) || !file_exists("$tmpdir/package.sig")) {
1015            return $this->raiseError("gpg sign failed");
1016        }
1017
1018        if (!$tar->addModify("$tmpdir/package.sig", '', $tmpdir)) {
1019            return $this->raiseError('failed adding signature to file');
1020        }
1021
1022        $this->ui->outputData("Package signed.", $command);
1023        return true;
1024    }
1025
1026    /**
1027     * For unit testing purposes
1028     */
1029    function &getInstaller(&$ui)
1030    {
1031        if (!class_exists('PEAR_Installer')) {
1032            require_once 'PEAR/Installer.php';
1033        }
1034        $a = &new PEAR_Installer($ui);
1035        return $a;
1036    }
1037
1038    /**
1039     * For unit testing purposes
1040     */
1041    function &getCommandPackaging(&$ui, &$config)
1042    {
1043        if (!class_exists('PEAR_Command_Packaging')) {
1044            if ($fp = @fopen('PEAR/Command/Packaging.php', 'r', true)) {
1045                fclose($fp);
1046                include_once 'PEAR/Command/Packaging.php';
1047            }
1048        }
1049
1050        if (class_exists('PEAR_Command_Packaging')) {
1051            $a = &new PEAR_Command_Packaging($ui, $config);
1052        } else {
1053            $a = null;
1054        }
1055
1056        return $a;
1057    }
1058
1059    function doMakeRPM($command, $options, $params)
1060    {
1061
1062        // Check to see if PEAR_Command_Packaging is installed, and
1063        // transparently switch to use the "make-rpm-spec" command from it
1064        // instead, if it does. Otherwise, continue to use the old version
1065        // of "makerpm" supplied with this package (PEAR).
1066        $packaging_cmd = $this->getCommandPackaging($this->ui, $this->config);
1067        if ($packaging_cmd !== null) {
1068            $this->ui->outputData('PEAR_Command_Packaging is installed; using '.
1069                'newer "make-rpm-spec" command instead');
1070            return $packaging_cmd->run('make-rpm-spec', $options, $params);
1071        }
1072
1073        $this->ui->outputData('WARNING: "pear makerpm" is no longer available; an '.
1074          'improved version is available via "pear make-rpm-spec", which '.
1075          'is available by installing PEAR_Command_Packaging');
1076        return true;
1077    }
1078
1079    function doConvert($command, $options, $params)
1080    {
1081        $packagexml    = isset($params[0]) ? $params[0] : 'package.xml';
1082        $newpackagexml = isset($params[1]) ? $params[1] : dirname($packagexml) .
1083            DIRECTORY_SEPARATOR . 'package2.xml';
1084        $pkg = &$this->getPackageFile($this->config, $this->_debug);
1085        PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
1086        $pf = $pkg->fromPackageFile($packagexml, PEAR_VALIDATE_NORMAL);
1087        PEAR::staticPopErrorHandling();
1088        if (PEAR::isError($pf)) {
1089            if (is_array($pf->getUserInfo())) {
1090                foreach ($pf->getUserInfo() as $warning) {
1091                    $this->ui->outputData($warning['message']);
1092                }
1093            }
1094            return $this->raiseError($pf);
1095        }
1096
1097        if (is_a($pf, 'PEAR_PackageFile_v2')) {
1098            $this->ui->outputData($packagexml . ' is already a package.xml version 2.0');
1099            return true;
1100        }
1101
1102        $gen   = &$pf->getDefaultGenerator();
1103        $newpf = &$gen->toV2();
1104        $newpf->setPackagefile($newpackagexml);
1105        $gen = &$newpf->getDefaultGenerator();
1106        PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
1107        $state = (isset($options['flat']) ? PEAR_VALIDATE_PACKAGING : PEAR_VALIDATE_NORMAL);
1108        $saved = $gen->toPackageFile(dirname($newpackagexml), $state, basename($newpackagexml));
1109        PEAR::staticPopErrorHandling();
1110        if (PEAR::isError($saved)) {
1111            if (is_array($saved->getUserInfo())) {
1112                foreach ($saved->getUserInfo() as $warning) {
1113                    $this->ui->outputData($warning['message']);
1114                }
1115            }
1116
1117            $this->ui->outputData($saved->getMessage());
1118            return true;
1119        }
1120
1121        $this->ui->outputData('Wrote new version 2.0 package.xml to "' . $saved . '"');
1122        return true;
1123    }
1124}
Note: See TracBrowser for help on using the repository browser.