annotate vendor/psy/psysh/src/Command/SudoCommand.php @ 19:fa3358dc1485 tip

Add ndrum files
author Chris Cannam
date Wed, 28 Aug 2019 13:14:47 +0100
parents 129ea1e6d783
children
rev   line source
Chris@13 1 <?php
Chris@13 2
Chris@13 3 /*
Chris@13 4 * This file is part of Psy Shell.
Chris@13 5 *
Chris@13 6 * (c) 2012-2018 Justin Hileman
Chris@13 7 *
Chris@13 8 * For the full copyright and license information, please view the LICENSE
Chris@13 9 * file that was distributed with this source code.
Chris@13 10 */
Chris@13 11
Chris@13 12 namespace Psy\Command;
Chris@13 13
Chris@13 14 use PhpParser\NodeTraverser;
Chris@13 15 use PhpParser\PrettyPrinter\Standard as Printer;
Chris@13 16 use Psy\Input\CodeArgument;
Chris@13 17 use Psy\ParserFactory;
Chris@13 18 use Psy\Readline\Readline;
Chris@13 19 use Psy\Sudo\SudoVisitor;
Chris@13 20 use Symfony\Component\Console\Input\InputInterface;
Chris@13 21 use Symfony\Component\Console\Output\OutputInterface;
Chris@13 22
Chris@13 23 /**
Chris@13 24 * Evaluate PHP code, bypassing visibility restrictions.
Chris@13 25 */
Chris@13 26 class SudoCommand extends Command
Chris@13 27 {
Chris@13 28 private $readline;
Chris@13 29 private $parser;
Chris@13 30 private $traverser;
Chris@13 31 private $printer;
Chris@13 32
Chris@13 33 /**
Chris@13 34 * {@inheritdoc}
Chris@13 35 */
Chris@13 36 public function __construct($name = null)
Chris@13 37 {
Chris@13 38 $parserFactory = new ParserFactory();
Chris@13 39 $this->parser = $parserFactory->createParser();
Chris@13 40
Chris@13 41 $this->traverser = new NodeTraverser();
Chris@13 42 $this->traverser->addVisitor(new SudoVisitor());
Chris@13 43
Chris@13 44 $this->printer = new Printer();
Chris@13 45
Chris@13 46 parent::__construct($name);
Chris@13 47 }
Chris@13 48
Chris@13 49 /**
Chris@13 50 * Set the Shell's Readline service.
Chris@13 51 *
Chris@13 52 * @param Readline $readline
Chris@13 53 */
Chris@13 54 public function setReadline(Readline $readline)
Chris@13 55 {
Chris@13 56 $this->readline = $readline;
Chris@13 57 }
Chris@13 58
Chris@13 59 /**
Chris@13 60 * {@inheritdoc}
Chris@13 61 */
Chris@13 62 protected function configure()
Chris@13 63 {
Chris@13 64 $this
Chris@13 65 ->setName('sudo')
Chris@13 66 ->setDefinition([
Chris@13 67 new CodeArgument('code', CodeArgument::REQUIRED, 'Code to execute.'),
Chris@13 68 ])
Chris@13 69 ->setDescription('Evaluate PHP code, bypassing visibility restrictions.')
Chris@13 70 ->setHelp(
Chris@13 71 <<<'HELP'
Chris@13 72 Evaluate PHP code, bypassing visibility restrictions.
Chris@13 73
Chris@13 74 e.g.
Chris@13 75 <return>>>> $sekret->whisper("hi")</return>
Chris@13 76 <return>PHP error: Call to private method Sekret::whisper() from context '' on line 1</return>
Chris@13 77
Chris@13 78 <return>>>> sudo $sekret->whisper("hi")</return>
Chris@13 79 <return>=> "hi"</return>
Chris@13 80
Chris@13 81 <return>>>> $sekret->word</return>
Chris@13 82 <return>PHP error: Cannot access private property Sekret::$word on line 1</return>
Chris@13 83
Chris@13 84 <return>>>> sudo $sekret->word</return>
Chris@13 85 <return>=> "hi"</return>
Chris@13 86
Chris@13 87 <return>>>> $sekret->word = "please"</return>
Chris@13 88 <return>PHP error: Cannot access private property Sekret::$word on line 1</return>
Chris@13 89
Chris@13 90 <return>>>> sudo $sekret->word = "please"</return>
Chris@13 91 <return>=> "please"</return>
Chris@13 92 HELP
Chris@13 93 );
Chris@13 94 }
Chris@13 95
Chris@13 96 /**
Chris@13 97 * {@inheritdoc}
Chris@13 98 */
Chris@13 99 protected function execute(InputInterface $input, OutputInterface $output)
Chris@13 100 {
Chris@13 101 $code = $input->getArgument('code');
Chris@13 102
Chris@13 103 // special case for !!
Chris@13 104 if ($code === '!!') {
Chris@13 105 $history = $this->readline->listHistory();
Chris@17 106 if (\count($history) < 2) {
Chris@13 107 throw new \InvalidArgumentException('No previous command to replay');
Chris@13 108 }
Chris@17 109 $code = $history[\count($history) - 2];
Chris@13 110 }
Chris@13 111
Chris@17 112 if (\strpos('<?', $code) === false) {
Chris@13 113 $code = '<?php ' . $code;
Chris@13 114 }
Chris@13 115
Chris@13 116 $nodes = $this->traverser->traverse($this->parse($code));
Chris@13 117
Chris@13 118 $sudoCode = $this->printer->prettyPrint($nodes);
Chris@13 119 $shell = $this->getApplication();
Chris@13 120 $shell->addCode($sudoCode, !$shell->hasCode());
Chris@13 121 }
Chris@13 122
Chris@13 123 /**
Chris@13 124 * Lex and parse a string of code into statements.
Chris@13 125 *
Chris@13 126 * @param string $code
Chris@13 127 *
Chris@13 128 * @return array Statements
Chris@13 129 */
Chris@13 130 private function parse($code)
Chris@13 131 {
Chris@13 132 try {
Chris@13 133 return $this->parser->parse($code);
Chris@13 134 } catch (\PhpParser\Error $e) {
Chris@17 135 if (\strpos($e->getMessage(), 'unexpected EOF') === false) {
Chris@13 136 throw $e;
Chris@13 137 }
Chris@13 138
Chris@13 139 // If we got an unexpected EOF, let's try it again with a semicolon.
Chris@13 140 return $this->parser->parse($code . ';');
Chris@13 141 }
Chris@13 142 }
Chris@13 143 }