Хранилища Subversion ant

Редакция

Содержимое файла | Последнее изменение | Открыть журнал | RSS

Редакция Автор № строки Строка
69 alex-w 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
 * LICENSE: This source file is subject to version 3.0 of the PHP license
9
 * that is available through the world-wide-web at the following URI:
10
 * http://www.php.net/license/3_0.txt.  If you did not receive a copy of
11
 * the PHP License and are unable to obtain it through the web, please
12
 * send a note to license@php.net so we can mail you a copy immediately.
13
 *
14
 * @category   pear
15
 * @package    PEAR
16
 * @author     Stig Bakken <ssb@php.net>
17
 * @author     Martin Jansen <mj@php.net>
18
 * @author     Greg Beaver <cellog@php.net>
19
 * @copyright  1997-2008 The PHP Group
20
 * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
21
 * @version    CVS: $Id: Package.php,v 1.128 2008/03/29 21:06:58 dufuz Exp $
22
 * @link       http://pear.php.net/package/PEAR
23
 * @since      File available since Release 0.1
24
 */
25
 
26
/**
27
 * base class
28
 */
29
require_once 'PEAR/Command/Common.php';
30
 
31
/**
32
 * PEAR commands for login/logout
33
 *
34
 * @category   pear
35
 * @package    PEAR
36
 * @author     Stig Bakken <ssb@php.net>
37
 * @author     Martin Jansen <mj@php.net>
38
 * @author     Greg Beaver <cellog@php.net>
39
 * @copyright  1997-2008 The PHP Group
40
 * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
41
 * @version    Release: @package_version@
42
 * @link       http://pear.php.net/package/PEAR
43
 * @since      Class available since Release 0.1
44
 */
45
 
46
class PEAR_Command_Package extends PEAR_Command_Common
47
{
48
    // {{{ properties
49
 
50
    var $commands = array(
51
        'package' => array(
52
            'summary' => 'Build Package',
53
            'function' => 'doPackage',
54
            'shortcut' => 'p',
55
            'options' => array(
56
                'nocompress' => array(
57
                    'shortopt' => 'Z',
58
                    'doc' => 'Do not gzip the package file'
59
                    ),
60
                'showname' => array(
61
                    'shortopt' => 'n',
62
                    'doc' => 'Print the name of the packaged file.',
63
                    ),
64
                ),
65
            'doc' => '[descfile] [descfile2]
66
Creates a PEAR package from its description file (usually called
67
package.xml).  If a second packagefile is passed in, then
68
the packager will check to make sure that one is a package.xml
69
version 1.0, and the other is a package.xml version 2.0.  The
70
package.xml version 1.0 will be saved as "package.xml" in the archive,
71
and the other as "package2.xml" in the archive"
72
'
73
            ),
74
        'package-validate' => array(
75
            'summary' => 'Validate Package Consistency',
76
            'function' => 'doPackageValidate',
77
            'shortcut' => 'pv',
78
            'options' => array(),
79
            'doc' => '
80
',
81
            ),
82
        'cvsdiff' => array(
83
            'summary' => 'Run a "cvs diff" for all files in a package',
84
            'function' => 'doCvsDiff',
85
            'shortcut' => 'cd',
86
            'options' => array(
87
                'quiet' => array(
88
                    'shortopt' => 'q',
89
                    'doc' => 'Be quiet',
90
                    ),
91
                'reallyquiet' => array(
92
                    'shortopt' => 'Q',
93
                    'doc' => 'Be really quiet',
94
                    ),
95
                'date' => array(
96
                    'shortopt' => 'D',
97
                    'doc' => 'Diff against revision of DATE',
98
                    'arg' => 'DATE',
99
                    ),
100
                'release' => array(
101
                    'shortopt' => 'R',
102
                    'doc' => 'Diff against tag for package release REL',
103
                    'arg' => 'REL',
104
                    ),
105
                'revision' => array(
106
                    'shortopt' => 'r',
107
                    'doc' => 'Diff against revision REV',
108
                    'arg' => 'REV',
109
                    ),
110
                'context' => array(
111
                    'shortopt' => 'c',
112
                    'doc' => 'Generate context diff',
113
                    ),
114
                'unified' => array(
115
                    'shortopt' => 'u',
116
                    'doc' => 'Generate unified diff',
117
                    ),
118
                'ignore-case' => array(
119
                    'shortopt' => 'i',
120
                    'doc' => 'Ignore case, consider upper- and lower-case letters equivalent',
121
                    ),
122
                'ignore-whitespace' => array(
123
                    'shortopt' => 'b',
124
                    'doc' => 'Ignore changes in amount of white space',
125
                    ),
126
                'ignore-blank-lines' => array(
127
                    'shortopt' => 'B',
128
                    'doc' => 'Ignore changes that insert or delete blank lines',
129
                    ),
130
                'brief' => array(
131
                    'doc' => 'Report only whether the files differ, no details',
132
                    ),
133
                'dry-run' => array(
134
                    'shortopt' => 'n',
135
                    'doc' => 'Don\'t do anything, just pretend',
136
                    ),
137
                ),
138
            'doc' => '<package.xml>
139
Compares all the files in a package.  Without any options, this
140
command will compare the current code with the last checked-in code.
141
Using the -r or -R option you may compare the current code with that
142
of a specific release.
143
',
144
            ),
145
        'cvstag' => array(
146
            'summary' => 'Set CVS Release Tag',
147
            'function' => 'doCvsTag',
148
            'shortcut' => 'ct',
149
            'options' => array(
150
                'quiet' => array(
151
                    'shortopt' => 'q',
152
                    'doc' => 'Be quiet',
153
                    ),
154
                'reallyquiet' => array(
155
                    'shortopt' => 'Q',
156
                    'doc' => 'Be really quiet',
157
                    ),
158
                'slide' => array(
159
                    'shortopt' => 'F',
160
                    'doc' => 'Move (slide) tag if it exists',
161
                    ),
162
                'delete' => array(
163
                    'shortopt' => 'd',
164
                    'doc' => 'Remove tag',
165
                    ),
166
                'dry-run' => array(
167
                    'shortopt' => 'n',
168
                    'doc' => 'Don\'t do anything, just pretend',
169
                    ),
170
                ),
171
            'doc' => '<package.xml> [files...]
172
Sets a CVS tag on all files in a package.  Use this command after you have
173
packaged a distribution tarball with the "package" command to tag what
174
revisions of what files were in that release.  If need to fix something
175
after running cvstag once, but before the tarball is released to the public,
176
use the "slide" option to move the release tag.
177
 
178
to include files (such as a second package.xml, or tests not included in the
179
release), pass them as additional parameters.
180
',
181
            ),
182
        'package-dependencies' => array(
183
            'summary' => 'Show package dependencies',
184
            'function' => 'doPackageDependencies',
185
            'shortcut' => 'pd',
186
            'options' => array(),
187
            'doc' => '
188
List all dependencies the package has.'
189
            ),
190
        'sign' => array(
191
            'summary' => 'Sign a package distribution file',
192
            'function' => 'doSign',
193
            'shortcut' => 'si',
194
            'options' => array(
195
                'verbose' => array(
196
                    'shortopt' => 'v',
197
                    'doc' => 'Display GnuPG output',
198
                    ),
199
            ),
200
            'doc' => '<package-file>
201
Signs a package distribution (.tar or .tgz) file with GnuPG.',
202
            ),
203
        'makerpm' => array(
204
            'summary' => 'Builds an RPM spec file from a PEAR package',
205
            'function' => 'doMakeRPM',
206
            'shortcut' => 'rpm',
207
            'options' => array(
208
                'spec-template' => array(
209
                    'shortopt' => 't',
210
                    'arg' => 'FILE',
211
                    'doc' => 'Use FILE as RPM spec file template'
212
                    ),
213
                'rpm-pkgname' => array(
214
                    'shortopt' => 'p',
215
                    'arg' => 'FORMAT',
216
                    'doc' => 'Use FORMAT as format string for RPM package name, %s is replaced
217
by the PEAR package name, defaults to "PEAR::%s".',
218
                    ),
219
                ),
220
            'doc' => '<package-file>
221
 
222
Creates an RPM .spec file for wrapping a PEAR package inside an RPM
223
package.  Intended to be used from the SPECS directory, with the PEAR
224
package tarball in the SOURCES directory:
225
 
226
$ pear makerpm ../SOURCES/Net_Socket-1.0.tgz
227
Wrote RPM spec file PEAR::Net_Geo-1.0.spec
228
$ rpm -bb PEAR::Net_Socket-1.0.spec
229
...
230
Wrote: /usr/src/redhat/RPMS/i386/PEAR::Net_Socket-1.0-1.i386.rpm
231
',
232
            ),
233
        'convert' => array(
234
            'summary' => 'Convert a package.xml 1.0 to package.xml 2.0 format',
235
            'function' => 'doConvert',
236
            'shortcut' => 'c2',
237
            'options' => array(
238
                'flat' => array(
239
                    'shortopt' => 'f',
240
                    'doc' => 'do not beautify the filelist.',
241
                    ),
242
                ),
243
            'doc' => '[descfile] [descfile2]
244
Converts a package.xml in 1.0 format into a package.xml
245
in 2.0 format.  The new file will be named package2.xml by default,
246
and package.xml will be used as the old file by default.
247
This is not the most intelligent conversion, and should only be
248
used for automated conversion or learning the format.
249
'
250
            ),
251
        );
252
 
253
    var $output;
254
 
255
    // }}}
256
    // {{{ constructor
257
 
258
    /**
259
     * PEAR_Command_Package constructor.
260
     *
261
     * @access public
262
     */
263
    function PEAR_Command_Package(&$ui, &$config)
264
    {
265
        parent::PEAR_Command_Common($ui, $config);
266
    }
267
 
268
    // }}}
269
 
270
    // {{{ _displayValidationResults()
271
 
272
    function _displayValidationResults($err, $warn, $strict = false)
273
    {
274
        foreach ($err as $e) {
275
            $this->output .= "Error: $e\n";
276
        }
277
        foreach ($warn as $w) {
278
            $this->output .= "Warning: $w\n";
279
        }
280
        $this->output .= sprintf('Validation: %d error(s), %d warning(s)'."\n",
281
                                       sizeof($err), sizeof($warn));
282
        if ($strict && sizeof($err) > 0) {
283
            $this->output .= "Fix these errors and try again.";
284
            return false;
285
        }
286
        return true;
287
    }
288
 
289
    // }}}
290
    function &getPackager()
291
    {
292
        if (!class_exists('PEAR_Packager')) {
293
            require_once 'PEAR/Packager.php';
294
        }
295
        $a = &new PEAR_Packager;
296
        return $a;
297
    }
298
 
299
    function &getPackageFile($config, $debug = false, $tmpdir = null)
300
    {
301
        if (!class_exists('PEAR_Common')) {
302
            require_once 'PEAR/Common.php';
303
        }
304
        if (!class_exists('PEAR_PackageFile')) {
305
            require_once 'PEAR/PackageFile.php';
306
        }
307
        $a = &new PEAR_PackageFile($config, $debug, $tmpdir);
308
        $common = new PEAR_Common;
309
        $common->ui = $this->ui;
310
        $a->setLogger($common);
311
        return $a;
312
    }
313
    // {{{ doPackage()
314
 
315
    function doPackage($command, $options, $params)
316
    {
317
        $this->output = '';
318
        $pkginfofile = isset($params[0]) ? $params[0] : 'package.xml';
319
        $pkg2 = isset($params[1]) ? $params[1] : null;
320
        if (!$pkg2 && !isset($params[0])) {
321
            if (file_exists('package2.xml')) {
322
                $pkg2 = 'package2.xml';
323
            }
324
        }
325
        $packager = &$this->getPackager();
326
        $compress = empty($options['nocompress']) ? true : false;
327
        $result = $packager->package($pkginfofile, $compress, $pkg2);
328
        if (PEAR::isError($result)) {
329
            return $this->raiseError($result);
330
        }
331
        // Don't want output, only the package file name just created
332
        if (isset($options['showname'])) {
333
            $this->output = $result;
334
        }
335
        if ($this->output) {
336
            $this->ui->outputData($this->output, $command);
337
        }
338
        return true;
339
    }
340
 
341
    // }}}
342
    // {{{ doPackageValidate()
343
 
344
    function doPackageValidate($command, $options, $params)
345
    {
346
        $this->output = '';
347
        if (sizeof($params) < 1) {
348
            $params[0] = "package.xml";
349
        }
350
        $obj = &$this->getPackageFile($this->config, $this->_debug);
351
        $obj->rawReturn();
352
        PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
353
        $info = $obj->fromTgzFile($params[0], PEAR_VALIDATE_NORMAL);
354
        if (PEAR::isError($info)) {
355
            $info = $obj->fromPackageFile($params[0], PEAR_VALIDATE_NORMAL);
356
        } else {
357
            $archive = $info->getArchiveFile();
358
            $tar = &new Archive_Tar($archive);
359
            $tar->extract(dirname($info->getPackageFile()));
360
            $info->setPackageFile(dirname($info->getPackageFile()) . DIRECTORY_SEPARATOR .
361
                $info->getPackage() . '-' . $info->getVersion() . DIRECTORY_SEPARATOR .
362
                basename($info->getPackageFile()));
363
        }
364
        PEAR::staticPopErrorHandling();
365
        if (PEAR::isError($info)) {
366
            return $this->raiseError($info);
367
        }
368
        $valid = false;
369
        if ($info->getPackagexmlVersion() == '2.0') {
370
            if ($valid = $info->validate(PEAR_VALIDATE_NORMAL)) {
371
                $info->flattenFileList();
372
                $valid = $info->validate(PEAR_VALIDATE_PACKAGING);
373
            }
374
        } else {
375
            $valid = $info->validate(PEAR_VALIDATE_PACKAGING);
376
        }
377
        $err = $warn = array();
378
        if ($errors = $info->getValidationWarnings()) {
379
            foreach ($errors as $error) {
380
                if ($error['level'] == 'warning') {
381
                    $warn[] = $error['message'];
382
                } else {
383
                    $err[] = $error['message'];
384
                }
385
            }
386
        }
387
        $this->_displayValidationResults($err, $warn);
388
        $this->ui->outputData($this->output, $command);
389
        return true;
390
    }
391
 
392
    // }}}
393
    // {{{ doCvsTag()
394
 
395
    function doCvsTag($command, $options, $params)
396
    {
397
        $this->output = '';
398
        $_cmd = $command;
399
        if (sizeof($params) < 1) {
400
            $help = $this->getHelp($command);
401
            return $this->raiseError("$command: missing parameter: $help[0]");
402
        }
403
        $obj = &$this->getPackageFile($this->config, $this->_debug);
404
        $info = $obj->fromAnyFile($params[0], PEAR_VALIDATE_NORMAL);
405
        if (PEAR::isError($info)) {
406
            return $this->raiseError($info);
407
        }
408
        $err = $warn = array();
409
        if (!$info->validate()) {
410
            foreach ($info->getValidationWarnings() as $error) {
411
                if ($error['level'] == 'warning') {
412
                    $warn[] = $error['message'];
413
                } else {
414
                    $err[] = $error['message'];
415
                }
416
            }
417
        }
418
        if (!$this->_displayValidationResults($err, $warn, true)) {
419
            $this->ui->outputData($this->output, $command);
420
            return $this->raiseError('CVS tag failed');
421
        }
422
        $version = $info->getVersion();
423
        $cvsversion = preg_replace('/[^a-z0-9]/i', '_', $version);
424
        $cvstag = "RELEASE_$cvsversion";
425
        $files = array_keys($info->getFilelist());
426
        $command = "cvs";
427
        if (isset($options['quiet'])) {
428
            $command .= ' -q';
429
        }
430
        if (isset($options['reallyquiet'])) {
431
            $command .= ' -Q';
432
        }
433
        $command .= ' tag';
434
        if (isset($options['slide'])) {
435
            $command .= ' -F';
436
        }
437
        if (isset($options['delete'])) {
438
            $command .= ' -d';
439
        }
440
        $command .= ' ' . $cvstag . ' ' . escapeshellarg($params[0]);
441
        array_shift($params);
442
        if (count($params)) {
443
            // add in additional files to be tagged
444
            $files = array_merge($files, $params);
445
        }
446
        foreach ($files as $file) {
447
            $command .= ' ' . escapeshellarg($file);
448
        }
449
        if ($this->config->get('verbose') > 1) {
450
            $this->output .= "+ $command\n";
451
        }
452
        $this->output .= "+ $command\n";
453
        if (empty($options['dry-run'])) {
454
            $fp = popen($command, "r");
455
            while ($line = fgets($fp, 1024)) {
456
                $this->output .= rtrim($line)."\n";
457
            }
458
            pclose($fp);
459
        }
460
        $this->ui->outputData($this->output, $_cmd);
461
        return true;
462
    }
463
 
464
    // }}}
465
    // {{{ doCvsDiff()
466
 
467
    function doCvsDiff($command, $options, $params)
468
    {
469
        $this->output = '';
470
        if (sizeof($params) < 1) {
471
            $help = $this->getHelp($command);
472
            return $this->raiseError("$command: missing parameter: $help[0]");
473
        }
474
        $obj = &$this->getPackageFile($this->config, $this->_debug);
475
        $info = $obj->fromAnyFile($params[0], PEAR_VALIDATE_NORMAL);
476
        if (PEAR::isError($info)) {
477
            return $this->raiseError($info);
478
        }
479
        $err = $warn = array();
480
        if (!$info->validate()) {
481
            foreach ($info->getValidationWarnings() as $error) {
482
                if ($error['level'] == 'warning') {
483
                    $warn[] = $error['message'];
484
                } else {
485
                    $err[] = $error['message'];
486
                }
487
            }
488
        }
489
        if (!$this->_displayValidationResults($err, $warn, true)) {
490
            $this->ui->outputData($this->output, $command);
491
            return $this->raiseError('CVS diff failed');
492
        }
493
        $info1 = $info->getFilelist();
494
        $files = $info1;
495
        $cmd = "cvs";
496
        if (isset($options['quiet'])) {
497
            $cmd .= ' -q';
498
            unset($options['quiet']);
499
        }
500
        if (isset($options['reallyquiet'])) {
501
            $cmd .= ' -Q';
502
            unset($options['reallyquiet']);
503
        }
504
        if (isset($options['release'])) {
505
            $cvsversion = preg_replace('/[^a-z0-9]/i', '_', $options['release']);
506
            $cvstag = "RELEASE_$cvsversion";
507
            $options['revision'] = $cvstag;
508
            unset($options['release']);
509
        }
510
        $execute = true;
511
        if (isset($options['dry-run'])) {
512
            $execute = false;
513
            unset($options['dry-run']);
514
        }
515
        $cmd .= ' diff';
516
        // the rest of the options are passed right on to "cvs diff"
517
        foreach ($options as $option => $optarg) {
518
            $arg = $short = false;
519
            if (isset($this->commands[$command]['options'][$option])) {
520
                $arg = $this->commands[$command]['options'][$option]['arg'];
521
                $short = $this->commands[$command]['options'][$option]['shortopt'];
522
            }
523
            $cmd .= $short ? " -$short" : " --$option";
524
            if ($arg && $optarg) {
525
                $cmd .= ($short ? '' : '=') . escapeshellarg($optarg);
526
            }
527
        }
528
        foreach ($files as $file) {
529
            $cmd .= ' ' . escapeshellarg($file['name']);
530
        }
531
        if ($this->config->get('verbose') > 1) {
532
            $this->output .= "+ $cmd\n";
533
        }
534
        if ($execute) {
535
            $fp = popen($cmd, "r");
536
            while ($line = fgets($fp, 1024)) {
537
                $this->output .= rtrim($line)."\n";
538
            }
539
            pclose($fp);
540
        }
541
        $this->ui->outputData($this->output, $command);
542
        return true;
543
    }
544
 
545
    // }}}
546
    // {{{ doPackageDependencies()
547
 
548
    function doPackageDependencies($command, $options, $params)
549
    {
550
        // $params[0] -> the PEAR package to list its information
551
        if (sizeof($params) != 1) {
552
            return $this->raiseError("bad parameter(s), try \"help $command\"");
553
        }
554
        $obj = &$this->getPackageFile($this->config, $this->_debug);
555
        $info = $obj->fromAnyFile($params[0], PEAR_VALIDATE_NORMAL);
556
        if (PEAR::isError($info)) {
557
            return $this->raiseError($info);
558
        }
559
        $deps = $info->getDeps();
560
        if (is_array($deps)) {
561
            if ($info->getPackagexmlVersion() == '1.0') {
562
                $data = array(
563
                    'caption' => 'Dependencies for pear/' . $info->getPackage(),
564
                    'border' => true,
565
                    'headline' => array("Required?", "Type", "Name", "Relation", "Version"),
566
                    );
567
 
568
                foreach ($deps as $d) {
569
                    if (isset($d['optional'])) {
570
                        if ($d['optional'] == 'yes') {
571
                            $req = 'No';
572
                        } else {
573
                            $req = 'Yes';
574
                        }
575
                    } else {
576
                        $req = 'Yes';
577
                    }
578
                    if (isset($this->_deps_rel_trans[$d['rel']])) {
579
                        $rel = $this->_deps_rel_trans[$d['rel']];
580
                    } else {
581
                        $rel = $d['rel'];
582
                    }
583
 
584
                    if (isset($this->_deps_type_trans[$d['type']])) {
585
                        $type = ucfirst($this->_deps_type_trans[$d['type']]);
586
                    } else {
587
                        $type = $d['type'];
588
                    }
589
 
590
                    if (isset($d['name'])) {
591
                        $name = $d['name'];
592
                    } else {
593
                        $name = '';
594
                    }
595
 
596
                    if (isset($d['version'])) {
597
                        $version = $d['version'];
598
                    } else {
599
                        $version = '';
600
                    }
601
 
602
                    $data['data'][] = array($req, $type, $name, $rel, $version);
603
                }
604
            } else { // package.xml 2.0 dependencies display
605
                require_once 'PEAR/Dependency2.php';
606
                $deps = $info->getDependencies();
607
                $reg = &$this->config->getRegistry();
608
                if (is_array($deps)) {
609
                    $d = new PEAR_Dependency2($this->config, array(), '');
610
                    $data = array(
611
                        'caption' => 'Dependencies for ' . $info->getPackage(),
612
                        'border' => true,
613
                        'headline' => array("Required?", "Type", "Name", 'Versioning', 'Group'),
614
                        );
615
                    foreach ($deps as $type => $subd) {
616
                        $req = ($type == 'required') ? 'Yes' : 'No';
617
                        if ($type == 'group') {
618
                            $group = $subd['attribs']['name'];
619
                        } else {
620
                            $group = '';
621
                        }
622
                        if (!isset($subd[0])) {
623
                            $subd = array($subd);
624
                        }
625
                        foreach ($subd as $groupa) {
626
                            foreach ($groupa as $deptype => $depinfo) {
627
                                if ($deptype == 'attribs') {
628
                                    continue;
629
                                }
630
                                if ($deptype == 'pearinstaller') {
631
                                    $deptype = 'pear Installer';
632
                                }
633
                                if (!isset($depinfo[0])) {
634
                                    $depinfo = array($depinfo);
635
                                }
636
                                foreach ($depinfo as $inf) {
637
                                    $name = '';
638
                                    if (isset($inf['channel'])) {
639
                                        $alias = $reg->channelAlias($inf['channel']);
640
                                        if (!$alias) {
641
                                            $alias = '(channel?) ' .$inf['channel'];
642
                                        }
643
                                        $name = $alias . '/';
644
                                    }
645
                                    if (isset($inf['name'])) {
646
                                        $name .= $inf['name'];
647
                                    } elseif (isset($inf['pattern'])) {
648
                                        $name .= $inf['pattern'];
649
                                    } else {
650
                                        $name .= '';
651
                                    }
652
                                    if (isset($inf['uri'])) {
653
                                        $name .= ' [' . $inf['uri'] .  ']';
654
                                    }
655
                                    if (isset($inf['conflicts'])) {
656
                                        $ver = 'conflicts';
657
                                    } else {
658
                                        $ver = $d->_getExtraString($inf);
659
                                    }
660
                                    $data['data'][] = array($req, ucfirst($deptype), $name,
661
                                        $ver, $group);
662
                                }
663
                            }
664
                        }
665
                    }
666
                }
667
            }
668
 
669
            $this->ui->outputData($data, $command);
670
            return true;
671
        }
672
 
673
        // Fallback
674
        $this->ui->outputData("This package does not have any dependencies.", $command);
675
    }
676
 
677
    // }}}
678
    // {{{ doSign()
679
 
680
    function doSign($command, $options, $params)
681
    {
682
        require_once 'System.php';
683
        require_once 'Archive/Tar.php';
684
        // should move most of this code into PEAR_Packager
685
        // so it'll be easy to implement "pear package --sign"
686
        if (sizeof($params) != 1) {
687
            return $this->raiseError("bad parameter(s), try \"help $command\"");
688
        }
689
        if (!file_exists($params[0])) {
690
            return $this->raiseError("file does not exist: $params[0]");
691
        }
692
        $obj = $this->getPackageFile($this->config, $this->_debug);
693
        $info = $obj->fromTgzFile($params[0], PEAR_VALIDATE_NORMAL);
694
        if (PEAR::isError($info)) {
695
            return $this->raiseError($info);
696
        }
697
        $tar = new Archive_Tar($params[0]);
698
        $tmpdir = System::mktemp('-d pearsign');
699
        if (!$tar->extractList('package2.xml package.xml package.sig', $tmpdir)) {
700
            return $this->raiseError("failed to extract tar file");
701
        }
702
        if (file_exists("$tmpdir/package.sig")) {
703
            return $this->raiseError("package already signed");
704
        }
705
        $packagexml = 'package.xml';
706
        if (file_exists("$tmpdir/package2.xml")) {
707
            $packagexml = 'package2.xml';
708
        }
709
        if (file_exists("$tmpdir/package.sig")) {
710
            unlink("$tmpdir/package.sig");
711
        }
712
        if (!file_exists("$tmpdir/$packagexml")) {
713
            return $this->raiseError("Extracted file $tmpdir/$packagexml not found.");
714
        }
715
        $input = $this->ui->userDialog($command,
716
                                       array('GnuPG Passphrase'),
717
                                       array('password'));
718
        if (!isset($input[0])) {
719
            //use empty passphrase
720
            $input[0] = '';
721
        }
722
 
723
        $devnull = (isset($options['verbose'])) ? '' : ' 2>/dev/null';
724
        $gpg = popen("gpg --batch --passphrase-fd 0 --armor --detach-sign --output $tmpdir/package.sig $tmpdir/$packagexml" . $devnull, "w");
725
        if (!$gpg) {
726
            return $this->raiseError("gpg command failed");
727
        }
728
        fwrite($gpg, "$input[0]\n");
729
        if (pclose($gpg) || !file_exists("$tmpdir/package.sig")) {
730
            return $this->raiseError("gpg sign failed");
731
        }
732
        if (!$tar->addModify("$tmpdir/package.sig", '', $tmpdir)) {
733
            return $this->raiseError('failed adding signature to file');
734
        }
735
 
736
        $this->ui->outputData("Package signed.", $command);
737
        return true;
738
    }
739
 
740
    // }}}
741
 
742
    /**
743
     * For unit testing purposes
744
     */
745
    function &getInstaller(&$ui)
746
    {
747
        if (!class_exists('PEAR_Installer')) {
748
            require_once 'PEAR/Installer.php';
749
        }
750
        $a = &new PEAR_Installer($ui);
751
        return $a;
752
    }
753
 
754
    /**
755
     * For unit testing purposes
756
     */
757
    function &getCommandPackaging(&$ui, &$config)
758
    {
759
        if (!class_exists('PEAR_Command_Packaging')) {
760
            if ($fp = @fopen('PEAR/Command/Packaging.php', 'r', true)) {
761
                fclose($fp);
762
                include_once 'PEAR/Command/Packaging.php';
763
            }
764
        }
765
 
766
        if (class_exists('PEAR_Command_Packaging')) {
767
            $a = &new PEAR_Command_Packaging($ui, $config);
768
        } else {
769
            $a = null;
770
        }
771
        return $a;
772
    }
773
 
774
    // {{{ doMakeRPM()
775
 
776
    function doMakeRPM($command, $options, $params)
777
    {
778
 
779
        // Check to see if PEAR_Command_Packaging is installed, and
780
        // transparently switch to use the "make-rpm-spec" command from it
781
        // instead, if it does. Otherwise, continue to use the old version
782
        // of "makerpm" supplied with this package (PEAR).
783
        $packaging_cmd = $this->getCommandPackaging($this->ui, $this->config);
784
        if ($packaging_cmd !== null) {
785
            $this->ui->outputData('PEAR_Command_Packaging is installed; using '.
786
                'newer "make-rpm-spec" command instead');
787
            return $packaging_cmd->run('make-rpm-spec', $options, $params);
788
        } else {
789
            $this->ui->outputData('WARNING: "pear makerpm" is no longer available; an '.
790
              'improved version is available via "pear make-rpm-spec", which '.
791
              'is available by installing PEAR_Command_Packaging');
792
        }
793
        return true;
794
    }
795
 
796
    function doConvert($command, $options, $params)
797
    {
798
        $packagexml = isset($params[0]) ? $params[0] : 'package.xml';
799
        $newpackagexml = isset($params[1]) ? $params[1] : dirname($packagexml) .
800
            DIRECTORY_SEPARATOR . 'package2.xml';
801
        $pkg = &$this->getPackageFile($this->config, $this->_debug);
802
        PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
803
        $pf = $pkg->fromPackageFile($packagexml, PEAR_VALIDATE_NORMAL);
804
        PEAR::staticPopErrorHandling();
805
        if (!PEAR::isError($pf)) {
806
            if (is_a($pf, 'PEAR_PackageFile_v2')) {
807
                $this->ui->outputData($packagexml . ' is already a package.xml version 2.0');
808
                return true;
809
            }
810
            $gen = &$pf->getDefaultGenerator();
811
            $newpf = &$gen->toV2();
812
            $newpf->setPackagefile($newpackagexml);
813
            $gen = &$newpf->getDefaultGenerator();
814
            PEAR::staticPushErrorHandling(PEAR_ERROR_RETURN);
815
            $state = (isset($options['flat']) ? PEAR_VALIDATE_PACKAGING : PEAR_VALIDATE_NORMAL);
816
            $saved = $gen->toPackageFile(dirname($newpackagexml), $state,
817
                basename($newpackagexml));
818
            PEAR::staticPopErrorHandling();
819
            if (PEAR::isError($saved)) {
820
                if (is_array($saved->getUserInfo())) {
821
                    foreach ($saved->getUserInfo() as $warning) {
822
                        $this->ui->outputData($warning['message']);
823
                    }
824
                }
825
                $this->ui->outputData($saved->getMessage());
826
                return true;
827
            }
828
            $this->ui->outputData('Wrote new version 2.0 package.xml to "' . $saved . '"');
829
            return true;
830
        } else {
831
            if (is_array($pf->getUserInfo())) {
832
                foreach ($pf->getUserInfo() as $warning) {
833
                    $this->ui->outputData($warning['message']);
834
                }
835
            }
836
            return $this->raiseError($pf);
837
        }
838
    }
839
 
840
    // }}}
841
}
842
 
843
?>