]> git.mxchange.org Git - quix0rs-gnu-social.git/commitdiff
[DEVTOOL] Add a robust and modern REPL
authorDaniel Supernault <danielsupernault@gmail.com>
Sun, 23 Jun 2019 16:59:20 +0000 (17:59 +0100)
committerDiogo Cordeiro <diogo@fc.up.pt>
Sat, 3 Aug 2019 16:47:26 +0000 (17:47 +0100)
composer.json
composer.lock
scripts/console.php [changed mode: 0755->0644]
scripts/simple_console.php [new file with mode: 0644]

index 06ef7344640370ed7ea742e72642ca25f7858d70..581f05e33467ac31b53a9448a3e402c08d5a2c0d 100644 (file)
         "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": "*",
index f697583607e73272f02efb417bcc372d9d47fb85..f1105b4724786cd408a9f6496ecad184279bd8f4 100644 (file)
@@ -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",
             "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",
             ],
             "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",
             ],
             "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",
             ],
             "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",
             "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",
old mode 100755 (executable)
new mode 100644 (file)
index 692cedf..25d12e5
 #!/usr/bin/env php
 <?php
-/*
- * StatusNet - the distributed open-source microblogging tool
- * Copyright (C) 2009, StatusNet, Inc.
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU Affero General Public License for more details.
+// This file is part of GNU social - https://www.gnu.org/software/social
+//
+// GNU social is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Affero General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// GNU social is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with GNU social.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Description of this file.
  *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ * @package   samples
+ * @author    Diogo Cordeiro <diogo@fc.up.pt>
+ * @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 = <<<ENDOFHELP
-console.php - provide an interactive PHP interpreter for testing
+require_once INSTALLDIR . '/lib/common.php';
 
-ENDOFHELP;
+// Try to find an autoloader for a local psysh version.
+// We'll wrap this whole mess in a Closure so it doesn't leak any globals.
+call_user_func(function () {
+    $cwd = null;
 
-require_once INSTALLDIR.'/scripts/commandline.inc';
+    // Find the cwd arg (if present)
+    $argv = isset($_SERVER['argv']) ? $_SERVER['argv'] : array();
+    foreach ($argv as $i => $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 <brion@status.net>
- *
- * @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 (file)
index 0000000..7df05fd
--- /dev/null
@@ -0,0 +1,169 @@
+#!/usr/bin/env php
+<?php
+/*
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2009, StatusNet, Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+// Abort if called from a web server
+
+define('INSTALLDIR', realpath(dirname(__FILE__) . '/..'));
+
+$helptext = <<<ENDOFHELP
+console.php - provide an interactive PHP interpreter for testing
+
+ENDOFHELP;
+
+require_once INSTALLDIR.'/scripts/commandline.inc';
+
+// 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 (CONSOLE_READLINE && CONSOLE_INTERACTIVE) {
+    define('CONSOLE_HISTORY', getenv("HOME") . "/.statusnet_console_history");
+    if (file_exists(CONSOLE_HISTORY)) {
+        readline_read_history(CONSOLE_HISTORY);
+    }
+}
+
+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);
+                }
+            }
+            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 <brion@status.net>
+ *
+ * @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";
+    }
+}