Subversion Repositories Applications.gtt

Rev

Rev 94 | Details | Compare with Previous | Last modification | View Log | RSS feed

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