annotate vendor/psy/psysh/src/Command/SudoCommand.php @ 4:a9cd425dd02b

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