Updated Drupal to 8.6. This goes with the following updates because it's possible...
[yaffs-website] / vendor / psy / psysh / src / functions.php
1 <?php
2
3 /*
4  * This file is part of Psy Shell.
5  *
6  * (c) 2012-2018 Justin Hileman
7  *
8  * For the full copyright and license information, please view the LICENSE
9  * file that was distributed with this source code.
10  */
11
12 namespace Psy;
13
14 use Psy\VersionUpdater\GitHubChecker;
15 use Symfony\Component\Console\Input\ArgvInput;
16 use Symfony\Component\Console\Input\InputArgument;
17 use Symfony\Component\Console\Input\InputDefinition;
18 use Symfony\Component\Console\Input\InputOption;
19 use XdgBaseDir\Xdg;
20
21 if (!\function_exists('Psy\sh')) {
22     /**
23      * Command to return the eval-able code to startup PsySH.
24      *
25      *     eval(\Psy\sh());
26      *
27      * @return string
28      */
29     function sh()
30     {
31         return 'extract(\Psy\debug(get_defined_vars(), isset($this) ? $this : @get_called_class()));';
32     }
33 }
34
35 if (!\function_exists('Psy\debug')) {
36     /**
37      * Invoke a Psy Shell from the current context.
38      *
39      * For example:
40      *
41      *     foreach ($items as $item) {
42      *         \Psy\debug(get_defined_vars());
43      *     }
44      *
45      * If you would like your shell interaction to affect the state of the
46      * current context, you can extract() the values returned from this call:
47      *
48      *     foreach ($items as $item) {
49      *         extract(\Psy\debug(get_defined_vars()));
50      *         var_dump($item); // will be whatever you set $item to in Psy Shell
51      *     }
52      *
53      * Optionally, supply an object as the `$bindTo` parameter. This determines
54      * the value `$this` will have in the shell, and sets up class scope so that
55      * private and protected members are accessible:
56      *
57      *     class Foo {
58      *         function bar() {
59      *             \Psy\debug(get_defined_vars(), $this);
60      *         }
61      *     }
62      *
63      * For the static equivalent, pass a class name as the `$bindTo` parameter.
64      * This makes `self` work in the shell, and sets up static scope so that
65      * private and protected static members are accessible:
66      *
67      *     class Foo {
68      *         static function bar() {
69      *             \Psy\debug(get_defined_vars(), get_called_class());
70      *         }
71      *     }
72      *
73      * @param array         $vars   Scope variables from the calling context (default: array())
74      * @param object|string $bindTo Bound object ($this) or class (self) value for the shell
75      *
76      * @return array Scope variables from the debugger session
77      */
78     function debug(array $vars = [], $bindTo = null)
79     {
80         echo PHP_EOL;
81
82         $sh = new Shell();
83         $sh->setScopeVariables($vars);
84
85         // Show a couple of lines of call context for the debug session.
86         //
87         // @todo come up with a better way of doing this which doesn't involve injecting input :-P
88         if ($sh->has('whereami')) {
89             $sh->addInput('whereami -n2', true);
90         }
91
92         if (\is_string($bindTo)) {
93             $sh->setBoundClass($bindTo);
94         } elseif ($bindTo !== null) {
95             $sh->setBoundObject($bindTo);
96         }
97
98         $sh->run();
99
100         return $sh->getScopeVariables(false);
101     }
102 }
103
104 if (!\function_exists('Psy\info')) {
105     /**
106      * Get a bunch of debugging info about the current PsySH environment and
107      * configuration.
108      *
109      * If a Configuration param is passed, that configuration is stored and
110      * used for the current shell session, and no debugging info is returned.
111      *
112      * @param Configuration|null $config
113      *
114      * @return array|null
115      */
116     function info(Configuration $config = null)
117     {
118         static $lastConfig;
119         if ($config !== null) {
120             $lastConfig = $config;
121
122             return;
123         }
124
125         $xdg = new Xdg();
126         $home = \rtrim(\str_replace('\\', '/', $xdg->getHomeDir()), '/');
127         $homePattern = '#^' . \preg_quote($home, '#') . '/#';
128
129         $prettyPath = function ($path) use ($homePattern) {
130             if (\is_string($path)) {
131                 return \preg_replace($homePattern, '~/', $path);
132             } else {
133                 return $path;
134             }
135         };
136
137         $config = $lastConfig ?: new Configuration();
138
139         $core = [
140             'PsySH version'       => Shell::VERSION,
141             'PHP version'         => PHP_VERSION,
142             'OS'                  => PHP_OS,
143             'default includes'    => $config->getDefaultIncludes(),
144             'require semicolons'  => $config->requireSemicolons(),
145             'error logging level' => $config->errorLoggingLevel(),
146             'config file'         => [
147                 'default config file' => $prettyPath($config->getConfigFile()),
148                 'local config file'   => $prettyPath($config->getLocalConfigFile()),
149                 'PSYSH_CONFIG env'    => $prettyPath(\getenv('PSYSH_CONFIG')),
150             ],
151             // 'config dir'  => $config->getConfigDir(),
152             // 'data dir'    => $config->getDataDir(),
153             // 'runtime dir' => $config->getRuntimeDir(),
154         ];
155
156         // Use an explicit, fresh update check here, rather than relying on whatever is in $config.
157         $checker = new GitHubChecker();
158         $updateAvailable = null;
159         $latest = null;
160         try {
161             $updateAvailable = !$checker->isLatest();
162             $latest = $checker->getLatest();
163         } catch (\Exception $e) {
164         }
165
166         $updates = [
167             'update available'       => $updateAvailable,
168             'latest release version' => $latest,
169             'update check interval'  => $config->getUpdateCheck(),
170             'update cache file'      => $prettyPath($config->getUpdateCheckCacheFile()),
171         ];
172
173         if ($config->hasReadline()) {
174             $info = \readline_info();
175
176             $readline = [
177                 'readline available' => true,
178                 'readline enabled'   => $config->useReadline(),
179                 'readline service'   => \get_class($config->getReadline()),
180             ];
181
182             if (isset($info['library_version'])) {
183                 $readline['readline library'] = $info['library_version'];
184             }
185
186             if (isset($info['readline_name']) && $info['readline_name'] !== '') {
187                 $readline['readline name'] = $info['readline_name'];
188             }
189         } else {
190             $readline = [
191                 'readline available' => false,
192             ];
193         }
194
195         $pcntl = [
196             'pcntl available' => \function_exists('pcntl_signal'),
197             'posix available' => \function_exists('posix_getpid'),
198         ];
199
200         $disabledFuncs = \array_map('trim', \explode(',', \ini_get('disable_functions')));
201         if (\in_array('pcntl_signal', $disabledFuncs) || \in_array('pcntl_fork', $disabledFuncs)) {
202             $pcntl['pcntl disabled'] = true;
203         }
204
205         $history = [
206             'history file'     => $prettyPath($config->getHistoryFile()),
207             'history size'     => $config->getHistorySize(),
208             'erase duplicates' => $config->getEraseDuplicates(),
209         ];
210
211         $docs = [
212             'manual db file'   => $prettyPath($config->getManualDbFile()),
213             'sqlite available' => true,
214         ];
215
216         try {
217             if ($db = $config->getManualDb()) {
218                 if ($q = $db->query('SELECT * FROM meta;')) {
219                     $q->setFetchMode(\PDO::FETCH_KEY_PAIR);
220                     $meta = $q->fetchAll();
221
222                     foreach ($meta as $key => $val) {
223                         switch ($key) {
224                             case 'built_at':
225                                 $d = new \DateTime('@' . $val);
226                                 $val = $d->format(\DateTime::RFC2822);
227                                 break;
228                         }
229                         $key = 'db ' . \str_replace('_', ' ', $key);
230                         $docs[$key] = $val;
231                     }
232                 } else {
233                     $docs['db schema'] = '0.1.0';
234                 }
235             }
236         } catch (Exception\RuntimeException $e) {
237             if ($e->getMessage() === 'SQLite PDO driver not found') {
238                 $docs['sqlite available'] = false;
239             } else {
240                 throw $e;
241             }
242         }
243
244         $autocomplete = [
245             'tab completion enabled' => $config->useTabCompletion(),
246             'custom matchers'        => \array_map('get_class', $config->getTabCompletionMatchers()),
247             'bracketed paste'        => $config->useBracketedPaste(),
248         ];
249
250         // Shenanigans, but totally justified.
251         if ($shell = Sudo::fetchProperty($config, 'shell')) {
252             $core['loop listeners'] = \array_map('get_class', Sudo::fetchProperty($shell, 'loopListeners'));
253             $core['commands']       = \array_map('get_class', $shell->all());
254
255             $autocomplete['custom matchers'] = \array_map('get_class', Sudo::fetchProperty($shell, 'matchers'));
256         }
257
258         // @todo Show Presenter / custom casters.
259
260         return \array_merge($core, \compact('updates', 'pcntl', 'readline', 'history', 'docs', 'autocomplete'));
261     }
262 }
263
264 if (!\function_exists('Psy\bin')) {
265     /**
266      * `psysh` command line executable.
267      *
268      * @return \Closure
269      */
270     function bin()
271     {
272         return function () {
273             $usageException = null;
274
275             $input = new ArgvInput();
276             try {
277                 $input->bind(new InputDefinition([
278                     new InputOption('help',     'h',  InputOption::VALUE_NONE),
279                     new InputOption('config',   'c',  InputOption::VALUE_REQUIRED),
280                     new InputOption('version',  'v',  InputOption::VALUE_NONE),
281                     new InputOption('cwd',      null, InputOption::VALUE_REQUIRED),
282                     new InputOption('color',    null, InputOption::VALUE_NONE),
283                     new InputOption('no-color', null, InputOption::VALUE_NONE),
284
285                     new InputArgument('include', InputArgument::IS_ARRAY),
286                 ]));
287             } catch (\RuntimeException $e) {
288                 $usageException = $e;
289             }
290
291             $config = [];
292
293             // Handle --config
294             if ($configFile = $input->getOption('config')) {
295                 $config['configFile'] = $configFile;
296             }
297
298             // Handle --color and --no-color
299             if ($input->getOption('color') && $input->getOption('no-color')) {
300                 $usageException = new \RuntimeException('Using both "--color" and "--no-color" options is invalid');
301             } elseif ($input->getOption('color')) {
302                 $config['colorMode'] = Configuration::COLOR_MODE_FORCED;
303             } elseif ($input->getOption('no-color')) {
304                 $config['colorMode'] = Configuration::COLOR_MODE_DISABLED;
305             }
306
307             $shell = new Shell(new Configuration($config));
308
309             // Handle --help
310             if ($usageException !== null || $input->getOption('help')) {
311                 if ($usageException !== null) {
312                     echo $usageException->getMessage() . PHP_EOL . PHP_EOL;
313                 }
314
315                 $version = $shell->getVersion();
316                 $name    = \basename(\reset($_SERVER['argv']));
317                 echo <<<EOL
318 $version
319
320 Usage:
321   $name [--version] [--help] [files...]
322
323 Options:
324   --help     -h Display this help message.
325   --config   -c Use an alternate PsySH config file location.
326   --cwd         Use an alternate working directory.
327   --version  -v Display the PsySH version.
328   --color       Force colors in output.
329   --no-color    Disable colors in output.
330
331 EOL;
332                 exit($usageException === null ? 0 : 1);
333             }
334
335             // Handle --version
336             if ($input->getOption('version')) {
337                 echo $shell->getVersion() . PHP_EOL;
338                 exit(0);
339             }
340
341             // Pass additional arguments to Shell as 'includes'
342             $shell->setIncludes($input->getArgument('include'));
343
344             try {
345                 // And go!
346                 $shell->run();
347             } catch (\Exception $e) {
348                 echo $e->getMessage() . PHP_EOL;
349
350                 // @todo this triggers the "exited unexpectedly" logic in the
351                 // ForkingLoop, so we can't exit(1) after starting the shell...
352                 // fix this :)
353
354                 // exit(1);
355             }
356         };
357     }
358 }