Skip to content

Commit e2ae8c0

Browse files
CopilotswissspidyCopilot
authored
Catch exceptions in REPL to preserve session state on errors (#83)
* Initial plan * Add exception handling to REPL to prevent session crashes Co-authored-by: swissspidy <841956+swissspidy@users.noreply.github.com> * Improve error message format for better user experience Co-authored-by: swissspidy <841956+swissspidy@users.noreply.github.com> * Update features/shell.feature Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Fix test failures: use 'try' instead of 'run' for STDERR output Co-authored-by: swissspidy <841956+swissspidy@users.noreply.github.com> * Fix variable name after merge and code style Co-authored-by: swissspidy <841956+swissspidy@users.noreply.github.com> * Suppress PHP warnings in eval to show clean error messages Co-authored-by: swissspidy <841956+swissspidy@users.noreply.github.com> * Remove error suppression operator - keep warnings visible Co-authored-by: swissspidy <841956+swissspidy@users.noreply.github.com> * Update assertion * Potential fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> * Lint fix --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: swissspidy <841956+swissspidy@users.noreply.github.com> Co-authored-by: Pascal Birchler <pascal.birchler@gmail.com> Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Co-authored-by: Pascal Birchler <pascalb@google.com>
1 parent 349cd9e commit e2ae8c0

File tree

2 files changed

+59
-5
lines changed

2 files changed

+59
-5
lines changed

features/shell.feature

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,44 @@ Feature: WordPress REPL
147147
history: -1: invalid option
148148
"""
149149
150+
Scenario: Exception handling preserves session state
151+
Given a WP install
152+
And a session file:
153+
"""
154+
$foo = 'test_value';
155+
require 'nonexistent_file.txt';
156+
echo $foo;
157+
"""
158+
159+
When I try `wp shell --basic < session`
160+
Then STDOUT should contain:
161+
"""
162+
test_value
163+
"""
164+
And STDERR should contain:
165+
"""
166+
Failed opening required 'nonexistent_file.txt'
167+
"""
168+
169+
Scenario: Exception handling for expression errors
170+
Given a WP install
171+
And a session file:
172+
"""
173+
$bar = 'preserved';
174+
nonexistent_function();
175+
$bar;
176+
"""
177+
178+
When I try `wp shell --basic < session`
179+
Then STDOUT should contain:
180+
"""
181+
string(9) "preserved"
182+
"""
183+
And STDERR should contain:
184+
"""
185+
Error: Call to undefined function nonexistent_function()
186+
"""
187+
150188
Scenario: User can define variable named $line
151189
Given a WP install
152190
And a session file:

src/WP_CLI/Shell/REPL.php

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -68,8 +68,13 @@ public function start() {
6868

6969
if ( self::starts_with( self::non_expressions(), $__repl_input_line ) ) {
7070
ob_start();
71-
// phpcs:ignore Squiz.PHP.Eval.Discouraged -- This is meant to be a REPL, no way to avoid eval.
72-
eval( $__repl_input_line );
71+
try {
72+
// phpcs:ignore Squiz.PHP.Eval.Discouraged -- This is meant to be a REPL, no way to avoid eval.
73+
eval( $__repl_input_line );
74+
} catch ( \Throwable $e ) {
75+
// Display the error message but continue the session
76+
fwrite( STDERR, get_class( $e ) . ': ' . $e->getMessage() . "\n" );
77+
}
7378
$__repl_output = (string) ob_get_clean();
7479
if ( 0 < strlen( $__repl_output ) ) {
7580
$__repl_output = rtrim( $__repl_output, "\n" ) . "\n";
@@ -82,12 +87,23 @@ public function start() {
8287

8388
// Write directly to STDOUT, to sidestep any output buffers created by plugins
8489
ob_start();
85-
// phpcs:ignore Squiz.PHP.Eval.Discouraged -- This is meant to be a REPL, no way to avoid eval.
86-
$__repl_eval_result = eval( $__repl_input_line );
87-
$__repl_output = (string) ob_get_clean();
90+
$__repl_eval_had_error = false;
91+
try {
92+
// phpcs:ignore Squiz.PHP.Eval.Discouraged -- This is meant to be a REPL, no way to avoid eval.
93+
$__repl_eval_result = eval( $__repl_input_line );
94+
} catch ( \Throwable $e ) {
95+
// Display the error message but continue the session
96+
fwrite( STDERR, get_class( $e ) . ': ' . $e->getMessage() . "\n" );
97+
$__repl_eval_had_error = true;
98+
$__repl_eval_result = null;
99+
}
100+
$__repl_output = (string) ob_get_clean();
88101
if ( 0 < strlen( $__repl_output ) ) {
89102
echo rtrim( $__repl_output, "\n" ) . "\n";
90103
}
104+
if ( $__repl_eval_had_error ) {
105+
continue;
106+
}
91107
ob_start();
92108
if ( ! $this->quiet ) {
93109
echo '=> ';

0 commit comments

Comments
 (0)