From e0ba1923e0f2de9e848585975527ece736cf3a56 Mon Sep 17 00:00:00 2001 From: Gunnar Wolf Date: Thu, 20 Jun 2024 09:53:09 -0600 Subject: [PATCH 1/6] Check for the presence of the MySQL binaries before calling them --- commands/db.bee.inc | 56 ++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 50 insertions(+), 6 deletions(-) diff --git a/commands/db.bee.inc b/commands/db.bee.inc index acff183d..6cae9139 100644 --- a/commands/db.bee.inc +++ b/commands/db.bee.inc @@ -119,8 +119,14 @@ function db_export_bee_callback($arguments, $options) { $extra = '--no-tablespaces '; } + $export_command = executable_for('mysqldump'); + if (is_null($export_command)) { + bee_message("The MySQL export command 'mysqldump' cannot be found in " . + "this system. Please install it and try again.", 'error'); + return null; + } // Export and compress the database. - $export_command = 'mysqldump '; + $export_command .= ' '; $export_command .= $connection_string; $export_command .= ' '; $export_command .= $extra; @@ -172,11 +178,23 @@ function db_import_bee_callback($arguments, $options) { } // Import the database. + $mysql_bin = executable_for('mysql'); + if (is_null($mysql_bin)) { + bee_message("The MySQL client command 'mysql' cannot be found in " . + "this system. Please install it and try again.", 'error'); + return null; + } $import_command = ''; if ($gzip) { - $import_command .= "gunzip -c $filename | "; + $gunzip_bin = executable_for('gunzip'); + if (is_null($gunzip_bin)) { + bee_message("The gzip decompressor command 'gunzip' cannot be found in " . + "this system. Please install it and try again.", 'error'); + return null; + } + $import_command .= "$gunzip_bin -c $filename | "; } - $import_command .= 'mysql ' . $connection_string; + $import_command .= $mysql_bin . ' ' . $connection_string; if (!$gzip) { $import_command .= " < $filename"; } @@ -218,7 +236,13 @@ function db_drop_bee_callback($arguments, $options) { $connection_file = $connection_details['filename']; // Drop the existing backdrop database as configured. - $command = 'mysql ' . $connection_string . ' -e "drop database ' . $db_database . '";'; + $mysql_command = executable_for('mysql'); + if (is_null($mysql_command)) { + bee_message("The MySQL client command 'mysql' cannot be found in " . + "this system. Please install it and try again.", 'error'); + return null; + } + $command = $mysql_command . ' ' . $connection_string . ' -e "drop database ' . $db_database . '";'; $result = proc_close(proc_open($command, array(STDIN, STDOUT, STDERR), $pipes)); if ($result == -1) { @@ -233,7 +257,7 @@ function db_drop_bee_callback($arguments, $options) { } // Re-create the existing backdrop database as configured. - $command = 'mysql ' . $connection_string . ' -e "create database ' . $db_database . '";'; + $command = $mysql_command .' ' . $connection_string . ' -e "create database ' . $db_database . '";'; $result = proc_close(proc_open($command, array(STDIN, STDOUT, STDERR), $pipes)); if ($result == -1) { @@ -265,7 +289,13 @@ function sql_bee_callback($arguments, $options) { $connection_file = $connection_details['filename']; // Open SQL command-line. - $command = 'mysql ' . $connection_string; + $mysql_command = executable_for('mysql'); + if (is_null($mysql_command)) { + bee_message("The MySQL client command 'mysql' cannot be found in " . + "this system. Please install it and try again.", 'error'); + return null; + } + $command = $mysql_command . ' ' . $connection_string; proc_close(proc_open($command, array(STDIN, STDOUT, STDERR), $pipes)); // Remove the temporary mysql options file. bee_delete($connection_file); @@ -348,3 +378,17 @@ function dbq_bee_callback($arguments, $options) { bee_message($e->getMessage(), 'error'); } } + +/** + * Checks whether a command exists in the PATH, and if so, returns the + * full path. Returns null if no such command is available. + */ +function executable_for($cmd) { + foreach (explode(":", getenv('PATH')) as $dir) { + $candidate = "$dir/$cmd"; + if (is_executable($candidate)) { + return $candidate; + } + } + return null; +} From 1c447f5ebf78f4f158e2dcb1ddfbd6ebf72f4538 Mon Sep 17 00:00:00 2001 From: Gunnar Wolf Date: Thu, 20 Jun 2024 10:34:30 -0600 Subject: [PATCH 2/6] Use the proper indentantion and line length for Bee's coding standards --- commands/db.bee.inc | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/commands/db.bee.inc b/commands/db.bee.inc index 6cae9139..f1b6ef90 100644 --- a/commands/db.bee.inc +++ b/commands/db.bee.inc @@ -180,16 +180,16 @@ function db_import_bee_callback($arguments, $options) { // Import the database. $mysql_bin = executable_for('mysql'); if (is_null($mysql_bin)) { - bee_message("The MySQL client command 'mysql' cannot be found in " . - "this system. Please install it and try again.", 'error'); + bee_message("The MySQL client command 'mysql' cannot be found in this " . + "system. Please install it and try again.", 'error'); return null; } $import_command = ''; if ($gzip) { $gunzip_bin = executable_for('gunzip'); if (is_null($gunzip_bin)) { - bee_message("The gzip decompressor command 'gunzip' cannot be found in " . - "this system. Please install it and try again.", 'error'); + bee_message("The gzip decompressor command 'gunzip' cannot be found " . + "in this system. Please install it and try again.", 'error'); return null; } $import_command .= "$gunzip_bin -c $filename | "; @@ -238,8 +238,8 @@ function db_drop_bee_callback($arguments, $options) { // Drop the existing backdrop database as configured. $mysql_command = executable_for('mysql'); if (is_null($mysql_command)) { - bee_message("The MySQL client command 'mysql' cannot be found in " . - "this system. Please install it and try again.", 'error'); + bee_message("The MySQL client command 'mysql' cannot be found in this " . + "system. Please install it and try again.", 'error'); return null; } $command = $mysql_command . ' ' . $connection_string . ' -e "drop database ' . $db_database . '";'; @@ -291,8 +291,8 @@ function sql_bee_callback($arguments, $options) { // Open SQL command-line. $mysql_command = executable_for('mysql'); if (is_null($mysql_command)) { - bee_message("The MySQL client command 'mysql' cannot be found in " . - "this system. Please install it and try again.", 'error'); + bee_message("The MySQL client command 'mysql' cannot be found in this " . + "system. Please install it and try again.", 'error'); return null; } $command = $mysql_command . ' ' . $connection_string; @@ -380,15 +380,15 @@ function dbq_bee_callback($arguments, $options) { } /** - * Checks whether a command exists in the PATH, and if so, returns the - * full path. Returns null if no such command is available. + * Checks whether a command exists in the PATH, and if so, returns the full + * path. Returns null if no such command is available. */ function executable_for($cmd) { - foreach (explode(":", getenv('PATH')) as $dir) { - $candidate = "$dir/$cmd"; - if (is_executable($candidate)) { - return $candidate; - } + foreach (explode(":", getenv('PATH')) as $dir) { + $candidate = "$dir/$cmd"; + if (is_executable($candidate)) { + return $candidate; } - return null; + } + return null; } From d129b8772a83494d784262feb63b55895646372f Mon Sep 17 00:00:00 2001 From: Gunnar Wolf Date: Fri, 21 Jun 2024 09:06:41 -0600 Subject: [PATCH 3/6] Follow Bee coding standards Use FALSE instead of null. Write a proper docblock for the introduced function. --- commands/db.bee.inc | 31 +++++++++++++++++++------------ 1 file changed, 19 insertions(+), 12 deletions(-) diff --git a/commands/db.bee.inc b/commands/db.bee.inc index f1b6ef90..9e7feda0 100644 --- a/commands/db.bee.inc +++ b/commands/db.bee.inc @@ -120,10 +120,10 @@ function db_export_bee_callback($arguments, $options) { } $export_command = executable_for('mysqldump'); - if (is_null($export_command)) { + if (!$export_command) { bee_message("The MySQL export command 'mysqldump' cannot be found in " . "this system. Please install it and try again.", 'error'); - return null; + return FALSE; } // Export and compress the database. $export_command .= ' '; @@ -179,18 +179,18 @@ function db_import_bee_callback($arguments, $options) { // Import the database. $mysql_bin = executable_for('mysql'); - if (is_null($mysql_bin)) { + if (!$mysql_bin) { bee_message("The MySQL client command 'mysql' cannot be found in this " . "system. Please install it and try again.", 'error'); - return null; + return FALSE; } $import_command = ''; if ($gzip) { $gunzip_bin = executable_for('gunzip'); - if (is_null($gunzip_bin)) { + if (!$gunzip_bin) { bee_message("The gzip decompressor command 'gunzip' cannot be found " . "in this system. Please install it and try again.", 'error'); - return null; + return FALSE; } $import_command .= "$gunzip_bin -c $filename | "; } @@ -237,10 +237,10 @@ function db_drop_bee_callback($arguments, $options) { // Drop the existing backdrop database as configured. $mysql_command = executable_for('mysql'); - if (is_null($mysql_command)) { + if (!$mysql_command) { bee_message("The MySQL client command 'mysql' cannot be found in this " . "system. Please install it and try again.", 'error'); - return null; + return FALSE; } $command = $mysql_command . ' ' . $connection_string . ' -e "drop database ' . $db_database . '";'; $result = proc_close(proc_open($command, array(STDIN, STDOUT, STDERR), $pipes)); @@ -290,10 +290,10 @@ function sql_bee_callback($arguments, $options) { // Open SQL command-line. $mysql_command = executable_for('mysql'); - if (is_null($mysql_command)) { + if (!$mysql_command) { bee_message("The MySQL client command 'mysql' cannot be found in this " . "system. Please install it and try again.", 'error'); - return null; + return FALSE; } $command = $mysql_command . ' ' . $connection_string; proc_close(proc_open($command, array(STDIN, STDOUT, STDERR), $pipes)); @@ -381,7 +381,14 @@ function dbq_bee_callback($arguments, $options) { /** * Checks whether a command exists in the PATH, and if so, returns the full - * path. Returns null if no such command is available. + * path. Returns FALSE if no such command is available. + * + * @param string $cmd + * Name of the command to be searched + * + * @return string + * Full path to the first occurence of $cmd in the search path. + * Returns FALSE if no matching command is found. */ function executable_for($cmd) { foreach (explode(":", getenv('PATH')) as $dir) { @@ -390,5 +397,5 @@ function executable_for($cmd) { return $candidate; } } - return null; + return FALSE; } From 1a35c716e2b93bb67577d24c6370e212b6b62455 Mon Sep 17 00:00:00 2001 From: Gunnar Wolf Date: Fri, 21 Jun 2024 09:10:09 -0600 Subject: [PATCH 4/6] Use bt() for translatable strings; avoid splitting strings at 80 columns --- commands/db.bee.inc | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/commands/db.bee.inc b/commands/db.bee.inc index 9e7feda0..4bc6c9a0 100644 --- a/commands/db.bee.inc +++ b/commands/db.bee.inc @@ -121,8 +121,7 @@ function db_export_bee_callback($arguments, $options) { $export_command = executable_for('mysqldump'); if (!$export_command) { - bee_message("The MySQL export command 'mysqldump' cannot be found in " . - "this system. Please install it and try again.", 'error'); + bee_message(bt("The MySQL export command 'mysqldump' cannot be found in this system. Please install it and try again."), 'error'); return FALSE; } // Export and compress the database. @@ -180,16 +179,14 @@ function db_import_bee_callback($arguments, $options) { // Import the database. $mysql_bin = executable_for('mysql'); if (!$mysql_bin) { - bee_message("The MySQL client command 'mysql' cannot be found in this " . - "system. Please install it and try again.", 'error'); + bee_message(bt("The MySQL client command 'mysql' cannot be found in this system. Please install it and try again."), 'error'); return FALSE; } $import_command = ''; if ($gzip) { $gunzip_bin = executable_for('gunzip'); if (!$gunzip_bin) { - bee_message("The gzip decompressor command 'gunzip' cannot be found " . - "in this system. Please install it and try again.", 'error'); + bee_message(bt("The gzip decompressor command 'gunzip' cannot be found in this system. Please install it and try again."), 'error'); return FALSE; } $import_command .= "$gunzip_bin -c $filename | "; @@ -238,8 +235,7 @@ function db_drop_bee_callback($arguments, $options) { // Drop the existing backdrop database as configured. $mysql_command = executable_for('mysql'); if (!$mysql_command) { - bee_message("The MySQL client command 'mysql' cannot be found in this " . - "system. Please install it and try again.", 'error'); + bee_message(bt("The MySQL client command 'mysql' cannot be found in this system. Please install it and try again."), 'error'); return FALSE; } $command = $mysql_command . ' ' . $connection_string . ' -e "drop database ' . $db_database . '";'; @@ -291,8 +287,7 @@ function sql_bee_callback($arguments, $options) { // Open SQL command-line. $mysql_command = executable_for('mysql'); if (!$mysql_command) { - bee_message("The MySQL client command 'mysql' cannot be found in this " . - "system. Please install it and try again.", 'error'); + bee_message(bt("The MySQL client command 'mysql' cannot be found in this system. Please install it and try again."), 'error'); return FALSE; } $command = $mysql_command . ' ' . $connection_string; From 6241d9237af9019a38b2aa12db2da95c104d8b99 Mon Sep 17 00:00:00 2001 From: Gunnar Wolf Date: Fri, 21 Jun 2024 09:15:10 -0600 Subject: [PATCH 5/6] Param string should end with a full stop MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Aren\'t we a bit over-pedantic? 😉 --- commands/db.bee.inc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/commands/db.bee.inc b/commands/db.bee.inc index 4bc6c9a0..32a24090 100644 --- a/commands/db.bee.inc +++ b/commands/db.bee.inc @@ -379,7 +379,7 @@ function dbq_bee_callback($arguments, $options) { * path. Returns FALSE if no such command is available. * * @param string $cmd - * Name of the command to be searched + * Name of the command to be searched. * * @return string * Full path to the first occurence of $cmd in the search path. From d94d0d7e52beeb0b3e50605ce3cbbd0486fad0c9 Mon Sep 17 00:00:00 2001 From: Gunnar Wolf Date: Sat, 22 Jun 2024 18:36:06 -0600 Subject: [PATCH 6/6] Further stylistic cleanup Change variable names to full words instead of abbr Rename introduced function to a more project-wide descriptive one Move introduced function to the filesystem includes --- commands/db.bee.inc | 31 +++++-------------------------- includes/filesystem.inc | 26 ++++++++++++++++++++++++++ 2 files changed, 31 insertions(+), 26 deletions(-) diff --git a/commands/db.bee.inc b/commands/db.bee.inc index 32a24090..81f85b30 100644 --- a/commands/db.bee.inc +++ b/commands/db.bee.inc @@ -119,7 +119,7 @@ function db_export_bee_callback($arguments, $options) { $extra = '--no-tablespaces '; } - $export_command = executable_for('mysqldump'); + $export_command = bee_get_executable_path('mysqldump'); if (!$export_command) { bee_message(bt("The MySQL export command 'mysqldump' cannot be found in this system. Please install it and try again."), 'error'); return FALSE; @@ -177,14 +177,14 @@ function db_import_bee_callback($arguments, $options) { } // Import the database. - $mysql_bin = executable_for('mysql'); + $mysql_bin = bee_get_executable_path('mysql'); if (!$mysql_bin) { bee_message(bt("The MySQL client command 'mysql' cannot be found in this system. Please install it and try again."), 'error'); return FALSE; } $import_command = ''; if ($gzip) { - $gunzip_bin = executable_for('gunzip'); + $gunzip_bin = bee_get_executable_path('gunzip'); if (!$gunzip_bin) { bee_message(bt("The gzip decompressor command 'gunzip' cannot be found in this system. Please install it and try again."), 'error'); return FALSE; @@ -233,7 +233,7 @@ function db_drop_bee_callback($arguments, $options) { $connection_file = $connection_details['filename']; // Drop the existing backdrop database as configured. - $mysql_command = executable_for('mysql'); + $mysql_command = bee_get_executable_path('mysql'); if (!$mysql_command) { bee_message(bt("The MySQL client command 'mysql' cannot be found in this system. Please install it and try again."), 'error'); return FALSE; @@ -285,7 +285,7 @@ function sql_bee_callback($arguments, $options) { $connection_file = $connection_details['filename']; // Open SQL command-line. - $mysql_command = executable_for('mysql'); + $mysql_command = bee_get_executable_path('mysql'); if (!$mysql_command) { bee_message(bt("The MySQL client command 'mysql' cannot be found in this system. Please install it and try again."), 'error'); return FALSE; @@ -373,24 +373,3 @@ function dbq_bee_callback($arguments, $options) { bee_message($e->getMessage(), 'error'); } } - -/** - * Checks whether a command exists in the PATH, and if so, returns the full - * path. Returns FALSE if no such command is available. - * - * @param string $cmd - * Name of the command to be searched. - * - * @return string - * Full path to the first occurence of $cmd in the search path. - * Returns FALSE if no matching command is found. - */ -function executable_for($cmd) { - foreach (explode(":", getenv('PATH')) as $dir) { - $candidate = "$dir/$cmd"; - if (is_executable($candidate)) { - return $candidate; - } - } - return FALSE; -} diff --git a/includes/filesystem.inc b/includes/filesystem.inc index 48386e0a..924dcdf0 100644 --- a/includes/filesystem.inc +++ b/includes/filesystem.inc @@ -373,3 +373,29 @@ function bee_copy($source, $destination, $self = TRUE) { return TRUE; } + +/** + * Get the full path for a command executable if it exists in PATH. + * + * If your function calls an executable on the system rather than using `bee`, + * `backdrop` or `php` functions, you can use this function to get the full + * path of the executable or return FALSE if the executable doesn't exist. The + * result can then be checked in your calling function, and you can exit with a + * user friendly error message if the executable doesn't exist in the system. + * + * @param string $command + * Name of the command to be searched. + * + * @return string|FALSE + * Full path to the first occurence of $command in the search path. + * Returns FALSE if no matching command is found. + */ +function bee_get_executable_path($command) { + foreach (explode(":", getenv('PATH')) as $directory) { + $candidate = "$directory/$command"; + if (is_executable($candidate)) { + return $candidate; + } + } + return FALSE; +}