diff --git a/commands/sql/sql.drush.inc b/commands/sql/sql.drush.inc index 23ab737db6..b6743035c0 100644 --- a/commands/sql/sql.drush.inc +++ b/commands/sql/sql.drush.inc @@ -5,162 +5,6 @@ * Drush sql commands */ -/** - * Implementation of hook_drush_help(). - */ -function sql_drush_help($section) { - switch ($section) { - case 'meta:sql:title': - return dt('SQL commands'); - case 'meta:sql:summary': - return dt('Examine and modify your Drupal database.'); - case 'drush:sql-sanitize': - return dt('Run sanitization operations on the current database. You can add more sanitization to this command by implementing hook_drush_sql_sync_sanitize().'); - } -} - -/** - * Implementation of hook_drush_command(). - */ -function sql_drush_command() { - $options['database'] = array( - 'description' => 'The DB connection key if using multiple connections in settings.php.', - 'example-value' => 'key', - ); - $db_url['db-url'] = array( - 'description' => 'A Drupal 6 style database URL.', - 'example-value' => 'mysql://root:pass@127.0.0.1/db', - ); - $options['target'] = array( - 'description' => 'The name of a target within the specified database connection. Defaults to \'default\'.', - 'example-value' => 'key', - // Gets unhidden in help_alter(). We only want to show this to D7 users but have to - // declare it here since some commands do not bootstrap fully. - 'hidden' => TRUE, - ); - - $items['sql-drop'] = array( - 'description' => 'Drop all tables in a given database.', - 'arguments' => array( - ), - 'bootstrap' => DRUSH_BOOTSTRAP_NONE, - 'options' => array( - 'yes' => 'Skip confirmation and proceed.', - 'result-file' => array( - 'description' => 'Save to a file. The file should be relative to Drupal root. Recommended.', - 'example-value' => '/path/to/file', - ), - ) + $options + $db_url, - 'topics' => array('docs-policy'), - ); - $items['sql-conf'] = array( - 'description' => 'Print database connection details using print_r().', - 'hidden' => TRUE, - 'bootstrap' => DRUSH_BOOTSTRAP_NONE, - 'options' => array( - 'all' => 'Show all database connections, instead of just one.', - 'show-passwords' => 'Show database password.', - ) + $options, - 'outputformat' => array( - 'default' => 'print-r', - 'pipe-format' => 'var_export', - 'private-fields' => 'password', - ), - ); - $items['sql-connect'] = array( - 'description' => 'A string for connecting to the DB.', - 'bootstrap' => DRUSH_BOOTSTRAP_NONE, - 'options' => $options + $db_url + array( - 'extra' => array( - 'description' => 'Add custom options to the connect string.', - 'example-value' => '--skip-column-names', - ), - ), - 'examples' => array( - '`drush sql-connect` < example.sql' => 'Bash: Import SQL statements from a file into the current database.', - 'eval (drush sql-connect) < example.sql' => 'Fish: Import SQL statements from a file into the current database.', - ), - ); - $items['sql-create'] = array( - 'description' => 'Create a database.', - 'bootstrap' => DRUSH_BOOTSTRAP_NONE, - 'examples' => array( - 'drush sql-create' => 'Create the database for the current site.', - 'drush @site.test sql-create' => 'Create the database as specified for @site.test.', - 'drush sql-create --db-su=root --db-su-pw=rootpassword --db-url="mysql://drupal_db_user:drupal_db_password@127.0.0.1/drupal_db"' => - 'Create the database as specified in the db-url option.' - ), - 'options' => array( - 'db-su' => 'Account to use when creating a new database. Optional.', - 'db-su-pw' => 'Password for the "db-su" account. Optional.', - ) + $options + $db_url, - ); - $items['sql-dump'] = array( - 'description' => 'Exports the Drupal DB as SQL using mysqldump or equivalent.', - 'bootstrap' => DRUSH_BOOTSTRAP_NONE, - 'examples' => array( - 'drush sql-dump --result-file=../18.sql' => 'Save SQL dump to the directory above Drupal root.', - 'drush sql-dump --skip-tables-key=common' => 'Skip standard tables. @see example.drushrc.php', - 'drush sql-dump --extra=--no-data' => 'Pass extra option to dump command.', - ), - 'options' => drush_sql_get_table_selection_options() + array( - 'result-file' => array( - 'description' => 'Save to a file. The file should be relative to Drupal root. If --result-file is provided with no value, then date based filename will be created under ~/drush-backups directory.', - 'example-value' => '/path/to/file', - 'value' => 'optional', - ), - 'create-db' => array('hidden' => TRUE, 'description' => 'Omit DROP TABLE statements. Postgres and Oracle only. Used by sql-sync, since including the DROP TABLE statements interfere with the import when the database is created.'), - 'data-only' => 'Dump data without statements to create any of the schema.', - 'ordered-dump' => 'Order by primary key and add line breaks for efficient diff in revision control. Slows down the dump. Mysql only.', - 'gzip' => 'Compress the dump using the gzip program which must be in your $PATH.', - 'extra' => 'Add custom options to the dump command.', - ) + $options + $db_url, - ); - $items['sql-query'] = array( - 'bootstrap' => DRUSH_BOOTSTRAP_NONE, - 'description' => 'Execute a query against a database.', - 'examples' => array( - 'drush sql-query "SELECT * FROM users WHERE uid=1"' => 'Browse user record. Table prefixes, if used, must be added to table names by hand.', - 'drush sql-query --db-prefix "SELECT * FROM {users} WHERE uid=1"' => 'Browse user record. Table prefixes are honored. Caution: curly-braces will be stripped from all portions of the query.', - '`drush sql-connect` < example.sql' => 'Import sql statements from a file into the current database.', - 'drush sql-query --file=example.sql' => 'Alternate way to import sql statements from a file.', - ), - 'arguments' => array( - 'query' => 'An SQL query. Ignored if \'file\' is provided.', - ), - 'options' => array( - 'result-file' => array( - 'description' => 'Save to a file. The file should be relative to Drupal root. Optional.', - 'example-value' => '/path/to/file', - ), - 'file' => 'Path to a file containing the SQL to be run. Gzip files are accepted.', - 'extra' => array( - 'description' => 'Add custom options to the database connection command.', - 'example-value' => '--skip-column-names', - ), - 'db-prefix' => 'Enable replacement of braces in your query.', - 'db-spec' => array( - 'description' => 'A database specification', - 'hidden' => TRUE, // Hide since this is only used with --backend calls. - ) - ) + $options + $db_url, - 'aliases' => array('sqlq'), - ); - $items['sql-cli'] = array( - 'description' => "Open a SQL command-line interface using Drupal's credentials.", - 'bootstrap' => DRUSH_BOOTSTRAP_NONE, - // 'options' => $options + $db_url, - 'allow-additional-options' => array('sql-connect'), - 'aliases' => array('sqlc'), - 'examples' => array( - 'drush sql-cli' => "Open a SQL command-line interface using Drupal's credentials.", - 'drush sql-cli --extra=-A' => "Open a SQL CLI and skip reading table information.", - ), - 'remote-tty' => TRUE, - ); - return $items; -} - /** * Implements hook_drush_help_alter(). */ @@ -198,61 +42,6 @@ function drush_sql_bootstrap_further() { } } -/** - * Command callback. Displays the Drupal site's database connection string. - */ -function drush_sql_conf() { - drush_sql_bootstrap_database_configuration(); - if (drush_get_option('all')) { - $sqlVersion = drush_sql_get_version(); - return $sqlVersion->getAll(); - } - else { - $sql = drush_sql_get_class(); - return $sql->db_spec(); - } -} - -/** - * Command callback. Emits a connect string. - */ -function drush_sql_connect() { - drush_sql_bootstrap_further(); - $sql = drush_sql_get_class(); - return $sql->connect(FALSE); -} - -/** - * Command callback. Create a database. - */ -function drush_sql_create() { - drush_sql_bootstrap_further(); - $sql = drush_sql_get_class(); - $db_spec = $sql->db_spec(); - // Prompt for confirmation. - if (!drush_get_context('DRUSH_SIMULATE')) { - // @todo odd - maybe for sql-sync. - $txt_destination = (isset($db_spec['remote-host']) ? $db_spec['remote-host'] . '/' : '') . $db_spec['database']; - drush_print(dt("Creating database !target. Any possible existing database will be dropped!", array('!target' => $txt_destination))); - - if (!drush_confirm(dt('Do you really want to continue?'))) { - return drush_user_abort(); - } - } - - return $sql->createdb(TRUE); -} - - -/** - * Command callback. Outputs the entire Drupal database in SQL format using mysqldump or equivalent. - */ -function drush_sql_dump() { - drush_sql_bootstrap_further(); - $sql = drush_sql_get_class(); - return $sql->dump(drush_get_option('result-file', FALSE)); -} - /** * Construct an array that places table names in appropriate * buckets based on whether the table is to be skipped, included @@ -277,6 +66,7 @@ function drush_sql_get_table_selection() { return array('skip' => $skip_tables, 'structure' => $structure_tables, 'tables' => $tables); } +// @todo Remove once sql-sync and archive-dump are using \Drush\Commands\OptionsCommands::optionsetTableSelection function drush_sql_get_table_selection_options() { return array( 'skip-tables-key' => 'A key in the $skip_tables array. @see example.drushrc.php. Optional.', @@ -395,58 +185,6 @@ function _drush_sql_get_raw_table_list($option_name) { return array(); } -/** - * Command callback. Executes the given SQL query on the Drupal database. - */ -function drush_sql_query($query = NULL) { - drush_sql_bootstrap_further(); - $filename = drush_get_option('file', NULL); - // Enable prefix processing when db-prefix option is used. - if (drush_get_option('db-prefix')) { - drush_bootstrap_max(DRUSH_BOOTSTRAP_DRUPAL_DATABASE); - } - if (drush_get_context('DRUSH_SIMULATE')) { - if ($query) { - drush_print(dt('Simulating sql-query: !q', array('!q' => $query))); - } - else { - drush_print(dt('Simulating sql-import from !f', array('!f' => drush_get_option('file')))); - } - } - else { - $sql = drush_sql_get_class(drush_get_option('db-spec')); - $result = $sql->query($query, $filename, drush_get_option('result-file')); - if (!$result) { - return drush_set_error('DRUSH_SQL_NO_QUERY', dt('Query failed.')); - } - drush_print(implode("\n", drush_shell_exec_output())); - } - return TRUE; -} - -/** - * Command callback. Drops all tables in the database. - */ -function drush_sql_drop() { - drush_sql_bootstrap_further(); - $sql = drush_sql_get_class(); - $db_spec = $sql->db_spec(); - if (!drush_confirm(dt('Do you really want to drop all tables in the database !db?', array('!db' => $db_spec['database'])))) { - return drush_user_abort(); - } - $tables = $sql->listTables(); - return $sql->drop($tables); -} - -/** - * Command callback. Launches console a DB backend. - */ -function drush_sql_cli() { - drush_sql_bootstrap_further(); - $sql = drush_sql_get_class(); - return !(bool)drush_shell_proc_open($sql->connect()); -} - /** * Call from a pre-sql-sync hook to register an sql * query to be executed in the post-sql-sync hook. diff --git a/includes/annotationcommand_adapter.inc b/includes/annotationcommand_adapter.inc index 1b7299ed52..be871e265d 100644 --- a/includes/annotationcommand_adapter.inc +++ b/includes/annotationcommand_adapter.inc @@ -445,8 +445,8 @@ function annotationcommand_adapter_get_commands_for_commandhandler($commandhandl if (isset($returnType)) { $command['return-type'] = $returnType; } - if ($commandinfo->getAnnotation('allow-additional-options') !== null) { - $command['allow-additional-options'] = TRUE; + if ($additional = $commandinfo->getAnnotation('allow-additional-options')) { + $command['allow-additional-options'] = _convert_csv_to_array($additional); } $command += drush_command_defaults($command_name, $commandfile, $commandfile_path); $commands[$command_name] = $command; diff --git a/lib/Drush/Commands/OptionsCommands.php b/lib/Drush/Commands/OptionsCommands.php index 1035ced178..0574f8a423 100644 --- a/lib/Drush/Commands/OptionsCommands.php +++ b/lib/Drush/Commands/OptionsCommands.php @@ -12,14 +12,35 @@ class OptionsCommands { * @option tty Create a tty (e.g. to run an interactive program). * @option escaped Command string already escaped; do not add additional quoting. */ - public function optionset_proc_build() {} + public function optionsetProcBuild() {} /** * @hook option @optionset_get_editor * @option editor A string of bash which launches user's preferred text editor. Defaults to ${VISUAL-${EDITOR-vi}}. * @option bg Run editor in the background. Does not work with editors such as `vi` that run in the terminal. */ - public function optionset_get_editor() {} + public function optionsetGetEditor() {} + + /** + * @hook option @optionset_sql + * @option database The DB connection key if using multiple connections in settings.php. + * @option db-url A Drupal 6 style database URL. + * @option target The name of a target within the specified database connection. Defaults to default + */ + public function optionsetSql() { + + } + + /** + * @hook option @optionset_table_selection + * @option skip-tables-key A key in the $skip_tables array. @see example.drushrc.php + * @option structure-tables-key A key in the $structure_tables array. @see example.drushrc.php + * @option tables-key A key in the $tables array. + * @option skip-tables-list A comma-separated list of tables to exclude completely. + * @option structure-tables-list A comma-separated list of tables to include for structure, but not data. + * @option tables-list A comma-separated list of tables to transfer. + */ + public function optionsetTableSelection($command, $annotationData) {} } diff --git a/lib/Drush/Commands/core/PhpCommands.php b/lib/Drush/Commands/core/PhpCommands.php index 47eff0b560..37fa983757 100644 --- a/lib/Drush/Commands/core/PhpCommands.php +++ b/lib/Drush/Commands/core/PhpCommands.php @@ -21,7 +21,6 @@ class PhpCommands extends DrushCommands { * @usage drush php-eval "node_access_rebuild();" * Rebuild node access permissions. * @aliases eval,ev - * @allow-additional-options * @bootstrap DRUSH_BOOTSTRAP_MAX */ public function evaluate($code, $options = ['format' => 'var_export']) { diff --git a/lib/Drush/Commands/core/SanitizeCommands.php b/lib/Drush/Commands/core/SanitizeCommands.php index 20aff2558a..566fb25573 100644 --- a/lib/Drush/Commands/core/SanitizeCommands.php +++ b/lib/Drush/Commands/core/SanitizeCommands.php @@ -27,11 +27,11 @@ protected function setWrap() { /** - * Sanitize the database by removed and obfuscating user data. + * Sanitize the database by removing or obfuscating user data. * - * @command sql-sanitize + * Commandfiles may add custom operations by implementing hook_drush_sql_sync_sanitize(). * - * @todo "drush dependencies" array('sqlsync') + * @command sql-sanitize * * @bootstrap DRUSH_BOOTSTRAP_NONE * @description Run sanitization operations on the current database. diff --git a/lib/Drush/Commands/core/SqlCommands.php b/lib/Drush/Commands/core/SqlCommands.php new file mode 100644 index 0000000000..699d92c673 --- /dev/null +++ b/lib/Drush/Commands/core/SqlCommands.php @@ -0,0 +1,201 @@ + 'yaml', 'all' => FALSE, 'show-passwords' => FALSE]) { + drush_sql_bootstrap_database_configuration(); + if ($options['all']) { + $sqlVersion = drush_sql_get_version(); + $return = $sqlVersion->getAll(); + foreach ($return as $key1 => $value) { + foreach ($value as $key2 => $spec) { + if (!$options['show-passwords']) { + unset($return[$key1][$key2]['password']); + } + } + } + } + else { + $sql = drush_sql_get_class(); + $return = $sql->db_spec(); + if (!$options['show-passwords']) { + unset($return['password']); + } + } + return $return; + } + + /** + * A string for connecting to the DB. + * + * @command sql-connect + * @option extra Add custom options to the connect string (e.g. --extra=--skip-column-names) + * @optionset_sql + * @usage `drush sql-connect` < example.sql + * Bash: Import SQL statements from a file into the current database. + * @usage eval (drush sql-connect) < example.sql + * Fish: Import SQL statements from a file into the current database. + */ + public function connect($options = ['extra' => '']) { + drush_sql_bootstrap_further(); + $sql = drush_sql_get_class(); + return $sql->connect(FALSE); + } + + /** + * Create a database. + * + * @command sql-create + * @option db-su Account to use when creating a new database. + * @option db-su-pw Password for the db-su account. + * @optionset_sql + * @usage drush sql-create + * Create the database for the current site. + * @usage drush @site.test sql-create + * Create the database as specified for @site.test. + * @usage drush sql-create --db-su=root --db-su-pw=rootpassword --db-url="mysql://drupal_db_user:drupal_db_password@127.0.0.1/drupal_db" + * Create the database as specified in the db-url option. + */ + public function create() { + drush_sql_bootstrap_further(); + $sql = drush_sql_get_class(); + $db_spec = $sql->db_spec(); + // Prompt for confirmation. + if (!drush_get_context('DRUSH_SIMULATE')) { + // @todo odd - maybe for sql-sync. + $txt_destination = (isset($db_spec['remote-host']) ? $db_spec['remote-host'] . '/' : '') . $db_spec['database']; + drush_print(dt("Creating database !target. Any possible existing database will be dropped!", array('!target' => $txt_destination))); + + if (!drush_confirm(dt('Do you really want to continue?'))) { + return drush_user_abort(); + } + } + + return $sql->createdb(TRUE); + } + + /** + * Drop all tables in a given database. + * + * @command sql-drop + * @option result-file Save to a file. Value should be relative to Drupal root. + * @optionset_sql + * @topics docs-policy + */ + public function drop() { + drush_sql_bootstrap_further(); + $sql = drush_sql_get_class(); + $db_spec = $sql->db_spec(); + if (!drush_confirm(dt('Do you really want to drop all tables in the database !db?', array('!db' => $db_spec['database'])))) { + return drush_user_abort(); + } + $tables = $sql->listTables(); + return $sql->drop($tables); + } + + /** + * Open a SQL command-line interface using Drupal's credentials. + * + * @command sql-cli + * @optionset_sql + * @allow-additional-options sql-connect + * @aliases sqlc + * @usage drush sql-cli + * Open a SQL command-line interface using Drupal's credentials. + * @usage drush sql-cli --extra=-A + * Open a SQL CLI and skip reading table information. + * @remote-tty + */ + public function cli() { + drush_sql_bootstrap_further(); + $sql = drush_sql_get_class(); + drush_shell_proc_open($sql->connect()); + } + + /** + * Execute a query against a database. + * + * @command sql-query + * @param $query An SQL query. Ignored if --file is provided. + * @optionset_sql + * @option result-file Save to a file. The file should be relative to Drupal root. + * @option file Path to a file containing the SQL to be run. Gzip files are accepted. + * @option extra Add custom options to the connect string (e.g. --extra=--skip-column-names) + * @option db-prefix Enable replacement of braces in your query. + * @option db-spec A database specification. Only used with --backend calls. + * @hidden-option db-spec + * @aliases sqlq + * @usage drush sql-query "SELECT * FROM users WHERE uid=1" + * Browse user record. Table prefixes, if used, must be added to table names by hand. + * @usage drush sql-query --db-prefix "SELECT * FROM {users} WHERE uid=1" + * Browse user record. Table prefixes are honored. Caution: curly-braces will be stripped from all portions of the query. + * @usage `drush sql-connect` < example.sql + * Import sql statements from a file into the current database. + * @usage drush sql-query --file=example.sql + * Alternate way to import sql statements from a file. + * + */ + public function query($query = '', $options = ['result-file' => NULL, 'file' => NULL, 'extra' => NULL, 'db-prefix' => NULL, 'db-spec' => NULL]) { + drush_sql_bootstrap_further(); + $filename = $options['file']; + // Enable prefix processing when db-prefix option is used. + if ($options['db-prefix']) { + drush_bootstrap_max(DRUSH_BOOTSTRAP_DRUPAL_DATABASE); + } + if (drush_get_context('DRUSH_SIMULATE')) { + if ($query) { + drush_print(dt('Simulating sql-query: !q', array('!q' => $query))); + } + else { + drush_print(dt('Simulating sql-import from !f', array('!f' => $options['file']))); + } + } + else { + $sql = drush_sql_get_class($options['db-spec']); + $result = $sql->query($query, $filename, $options['result-file']); + if (!$result) { + return drush_set_error('DRUSH_SQL_NO_QUERY', dt('Query failed.')); + } + drush_print(implode("\n", drush_shell_exec_output())); + } + return TRUE; + } + + /** + * Exports the Drupal DB as SQL using mysqldump or equivalent. + * + * @command sql-dump + * @optionset_sql + * @optionset_table_selection + * @option result-file Save to a file. The file should be relative to Drupal root. + * @option create-db Omit DROP TABLE statements. Postgres and Oracle only. Used by sql-sync, since including the DROP TABLE statements interfere with the import when the database is created. + * @option data-only Dump data without statements to create any of the schema. + * @option ordered-dump Order by primary key and add line breaks for efficient diff in revision control. Slows down the dump. Mysql only. + * @option gzip Compress the dump using the gzip program which must be in your $PATH. + * @option extra Add custom options to the dump command. + * @usage drush sql-dump --result-file=../18.sql + * Save SQL dump to the directory above Drupal root. + * @usage drush sql-dump --skip-tables-key=common + * Skip standard tables. @see example.drushrc.php + * @usage drush sql-dump --extra=--no-data + * Pass extra option to dump command. + * @hidden-option create-db + */ + public function dump($options = ['result-file' => NULL, 'create-db' => NULL, 'data-only' => NULL, 'ordered-dump' => NULL, 'gzip' => NULL, 'extra' => NULL]) { + drush_sql_bootstrap_further(); + $sql = drush_sql_get_class(); + return $sql->dump($options['result-file']); + } +} \ No newline at end of file diff --git a/tests/contextTest.php b/tests/contextTest.php index 94a8c50684..12ca5dfb13 100644 --- a/tests/contextTest.php +++ b/tests/contextTest.php @@ -166,6 +166,7 @@ function testContextHierarchy() { $config = UNISH_SANDBOX . '/drushrc.php'; $options = array( 'cli1' => NULL, + 'strict' => 0, 'config' => $config, 'root' => $this->webroot(), 'uri' => key($this->getSites()),