From a4907198eb0edd9726f585b3d0f3b301f9a1d5ab Mon Sep 17 00:00:00 2001
From: Marcus Eibrink-Lunzenauer <lunzenauer@elan-ev.de>
Date: Tue, 26 Mar 2024 21:11:58 +0000
Subject: [PATCH] Add REPL cli script.

Closes #3897

Merge request studip/studip!2756
---
 cli/Commands/Base/Tinker.php |  40 +++++
 cli/studip                   |  13 +-
 composer.json                |   3 +-
 composer.lock                | 319 +++++++++++++++++++++++++----------
 4 files changed, 277 insertions(+), 98 deletions(-)
 create mode 100644 cli/Commands/Base/Tinker.php

diff --git a/cli/Commands/Base/Tinker.php b/cli/Commands/Base/Tinker.php
new file mode 100644
index 00000000000..1bc4f127738
--- /dev/null
+++ b/cli/Commands/Base/Tinker.php
@@ -0,0 +1,40 @@
+<?php
+
+namespace Studip\Cli\Commands\Base;
+
+use Symfony\Component\Console\Command\Command;
+use Symfony\Component\Console\Input\InputArgument;
+use Symfony\Component\Console\Input\InputInterface;
+use Symfony\Component\Console\Input\InputOption;
+use Symfony\Component\Console\Output\OutputInterface;
+use Symfony\Component\Console\Style\SymfonyStyle;
+use Symfony\Component\Process\PhpExecutableFinder;
+use Symfony\Component\Process\Process;
+use Psy\Configuration;
+use Psy\Shell;
+use Psy\VersionUpdater\Checker;
+
+class Tinker extends Command
+{
+    protected static $defaultName = 'tinker';
+
+    protected function configure(): void
+    {
+        $this->setDescription('Interact with your Stud.IP in a read-eval-print loop (REPL).');
+    }
+
+    /**
+     * @SuppressWarnings(PHPMD.StaticAccess)
+     * @SuppressWarnings(PHPMD.UnusedFormalParameter)
+     */
+    protected function execute(InputInterface $input, OutputInterface $output): int
+    {
+        $config = Configuration::fromInput($input);
+        $config->setUpdateCheck(Checker::NEVER);
+        $config->setDefaultIncludes([__DIR__ . '/../../studip_cli_env.inc.php']);
+
+        $shell = new Shell($config);
+
+        return $shell->run();
+    }
+}
diff --git a/cli/studip b/cli/studip
index d981bd96884..3acd4bc32a8 100755
--- a/cli/studip
+++ b/cli/studip
@@ -13,6 +13,7 @@ require __DIR__.'/../composer/autoload.php';
 $application = new Application();
 $commands = [
     Commands\Base\Dump::class,
+    Commands\Base\Tinker::class,
     Commands\Checks\Compatibility::class,
     Commands\Checks\GlobalizedConfig::class,
     Commands\Checks\HelpTours::class,
@@ -38,29 +39,29 @@ $commands = [
     Commands\Fix\Biest8136::class,
     Commands\Fix\IconDimensions::class,
     Commands\HelpContent\Migrate::class,
+    Commands\Migrate\Migrate::class,
     Commands\Migrate\MigrateList::class,
     Commands\Migrate\MigrateStatus::class,
-    Commands\Migrate\Migrate::class,
     Commands\OAuth2\Keys::class,
     Commands\OAuth2\Purge::class,
+    Commands\Plugins\I18N\I18NCompile::class,
+    Commands\Plugins\I18N\I18NDetect::class,
+    Commands\Plugins\I18N\I18NExtract::class,
     Commands\Plugins\PluginActivate::class,
     Commands\Plugins\PluginDeactivate::class,
     Commands\Plugins\PluginInfo::class,
     Commands\Plugins\PluginInstall::class,
     Commands\Plugins\PluginListMigrations::class,
-    Commands\Plugins\PluginStatusMigrations::class,
     Commands\Plugins\PluginMigrate::class,
     Commands\Plugins\PluginRegister::class,
     Commands\Plugins\PluginScan::class,
+    Commands\Plugins\PluginStatusMigrations::class,
     Commands\Plugins\PluginUnregister::class,
-    Commands\Plugins\I18N\I18NDetect::class,
-    Commands\Plugins\I18N\I18NExtract::class,
-    Commands\Plugins\I18N\I18NCompile::class,
     Commands\Resources\UpdateBookingIntervals::class,
     Commands\SORM\DescribeModels::class,
     Commands\Twillo\PrivateKeys::class,
-    Commands\User\UsersDelete::class,
     Commands\User\GetUser::class,
+    Commands\User\UsersDelete::class,
 ];
 $creator = function ($command) {
     return app($command);
diff --git a/composer.json b/composer.json
index 031bd0f0a3a..dd95f12cd50 100644
--- a/composer.json
+++ b/composer.json
@@ -60,7 +60,8 @@
         "ksubileau/color-thief-php": "^2.0",
         "symfony/polyfill-php82": "^1.28",
         "symfony/polyfill-php83": "^1.28",
-        "phpoffice/phpspreadsheet": "^1.19"
+        "phpoffice/phpspreadsheet": "^1.19",
+        "psy/psysh": "^0.12.2"
     },
     "replace": {
         "symfony/polyfill-php54": "*",
diff --git a/composer.lock b/composer.lock
index cd649f945f2..dd520827d26 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": "76e4dce9372399bca6af1762cd407649",
+    "content-hash": "57c5409fb404051d418751e660f3210f",
     "packages": [
         {
             "name": "algo26-matthias/idna-convert",
@@ -1689,6 +1689,64 @@
             },
             "time": "2018-02-13T20:26:39+00:00"
         },
+        {
+            "name": "nikic/php-parser",
+            "version": "v5.0.2",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/nikic/PHP-Parser.git",
+                "reference": "139676794dc1e9231bf7bcd123cfc0c99182cb13"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/139676794dc1e9231bf7bcd123cfc0c99182cb13",
+                "reference": "139676794dc1e9231bf7bcd123cfc0c99182cb13",
+                "shasum": ""
+            },
+            "require": {
+                "ext-ctype": "*",
+                "ext-json": "*",
+                "ext-tokenizer": "*",
+                "php": ">=7.4"
+            },
+            "require-dev": {
+                "ircmaxell/php-yacc": "^0.0.7",
+                "phpunit/phpunit": "^7.0 || ^8.0 || ^9.0"
+            },
+            "bin": [
+                "bin/php-parse"
+            ],
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "5.0-dev"
+                }
+            },
+            "autoload": {
+                "psr-4": {
+                    "PhpParser\\": "lib/PhpParser"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "BSD-3-Clause"
+            ],
+            "authors": [
+                {
+                    "name": "Nikita Popov"
+                }
+            ],
+            "description": "A PHP parser written in PHP",
+            "keywords": [
+                "parser",
+                "php"
+            ],
+            "support": {
+                "issues": "https://github.com/nikic/PHP-Parser/issues",
+                "source": "https://github.com/nikic/PHP-Parser/tree/v5.0.2"
+            },
+            "time": "2024-03-05T20:51:40+00:00"
+        },
         {
             "name": "opis/closure",
             "version": "3.6.3",
@@ -3006,6 +3064,85 @@
             },
             "time": "2017-10-23T01:57:42+00:00"
         },
+        {
+            "name": "psy/psysh",
+            "version": "v0.12.2",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/bobthecow/psysh.git",
+                "reference": "9185c66c2165bbf4d71de78a69dccf4974f9538d"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/bobthecow/psysh/zipball/9185c66c2165bbf4d71de78a69dccf4974f9538d",
+                "reference": "9185c66c2165bbf4d71de78a69dccf4974f9538d",
+                "shasum": ""
+            },
+            "require": {
+                "ext-json": "*",
+                "ext-tokenizer": "*",
+                "nikic/php-parser": "^5.0 || ^4.0",
+                "php": "^8.0 || ^7.4",
+                "symfony/console": "^7.0 || ^6.0 || ^5.0 || ^4.0 || ^3.4",
+                "symfony/var-dumper": "^7.0 || ^6.0 || ^5.0 || ^4.0 || ^3.4"
+            },
+            "conflict": {
+                "symfony/console": "4.4.37 || 5.3.14 || 5.3.15 || 5.4.3 || 5.4.4 || 6.0.3 || 6.0.4"
+            },
+            "require-dev": {
+                "bamarni/composer-bin-plugin": "^1.2"
+            },
+            "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."
+            },
+            "bin": [
+                "bin/psysh"
+            ],
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-main": "0.12.x-dev"
+                },
+                "bamarni-bin": {
+                    "bin-links": false,
+                    "forward-command": false
+                }
+            },
+            "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"
+            ],
+            "support": {
+                "issues": "https://github.com/bobthecow/psysh/issues",
+                "source": "https://github.com/bobthecow/psysh/tree/v0.12.2"
+            },
+            "time": "2024-03-17T01:53:00+00:00"
+        },
         {
             "name": "ralouphie/getallheaders",
             "version": "3.0.3",
@@ -4365,6 +4502,95 @@
             ],
             "time": "2023-02-22T08:00:55+00:00"
         },
+        {
+            "name": "symfony/var-dumper",
+            "version": "v5.4.21",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/symfony/var-dumper.git",
+                "reference": "6c5ac3a1be8b849d59a1a77877ee110e1b55eb74"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/symfony/var-dumper/zipball/6c5ac3a1be8b849d59a1a77877ee110e1b55eb74",
+                "reference": "6c5ac3a1be8b849d59a1a77877ee110e1b55eb74",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=7.2.5",
+                "symfony/polyfill-mbstring": "~1.0",
+                "symfony/polyfill-php80": "^1.16"
+            },
+            "conflict": {
+                "phpunit/phpunit": "<5.4.3",
+                "symfony/console": "<4.4"
+            },
+            "require-dev": {
+                "ext-iconv": "*",
+                "symfony/console": "^4.4|^5.0|^6.0",
+                "symfony/process": "^4.4|^5.0|^6.0",
+                "symfony/uid": "^5.1|^6.0",
+                "twig/twig": "^2.13|^3.0.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",
+                "symfony/console": "To use the ServerDumpCommand and/or the bin/var-dump-server script"
+            },
+            "bin": [
+                "Resources/bin/var-dump-server"
+            ],
+            "type": "library",
+            "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": "Provides mechanisms for walking through any arbitrary PHP variable",
+            "homepage": "https://symfony.com",
+            "keywords": [
+                "debug",
+                "dump"
+            ],
+            "support": {
+                "source": "https://github.com/symfony/var-dumper/tree/v5.4.21"
+            },
+            "funding": [
+                {
+                    "url": "https://symfony.com/sponsor",
+                    "type": "custom"
+                },
+                {
+                    "url": "https://github.com/fabpot",
+                    "type": "github"
+                },
+                {
+                    "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
+                    "type": "tidelift"
+                }
+            ],
+            "time": "2023-02-23T10:00:28+00:00"
+        },
         {
             "name": "symfony/yaml",
             "version": "v5.4.21",
@@ -7325,95 +7551,6 @@
             ],
             "time": "2023-02-16T09:33:00+00:00"
         },
-        {
-            "name": "symfony/var-dumper",
-            "version": "v5.4.21",
-            "source": {
-                "type": "git",
-                "url": "https://github.com/symfony/var-dumper.git",
-                "reference": "6c5ac3a1be8b849d59a1a77877ee110e1b55eb74"
-            },
-            "dist": {
-                "type": "zip",
-                "url": "https://api.github.com/repos/symfony/var-dumper/zipball/6c5ac3a1be8b849d59a1a77877ee110e1b55eb74",
-                "reference": "6c5ac3a1be8b849d59a1a77877ee110e1b55eb74",
-                "shasum": ""
-            },
-            "require": {
-                "php": ">=7.2.5",
-                "symfony/polyfill-mbstring": "~1.0",
-                "symfony/polyfill-php80": "^1.16"
-            },
-            "conflict": {
-                "phpunit/phpunit": "<5.4.3",
-                "symfony/console": "<4.4"
-            },
-            "require-dev": {
-                "ext-iconv": "*",
-                "symfony/console": "^4.4|^5.0|^6.0",
-                "symfony/process": "^4.4|^5.0|^6.0",
-                "symfony/uid": "^5.1|^6.0",
-                "twig/twig": "^2.13|^3.0.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",
-                "symfony/console": "To use the ServerDumpCommand and/or the bin/var-dump-server script"
-            },
-            "bin": [
-                "Resources/bin/var-dump-server"
-            ],
-            "type": "library",
-            "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": "Provides mechanisms for walking through any arbitrary PHP variable",
-            "homepage": "https://symfony.com",
-            "keywords": [
-                "debug",
-                "dump"
-            ],
-            "support": {
-                "source": "https://github.com/symfony/var-dumper/tree/v5.4.21"
-            },
-            "funding": [
-                {
-                    "url": "https://symfony.com/sponsor",
-                    "type": "custom"
-                },
-                {
-                    "url": "https://github.com/fabpot",
-                    "type": "github"
-                },
-                {
-                    "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
-                    "type": "tidelift"
-                }
-            ],
-            "time": "2023-02-23T10:00:28+00:00"
-        },
         {
             "name": "theseer/tokenizer",
             "version": "1.2.1",
@@ -7553,5 +7690,5 @@
     "platform-overrides": {
         "php": "7.4"
     },
-    "plugin-api-version": "2.6.0"
+    "plugin-api-version": "2.2.0"
 }
-- 
GitLab