annotate vendor/psy/psysh/src/Psy/Command/SudoCommand.php @ 12:7a779792577d

Update Drupal core to v8.4.5 (via Composer)
author Chris Cannam
date Fri, 23 Feb 2018 15:52:07 +0000
parents 4c8ae668cc8c
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-2017 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\InputArgument;
Chris@0 21 use Symfony\Component\Console\Input\InputInterface;
Chris@0 22 use Symfony\Component\Console\Output\OutputInterface;
Chris@0 23
Chris@0 24 /**
Chris@0 25 * Evaluate PHP code, bypassing visibility restrictions.
Chris@0 26 */
Chris@0 27 class SudoCommand extends Command
Chris@0 28 {
Chris@0 29 private $readline;
Chris@0 30 private $parser;
Chris@0 31 private $traverser;
Chris@0 32 private $printer;
Chris@0 33
Chris@0 34 /**
Chris@0 35 * {@inheritdoc}
Chris@0 36 */
Chris@0 37 public function __construct($name = null)
Chris@0 38 {
Chris@0 39 $parserFactory = new ParserFactory();
Chris@0 40 $this->parser = $parserFactory->createParser();
Chris@0 41
Chris@0 42 $this->traverser = new NodeTraverser();
Chris@0 43 $this->traverser->addVisitor(new SudoVisitor());
Chris@0 44
Chris@0 45 $this->printer = new Printer();
Chris@0 46
Chris@0 47 parent::__construct($name);
Chris@0 48 }
Chris@0 49
Chris@0 50 /**
Chris@0 51 * Set the Shell's Readline service.
Chris@0 52 *
Chris@0 53 * @param Readline $readline
Chris@0 54 */
Chris@0 55 public function setReadline(Readline $readline)
Chris@0 56 {
Chris@0 57 $this->readline = $readline;
Chris@0 58 }
Chris@0 59
Chris@0 60 /**
Chris@0 61 * {@inheritdoc}
Chris@0 62 */
Chris@0 63 protected function configure()
Chris@0 64 {
Chris@0 65 $this
Chris@0 66 ->setName('sudo')
Chris@0 67 ->setDefinition(array(
Chris@0 68 new CodeArgument('code', InputArgument::REQUIRED, 'Code to execute.'),
Chris@0 69 ))
Chris@0 70 ->setDescription('Evaluate PHP code, bypassing visibility restrictions.')
Chris@0 71 ->setHelp(
Chris@0 72 <<<'HELP'
Chris@0 73 Evaluate PHP code, bypassing visibility restrictions.
Chris@0 74
Chris@0 75 e.g.
Chris@0 76 <return>>>> $sekret->whisper("hi")</return>
Chris@0 77 <return>PHP error: Call to private method Sekret::whisper() from context '' on line 1</return>
Chris@0 78
Chris@0 79 <return>>>> sudo $sekret->whisper("hi")</return>
Chris@0 80 <return>=> "hi"</return>
Chris@0 81
Chris@0 82 <return>>>> $sekret->word</return>
Chris@0 83 <return>PHP error: Cannot access private property Sekret::$word on line 1</return>
Chris@0 84
Chris@0 85 <return>>>> sudo $sekret->word</return>
Chris@0 86 <return>=> "hi"</return>
Chris@0 87
Chris@0 88 <return>>>> $sekret->word = "please"</return>
Chris@0 89 <return>PHP error: Cannot access private property Sekret::$word on line 1</return>
Chris@0 90
Chris@0 91 <return>>>> sudo $sekret->word = "please"</return>
Chris@0 92 <return>=> "please"</return>
Chris@0 93 HELP
Chris@0 94 );
Chris@0 95 }
Chris@0 96
Chris@0 97 /**
Chris@0 98 * {@inheritdoc}
Chris@0 99 */
Chris@0 100 protected function execute(InputInterface $input, OutputInterface $output)
Chris@0 101 {
Chris@0 102 $code = $input->getArgument('code');
Chris@0 103
Chris@0 104 // special case for !!
Chris@0 105 if ($code === '!!') {
Chris@0 106 $history = $this->readline->listHistory();
Chris@0 107 if (count($history) < 2) {
Chris@0 108 throw new \InvalidArgumentException('No previous command to replay');
Chris@0 109 }
Chris@0 110 $code = $history[count($history) - 2];
Chris@0 111 }
Chris@0 112
Chris@0 113 if (strpos('<?', $code) === false) {
Chris@0 114 $code = '<?php ' . $code;
Chris@0 115 }
Chris@0 116
Chris@0 117 $nodes = $this->traverser->traverse($this->parse($code));
Chris@0 118
Chris@0 119 $sudoCode = $this->printer->prettyPrint($nodes);
Chris@0 120 $this->getApplication()->addInput($sudoCode, true);
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@0 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 }