Skip to content

Commit c5cd08d

Browse files
CopilotswissspidyCopilot
authored
Add ksh support for OpenBSD (and mksh/pdksh) (#87)
* Initial plan * Add ksh support: detect ksh shells and use POSIX-compatible read commands Co-authored-by: swissspidy <841956+swissspidy@users.noreply.github.com> * Potential fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --------- 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 Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
1 parent 7256aa3 commit c5cd08d

File tree

1 file changed

+48
-10
lines changed

1 file changed

+48
-10
lines changed

src/WP_CLI/Shell/REPL.php

Lines changed: 48 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -125,8 +125,8 @@ private static function create_prompt_cmd( $prompt, $history_path ) {
125125
} elseif ( is_file( '/bin/bash' ) && is_readable( '/bin/bash' ) ) {
126126
// Prefer /bin/bash when available since we use bash-specific commands.
127127
$shell_binary = '/bin/bash';
128-
} elseif ( getenv( 'SHELL' ) && self::is_bash_shell( (string) getenv( 'SHELL' ) ) ) {
129-
// Only use SHELL as fallback if it's bash (we use bash-specific commands).
128+
} elseif ( getenv( 'SHELL' ) && self::is_supported_shell( (string) getenv( 'SHELL' ) ) ) {
129+
// Use SHELL as fallback if it's a supported shell (bash or ksh).
130130
$shell_binary = (string) getenv( 'SHELL' );
131131
} else {
132132
// Final fallback for systems without /bin/bash.
@@ -137,16 +137,27 @@ private static function create_prompt_cmd( $prompt, $history_path ) {
137137
WP_CLI::error( "The shell binary '{$shell_binary}' is not valid. You can override the shell to be used through the WP_CLI_CUSTOM_SHELL environment variable." );
138138
}
139139

140+
$is_ksh = self::is_ksh_shell( $shell_binary );
140141
$shell_binary = escapeshellarg( $shell_binary );
141142

142-
$cmd = 'set -f; '
143-
. "history -r {$history_path}; "
144-
. 'LINE=""; '
145-
. "read -re -p {$prompt} LINE; "
146-
. '[ $? -eq 0 ] || exit; '
147-
. 'history -s -- "$LINE"; '
148-
. "history -w {$history_path}; "
149-
. 'echo $LINE; ';
143+
if ( $is_ksh ) {
144+
// ksh does not support bash-specific history commands or `read -e`/`read -p`.
145+
// Use POSIX-compatible read and print the prompt via printf to stderr.
146+
$cmd = 'set -f; '
147+
. 'LINE=""; '
148+
. "printf %s {$prompt} >&2; "
149+
. 'IFS= read -r LINE || exit; '
150+
. 'printf \'%s\n\' "$LINE"; ';
151+
} else {
152+
$cmd = 'set -f; '
153+
. "history -r {$history_path}; "
154+
. 'LINE=""; '
155+
. "read -re -p {$prompt} LINE; "
156+
. '[ $? -eq 0 ] || exit; '
157+
. 'history -s -- "$LINE"; '
158+
. "history -w {$history_path}; "
159+
. 'printf \'%s\n\' "$LINE"; ';
160+
}
150161

151162
return "{$shell_binary} -c " . escapeshellarg( $cmd );
152163
}
@@ -166,6 +177,33 @@ private static function is_bash_shell( $shell_path ) {
166177
return 'bash' === $basename || 0 === strpos( $basename, 'bash-' );
167178
}
168179

180+
/**
181+
* Check if a shell binary is ksh or a ksh-compatible shell (mksh, pdksh, ksh93, etc.).
182+
*
183+
* @param string $shell_path Path to the shell binary.
184+
* @return bool True if the shell is ksh-compatible, false otherwise.
185+
*/
186+
private static function is_ksh_shell( $shell_path ) {
187+
if ( ! is_file( $shell_path ) || ! is_readable( $shell_path ) ) {
188+
return false;
189+
}
190+
$basename = basename( $shell_path );
191+
// Matches ksh, ksh93, ksh88, mksh, pdksh, etc.
192+
return 0 === strpos( $basename, 'ksh' )
193+
|| 'mksh' === $basename
194+
|| 'pdksh' === $basename;
195+
}
196+
197+
/**
198+
* Check if a shell binary is supported (bash or ksh-compatible).
199+
*
200+
* @param string $shell_path Path to the shell binary.
201+
* @return bool True if the shell is supported, false otherwise.
202+
*/
203+
private static function is_supported_shell( $shell_path ) {
204+
return self::is_bash_shell( $shell_path ) || self::is_ksh_shell( $shell_path );
205+
}
206+
169207
private function set_history_file() {
170208
$data = getcwd() . get_current_user();
171209

0 commit comments

Comments
 (0)