Yaffs site version 1.1
[yaffs-website] / vendor / drush / drush / commands / sql / sqlsync.drush.inc
1 <?php
2
3 use Drush\Log\LogLevel;
4 use Webmozart\PathUtil\Path;
5
6 /**
7  * Implementation of hook_drush_command().
8  */
9 function sqlsync_drush_command() {
10   $items['sql-sync'] = array(
11     'description' => 'Copies the database contents from a source site to a target site. Transfers the database dump via rsync.',
12     'bootstrap' => DRUSH_BOOTSTRAP_NONE,
13     'drush dependencies' => array('sql', 'core'), // core-rsync.
14     'package' => 'sql',
15     'examples' => array(
16       'drush sql-sync @source @target' => 'Copy the database from the site with the alias "source" to the site with the alias "target".',
17       'drush sql-sync prod dev' => 'Copy the database from the site in /sites/prod to the site in /sites/dev (multisite installation).',
18     ),
19     'arguments' => array(
20       'source' => 'A site-alias or the name of a subdirectory within /sites whose database you want to copy from.',
21       'target' => 'A site-alias or the name of a subdirectory within /sites whose database you want to replace.',
22     ),
23     'required-arguments' => TRUE,
24     'options' => drush_sql_get_table_selection_options() + array(
25       // 'cache' => 'Skip dump if result file exists and is less than "cache" hours old. Optional; default is 24 hours.',
26       // 'no-cache' => 'Do not cache the sql-dump file.',
27       'no-dump' => 'Do not dump the sql database; always use an existing dump file.',
28       'no-sync' => 'Do not rsync the database dump file from source to target.',
29       'runner' => 'Where to run the rsync command; defaults to the local site. Can also be "source" or "destination".',
30       'source-db-url' => 'Database specification for source system to dump from.',
31       'source-remote-port' => 'Override sql database port number in source-db-url. Optional.',
32       'source-remote-host' => 'Remote machine to run sql-dump file on. Optional; default is local machine.',
33       'source-dump' => array(
34         'description' => 'The destination for the dump file, or the path to the dump file when --no-dump is specified.',
35         'example-value' => '/dumpdir/db.sql',
36       ),
37       'source-database' => 'A key in the $db_url (D6) or $databases (D7+) array which provides the data.',
38       'source-target' => array(
39         'description' => 'A key within the SOURCE database identifying a particular server in the database group.',
40         'example-value' => 'key',
41         // Gets unhidden in help_alter(). We only want to show to D7+ users but have to
42         // declare it here since this command does not bootstrap fully.
43         'hidden' => TRUE,
44       ),
45       'target-db-url' => '',
46       'target-remote-port' => '',
47       'target-remote-host' => '',
48       'target-dump' => array(
49         'description' => 'A path for saving the dump file on target. Mandatory when using --no-sync.',
50         'example-value' => '/dumpdir/db.sql.gz',
51       ),
52       'target-database' => 'A key in the $db_url (D6) or $databases (D7+) array which shall receive the data.',
53       'target-target' => array(
54         'description' => 'Oy. A key within the TARGET database identifying a particular server in the database group.',
55         'example-value' => 'key',
56         // Gets unhidden in help_alter(). We only want to show to D7+ users but have to
57         // declare it here since this command does not bootstrap fully.
58         'hidden' => TRUE,
59       ),
60       'create-db' => 'Create a new database before importing the database dump on the target machine.',
61       'db-su' => array(
62         'description' => 'Account to use when creating a new database. Optional.',
63         'example-value' => 'root',
64       ),
65       'db-su-pw' => array(
66         'description' => 'Password for the "db-su" account. Optional.',
67         'example-value' => 'pass',
68       ),
69       // 'no-ordered-dump' => 'Do not pass --ordered-dump to sql-dump.  sql-sync orders the dumpfile by default in order to increase the efficiency of rsync.',
70       'sanitize' => 'Obscure email addresses and reset passwords in the user table post-sync.',
71     ),
72     'sub-options' => array(
73       'sanitize' => drupal_sanitize_options() + array(
74           'confirm-sanitizations' => 'Prompt yes/no after importing the database, but before running the sanitizations',
75         ),
76     ),
77     'topics' => array('docs-aliases', 'docs-policy', 'docs-example-sync-via-http', 'docs-example-sync-extension'),
78   );
79   return $items;
80 }
81
82 /**
83  * Implements hook_drush_help_alter().
84  */
85 function sqlsync_drush_help_alter(&$command) {
86   // Drupal 7+ only options.
87   if (drush_drupal_major_version() >= 7) {
88     if ($command['command'] == 'sql-sync') {
89       unset($command['options']['source-target']['hidden'], $command['options']['target-target']['hidden']);
90     }
91   }
92 }
93
94 /**
95  * Command argument complete callback.
96  *
97  * @return
98  *  Array of available site aliases.
99  */
100 function sql_sql_sync_complete() {
101   return array('values' => array_keys(_drush_sitealias_all_list()));
102 }
103
104 /*
105  * Implements COMMAND hook init.
106  */
107 function drush_sql_sync_init($source, $destination) {
108   // Try to get @self defined when --uri was not provided.
109   drush_bootstrap_max(DRUSH_BOOTSTRAP_DRUPAL_SITE);
110
111   // Preflight destination in case it defines the alias used by the source
112   _drush_sitealias_get_record($destination);
113
114   // After preflight, get source and destination settings
115   $source_settings = drush_sitealias_get_record($source);
116   $destination_settings = drush_sitealias_get_record($destination);
117
118   // Apply command-specific options.
119   drush_sitealias_command_default_options($source_settings, 'source-');
120   drush_sitealias_command_default_options($destination_settings, 'target-');
121 }
122
123 /*
124  * A command validate callback.
125  */
126 function drush_sqlsync_sql_sync_validate($source, $destination) {
127   // Get destination info for confirmation prompt.
128   $source_settings = drush_sitealias_overlay_options(drush_sitealias_get_record($source), 'source-');
129   $destination_settings = drush_sitealias_overlay_options(drush_sitealias_get_record($destination), 'target-');
130   $source_db_spec = drush_sitealias_get_db_spec($source_settings, FALSE, 'source-');
131   $target_db_spec = drush_sitealias_get_db_spec($destination_settings, FALSE, 'target-');
132   $txt_source = (isset($source_db_spec['remote-host']) ? $source_db_spec['remote-host'] . '/' : '') . $source_db_spec['database'];
133   $txt_destination = (isset($target_db_spec['remote-host']) ? $target_db_spec['remote-host'] . '/' : '') . $target_db_spec['database'];
134
135   // Validate.
136   if (empty($source_db_spec)) {
137     if (empty($source_settings)) {
138       return drush_set_error('DRUSH_ALIAS_NOT_FOUND', dt('Error: no alias record could be found for source !source', array('!source' => $source)));
139     }
140     return drush_set_error('DRUSH_DATABASE_NOT_FOUND', dt('Error: no database record could be found for source !source', array('!source' => $source)));
141   }
142   if (empty($target_db_spec)) {
143     if (empty($destination_settings)) {
144       return drush_set_error('DRUSH_ALIAS_NOT_FOUND', dt('Error: no alias record could be found for target !destination', array('!destination' => $destination)));
145     }
146     return drush_set_error('DRUSH_DATABASE_NOT_FOUND', dt('Error: no database record could be found for target !destination', array('!destination' => $destination)));
147   }
148
149   if (drush_get_option('no-dump') && !drush_get_option('source-dump')) {
150     return drush_set_error('DRUSH_SOURCE_DUMP_MISSING', dt('The --source-dump option must be supplied when --no-dump is specified.'));
151   }
152
153   if (drush_get_option('no-sync') && !drush_get_option('target-dump')) {
154     return drush_set_error('DRUSH_TARGET_DUMP_MISSING', dt('The --target-dump option must be supplied when --no-sync is specified.'));
155   }
156
157   if (!drush_get_context('DRUSH_SIMULATE')) {
158     drush_print(dt("You will destroy data in !target and replace with data from !source.", array('!source' => $txt_source, '!target' => $txt_destination)));
159     // @todo Move sanitization prompts to here. They currently show much later.
160     if (!drush_confirm(dt('Do you really want to continue?'))) {
161       return drush_user_abort();
162     }
163   }
164 }
165
166 /*
167  * A command callback.
168  */
169 function drush_sqlsync_sql_sync($source, $destination) {
170   $source_settings = drush_sitealias_overlay_options(drush_sitealias_get_record($source), 'source-');
171   $destination_settings = drush_sitealias_overlay_options(drush_sitealias_get_record($destination), 'target-');
172   $source_is_local = !array_key_exists('remote-host', $source_settings) || drush_is_local_host($source_settings);
173   $destination_is_local = !array_key_exists('remote-host', $destination_settings) || drush_is_local_host($destination_settings);
174
175   // These options are passed along to subcommands like sql-create, sql-dump, sql-query, sql-sanitize, ...
176   $source_options = drush_get_merged_prefixed_options('source-');
177   $target_options = drush_get_merged_prefixed_options('target-');
178
179   $backend_options = array();
180   // @todo drush_redispatch_get_options() assumes you will execute same command. Not good.
181   $global_options = drush_redispatch_get_options() + array(
182      'strict' => 0,
183   );
184   // We do not want to include root or uri here.  If the user
185   // provided -r or -l, their key has already been remapped to
186   // 'root' or 'uri' by the time we get here.
187   unset($global_options['root']);
188   unset($global_options['uri']);
189
190   if (drush_get_context('DRUSH_SIMULATE')) {
191     $backend_options['backend-simulate'] = TRUE;
192   }
193
194   // Create destination DB if needed.
195   if (drush_get_option('create-db')) {
196     drush_log(dt('Starting to create database on Destination.'), LogLevel::OK);
197     $return = drush_invoke_process($destination, 'sql-create', array(), $global_options + $target_options, $backend_options);
198     if ($return['error_status']) {
199       return drush_set_error('DRUSH_SQL_CREATE_FAILED', dt('sql-create failed.'));
200     }
201   }
202
203   // Perform sql-dump on source unless told otherwise.
204   $options = $global_options + $source_options + array(
205     'gzip' => TRUE,
206     'result-file' => drush_get_option('source-dump', TRUE),
207     // 'structure-tables-list' => 'cache*', // Do we want to default to this?
208   );
209   if (!drush_get_option('no-dump')) {
210     drush_log(dt('Starting to dump database on Source.'), LogLevel::OK);
211     $return = drush_invoke_process($source, 'sql-dump', array(), $options, $backend_options);
212     if ($return['error_status']) {
213       return drush_set_error('DRUSH_SQL_DUMP_FAILED', dt('sql-dump failed.'));
214     }
215     else {
216       $source_dump_path = $return['object'];
217       if (!is_string($source_dump_path)) {
218         return drush_set_error('DRUSH_SQL_DUMP_FILE_NOT_REPORTED', dt('The Drush sql-dump command did not report the path to the dump file produced.  Try upgrading the version of Drush you are using on the source machine.'));
219       }
220     }
221   }
222   else {
223     $source_dump_path = drush_get_option('source-dump');
224   }
225
226   $do_rsync = !drush_get_option('no-sync');
227   // Determine path/to/dump on destination.
228   if (drush_get_option('target-dump')) {
229     $destination_dump_path = drush_get_option('target-dump');
230     $rsync_options['yes'] = TRUE;  // @temporary: See https://github.com/drush-ops/drush/pull/555
231   }
232   elseif ($source_is_local && $destination_is_local) {
233     $destination_dump_path = $source_dump_path;
234     $do_rsync = FALSE;
235   }
236   else {
237     $tmp = '/tmp'; // Our fallback plan.
238     drush_log(dt('Starting to discover temporary files directory on Destination.'), LogLevel::OK);
239     $return = drush_invoke_process($destination, 'core-status', array(), array(), array('integrate' => FALSE, 'override-simulated' => TRUE));
240     if (!$return['error_status'] && isset($return['object']['drush-temp'])) {
241       $tmp = $return['object']['drush-temp'];
242     }
243     $destination_dump_path = Path::join($tmp, basename($source_dump_path));
244     $rsync_options['yes'] = TRUE;  // No need to prompt as destination is a tmp file.
245   }
246
247   if ($do_rsync) {
248     if (!drush_get_option('no-dump')) {
249       // Cleanup if this command created the dump file.
250       $rsync_options['remove-source-files'] = TRUE;
251     }
252     $runner = drush_get_runner($source_settings, $destination_settings, drush_get_option('runner', FALSE));
253     // Since core-rsync is a strict-handling command and drush_invoke_process() puts options at end, we can't send along cli options to rsync.
254     // Alternatively, add options like --ssh-options to a site alias (usually on the machine that initiates the sql-sync).
255     $return = drush_invoke_process($runner, 'core-rsync', array("$source:$source_dump_path", "$destination:$destination_dump_path"), $rsync_options);
256     drush_log(dt('Copying dump file from Source to Destination.'), LogLevel::OK);
257     if ($return['error_status']) {
258       return drush_set_error('DRUSH_RSYNC_FAILED', dt('core-rsync failed.'));
259     }
260   }
261
262   // Import file into destination.
263   drush_log(dt('Starting to import dump file onto Destination database.'), LogLevel::OK);
264   $options = $global_options + $target_options + array(
265     'file' => $destination_dump_path,
266     'file-delete' => TRUE,
267   );
268   $return = drush_invoke_process($destination, 'sql-query', array(), $options, $backend_options);
269   if ($return['error_status']) {
270     // An error was already logged.
271     return FALSE;
272   }
273
274   // Run Sanitize if needed.
275   $options = $global_options + $target_options;
276   if (drush_get_option('sanitize')) {
277     drush_log(dt('Starting to sanitize target database on Destination.'), LogLevel::OK);
278     $return = drush_invoke_process($destination, 'sql-sanitize', array(), $options, $backend_options);
279     if ($return['error_status']) {
280       return drush_set_error('DRUSH_SQL_SANITIZE_FAILED', dt('sql-sanitize failed.'));
281     }
282   }
283 }