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

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

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

Line 
1<?php
2/**
3 * PEAR_Frontend_CLI
4 *
5 * PHP versions 4 and 5
6 *
7 * @category   pear
8 * @package    PEAR
9 * @author     Stig Bakken <ssb@php.net>
10 * @author     Greg Beaver <cellog@php.net>
11 * @copyright  1997-2009 The Authors
12 * @license    http://opensource.org/licenses/bsd-license.php New BSD License
13 * @version    CVS: $Id: CLI.php 313023 2011-07-06 19:17:11Z dufuz $
14 * @link       http://pear.php.net/package/PEAR
15 * @since      File available since Release 0.1
16 */
17/**
18 * base class
19 */
20require_once 'PEAR/Frontend.php';
21
22/**
23 * Command-line Frontend for the PEAR Installer
24 * @category   pear
25 * @package    PEAR
26 * @author     Stig Bakken <ssb@php.net>
27 * @author     Greg Beaver <cellog@php.net>
28 * @copyright  1997-2009 The Authors
29 * @license    http://opensource.org/licenses/bsd-license.php New BSD License
30 * @version    Release: 1.9.4
31 * @link       http://pear.php.net/package/PEAR
32 * @since      Class available since Release 0.1
33 */
34class PEAR_Frontend_CLI extends PEAR_Frontend
35{
36    /**
37     * What type of user interface this frontend is for.
38     * @var string
39     * @access public
40     */
41    var $type = 'CLI';
42    var $lp = ''; // line prefix
43
44    var $params = array();
45    var $term = array(
46        'bold'   => '',
47        'normal' => '',
48    );
49
50    function PEAR_Frontend_CLI()
51    {
52        parent::PEAR();
53        $term = getenv('TERM'); //(cox) $_ENV is empty for me in 4.1.1
54        if (function_exists('posix_isatty') && !posix_isatty(1)) {
55            // output is being redirected to a file or through a pipe
56        } elseif ($term) {
57            if (preg_match('/^(xterm|vt220|linux)/', $term)) {
58                $this->term['bold']   = sprintf("%c%c%c%c", 27, 91, 49, 109);
59                $this->term['normal'] = sprintf("%c%c%c", 27, 91, 109);
60            } elseif (preg_match('/^vt100/', $term)) {
61                $this->term['bold']   = sprintf("%c%c%c%c%c%c", 27, 91, 49, 109, 0, 0);
62                $this->term['normal'] = sprintf("%c%c%c%c%c", 27, 91, 109, 0, 0);
63            }
64        } elseif (OS_WINDOWS) {
65            // XXX add ANSI codes here
66        }
67    }
68
69    /**
70     * @param object PEAR_Error object
71     */
72    function displayError($e)
73    {
74        return $this->_displayLine($e->getMessage());
75    }
76
77    /**
78     * @param object PEAR_Error object
79     */
80    function displayFatalError($eobj)
81    {
82        $this->displayError($eobj);
83        if (class_exists('PEAR_Config')) {
84            $config = &PEAR_Config::singleton();
85            if ($config->get('verbose') > 5) {
86                if (function_exists('debug_print_backtrace')) {
87                    debug_print_backtrace();
88                    exit(1);
89                }
90
91                $raised = false;
92                foreach (debug_backtrace() as $i => $frame) {
93                    if (!$raised) {
94                        if (isset($frame['class'])
95                            && strtolower($frame['class']) == 'pear'
96                            && strtolower($frame['function']) == 'raiseerror'
97                        ) {
98                            $raised = true;
99                        } else {
100                            continue;
101                        }
102                    }
103
104                    $frame['class']    = !isset($frame['class'])    ? '' : $frame['class'];
105                    $frame['type']     = !isset($frame['type'])     ? '' : $frame['type'];
106                    $frame['function'] = !isset($frame['function']) ? '' : $frame['function'];
107                    $frame['line']     = !isset($frame['line'])     ? '' : $frame['line'];
108                    $this->_displayLine("#$i: $frame[class]$frame[type]$frame[function] $frame[line]");
109                }
110            }
111        }
112
113        exit(1);
114    }
115
116    /**
117     * Instruct the runInstallScript method to skip a paramgroup that matches the
118     * id value passed in.
119     *
120     * This method is useful for dynamically configuring which sections of a post-install script
121     * will be run based on the user's setup, which is very useful for making flexible
122     * post-install scripts without losing the cross-Frontend ability to retrieve user input
123     * @param string
124     */
125    function skipParamgroup($id)
126    {
127        $this->_skipSections[$id] = true;
128    }
129
130    function runPostinstallScripts(&$scripts)
131    {
132        foreach ($scripts as $i => $script) {
133            $this->runInstallScript($scripts[$i]->_params, $scripts[$i]->_obj);
134        }
135    }
136
137    /**
138     * @param array $xml contents of postinstallscript tag
139     * @param object $script post-installation script
140     * @param string install|upgrade
141     */
142    function runInstallScript($xml, &$script)
143    {
144        $this->_skipSections = array();
145        if (!is_array($xml) || !isset($xml['paramgroup'])) {
146            $script->run(array(), '_default');
147            return;
148        }
149
150        $completedPhases = array();
151        if (!isset($xml['paramgroup'][0])) {
152            $xml['paramgroup'] = array($xml['paramgroup']);
153        }
154
155        foreach ($xml['paramgroup'] as $group) {
156            if (isset($this->_skipSections[$group['id']])) {
157                // the post-install script chose to skip this section dynamically
158                continue;
159            }
160
161            if (isset($group['name'])) {
162                $paramname = explode('::', $group['name']);
163                if ($lastgroup['id'] != $paramname[0]) {
164                    continue;
165                }
166
167                $group['name'] = $paramname[1];
168                if (!isset($answers)) {
169                    return;
170                }
171
172                if (isset($answers[$group['name']])) {
173                    switch ($group['conditiontype']) {
174                        case '=' :
175                            if ($answers[$group['name']] != $group['value']) {
176                                continue 2;
177                            }
178                        break;
179                        case '!=' :
180                            if ($answers[$group['name']] == $group['value']) {
181                                continue 2;
182                            }
183                        break;
184                        case 'preg_match' :
185                            if (!@preg_match('/' . $group['value'] . '/',
186                                  $answers[$group['name']])) {
187                                continue 2;
188                            }
189                        break;
190                        default :
191                        return;
192                    }
193                }
194            }
195
196            $lastgroup = $group;
197            if (isset($group['instructions'])) {
198                $this->_display($group['instructions']);
199            }
200
201            if (!isset($group['param'][0])) {
202                $group['param'] = array($group['param']);
203            }
204
205            if (isset($group['param'])) {
206                if (method_exists($script, 'postProcessPrompts')) {
207                    $prompts = $script->postProcessPrompts($group['param'], $group['id']);
208                    if (!is_array($prompts) || count($prompts) != count($group['param'])) {
209                        $this->outputData('postinstall', 'Error: post-install script did not ' .
210                            'return proper post-processed prompts');
211                        $prompts = $group['param'];
212                    } else {
213                        foreach ($prompts as $i => $var) {
214                            if (!is_array($var) || !isset($var['prompt']) ||
215                                  !isset($var['name']) ||
216                                  ($var['name'] != $group['param'][$i]['name']) ||
217                                  ($var['type'] != $group['param'][$i]['type'])
218                            ) {
219                                $this->outputData('postinstall', 'Error: post-install script ' .
220                                    'modified the variables or prompts, severe security risk. ' .
221                                    'Will instead use the defaults from the package.xml');
222                                $prompts = $group['param'];
223                            }
224                        }
225                    }
226
227                    $answers = $this->confirmDialog($prompts);
228                } else {
229                    $answers = $this->confirmDialog($group['param']);
230                }
231            }
232
233            if ((isset($answers) && $answers) || !isset($group['param'])) {
234                if (!isset($answers)) {
235                    $answers = array();
236                }
237
238                array_unshift($completedPhases, $group['id']);
239                if (!$script->run($answers, $group['id'])) {
240                    $script->run($completedPhases, '_undoOnError');
241                    return;
242                }
243            } else {
244                $script->run($completedPhases, '_undoOnError');
245                return;
246            }
247        }
248    }
249
250    /**
251     * Ask for user input, confirm the answers and continue until the user is satisfied
252     * @param array an array of arrays, format array('name' => 'paramname', 'prompt' =>
253     *              'text to display', 'type' => 'string'[, default => 'default value'])
254     * @return array
255     */
256    function confirmDialog($params)
257    {
258        $answers = $prompts = $types = array();
259        foreach ($params as $param) {
260            $prompts[$param['name']] = $param['prompt'];
261            $types[$param['name']]   = $param['type'];
262            $answers[$param['name']] = isset($param['default']) ? $param['default'] : '';
263        }
264
265        $tried = false;
266        do {
267            if ($tried) {
268                $i = 1;
269                foreach ($answers as $var => $value) {
270                    if (!strlen($value)) {
271                        echo $this->bold("* Enter an answer for #" . $i . ": ({$prompts[$var]})\n");
272                    }
273                    $i++;
274                }
275            }
276
277            $answers = $this->userDialog('', $prompts, $types, $answers);
278            $tried   = true;
279        } while (is_array($answers) && count(array_filter($answers)) != count($prompts));
280
281        return $answers;
282    }
283
284    function userDialog($command, $prompts, $types = array(), $defaults = array(), $screensize = 20)
285    {
286        if (!is_array($prompts)) {
287            return array();
288        }
289
290        $testprompts = array_keys($prompts);
291        $result      = $defaults;
292
293        reset($prompts);
294        if (count($prompts) === 1) {
295            foreach ($prompts as $key => $prompt) {
296                $type    = $types[$key];
297                $default = @$defaults[$key];
298                print "$prompt ";
299                if ($default) {
300                    print "[$default] ";
301                }
302                print ": ";
303
304                $line         = fgets(STDIN, 2048);
305                $result[$key] =  ($default && trim($line) == '') ? $default : trim($line);
306            }
307
308            return $result;
309        }
310
311        $first_run = true;
312        while (true) {
313            $descLength = max(array_map('strlen', $prompts));
314            $descFormat = "%-{$descLength}s";
315            $last       = count($prompts);
316
317            $i = 0;
318            foreach ($prompts as $n => $var) {
319                $res = isset($result[$n]) ? $result[$n] : null;
320                printf("%2d. $descFormat : %s\n", ++$i, $prompts[$n], $res);
321            }
322            print "\n1-$last, 'all', 'abort', or Enter to continue: ";
323
324            $tmp = trim(fgets(STDIN, 1024));
325            if (empty($tmp)) {
326                break;
327            }
328
329            if ($tmp == 'abort') {
330                return false;
331            }
332
333            if (isset($testprompts[(int)$tmp - 1])) {
334                $var     = $testprompts[(int)$tmp - 1];
335                $desc    = $prompts[$var];
336                $current = @$result[$var];
337                print "$desc [$current] : ";
338                $tmp = trim(fgets(STDIN, 1024));
339                if ($tmp !== '') {
340                    $result[$var] = $tmp;
341                }
342            } elseif ($tmp == 'all') {
343                foreach ($prompts as $var => $desc) {
344                    $current = $result[$var];
345                    print "$desc [$current] : ";
346                    $tmp = trim(fgets(STDIN, 1024));
347                    if (trim($tmp) !== '') {
348                        $result[$var] = trim($tmp);
349                    }
350                }
351            }
352
353            $first_run = false;
354        }
355
356        return $result;
357    }
358
359    function userConfirm($prompt, $default = 'yes')
360    {
361        trigger_error("PEAR_Frontend_CLI::userConfirm not yet converted", E_USER_ERROR);
362        static $positives = array('y', 'yes', 'on', '1');
363        static $negatives = array('n', 'no', 'off', '0');
364        print "$this->lp$prompt [$default] : ";
365        $fp = fopen("php://stdin", "r");
366        $line = fgets($fp, 2048);
367        fclose($fp);
368        $answer = strtolower(trim($line));
369        if (empty($answer)) {
370            $answer = $default;
371        }
372        if (in_array($answer, $positives)) {
373            return true;
374        }
375        if (in_array($answer, $negatives)) {
376            return false;
377        }
378        if (in_array($default, $positives)) {
379            return true;
380        }
381        return false;
382    }
383
384    function outputData($data, $command = '_default')
385    {
386        switch ($command) {
387            case 'channel-info':
388                foreach ($data as $type => $section) {
389                    if ($type == 'main') {
390                        $section['data'] = array_values($section['data']);
391                    }
392
393                    $this->outputData($section);
394                }
395                break;
396            case 'install':
397            case 'upgrade':
398            case 'upgrade-all':
399                if (is_array($data) && isset($data['release_warnings'])) {
400                    $this->_displayLine('');
401                    $this->_startTable(array(
402                        'border' => false,
403                        'caption' => 'Release Warnings'
404                    ));
405                    $this->_tableRow(array($data['release_warnings']), null, array(1 => array('wrap' => 55)));
406                    $this->_endTable();
407                    $this->_displayLine('');
408                }
409
410                $this->_displayLine(is_array($data) ? $data['data'] : $data);
411                break;
412            case 'search':
413                $this->_startTable($data);
414                if (isset($data['headline']) && is_array($data['headline'])) {
415                    $this->_tableRow($data['headline'], array('bold' => true), array(1 => array('wrap' => 55)));
416                }
417
418                $packages = array();
419                foreach($data['data'] as $category) {
420                    foreach($category as $name => $pkg) {
421                        $packages[$pkg[0]] = $pkg;
422                    }
423                }
424
425                $p = array_keys($packages);
426                natcasesort($p);
427                foreach ($p as $name) {
428                    $this->_tableRow($packages[$name], null, array(1 => array('wrap' => 55)));
429                }
430
431                $this->_endTable();
432                break;
433            case 'list-all':
434                if (!isset($data['data'])) {
435                      $this->_displayLine('No packages in channel');
436                      break;
437                }
438
439                $this->_startTable($data);
440                if (isset($data['headline']) && is_array($data['headline'])) {
441                    $this->_tableRow($data['headline'], array('bold' => true), array(1 => array('wrap' => 55)));
442                }
443
444                $packages = array();
445                foreach($data['data'] as $category) {
446                    foreach($category as $name => $pkg) {
447                        $packages[$pkg[0]] = $pkg;
448                    }
449                }
450
451                $p = array_keys($packages);
452                natcasesort($p);
453                foreach ($p as $name) {
454                    $pkg = $packages[$name];
455                    unset($pkg[4], $pkg[5]);
456                    $this->_tableRow($pkg, null, array(1 => array('wrap' => 55)));
457                }
458
459                $this->_endTable();
460                break;
461            case 'config-show':
462                $data['border'] = false;
463                $opts = array(
464                    0 => array('wrap' => 30),
465                    1 => array('wrap' => 20),
466                    2 => array('wrap' => 35)
467                );
468
469                $this->_startTable($data);
470                if (isset($data['headline']) && is_array($data['headline'])) {
471                    $this->_tableRow($data['headline'], array('bold' => true), $opts);
472                }
473
474                foreach ($data['data'] as $group) {
475                    foreach ($group as $value) {
476                        if ($value[2] == '') {
477                            $value[2] = "<not set>";
478                        }
479
480                        $this->_tableRow($value, null, $opts);
481                    }
482                }
483
484                $this->_endTable();
485                break;
486            case 'remote-info':
487                $d = $data;
488                $data = array(
489                    'caption' => 'Package details:',
490                    'border'  => false,
491                    'data'    => array(
492                        array("Latest",      $data['stable']),
493                        array("Installed",   $data['installed']),
494                        array("Package",     $data['name']),
495                        array("License",     $data['license']),
496                        array("Category",    $data['category']),
497                        array("Summary",     $data['summary']),
498                        array("Description", $data['description']),
499                    ),
500                );
501
502                if (isset($d['deprecated']) && $d['deprecated']) {
503                    $conf = &PEAR_Config::singleton();
504                    $reg = $conf->getRegistry();
505                    $name = $reg->parsedPackageNameToString($d['deprecated'], true);
506                    $data['data'][] = array('Deprecated! use', $name);
507                }
508            default: {
509                if (is_array($data)) {
510                    $this->_startTable($data);
511                    $count = count($data['data'][0]);
512                    if ($count == 2) {
513                        $opts = array(0 => array('wrap' => 25),
514                                      1 => array('wrap' => 48)
515                        );
516                    } elseif ($count == 3) {
517                        $opts = array(0 => array('wrap' => 30),
518                                      1 => array('wrap' => 20),
519                                      2 => array('wrap' => 35)
520                        );
521                    } else {
522                        $opts = null;
523                    }
524                    if (isset($data['headline']) && is_array($data['headline'])) {
525                        $this->_tableRow($data['headline'],
526                                         array('bold' => true),
527                                         $opts);
528                    }
529
530                    if (is_array($data['data'])) {
531                        foreach($data['data'] as $row) {
532                            $this->_tableRow($row, null, $opts);
533                        }
534                    } else {
535                        $this->_tableRow(array($data['data']), null, $opts);
536                     }
537                    $this->_endTable();
538                } else {
539                    $this->_displayLine($data);
540                }
541            }
542        }
543    }
544
545    function log($text, $append_crlf = true)
546    {
547        if ($append_crlf) {
548            return $this->_displayLine($text);
549        }
550
551        return $this->_display($text);
552    }
553
554    function bold($text)
555    {
556        if (empty($this->term['bold'])) {
557            return strtoupper($text);
558        }
559
560        return $this->term['bold'] . $text . $this->term['normal'];
561    }
562
563    function _displayHeading($title)
564    {
565        print $this->lp.$this->bold($title)."\n";
566        print $this->lp.str_repeat("=", strlen($title))."\n";
567    }
568
569    function _startTable($params = array())
570    {
571        $params['table_data'] = array();
572        $params['widest']     = array();  // indexed by column
573        $params['highest']    = array(); // indexed by row
574        $params['ncols']      = 0;
575        $this->params         = $params;
576    }
577
578    function _tableRow($columns, $rowparams = array(), $colparams = array())
579    {
580        $highest = 1;
581        for ($i = 0; $i < count($columns); $i++) {
582            $col = &$columns[$i];
583            if (isset($colparams[$i]) && !empty($colparams[$i]['wrap'])) {
584                $col = wordwrap($col, $colparams[$i]['wrap']);
585            }
586
587            if (strpos($col, "\n") !== false) {
588                $multiline = explode("\n", $col);
589                $w = 0;
590                foreach ($multiline as $n => $line) {
591                    $len = strlen($line);
592                    if ($len > $w) {
593                        $w = $len;
594                    }
595                }
596                $lines = count($multiline);
597            } else {
598                $w = strlen($col);
599            }
600
601            if (isset($this->params['widest'][$i])) {
602                if ($w > $this->params['widest'][$i]) {
603                    $this->params['widest'][$i] = $w;
604                }
605            } else {
606                $this->params['widest'][$i] = $w;
607            }
608
609            $tmp = count_chars($columns[$i], 1);
610            // handle unix, mac and windows formats
611            $lines = (isset($tmp[10]) ? $tmp[10] : (isset($tmp[13]) ? $tmp[13] : 0)) + 1;
612            if ($lines > $highest) {
613                $highest = $lines;
614            }
615        }
616
617        if (count($columns) > $this->params['ncols']) {
618            $this->params['ncols'] = count($columns);
619        }
620
621        $new_row = array(
622            'data'      => $columns,
623            'height'    => $highest,
624            'rowparams' => $rowparams,
625            'colparams' => $colparams,
626        );
627        $this->params['table_data'][] = $new_row;
628    }
629
630    function _endTable()
631    {
632        extract($this->params);
633        if (!empty($caption)) {
634            $this->_displayHeading($caption);
635        }
636
637        if (count($table_data) === 0) {
638            return;
639        }
640
641        if (!isset($width)) {
642            $width = $widest;
643        } else {
644            for ($i = 0; $i < $ncols; $i++) {
645                if (!isset($width[$i])) {
646                    $width[$i] = $widest[$i];
647                }
648            }
649        }
650
651        $border = false;
652        if (empty($border)) {
653            $cellstart  = '';
654            $cellend    = ' ';
655            $rowend     = '';
656            $padrowend  = false;
657            $borderline = '';
658        } else {
659            $cellstart  = '| ';
660            $cellend    = ' ';
661            $rowend     = '|';
662            $padrowend  = true;
663            $borderline = '+';
664            foreach ($width as $w) {
665                $borderline .= str_repeat('-', $w + strlen($cellstart) + strlen($cellend) - 1);
666                $borderline .= '+';
667            }
668        }
669
670        if ($borderline) {
671            $this->_displayLine($borderline);
672        }
673
674        for ($i = 0; $i < count($table_data); $i++) {
675            extract($table_data[$i]);
676            if (!is_array($rowparams)) {
677                $rowparams = array();
678            }
679
680            if (!is_array($colparams)) {
681                $colparams = array();
682            }
683
684            $rowlines = array();
685            if ($height > 1) {
686                for ($c = 0; $c < count($data); $c++) {
687                    $rowlines[$c] = preg_split('/(\r?\n|\r)/', $data[$c]);
688                    if (count($rowlines[$c]) < $height) {
689                        $rowlines[$c] = array_pad($rowlines[$c], $height, '');
690                    }
691                }
692            } else {
693                for ($c = 0; $c < count($data); $c++) {
694                    $rowlines[$c] = array($data[$c]);
695                }
696            }
697
698            for ($r = 0; $r < $height; $r++) {
699                $rowtext = '';
700                for ($c = 0; $c < count($data); $c++) {
701                    if (isset($colparams[$c])) {
702                        $attribs = array_merge($rowparams, $colparams);
703                    } else {
704                        $attribs = $rowparams;
705                    }
706
707                    $w = isset($width[$c]) ? $width[$c] : 0;
708                    //$cell = $data[$c];
709                    $cell = $rowlines[$c][$r];
710                    $l = strlen($cell);
711                    if ($l > $w) {
712                        $cell = substr($cell, 0, $w);
713                    }
714
715                    if (isset($attribs['bold'])) {
716                        $cell = $this->bold($cell);
717                    }
718
719                    if ($l < $w) {
720                        // not using str_pad here because we may
721                        // add bold escape characters to $cell
722                        $cell .= str_repeat(' ', $w - $l);
723                    }
724
725                    $rowtext .= $cellstart . $cell . $cellend;
726                }
727
728                if (!$border) {
729                    $rowtext = rtrim($rowtext);
730                }
731
732                $rowtext .= $rowend;
733                $this->_displayLine($rowtext);
734            }
735        }
736
737        if ($borderline) {
738            $this->_displayLine($borderline);
739        }
740    }
741
742    function _displayLine($text)
743    {
744        print "$this->lp$text\n";
745    }
746
747    function _display($text)
748    {
749        print $text;
750    }
751}
Note: See TracBrowser for help on using the repository browser.