/[drupal]/contributions/modules/drush/includes/sitealias.inc
ViewVC logotype

Contents of /contributions/modules/drush/includes/sitealias.inc

Parent Directory Parent Directory | Revision Log Revision Log | View Revision Graph Revision Graph


Revision 1.4 - (show annotations) (download) (as text)
Wed Nov 4 22:29:52 2009 UTC (3 weeks, 2 days ago) by weitzman
Branch: MAIN
Changes since 1.3: +8 -5 lines
File MIME type: text/x-php
#460924 by greg.1.anderson. remote aliases bug fix - backend_invoke(), small refactor.
1 <?php
2 // $Id: sitealias.inc,v 1.3 2009/10/28 11:57:56 weitzman Exp $
3
4 /**
5 * Check to see if the first command-line arg or the
6 * -l option is a site alias; if it is, copy its record
7 * values to the 'alias' context.
8 *
9 * @return boolean
10 * TRUE if a site alias was found and processed.
11 */
12 function drush_sitealias_check_arg() {
13 $args = drush_get_arguments();
14
15 // Test to see if the first arg is a site specification
16 if (_drush_sitealias_set_context_by_name($args[0])) {
17 array_shift($args);
18 // We only need to expand the site specification
19 // once, then we are done.
20 drush_set_arguments($args);
21 return TRUE;
22 }
23
24 // Return false to indicate that no site alias was specified.
25 return FALSE;
26 }
27
28 /**
29 * Get a site alias record given an alias name or site specification.
30 *
31 * If it is the name of a site alias, return the alias record from
32 * the site aliases array.
33 *
34 * If it is the name of a folder in the 'sites' folder, construct
35 * an alias record from values stored in settings.php.
36 *
37 * If it is a site specification, construct an alias record from the
38 * values in the specification.
39 *
40 * Site specifications come in several forms:
41 *
42 * 1.) /path/to/drupal#sitename
43 * 2.) user@server/path/to/drupal#sitename
44 * 3.) user@server/path/to/drupal (sitename == server)
45 * 4.) user@server#sitename (only if $option['r'] set in some drushrc file on server)
46 * 5.) #sitename (only if $option['r'] already set, and 'sitename' is a folder in $option['r']/sites)
47 * 6.) sitename (only if $option['r'] already set, and 'sitename' is a folder in $option['r']/sites)
48 *
49 * Note that in the case of the first four forms, it is also possible
50 * to add additional site variable to the specification using uri query
51 * syntax. For example:
52 *
53 * user@server/path/to/drupal?db-url=...#sitename
54 *
55 * @param alias
56 * An alias name or site specification
57 * @param db_settings_needed
58 * 'true' if the caller needs the 'databases' record. We
59 * Will look it up the first time it is requested.
60 * @return array
61 * An alias record.
62 */
63 function drush_sitealias_get_record($alias, $db_settings_needed = false) {
64 // Sometimes getting an alias record involves loading settings.php or calling
65 // backend invoke. We'll cache all alias records fetched by this routine to
66 // insure that we never have to do anything like that twice.
67 $alias_record = drush_get_option('sitealias-' . $alias, array(), 'sitealias-cache');
68 if (empty($alias_record)) {
69 // Check to see if the provided parameter is in fact a defined alias.
70 $all_site_aliases = drush_get_option('site-aliases', array());
71 if (array_key_exists($alias, $all_site_aliases)) {
72 $alias_record = $all_site_aliases[$alias];
73 // If the alias record does not have a defined 'databases' entry,
74 // then we'll need to look one up
75 if ($db_settings_needed && !isset($alias_record['db-url']) && !isset($alias_record['databases'])) {
76 // Check to see if we've cached the databases record from a previous invocation of this function
77 $alias_record['databases'] = drush_get_option('databases-' . $alias, NULL, 'sitealias-cache');
78 if (!isset($alias_record['databases'])) {
79 // If the alias record is remote, then we'll use backend_invoke to fetch the
80 // database settings from the remote machine
81 if (array_key_exists('remote-host', $alias_record)) {
82 $data = array('root' => $alias_record['path-aliases']['!root'], 'uri' => $alias_record['uri'], 'all' => TRUE);
83 $args = array();
84 $values = drush_backend_invoke_args("sql conf", $args, $data, 'GET', FALSE, $alias_record['path-aliases']['!drush-script'], $alias_record['remote-host'], $alias_record['remote-user']);
85 $alias_record['databases'] = $values['object'];
86 }
87 // If the alias record is for a local machine, then look up and
88 // use the database settings from the appropriate settings.php file.
89 else {
90 $alias_record = array_merge(_drush_sitealias_build_record_from_settings($alias), $alias_record);
91 }
92 // Cache our result so we don't need to do IPC for successive calls to this function
93 drush_set_option('databases-' . $alias, $alias_record['databases'], 'sitealias-cache');
94 }
95 }
96 }
97 // If the parameter is not an alias, then it is some form of
98 // site specification (or it is nothing at all)
99 elseif (isset($alias)) {
100 // Cases 1.) - 4.):
101 // We will check for a site specification if the alias has at least
102 // two characters from the set '@', '/', '#'.
103 if ((strpos($alias, '@') === FALSE ? 0 : 1) + (strpos($alias, '/') === FALSE ? 0 : 1) + (strpos($alias, '#') === FALSE ? 0 : 1) >= 2) {
104 if ((substr($alias,0,7) != 'http://') && (substr($alias,0,1) != '/')) {
105 // Add on a scheme so that "user:pass@server" will always parse correctly
106 $parsed = parse_url('http://' . $alias);
107 }
108 else {
109 $parsed = parse_url($alias);
110 }
111 // Copy various parts of the parsed URL into the appropriate records of the alias record
112 foreach (array('user' => 'remote-user', 'pass' => 'remote-pass', 'host' => 'remote-host', 'fragment' => 'uri', 'path' => '!root') as $url_key => $option_key) {
113 if (array_key_exists($url_key, $parsed)) {
114 _drush_sitealias_set_record_element($alias_record, $option_key, $parsed[$url_key]);
115 }
116 }
117 // If the site specification has a query, also set the query items
118 // in the alias record. This allows passing db_url as part of the
119 // site specification, for example.
120 foreach (explode('&', $parsed['query']) as $query_arg) {
121 $query_components = explode('=', $query_arg);
122 _drush_sitealias_set_record_element($alias_record, urldecode($query_components[0]), urldecode($query_components[1]));
123 }
124
125 // Case 3.): If the URL contains a 'host' portion but no fragment, then set the uri to the host
126 // Note: We presume that 'server' is the best default for case 3; without this code, the default would
127 // be whatever is set in $options['l'] on the target machine's drushrc.php settings file.
128 if (array_key_exists('host', $parsed) && !array_key_exists('fragment', $parsed)) {
129 $alias_record['uri'] = $parsed['host'];
130 }
131 }
132 else {
133 // Case 5.) and 6.):
134 // If the alias is the name of a folder in the 'sites' directory,
135 // then use it as a local site specification.
136 $alias_record = _drush_sitealias_find_record_for_local_site($alias, $db_settings_needed);
137 }
138 }
139 _drush_sitealias_add_static_defaults($alias_record);
140 // Fail fast if database settings are not available and the caller
141 // said that they are required
142 if ($db_settings_needed && !isset($alias_record['databases'])) {
143 drush_print("Error: could not get database spec when it was required for " . $alias);
144 exit(1);
145 }
146 drush_set_option('sitealias-' . $alias, $alias_record, 'sitealias-cache');
147 }
148 return $alias_record;
149 }
150
151 /**
152 * Add "static" default values to the given alias record. The
153 * difference between a static default and a transient default is
154 * that static defaults -always- exist in the alias record, and
155 * they are cached, whereas transient defaults are only added
156 * if the given drush command explicitly adds them.
157 *
158 * @param alias_record
159 * An alias record with most values already filled in
160 */
161 function _drush_sitealias_add_static_defaults(&$alias_record) {
162 // If there is a 'db-url' entry but not 'databases' entry, then we will
163 // build 'databases' from 'db-url' so that drush commands that use aliases
164 // can always count on using a uniform 'databases' array.
165 if (isset($alias_record['db-url']) && !isset($alias_record['databases'])) {
166 $alias_record['databases'] = array('default' => array('default' => drush_convert_db_from_db_url($alias_record['db-url'])));
167 }
168 }
169
170 /**
171 * Add "transient" default values to the given alias record. The
172 * difference between a static default and a transient default is
173 * that static defaults -always- exist in the alias record,
174 * whereas transient defaults are only added if the given drush
175 * command explicitly calls this function. The other advantage
176 * of transient defaults is that it is possible to differentiate
177 * between a default value and an unspecified value, since the
178 * transient defaults are not added until requested.
179 *
180 * Since transient defaults are not cached, you should avoid doing
181 * expensive operations here. To be safe, drush commands should
182 * avoid calling this function more than once.
183 *
184 * @param alias_record
185 * An alias record with most values already filled in
186 */
187 function _drush_sitealias_add_transient_defaults(&$alias_record) {
188 if (isset($alias_record['path-aliases'])) {
189 if (!array_key_exists('!drush', $alias_record['path-aliases'])) {
190 if (array_key_exists('!drush-script', $alias_record['path-aliases'])) {
191 $alias_record['path-aliases']['!drush'] = dirname($alias_record['path-aliases']['!drush-script']);
192 }
193 else {
194 $alias_record['path-aliases']['!drush'] = dirname(DRUSH_COMMAND);
195 }
196 }
197 }
198 }
199
200 /**
201 * Find a record in the site aliases list for a local site with
202 * the requested uri, if one exists. Otherwise, build one from
203 * the settings.php file for the specified site.
204 */
205 function _drush_sitealias_find_record_for_local_site($alias, $db_settings_needed = false) {
206 $alias_record = array();
207
208 // Clip off the leading '#' if it is there
209 if (substr($alias,0,1) == '#') {
210 $alias = substr($alias,1);
211 }
212
213 // This function may be called during the drush bootstrap
214 // (i.e., from drush_sitealias_check_arg()), when 'DRUSH_DRUPAL_ROOT'
215 // has not been set. It may also be called after bootstraping
216 // has finished (e.g. to process an argument from sync or sql sync)
217 // when it would be wasteful to call drush_locate_root again.
218 // If we find an alias or site specification during drush_sitealias_check_arg(),
219 // then we will set the 'root' option. If we do not, though,
220 // we will end up calling drush_locate_root every time this
221 // function is called.
222 // TODO: Would it be valid to use some other mechanism to test
223 // to see if the drupal root has already been cached? Maybe
224 // drush should just drush_set_option('root', $drupal_root) rather
225 // than setting a context and a bootstrap value?
226 //$drupal_root = drush_get_context('DRUSH_DRUPAL_ROOT');
227 //$drupal_root = drush_bootstrap_value('drupal_root');
228 $drupal_root = drush_get_option(array('r', 'root'), drush_locate_root());
229
230 $all_site_aliases = drush_get_option('site-aliases', array());
231 foreach ($all_site_aliases as $one_alias_name => $one_alias_record) {
232 if (!isset($one_alias_record['remote-host']) && isset($one_alias_record['path-aliases']) && isset($one_alias_record['path-aliases']['!root']) && ($one_alias_record['uri'] == $alias) && ($one_alias_record['path-aliases']['!root'] == $drupal_root)) {
233 $alias_record = $one_alias_record;
234 }
235 }
236
237 if (empty($alias_record) || ($db_settings_needed && !isset($alias_record['db-url']) && !isset($alias_record['databases']) )) {
238 $alias_record = array_merge(_drush_sitealias_build_record_from_settings($alias, $drupal_root), $alias_record);
239 }
240
241 return $alias_record;
242 }
243
244 /**
245 * Use the information from a particular settings.php file
246 * to build an alias record.
247 *
248 * @param alias
249 * The name of the site in the 'sites' folder to convert
250 * @return array
251 * An alias record.
252 */
253 function _drush_sitealias_build_record_from_settings($alias, $drupal_root = null) {
254 $alias_record = array();
255
256 // Clip off the leading '#' if it is there
257 if (substr($alias,0,1) == '#') {
258 $alias = substr($alias,1);
259 }
260
261 if (!isset($drupal_root)) {
262 //$drupal_root = drush_get_context('DRUSH_DRUPAL_ROOT');
263 $drupal_root = drush_get_option(array('r', 'root'), drush_locate_root());
264 }
265
266 // If we did not find an alias record that matches,
267 // then build one.
268 if (empty($alias_record)) {
269 $site_settings_file = $drupal_root . '/sites/' . $alias . '/settings.php';
270 if (isset($drupal_root) && file_exists($site_settings_file)) {
271 $alias_record['uri'] = $alias;
272 global $databases, $db_url;
273 require $site_settings_file;
274 if (isset($db_url)) {
275 $alias_record['db-url'] = $db_url;
276 }
277 else {
278 $alias_record['databases'] = $databases;
279 }
280 $alias_record['path-aliases'] = array(
281 '!root' => $drupal_root,
282 /*'!files' => '/path/to/file/storage', */
283 /*'!dump' => '/path/to/sql/dumpfile', */ );
284 }
285 }
286 return $alias_record;
287 }
288
289 /**
290 * Convert from an old-style database URL to an array of database settings
291 *
292 * @param db_url
293 * A Drupal 6 db-url string to convert.
294 * @return array
295 * An array of database values.
296 */
297 function drush_convert_db_from_db_url($db_url) {
298 $url = parse_url($db_url);
299 // Fill in defaults to prevent notices.
300 $url += array(
301 'driver' => NULL,
302 'user' => NULL,
303 'pass' => NULL,
304 'port' => NULL,
305 'database' => NULL,
306 );
307 $url = (object)$url;
308 return array(
309 'driver' => $url->scheme == 'mysqli' ? 'mysql' : $url->scheme,
310 'username' => urldecode($url->user),
311 'password' => urldecode($url->pass),
312 'port' => urldecode($url->port),
313 'host' => urldecode($url->host),
314 'database' => substr(urldecode($url->path), 1), // skip leading '/' character
315 );
316 }
317
318 /**
319 * Utility function used by drush_get_alias; keys that start with
320 * '!' are path aliases, the rest are entries in the alias record.
321 */
322 function _drush_sitealias_set_record_element(&$alias_record, $key, $value) {
323 if (substr($key,0,1) == '!') {
324 $alias_record['path-aliases'][$key] = $value;
325 }
326 elseif (!empty($key)) {
327 $alias_record[$key] = $value;
328 }
329 }
330
331 /**
332 * Looks up the specified alias record and calls through to
333 * drush_sitealias_set_alias_context, below.
334 *
335 * @param alias
336 * The name of the alias record
337 * @param prefix
338 * The prefix value to afix to the beginning of every
339 * key set.
340 * @return boolean
341 * TRUE is an alias was found and processed.
342 */
343 function _drush_sitealias_set_context_by_name($alias, $prefix = '') {
344 $site_alias_settings = drush_sitealias_get_record($alias);
345 if (!empty($site_alias_settings)) {
346 drush_sitealias_set_alias_context($site_alias_settings, $prefix);
347 return TRUE;
348 }
349 return FALSE;
350 }
351
352 /**
353 * Given a site alias record, copy selected fields from it
354 * into the drush 'alias' context. The 'alias' context has
355 * lower precedence than the 'options' context, so values
356 * set by an alias record can be overridden by command-line
357 * parameters.
358 *
359 * @param site_alias_settings
360 * An alias record
361 * @param prefix
362 * The prefix value to afix to the beginning of every
363 * key set. For example, if this function is called once with
364 * 'source-' and again with 'destination-' prefixes, then the
365 * source database records will be stored in 'source-databases',
366 * and the destination database records will be in
367 * 'destination-databases'.
368 */
369 function drush_sitealias_set_alias_context($site_alias_settings, $prefix) {
370 // Transfer all non-array options from the site alias to the drush options
371 // in the 'alias' context.
372 foreach ($site_alias_settings as $key => $value) {
373 if (!is_array($value) || ($key == "databases")) {
374 drush_set_option($prefix . $key, $value, 'alias');
375 }
376 }
377 // Transfer selected path aliases to the drush options.
378 if (array_key_exists('path-aliases', $site_alias_settings)) {
379 foreach (array('!root', '!drush', '!drush-script', '!dump', '!include') as $key) {
380 if (array_key_exists($key, $site_alias_settings['path-aliases'])) {
381 drush_set_option($prefix . substr($key, 1), $site_alias_settings['path-aliases'][$key], 'alias');
382 }
383 }
384 }
385 // If there are prefix-specific options (e.g. 'source-options' or 'target-options'),
386 // then transfer those values as well.
387 drush_sitealias_apply_special_alias_record_options($site_alias_settings, $prefix);
388 }
389
390 /**
391 * Looks up the specified alias record and then calls through
392 * to drush_sitealias_apply_special_alias_record_options, below.
393 *
394 * @param alias
395 * The name of the alias record.
396 * @param prefix
397 * The prefix value to afix to the beginning of every
398 * key set.
399 */
400 function drush_sitealias_apply_special_alias_options($alias, $prefix) {
401 if ($prefix != '') {
402 $site_alias_settings = drush_sitealias_get_record($alias);
403 if (!empty($site_alias_settings)) {
404 drush_sitealias_apply_special_alias_record_options($site_alias_settings, $prefix);
405 }
406 }
407 }
408
409 /**
410 * Site alias records can have special options sections,
411 * one for every kind of prefix used with 'drush_sitealias_set_alias_context.
412 * The options stored in this record are copied to the 'alias'
413 * context whenever that prefix is used.
414 *
415 * @param site_alias_settings
416 * The alias record.
417 * @param prefix
418 * The prefix value to afix to the beginning of every
419 * key set.
420 */
421 function drush_sitealias_apply_special_alias_record_options($site_alias_settings, $prefix) {
422 if ($prefix != '') {
423 if ((array_key_exists($prefix . 'options', $site_alias_settings))) {
424 foreach ($site_alias_settings[$prefix . 'options'] as $key => $value) {
425 drush_set_option($key, $value, 'alias');
426 }
427 }
428 }
429 }

  ViewVC Help
Powered by ViewVC 1.1.2