From c1c2a9f1a17ee4d2eda929577ad8488aebd1676b Mon Sep 17 00:00:00 2001 From: Daniel Supernault Date: Sun, 23 Jun 2019 17:59:20 +0100 Subject: [PATCH] [DEVTOOL] Add a robust and modern REPL --- composer.json | 11 +- composer.lock | 321 ++++++++++++++++++++++++++++++++++++- scripts/console.php | 270 +++++++++++++++---------------- scripts/simple_console.php | 169 +++++++++++++++++++ 4 files changed, 623 insertions(+), 148 deletions(-) mode change 100755 => 100644 scripts/console.php create mode 100644 scripts/simple_console.php diff --git a/composer.json b/composer.json index 06ef734464..581f05e334 100644 --- a/composer.json +++ b/composer.json @@ -16,20 +16,21 @@ "ext-simplexml": "*", "ext-xml": "*", "ext-xmlwriter": "*", + "apereo/phpcas": "^1.3", + "diogocomposer/xmpphp": "^3.0", "ezyang/htmlpurifier": "^4.10", "masterminds/html5": "^2.6", "mf2/mf2": "^0.4.6", - "openid/php-openid": "^2.3", "michelf/php-markdown": "^1.8.0", + "openid/php-openid": "^2.3", "paragonie/constant_time_encoding": "^1.0.4", - "stomp-php/stomp-php": "^4.5.1", "phpseclib/phpseclib": "^2.0.19", - "diogocomposer/xmpphp": "^3.0", - "apereo/phpcas": "^1.3" + "stomp-php/stomp-php": "^4.5.1" }, "require-dev": { "phpdocumentor/phpdocumentor": "^2.9", - "phpunit/phpunit": "^8.2" + "phpunit/phpunit": "^8.2", + "psy/psysh": "^0.9.9" }, "suggest": { "ext-apache": "*", diff --git a/composer.lock b/composer.lock index f697583607..f1105b4724 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "dea0804dd9970a97dcd17a53410327a0", + "content-hash": "1511cdda74eee145816ad9fe85138588", "packages": [ { "name": "apereo/phpcas", @@ -762,6 +762,39 @@ "homepage": "https://github.com/container-interop/container-interop", "time": "2017-02-14T19:40:03+00:00" }, + { + "name": "dnoegel/php-xdg-base-dir", + "version": "0.1", + "source": { + "type": "git", + "url": "https://github.com/dnoegel/php-xdg-base-dir.git", + "reference": "265b8593498b997dc2d31e75b89f053b5cc9621a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/dnoegel/php-xdg-base-dir/zipball/265b8593498b997dc2d31e75b89f053b5cc9621a", + "reference": "265b8593498b997dc2d31e75b89f053b5cc9621a", + "shasum": "" + }, + "require": { + "php": ">=5.3.2" + }, + "require-dev": { + "phpunit/phpunit": "@stable" + }, + "type": "project", + "autoload": { + "psr-4": { + "XdgBaseDir\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "implementation of xdg base directory specification for php", + "time": "2014-10-24T07:27:01+00:00" + }, { "name": "doctrine/annotations", "version": "v1.6.1", @@ -1894,6 +1927,94 @@ ], "time": "2017-01-10T10:39:54+00:00" }, + { + "name": "jakub-onderka/php-console-color", + "version": "v0.2", + "source": { + "type": "git", + "url": "https://github.com/JakubOnderka/PHP-Console-Color.git", + "reference": "d5deaecff52a0d61ccb613bb3804088da0307191" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/JakubOnderka/PHP-Console-Color/zipball/d5deaecff52a0d61ccb613bb3804088da0307191", + "reference": "d5deaecff52a0d61ccb613bb3804088da0307191", + "shasum": "" + }, + "require": { + "php": ">=5.4.0" + }, + "require-dev": { + "jakub-onderka/php-code-style": "1.0", + "jakub-onderka/php-parallel-lint": "1.0", + "jakub-onderka/php-var-dump-check": "0.*", + "phpunit/phpunit": "~4.3", + "squizlabs/php_codesniffer": "1.*" + }, + "type": "library", + "autoload": { + "psr-4": { + "JakubOnderka\\PhpConsoleColor\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-2-Clause" + ], + "authors": [ + { + "name": "Jakub Onderka", + "email": "jakub.onderka@gmail.com" + } + ], + "time": "2018-09-29T17:23:10+00:00" + }, + { + "name": "jakub-onderka/php-console-highlighter", + "version": "v0.4", + "source": { + "type": "git", + "url": "https://github.com/JakubOnderka/PHP-Console-Highlighter.git", + "reference": "9f7a229a69d52506914b4bc61bfdb199d90c5547" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/JakubOnderka/PHP-Console-Highlighter/zipball/9f7a229a69d52506914b4bc61bfdb199d90c5547", + "reference": "9f7a229a69d52506914b4bc61bfdb199d90c5547", + "shasum": "" + }, + "require": { + "ext-tokenizer": "*", + "jakub-onderka/php-console-color": "~0.2", + "php": ">=5.4.0" + }, + "require-dev": { + "jakub-onderka/php-code-style": "~1.0", + "jakub-onderka/php-parallel-lint": "~1.0", + "jakub-onderka/php-var-dump-check": "~0.1", + "phpunit/phpunit": "~4.0", + "squizlabs/php_codesniffer": "~1.5" + }, + "type": "library", + "autoload": { + "psr-4": { + "JakubOnderka\\PhpConsoleHighlighter\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jakub Onderka", + "email": "acci@acci.cz", + "homepage": "http://www.acci.cz/" + } + ], + "description": "Highlight PHP code in terminal", + "time": "2018-09-29T18:48:56+00:00" + }, { "name": "jms/metadata", "version": "2.0.0", @@ -3327,6 +3448,80 @@ ], "time": "2017-10-23T01:57:42+00:00" }, + { + "name": "psy/psysh", + "version": "v0.9.9", + "source": { + "type": "git", + "url": "https://github.com/bobthecow/psysh.git", + "reference": "9aaf29575bb8293206bb0420c1e1c87ff2ffa94e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/bobthecow/psysh/zipball/9aaf29575bb8293206bb0420c1e1c87ff2ffa94e", + "reference": "9aaf29575bb8293206bb0420c1e1c87ff2ffa94e", + "shasum": "" + }, + "require": { + "dnoegel/php-xdg-base-dir": "0.1", + "ext-json": "*", + "ext-tokenizer": "*", + "jakub-onderka/php-console-highlighter": "0.3.*|0.4.*", + "nikic/php-parser": "~1.3|~2.0|~3.0|~4.0", + "php": ">=5.4.0", + "symfony/console": "~2.3.10|^2.4.2|~3.0|~4.0", + "symfony/var-dumper": "~2.7|~3.0|~4.0" + }, + "require-dev": { + "bamarni/composer-bin-plugin": "^1.2", + "hoa/console": "~2.15|~3.16", + "phpunit/phpunit": "~4.8.35|~5.0|~6.0|~7.0" + }, + "suggest": { + "ext-pcntl": "Enabling the PCNTL extension makes PsySH a lot happier :)", + "ext-pdo-sqlite": "The doc command requires SQLite to work.", + "ext-posix": "If you have PCNTL, you'll want the POSIX extension as well.", + "ext-readline": "Enables support for arrow-key history navigation, and showing and manipulating command history.", + "hoa/console": "A pure PHP readline implementation. You'll want this if your PHP install doesn't already support readline or libedit." + }, + "bin": [ + "bin/psysh" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-develop": "0.9.x-dev" + } + }, + "autoload": { + "files": [ + "src/functions.php" + ], + "psr-4": { + "Psy\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Justin Hileman", + "email": "justin@justinhileman.info", + "homepage": "http://justinhileman.com" + } + ], + "description": "An interactive shell for modern PHP.", + "homepage": "http://psysh.org", + "keywords": [ + "REPL", + "console", + "interactive", + "shell" + ], + "time": "2018-10-13T15:16:03+00:00" + }, { "name": "sebastian/code-unit-reverse-lookup", "version": "1.0.1", @@ -4441,6 +4636,61 @@ ], "time": "2019-02-06T07:57:58+00:00" }, + { + "name": "symfony/polyfill-php72", + "version": "v1.11.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-php72.git", + "reference": "ab50dcf166d5f577978419edd37aa2bb8eabce0c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-php72/zipball/ab50dcf166d5f577978419edd37aa2bb8eabce0c", + "reference": "ab50dcf166d5f577978419edd37aa2bb8eabce0c", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.11-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Polyfill\\Php72\\": "" + }, + "files": [ + "bootstrap.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill backporting some PHP 7.2+ features to lower PHP versions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "polyfill", + "portable", + "shim" + ], + "time": "2019-02-06T07:57:58+00:00" + }, { "name": "symfony/process", "version": "v2.8.50", @@ -4677,6 +4927,75 @@ "homepage": "https://symfony.com", "time": "2018-11-14T14:06:48+00:00" }, + { + "name": "symfony/var-dumper", + "version": "v4.0.15", + "source": { + "type": "git", + "url": "https://github.com/symfony/var-dumper.git", + "reference": "3af63f44ddb45b03af4d172a4ce3e5c58b25fc5b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/var-dumper/zipball/3af63f44ddb45b03af4d172a4ce3e5c58b25fc5b", + "reference": "3af63f44ddb45b03af4d172a4ce3e5c58b25fc5b", + "shasum": "" + }, + "require": { + "php": "^7.1.3", + "symfony/polyfill-mbstring": "~1.0", + "symfony/polyfill-php72": "~1.5" + }, + "conflict": { + "phpunit/phpunit": "<4.8.35|<5.4.3,>=5.0" + }, + "require-dev": { + "ext-iconv": "*", + "twig/twig": "~1.34|~2.4" + }, + "suggest": { + "ext-iconv": "To convert non-UTF-8 strings to UTF-8 (or symfony/polyfill-iconv in case ext-iconv cannot be used).", + "ext-intl": "To show region name in time zone dump" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.0-dev" + } + }, + "autoload": { + "files": [ + "Resources/functions/dump.php" + ], + "psr-4": { + "Symfony\\Component\\VarDumper\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony mechanism for exploring and dumping PHP variables", + "homepage": "https://symfony.com", + "keywords": [ + "debug", + "dump" + ], + "time": "2018-07-26T11:22:46+00:00" + }, { "name": "theseer/tokenizer", "version": "1.1.3", diff --git a/scripts/console.php b/scripts/console.php old mode 100755 new mode 100644 index 692cedf8d1..25d12e52e1 --- a/scripts/console.php +++ b/scripts/console.php @@ -1,169 +1,155 @@ #!/usr/bin/env php . + +/** + * Description of this file. * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . + * @package samples + * @author Diogo Cordeiro + * @copyright 2019 Free Software Foundation, Inc http://www.fsf.org + * @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later */ -// Abort if called from a web server - -define('INSTALLDIR', realpath(dirname(__FILE__) . '/..')); +define('INSTALLDIR', dirname(__FILE__)); +define('GNUSOCIAL', true); +define('STATUSNET', true); -$helptext = << $arg) { + if ($arg === '--cwd') { + if ($i >= count($argv) - 1) { + echo 'Missing --cwd argument.' . PHP_EOL; + exit(1); + } + $cwd = $argv[$i + 1]; + break; + } -// Assume we're on a terminal if on Windows, otherwise posix_isatty tells us. -define('CONSOLE_INTERACTIVE', !function_exists('posix_isatty') || posix_isatty(0)); -define('CONSOLE_READLINE', CONSOLE_INTERACTIVE && function_exists('readline')); + if (preg_match('/^--cwd=/', $arg)) { + $cwd = substr($arg, 6); + break; + } + } -if (CONSOLE_READLINE && CONSOLE_INTERACTIVE) { - define('CONSOLE_HISTORY', getenv("HOME") . "/.statusnet_console_history"); - if (file_exists(CONSOLE_HISTORY)) { - readline_read_history(CONSOLE_HISTORY); + // Or fall back to the actual cwd + if (!isset($cwd)) { + $cwd = getcwd(); } -} -function read_input_line($prompt) -{ - if (CONSOLE_INTERACTIVE) { - if (CONSOLE_READLINE) { - $line = readline($prompt); - if (trim($line) != '') { - readline_add_history($line); - if (defined('CONSOLE_HISTORY')) { - // Save often; it's easy to hit fatal errors. - readline_write_history(CONSOLE_HISTORY); + $cwd = str_replace('\\', '/', $cwd); + + $chunks = explode('/', $cwd); + while (!empty($chunks)) { + $path = implode('/', $chunks); + + // Find composer.json + if (is_file($path . '/composer.json')) { + if ($cfg = json_decode(file_get_contents($path . '/composer.json'), true)) { + if (isset($cfg['name']) && $cfg['name'] === 'psy/psysh') { + // We're inside the psysh project. Let's use the local + // Composer autoload. + if (is_file($path . '/vendor/autoload.php')) { + require $path . '/vendor/autoload.php'; + } + + return; } } - return $line; - } else { - return readline_emulation($prompt); } - } else { - return fgets(STDIN); - } -} -/** - * On Unix-like systems where PHP readline extension isn't present, - * -cough- Mac OS X -cough- we can shell out to bash to do it for us. - * This lets us at least handle things like arrow keys, but we don't - * get any entry history. :( - * - * Shamelessly ripped from when I wrote the same code for MediaWiki. :) - * @author Brion Vibber - * - * @param string $prompt - * @return mixed string on success, false on fail or EOF - */ -function readline_emulation($prompt) -{ - if(CONSOLE_INTERACTIVE && file_exists(trim(shell_exec('which bash')))) { - $encPrompt = escapeshellarg($prompt); - $command = "read -er -p $encPrompt && echo \"\$REPLY\""; - $encCommand = escapeshellarg($command); - $metaCommand = "bash -c $encCommand"; - - // passthru passes our STDIN and TTY to the child... - // We can pull the returned string via output buffering. - ob_start(); - $retval = false; - passthru($metaCommand, $retval); - $line = ob_get_contents(); - ob_end_clean(); - - if ($retval == 0) { - return $line; - } elseif ($retval == 127) { - // Couldn't execute bash even though we thought we saw it. - // Shell probably spit out an error message, sorry :( - // Fall through to fgets()... - } else { - // EOF/ctrl+D - return false; + // Or a composer.lock + if (is_file($path . '/composer.lock')) { + if ($cfg = json_decode(file_get_contents($path . '/composer.lock'), true)) { + foreach (array_merge($cfg['packages'], $cfg['packages-dev']) as $pkg) { + if (isset($pkg['name']) && $pkg['name'] === 'psy/psysh') { + // We're inside a project which requires psysh. We'll + // use the local Composer autoload. + if (is_file($path . '/vendor/autoload.php')) { + require $path . '/vendor/autoload.php'; + } + + return; + } + } + } } - } - // Fallback... we'll have no editing controls, EWWW - if (feof(STDIN)) { - return false; + array_pop($chunks); } - if (CONSOLE_INTERACTIVE) { - print $prompt; +}); + +// We didn't find an autoloader for a local version, so use the autoloader that +// came with this script. +if (!class_exists('Psy\Shell')) { + /* <<< */ + if (is_file(__DIR__ . '/../vendor/autoload.php')) { + require __DIR__ . '/../vendor/autoload.php'; + } elseif (is_file(__DIR__ . '/../../../autoload.php')) { + require __DIR__ . '/../../../autoload.php'; + } else { + echo 'PsySH dependencies not found, be sure to run `composer install`.' . PHP_EOL; + echo 'See https://getcomposer.org to get Composer.' . PHP_EOL; + exit(1); } - return fgets(STDIN); + /* >>> */ } -function console_help() -{ - print "Welcome to GNU social's interactive PHP console!\n"; - print "Type some PHP code and it'll execute...\n"; - print "\n"; - print "Hint: return a value of any type to output it via var_export():\n"; - print " \$profile = new Profile();\n"; - print " \$profile->find();\n"; - print " \$profile->fetch();\n"; - print " return \$profile;\n"; - print "\n"; - print "Note that PHP is cranky and you can easily kill your session by mistyping.\n"; - print "\n"; - print "Type ctrl+D or enter 'exit' to exit.\n"; +// If the psysh binary was included directly, assume they just wanted an +// autoloader and bail early. +if (version_compare(PHP_VERSION, '5.3.6', '<')) { + $trace = debug_backtrace(); +} elseif (version_compare(PHP_VERSION, '5.4.0', '<')) { + $trace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS); +} else { + $trace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 1); } -if (CONSOLE_INTERACTIVE) { - print "GNU social interactive PHP console... type ctrl+D or enter 'exit' to exit.\n"; - $prompt = common_slugify(common_config('site', 'name')) . '> '; -} else { - $prompt = ''; +if (Psy\Shell::isIncluded($trace)) { + unset($trace); + + return; } -while (!feof(STDIN)) { - $line = read_input_line($prompt); - if ($line === false) { - if (CONSOLE_INTERACTIVE) { - print "\n"; - } - break; - } elseif ($line !== '') { - try { - if (trim($line) == 'exit') { - break; - } elseif (trim($line) == 'help') { - console_help(); - continue; - } - - // Let's do this! - $result = eval($line); - if ($result === false) { - // parse error - } elseif ($result === null) { - // no return - } else { - // return value from eval'd code - var_export($result); - } - } catch(Exception $e) { - print get_class($e) . ": " . $e->getMessage() . "\n"; - } - } - if (CONSOLE_INTERACTIVE) { - print "\n"; + +// Clean up after ourselves. +unset($trace); + +// If the local version is too old, we can't do this +if (!function_exists('Psy\bin')) { + $argv = $_SERVER['argv']; + $first = array_shift($argv); + if (preg_match('/php(\.exe)?$/', $first)) { + array_shift($argv); } + array_unshift($argv, 'vendor/bin/psysh'); + + echo 'A local PsySH dependency was found, but it cannot be loaded. Please update to' . PHP_EOL; + echo 'the latest version, or run the local copy directly, e.g.:' . PHP_EOL; + echo PHP_EOL; + echo ' ' . implode(' ', $argv) . PHP_EOL; + exit(1); } + +// And go! +call_user_func(Psy\bin()); diff --git a/scripts/simple_console.php b/scripts/simple_console.php new file mode 100644 index 0000000000..7df05fd6e9 --- /dev/null +++ b/scripts/simple_console.php @@ -0,0 +1,169 @@ +#!/usr/bin/env php +. + */ + +// Abort if called from a web server + +define('INSTALLDIR', realpath(dirname(__FILE__) . '/..')); + +$helptext = << + * + * @param string $prompt + * @return mixed string on success, false on fail or EOF + */ +function readline_emulation($prompt) +{ + if (CONSOLE_INTERACTIVE && file_exists(trim(shell_exec('which bash')))) { + $encPrompt = escapeshellarg($prompt); + $command = "read -er -p $encPrompt && echo \"\$REPLY\""; + $encCommand = escapeshellarg($command); + $metaCommand = "bash -c $encCommand"; + + // passthru passes our STDIN and TTY to the child... + // We can pull the returned string via output buffering. + ob_start(); + $retval = false; + passthru($metaCommand, $retval); + $line = ob_get_contents(); + ob_end_clean(); + + if ($retval == 0) { + return $line; + } elseif ($retval == 127) { + // Couldn't execute bash even though we thought we saw it. + // Shell probably spit out an error message, sorry :( + // Fall through to fgets()... + } else { + // EOF/ctrl+D + return false; + } + } + + // Fallback... we'll have no editing controls, EWWW + if (feof(STDIN)) { + return false; + } + if (CONSOLE_INTERACTIVE) { + print $prompt; + } + return fgets(STDIN); +} + +function console_help() +{ + print "Welcome to GNU social's interactive PHP console!\n"; + print "Type some PHP code and it'll execute...\n"; + print "\n"; + print "Hint: return a value of any type to output it via var_export():\n"; + print " \$profile = new Profile();\n"; + print " \$profile->find();\n"; + print " \$profile->fetch();\n"; + print " return \$profile;\n"; + print "\n"; + print "Note that PHP is cranky and you can easily kill your session by mistyping.\n"; + print "\n"; + print "Type ctrl+D or enter 'exit' to exit.\n"; +} + +if (CONSOLE_INTERACTIVE) { + print "GNU social interactive PHP console... type ctrl+D or enter 'exit' to exit.\n"; + $prompt = common_slugify(common_config('site', 'name')) . '> '; +} else { + $prompt = ''; +} +while (!feof(STDIN)) { + $line = read_input_line($prompt); + if ($line === false) { + if (CONSOLE_INTERACTIVE) { + print "\n"; + } + break; + } elseif ($line !== '') { + try { + if (trim($line) == 'exit') { + break; + } elseif (trim($line) == 'help') { + console_help(); + continue; + } + + // Let's do this! + $result = eval($line); + if ($result === false) { + // parse error + } elseif ($result === null) { + // no return + } else { + // return value from eval'd code + var_export($result); + } + } catch (Exception $e) { + print get_class($e) . ": " . $e->getMessage() . "\n"; + } + } + if (CONSOLE_INTERACTIVE) { + print "\n"; + } +} -- 2.39.5