sitealias.inc

  1. 8.0.x includes/sitealias.inc
  2. 6.x includes/sitealias.inc
  3. 7.x includes/sitealias.inc
  4. 3.x includes/sitealias.inc
  5. 4.x includes/sitealias.inc
  6. 5.x includes/sitealias.inc
  7. master includes/sitealias.inc

The site alias API.

Run commands on remote server(s).

See also

example.aliases.drushrc.php

http://drupal.org/node/670460

Functions

Namesort descending Description
drush_convert_db_from_db_url Convert from an old-style database URL to an array of database settings.
drush_get_runner Decide on which side to run a core-rsync.
drush_get_special_keys Helper function to obtain the keys' names that need special handling in certain cases.
drush_sitealias_add_db_settings If the alias record does not contain a 'databases' or 'db-url' entry, then use backend invoke to look up the settings value from the remote or local site. The 'databases' form is preferred; 'db_url' will be…
drush_sitealias_add_db_url If the alias record does not contain a 'databases' or 'db-url' entry, then use backend invoke to look up the settings value from the remote or local site. The 'db_url' form is preferred; nothing is done if…
drush_sitealias_add_to_alias_path Add a path to the array of paths where alias files are searched for.
drush_sitealias_alias_base_directory If there is a directory 'site-aliases' in the specified search location, then search ONLY in that directory for aliases. Otherwise, search anywhere inside the specified directory for aliases.
drush_sitealias_alias_path Return the array of paths where alias files are searched for.
drush_sitealias_alias_record_to_spec Convert from an alias record to a site specification
drush_sitealias_bootstrapped_site_name Get the name of the current bootstrapped site
drush_sitealias_build_record_from_settings_file
drush_sitealias_cache_alias_by_path Cache the specified alias in the alias path cache. The alias path cache creates a lookup from the site folder (/path/to/drupal/sites/default) to the provided alias record.
drush_sitealias_cache_db_settings
drush_sitealias_check_arg Check to see if the first command-line arg or the -l option is a site alias; if it is, copy its record values to the 'alias' context.
drush_sitealias_check_arg_and_site_set Check to see if the user specified an alias in an arguement, or via site-set. If so, return the name of the alias.
drush_sitealias_check_site_env
drush_sitealias_convert_databases_to_db_url Create a db-url from the databases record.
drush_sitealias_convert_db_from_db_url Convert from an old-style database URL to an array of database settings
drush_sitealias_convert_db_spec_to_db_url Drush still accepts --db-url format database specifications as cli parameters; it is therefore useful to be able to convert from a database record back to a db-url sometimes.
drush_sitealias_create_self_alias Check to see if a '@self' record was created during bootstrap. If not, make one now.
drush_sitealias_create_sites_alias
drush_sitealias_evaluate_path Evaluate a path from its shorthand form to a literal path usable by rsync.
drush_sitealias_evaluate_paths_in_options Given a properly-escaped options string, replace any occurance of %files and so on embedded inside it with its corresponding path.
drush_sitealias_get_db_spec Return the $db_spec record for the database associated with the provided alias record. which will be used to first add the database information to the alias records, invoking sql-conf to look them up if necessary.
drush_sitealias_get_envar_filename Returns the filename for the file that stores the DRUPAL_SITE variable.
drush_sitealias_get_path_option First return an option set via drush_sitealias_overlay_options, if any, then fall back on "%" . $option from the path aliases.
drush_sitealias_get_record Get a site alias record given an alias name or site specification.
drush_sitealias_get_root Return the site root, if there is one in the record.
drush_sitealias_is_bootstrapped_site Check to see if we have already bootstrapped to a site.
drush_sitealias_is_remote_site Determines whether a given site alias is for a remote site.
drush_sitealias_load_all Load every alias file that can be found anywhere in the alias search path.
drush_sitealias_local_site_path Return the full path to the site directory of the given alias record.
drush_sitealias_lookup_alias_by_path Look for a defined alias that points to the specified site directory. The cache is tested first; if nothing is cached, then an exhaustive search is done for the specified site. If the exhaustive search returns a match, then it is cached.
drush_sitealias_overlay_options Given an alias record, overwrite its values with options from the command line and other drush contexts as specified by the provided prefix. For example, if the prefix is 'source-', then any option 'source-foo' will set the value…
drush_sitealias_quick_lookup_cached_alias_by_path Look for a cached alias that points to the specified site directory. Nothing is returned if there is no matching cached alias.
drush_sitealias_resolve_path_references If there are any path aliases (items beginning with "%") in the test string, then resolve them as path aliases and add them to the provided alias record.
drush_sitealias_resolve_sitelist Given an alias record that is a site list (contains a 'site-list' entry), resolve all of the members of the site list and return them is an array of alias records.
drush_sitealias_resolve_sitespecs Given an array of site specifications, resolve each one in turn and return an array of alias records. If you only want a single record, it is preferable to simply call drush_sitealias_get_record() directly.
drush_sitealias_set_alias_context Given a site alias record, copy selected fields from it into the drush 'alias' context. The 'alias' context has lower precedence than the 'cli' context, so values set by an alias record can be overridden by…
drush_sitealias_simplify_names Given a list of alias records, shorten the name used if possible
drush_sitealias_site_clear Un-set the currently use'd site alias.
drush_sitealias_site_dir_from_filename Pull the site directory from the path to settings.php
drush_sitealias_site_get Read the tmp file where the persistent site setting is stored.
drush_sitealias_site_selection_keys Option keys used for site selection.
drush_sitealias_uri_to_site_dir Convert from a URI to a site directory.
drush_sitealias_valid_alias_format Returns TRUE if $alias is a valid format for an alias name.
sitealias_find_local_drupal_root
sitealias_get_databases_from_record Return the databases record from the alias record
_drush_find_local_sites_at_root Return a list of all of the local sites at the specified drupal root.
_drush_find_local_sites_in_sites_folder Return a list of all of the local sites at the specified 'sites' folder.
_drush_sitealias_add_inherited_values Check to see if there is a 'parent' item in the alias; if there is, then load the parent alias record and overlay the entries in the current alias record on top of the items from the parent record.
_drush_sitealias_add_inherited_values_to_record
_drush_sitealias_add_static_defaults Add "static" default values to the given alias record. The difference between a static default and a transient default is that static defaults -always- exist in the alias record, and they are cached, whereas transient defaults are only…
_drush_sitealias_add_transient_defaults Add "transient" default values to the given alias record. The difference between a static default and a transient default is that static defaults -always- exist in the alias record, whereas transient defaults are only added if the given…
_drush_sitealias_cache_alias Add an empty record for the specified alias name
_drush_sitealias_derive_record
_drush_sitealias_find_alias_files Function to find all alias files that might contain aliases that match the requested alias name.
_drush_sitealias_find_and_load_alias Traverses the alias search path and finds the specified alias record.
_drush_sitealias_find_and_load_alias_from_file
_drush_sitealias_find_and_load_all_aliases Worker function called by _drush_sitealias_load_alias and drush_sitealias_load_all. Traverses the alias search path and finds the specified alias record.
_drush_sitealias_find_local_alias_name Find the name of a local alias record that has the specified root and uri.
_drush_sitealias_find_local_sites Search for drupal installations in the search path.
_drush_sitealias_find_record_for_local_site If '$alias' is the name of a folder in the sites folder of the given drupal root, then build an alias record for it
_drush_sitealias_get_record This is a continuation of drush_sitealias_get_record, above. It is not intended to be called directly.
_drush_sitealias_initialize_alias_record Initialize an alias record; called as soon as the alias record is loaded from its alias file, before it is stored in the cache.
_drush_sitealias_load_alias Check and see if an alias definition for $alias is available. If it is, load it into the list of aliases cached in the 'site-aliases' context.
_drush_sitealias_preflight_path Call prior to drush_sitealias_evaluate_path to insure that any site-specific aliases associated with any local site in $path are defined.
_drush_sitealias_set_context_by_name Looks up the specified alias record and calls through to drush_sitealias_set_alias_context, below.
_drush_sitealias_set_record_element Utility function used by drush_get_alias; keys that start with '%' or '!' are path aliases, the rest are entries in the alias record.
_drush_sitelist_check_site_records
_drush_sitelist_find_in_list
_sitealias_array_merge Merges two site aliases.

File

includes/sitealias.inc
View source
  1. <?php
  2. /**
  3. * @file
  4. * The site alias API.
  5. *
  6. * Run commands on remote server(s).
  7. * @see example.aliases.drushrc.php
  8. * @see http://drupal.org/node/670460
  9. */
  10. use Drush\Log\LogLevel;
  11. use Webmozart\PathUtil\Path;
  12. /**
  13. * Check to see if the user specified an alias
  14. * in an arguement, or via site-set. If so, return
  15. * the name of the alias.
  16. *
  17. * If the alias came from args, then remove it
  18. * from args.
  19. */
  20. function drush_sitealias_check_arg_and_site_set() {
  21. $args = drush_get_arguments();
  22. $target_alias = FALSE;
  23. // Test to see if the first arg is a valid alias identifier.
  24. // If the first arguement is a well-formed identifier, but we
  25. // cannot find a record for it, then we will fail with an error.
  26. if (!empty($args) && drush_sitealias_valid_alias_format($args[0])) {
  27. // Pop the alias off the arguments list first thing.
  28. $target_alias = array_shift($args);
  29. drush_set_arguments($args);
  30. }
  31. else {
  32. // If the user did not specify an alias via an argument,
  33. // check to see if a site env was set.
  34. $target_alias = drush_sitealias_site_get();
  35. }
  36. // Record the user's desired target alias name
  37. if ($target_alias) {
  38. drush_set_context('DRUSH_TARGET_SITE_ALIAS', $target_alias);
  39. }
  40. return $target_alias;
  41. }
  42. /**
  43. * Check to see if the first command-line arg or the
  44. * -l option is a site alias; if it is, copy its record
  45. * values to the 'alias' context.
  46. *
  47. * @return boolean
  48. * TRUE if a site alias was found and processed.
  49. */
  50. function drush_sitealias_check_arg() {
  51. $args = drush_get_arguments();
  52. // Test to see if the first arg is a site specification
  53. if (!empty($args) && _drush_sitealias_set_context_by_name($args[0])) {
  54. drush_set_context('DRUSH_TARGET_SITE_ALIAS', $args[0]);
  55. array_shift($args);
  56. // We only need to expand the site specification
  57. // once, then we are done.
  58. drush_set_arguments($args);
  59. return TRUE;
  60. }
  61. // Return false to indicate that no site alias was specified.
  62. return FALSE;
  63. }
  64. /*
  65. * Check to see if user has selected a site via site-set command.
  66. */
  67. function drush_sitealias_check_site_env() {
  68. $site = drush_get_context('DRUSH_TARGET_SITE_ALIAS');
  69. if (empty($site)) {
  70. $site_env = drush_sitealias_site_get();
  71. if (!empty($site_env) && (_drush_sitealias_set_context_by_name($site_env))) {
  72. drush_set_context('DRUSH_TARGET_SITE_ALIAS', $site_env);
  73. return TRUE;
  74. }
  75. }
  76. // Return false to indicate that no site alias was specified.
  77. return FALSE;
  78. }
  79. /**
  80. * Check to see if a '@self' record was created during bootstrap.
  81. * If not, make one now.
  82. */
  83. function drush_sitealias_create_self_alias() {
  84. $self_record = drush_sitealias_get_record('@self');
  85. if (!array_key_exists('root', $self_record) && !array_key_exists('remote-host', $self_record)) {
  86. $drupal_root = \Drush::bootstrapManager()->getRoot();
  87. $uri = drush_get_context('DRUSH_SELECTED_URI');
  88. if (!empty($drupal_root) && !empty($uri)) {
  89. // Create an alias '@self'
  90. _drush_sitealias_cache_alias('@self', array('root' => $drupal_root, 'uri' => $uri));
  91. }
  92. }
  93. }
  94. /**
  95. * Given a list of alias records, shorten the name used if possible
  96. */
  97. function drush_sitealias_simplify_names($site_list) {
  98. $result = array();
  99. foreach ($site_list as $original_name => $alias_record) {
  100. $adjusted_name = $alias_record['#name'];
  101. $hashpos = strpos($original_name, '#');
  102. if ($hashpos !== FALSE) {
  103. $adjusted_name = substr($original_name, $hashpos);
  104. if (array_key_exists('remote-host', $alias_record)) {
  105. $adjusted_name = $alias_record['remote-host'] . $adjusted_name;
  106. }
  107. }
  108. $result[$adjusted_name] = $alias_record;
  109. }
  110. return $result;
  111. }
  112. /**
  113. * Given an array of site specifications, resolve each one in turn and
  114. * return an array of alias records. If you only want a single record,
  115. * it is preferable to simply call drush_sitealias_get_record() directly.
  116. *
  117. * @param $site_specifications
  118. * One of:
  119. * A comma-separated list of site specifications: '@site1,@site2'
  120. * An array of site specifications: array('@site1','@site2')
  121. * An array of alias records:
  122. * array(
  123. * 'site1' => array('root' => ...),
  124. * 'site2' => array('root' => ...)
  125. * )
  126. * An array of site specifications.
  127. * @see drush_sitealias_get_record() for the format of site specifications.
  128. * @return
  129. * An array of alias records
  130. */
  131. function drush_sitealias_resolve_sitespecs($site_specifications, $alias_path_context = NULL) {
  132. $result_list = array();
  133. $not_found = array();
  134. if (!is_array($site_specifications)) {
  135. $site_specifications = explode(',', $site_specifications);
  136. }
  137. if (!empty($site_specifications)) {
  138. foreach ($site_specifications as $site) {
  139. if (is_array($site)) {
  140. $result_list[] = $site;
  141. }
  142. else {
  143. $alias_record = drush_sitealias_get_record($site, $alias_path_context);
  144. if (!$alias_record) {
  145. $not_found[] = $site;
  146. }
  147. else {
  148. $result_list = array_merge($result_list, drush_sitealias_resolve_sitelist($alias_record));
  149. }
  150. }
  151. }
  152. }
  153. return array($result_list, $not_found);
  154. }
  155. /**
  156. * Returns TRUE if $alias is a valid format for an alias name.
  157. *
  158. * Mirrors the allowed formats shown below for drush_sitealias_get_record.
  159. */
  160. function drush_sitealias_valid_alias_format($alias) {
  161. return ( (strpos($alias, ',') !== false) ||
  162. ((strpos($alias, '@') === FALSE ? 0 : 1) + (strpos($alias, '/') === FALSE ? 0 : 1) + (strpos($alias, '#') === FALSE ? 0 : 1) >= 2) ||
  163. ($alias{0} == '#') ||
  164. ($alias{0} == '@')
  165. );
  166. }
  167. /**
  168. * Get a site alias record given an alias name or site specification.
  169. *
  170. * If it is the name of a site alias, return the alias record from
  171. * the site aliases array.
  172. *
  173. * If it is the name of a folder in the 'sites' folder, construct
  174. * an alias record from values stored in settings.php.
  175. *
  176. * If it is a site specification, construct an alias record from the
  177. * values in the specification.
  178. *
  179. * Site specifications come in several forms:
  180. * - /path/to/drupal#sitename
  181. * - user@server/path/to/drupal#sitename
  182. * - user@server/path/to/drupal (sitename == server)
  183. * - user@server#sitename (only if $option['r'] set in some drushrc file on server)
  184. * - #sitename (only if $option['r'] already set, and 'sitename' is a folder in $option['r']/sites)
  185. * - sitename (only if $option['r'] already set, and 'sitename' is a folder in $option['r']/sites)
  186. *
  187. * Note that in the case of the first four forms, it is also possible
  188. * to add additional site variable to the specification using uri query
  189. * syntax. For example:
  190. *
  191. * user@server/path/to/drupal?db-url=...#sitename
  192. *
  193. * @param alias
  194. * An alias name or site specification
  195. * @return array
  196. * An alias record, or empty if none found.
  197. */
  198. function drush_sitealias_get_record($alias, $alias_context = NULL) {
  199. // Check to see if the alias contains commas. If it does, then
  200. // we will go ahead and make a site list record
  201. $alias_record = array();
  202. if (strpos($alias, ',') !== false) {
  203. // TODO: If the site list contains any site lists, or site
  204. // search paths, then we should expand those and merge them
  205. // into this list longhand.
  206. $alias_record['site-list'] = explode(',', $alias);
  207. }
  208. else {
  209. $alias_record = _drush_sitealias_get_record($alias, $alias_context);
  210. }
  211. if (!empty($alias_record)) {
  212. if (array_key_exists('#name', $alias_record)) {
  213. if ($alias_record['#name'] == 'self') {
  214. $path = drush_sitealias_local_site_path($alias_record);
  215. if ($path) {
  216. $cached_alias_record = drush_sitealias_lookup_alias_by_path($path);
  217. // Don't overrite keys which have already been negotiated.
  218. unset($cached_alias_record['#name'], $cached_alias_record['root'], $cached_alias_record['uri']);
  219. $alias_record = array_merge($alias_record, $cached_alias_record);
  220. }
  221. }
  222. }
  223. else {
  224. $alias_record['#name'] = drush_sitealias_uri_to_site_dir($alias);
  225. }
  226. }
  227. return $alias_record;
  228. }
  229. /**
  230. * This is a continuation of drush_sitealias_get_record, above. It is
  231. * not intended to be called directly.
  232. */
  233. function _drush_sitealias_get_record($alias, $alias_context = NULL) {
  234. $alias_record = array();
  235. // Before we do anything else, load $alias if it needs to be loaded
  236. _drush_sitealias_load_alias($alias, $alias_context);
  237. // Check to see if the provided parameter is in fact a defined alias.
  238. $all_site_aliases =& drush_get_context('site-aliases');
  239. if (array_key_exists($alias, $all_site_aliases)) {
  240. $alias_record = $all_site_aliases[$alias];
  241. }
  242. // If the parameter is not an alias, then it is some form of
  243. // site specification (or it is nothing at all)
  244. else {
  245. if (isset($alias)) {
  246. // Cases 1.) - 4.):
  247. // We will check for a site specification if the alias has at least
  248. // two characters from the set '@', '/', '#'.
  249. if ((strpos($alias, '@') === FALSE ? 0 : 1) + ((strpos($alias, '/') === FALSE && strpos($alias, '\\') === FALSE) ? 0 : 1) + (strpos($alias, '#') === FALSE ? 0 : 1) >= 2) {
  250. if ((substr($alias,0,7) != 'http://') && !drush_is_absolute_path($alias)) {
  251. // Add on a scheme so that "user:pass@server" will always parse correctly
  252. $parsed = parse_url('http://' . $alias);
  253. }
  254. else if (drush_is_windows() && drush_is_absolute_path($alias)) {
  255. // On windows if alias begins with a filesystem path we must add file:// scheme to make it parse correcly
  256. $parsed = parse_url('file:///' . $alias);
  257. }
  258. else {
  259. $parsed = parse_url($alias);
  260. }
  261. // Copy various parts of the parsed URL into the appropriate records of the alias record
  262. foreach (array('user' => 'remote-user', 'pass' => 'remote-pass', 'host' => 'remote-host', 'fragment' => 'uri', 'path' => 'root') as $url_key => $option_key) {
  263. if (array_key_exists($url_key, $parsed)) {
  264. _drush_sitealias_set_record_element($alias_record, $option_key, $parsed[$url_key]);
  265. }
  266. }
  267. // If the site specification has a query, also set the query items
  268. // in the alias record. This allows passing db_url as part of the
  269. // site specification, for example.
  270. if (array_key_exists('query', $parsed)) {
  271. foreach (explode('&', $parsed['query']) as $query_arg) {
  272. $query_components = explode('=', $query_arg);
  273. _drush_sitealias_set_record_element($alias_record, urldecode($query_components[0]), urldecode($query_components[1]));
  274. }
  275. }
  276. // Case 3.): If the URL contains a 'host' portion but no fragment, then set the uri to the host
  277. // Note: We presume that 'server' is the best default for case 3; without this code, the default would
  278. // be whatever is set in $options['l'] on the target machine's drushrc.php settings file.
  279. if (array_key_exists('host', $parsed) && !array_key_exists('fragment', $parsed)) {
  280. $alias_record['uri'] = $parsed['host'];
  281. }
  282. // Special checking: relative aliases embedded in a path
  283. $relative_alias_pos = strpos($alias_record['root'], '/@');
  284. if ($relative_alias_pos !== FALSE) {
  285. // Special checking: /path/@sites
  286. $base = substr($alias_record['root'], 0, $relative_alias_pos);
  287. $relative_alias = substr($alias_record['root'], $relative_alias_pos + 1);
  288. if (drush_valid_root($base) || ($relative_alias == '@sites')) {
  289. drush_sitealias_create_sites_alias($base);
  290. $alias_record = drush_sitealias_get_record($relative_alias);
  291. }
  292. else {
  293. $alias_record = array();
  294. }
  295. }
  296. }
  297. else {
  298. // Case 5.) and 6.):
  299. // If the alias is the name of a folder in the 'sites' directory,
  300. // then use it as a local site specification.
  301. $alias_record = _drush_sitealias_find_record_for_local_site($alias);
  302. }
  303. }
  304. }
  305. if (!empty($alias_record)) {
  306. if (!isset($alias_record['remote']) && !isset($alias_record['#loaded-config'])) {
  307. if (array_key_exists('root', $alias_record)) {
  308. drush_sitealias_add_to_alias_path($alias_record['root'] . '/drush');
  309. drush_sitealias_add_to_alias_path($alias_record['root'] . '/sites/all/drush');
  310. }
  311. // TODO: We should probably remove this feature, and put it back
  312. // in, but in different places (e.g. site selection, sql-sync + rsync
  313. // parameters, etc.)
  314. $alias_site_dir = drush_sitealias_local_site_path($alias_record);
  315. if (isset($alias_site_dir)) {
  316. // Add the sites folder of this site to the alias search path list
  317. drush_sitealias_add_to_alias_path($alias_site_dir);
  318. }
  319. if (isset($alias_record['config']) && file_exists($alias_record['config'])) {
  320. drush_load_config_file('site', $alias_record['config']);
  321. $alias_record['#loaded-config'] = TRUE;
  322. }
  323. unset($alias_record['config']);
  324. }
  325. // Add the static defaults
  326. _drush_sitealias_add_static_defaults($alias_record);
  327. // Cache the result with all of its calculated values
  328. $all_site_aliases[$alias] = $alias_record;
  329. }
  330. return $alias_record;
  331. }
  332. /**
  333. * Add a path to the array of paths where alias files are searched for.
  334. *
  335. * @param $add_path
  336. * A path to add to the search path (or NULL to not add any).
  337. * Once added, the new path will remain available until drush
  338. * exits.
  339. * @return
  340. * An array of paths containing all values added so far
  341. */
  342. function drush_sitealias_add_to_alias_path($add_path) {
  343. static $site_paths = array();
  344. if ($add_path != NULL) {
  345. if (!is_array($add_path)) {
  346. $add_path = explode(PATH_SEPARATOR, $add_path);
  347. }
  348. // Normalize path to make sure we don't add the same path twice on
  349. // windows due to different spelling. e.g. c:\tmp and c:/tmp
  350. foreach($add_path as &$path) {
  351. $path = drush_normalize_path($path);
  352. }
  353. $site_paths = array_unique(array_merge($site_paths, $add_path));
  354. }
  355. return $site_paths;
  356. }
  357. /**
  358. * Return the array of paths where alias files are searched for.
  359. *
  360. * @param $alias_path_context
  361. * If the alias being looked up is part of a relative alias,
  362. * the alias path context specifies the context of the primary
  363. * alias the new alias is rooted from. Alias files stored in
  364. * the sites folder of this context, or inside the context itself
  365. * takes priority over any other search path that might define
  366. * a similarly-named alias. In this way, multiple sites can define
  367. * a '@peer' alias.
  368. * @return
  369. * An array of paths
  370. */
  371. function drush_sitealias_alias_path($alias_path_context = NULL) {
  372. $context_path = array();
  373. if (isset($alias_path_context)) {
  374. $context_path = array(drush_sitealias_local_site_path($alias_path_context));
  375. }
  376. // We get the current list of site paths by adding NULL
  377. // (nothing) to the path list, which is a no-op
  378. $site_paths = drush_sitealias_add_to_alias_path(NULL);
  379. // If the user defined the root of a drupal site, then also
  380. // look for alias files in /drush and /sites/all/drush.
  381. $drupal_root = \Drush::bootstrapManager()->getRoot();
  382. if (!empty($drupal_root)) {
  383. $site_paths[] = drush_sitealias_alias_base_directory($drupal_root . '/../drush');
  384. $site_paths[] = drush_sitealias_alias_base_directory($drupal_root . '/drush');
  385. $site_paths[] = drush_sitealias_alias_base_directory($drupal_root . '/sites/all/drush');
  386. $uri = drush_get_context('DRUSH_SELECTED_URI');
  387. if (empty($uri)) {
  388. $uri = 'default';
  389. }
  390. $site_dir = drush_sitealias_uri_to_site_dir($uri, $drupal_root);
  391. if ($site_dir) {
  392. $site_paths[] = drush_sitealias_alias_base_directory("$drupal_root/sites/$site_dir");
  393. }
  394. }
  395. $alias_path = (array) drush_get_context('ALIAS_PATH', array());
  396. return array_unique(array_merge($context_path, $alias_path, $site_paths));
  397. }
  398. /**
  399. * If there is a directory 'site-aliases' in the specified search location,
  400. * then search ONLY in that directory for aliases. Otherwise, search
  401. * anywhere inside the specified directory for aliases.
  402. */
  403. function drush_sitealias_alias_base_directory($dir) {
  404. $potential_location = $dir . '/site-aliases';
  405. if (is_dir($potential_location)) {
  406. return $potential_location;
  407. }
  408. return $dir;
  409. }
  410. /**
  411. * Return the full path to the site directory of the
  412. * given alias record.
  413. *
  414. * @param $alias_record
  415. * The alias record
  416. * @return
  417. * The path to the site directory of the associated
  418. * alias record, or NULL if the record is not a local site.
  419. */
  420. function drush_sitealias_local_site_path($alias_record) {
  421. $result = NULL;
  422. if (isset($alias_record['root']) && !isset($alias_record['remote-host'])) {
  423. if (isset($alias_record['uri'])) {
  424. $uri = $alias_record['uri'];
  425. $uri = preg_replace('#^[^:]*://#', '', $uri);
  426. while (!$result && !empty($uri)) {
  427. if (file_exists($alias_record['root'] . '/sites/sites.php')) {
  428. $sites = array();
  429. include($alias_record['root'] . '/sites/sites.php');
  430. if (array_key_exists($uri, $sites)) {
  431. $result = $alias_record['root'] . '/sites/' . $sites[$uri];
  432. }
  433. }
  434. if (!$result) {
  435. $result = ($alias_record['root'] . '/sites/' . drush_sitealias_uri_to_site_dir($uri, drush_sitealias_get_root($alias_record)));
  436. }
  437. $result = realpath($result);
  438. $uri = preg_replace('#^[^.]*\.*#', '', $uri);
  439. }
  440. }
  441. if (!$result) {
  442. $result = realpath($alias_record['root'] . '/sites/default');
  443. }
  444. }
  445. return $result;
  446. }
  447. /**
  448. * Check and see if an alias definition for $alias is available.
  449. * If it is, load it into the list of aliases cached in the
  450. * 'site-aliases' context.
  451. *
  452. * @param $alias
  453. * The name of the alias to load in ordinary form ('@name')
  454. * @param $alias_path_context
  455. * When looking up a relative alias, the alias path context is
  456. * the primary alias that we will start our search from.
  457. */
  458. function _drush_sitealias_load_alias($alias, $alias_path_context = NULL) {
  459. $all_site_aliases = drush_get_context('site-aliases');
  460. $result = array();
  461. // Only aliases--those named entities that begin with '@'--can be loaded this way.
  462. // We also skip any alias that has already been loaded.
  463. if ((substr($alias,0,1) == '@') && !array_key_exists($alias,$all_site_aliases)) {
  464. $aliasname = substr($alias,1);
  465. $result = _drush_sitealias_find_and_load_alias($aliasname, $alias_path_context);
  466. if (!empty($result)) {
  467. $alias_options = array('site-aliases' => array($aliasname => $result));
  468. _drush_sitealias_add_inherited_values($alias_options['site-aliases']);
  469. drush_set_config_special_contexts($alias_options);
  470. if (array_key_exists('#file', $result)) {
  471. drush_log(dt('Loaded alias !alias from file !file', array('!alias' => $alias, '!file' => $result['#file'])));
  472. }
  473. }
  474. }
  475. return $result;
  476. }
  477. /**
  478. * Load every alias file that can be found anywhere in the
  479. * alias search path.
  480. */
  481. function drush_sitealias_load_all($resolve_parent = TRUE) {
  482. $result = _drush_sitealias_find_and_load_all_aliases();
  483. if (!empty($result) && ($resolve_parent == TRUE)) {
  484. // If any aliases were returned, then check for
  485. // inheritance and then store the aliases into the
  486. // alias cache
  487. _drush_sitealias_add_inherited_values($result);
  488. $alias_options = array('site-aliases' => $result);
  489. drush_set_config_special_contexts($alias_options);
  490. }
  491. }
  492. /**
  493. * Worker function called by _drush_sitealias_load_alias and
  494. * drush_sitealias_load_all. Traverses the alias search path
  495. * and finds the specified alias record.
  496. *
  497. * @return
  498. * An array of $kay => $value pair of alias names and alias records
  499. * loaded.
  500. */
  501. function _drush_sitealias_find_and_load_all_aliases() {
  502. $result = array();
  503. $drush_alias_files = _drush_sitealias_find_alias_files();
  504. drush_set_context('drush-alias-files', $drush_alias_files);
  505. // For every file that matches, check inside it for
  506. // an alias with a matching name.
  507. foreach ($drush_alias_files as $filename) {
  508. if (file_exists($filename)) {
  509. $aliases = $options = array();
  510. // silently ignore files we can't include
  511. if ((@include $filename) === FALSE) {
  512. drush_log(dt('Cannot open alias file "!alias", ignoring.', array('!alias' => realpath($filename))), LogLevel::BOOTSTRAP);
  513. continue;
  514. }
  515. unset($options['site-aliases']); // maybe unnecessary
  516. // If $aliases are not set, but $options are, then define one alias named
  517. // after the first word of the file, before '.alias.drushrc.php.
  518. if (empty($aliases) && !empty($options)) {
  519. $this_alias_name = substr(basename($filename),0,strpos(basename($filename),'.'));
  520. $aliases[$this_alias_name] = $options;
  521. $options = array();
  522. }
  523. // If this is a group alias file, then make an
  524. // implicit alias from the group name that contains
  525. // a site-list of all of the aliases in the file
  526. $group_name = '';
  527. if (substr($filename, -20) == ".aliases.drushrc.php") {
  528. $group_name = basename($filename,".aliases.drushrc.php");
  529. if (!empty($aliases) && !array_key_exists($group_name, $aliases)) {
  530. $alias_names = array();
  531. foreach (array_keys($aliases) as $one_alias) {
  532. $alias_names[] = "@$group_name.$one_alias";
  533. $aliases["$group_name.$one_alias"] = $aliases[$one_alias];
  534. unset($aliases[$one_alias]);
  535. }
  536. $aliases[$group_name] = array('site-list' => implode(',', $alias_names));
  537. }
  538. }
  539. if (!empty($aliases)) {
  540. if (!empty($options)) {
  541. foreach ($aliases as $name => $value) {
  542. $aliases[$name] = array_merge($options, $value);
  543. }
  544. $options = array();
  545. }
  546. foreach ($aliases as $name => $value) {
  547. _drush_sitealias_initialize_alias_record($aliases[$name]);
  548. $aliases[$name]['#name'] = $name;
  549. $aliases[$name]['#file'] = $filename;
  550. }
  551. $result = _sitealias_array_merge($result, $aliases);
  552. // If we found at least one alias from this file
  553. // then record it in the drush-alias-files context.
  554. $drush_alias_files = drush_get_context('drush-alias-files');
  555. if (!in_array($filename, $drush_alias_files)) {
  556. $drush_alias_files[] = $filename;
  557. }
  558. drush_set_context('drush-alias-files', $drush_alias_files);
  559. }
  560. }
  561. }
  562. return $result;
  563. }
  564. /**
  565. * Function to find all alias files that might contain aliases
  566. * that match the requested alias name.
  567. */
  568. function _drush_sitealias_find_alias_files($aliasname = NULL, $alias_path_context = NULL) {
  569. $alias_files_to_consider = array();
  570. // The alias path is a list of folders to search for alias settings files
  571. $alias_path = drush_sitealias_alias_path($alias_path_context);
  572. // $alias_files contains a list of filename patterns
  573. // to search for. We will find any matching file in
  574. // any folder in the alias path. The directory scan
  575. // is not deep, though; only files immediately in the
  576. // search path are considered.
  577. $alias_files = array('/.*aliases\.drush(' . DRUSH_MAJOR_VERSION . '|)rc\.php$/');
  578. if ($aliasname == NULL) {
  579. $alias_files[] = '/.*\.alias\.drush(' . DRUSH_MAJOR_VERSION . '|)rc\.php$/';
  580. }
  581. else {
  582. $alias_files[] = '/' . preg_quote($aliasname, '/') . '\.alias\.drush(' . DRUSH_MAJOR_VERSION . '|)rc\.php$/';
  583. }
  584. // Do not scan into the files directory.
  585. $blacklist = array_merge(array('files'), drush_filename_blacklist());
  586. // Search each path in turn.
  587. foreach ($alias_path as $path) {
  588. // Find all of the matching files in this location
  589. foreach ($alias_files as $file_pattern_to_search_for) {
  590. drush_log(dt('Scanning into @path for @pattern', array('@path' => $path, '@pattern' => $file_pattern_to_search_for)), LogLevel::DEBUG_NOTIFY);
  591. $alias_files_to_consider = array_merge($alias_files_to_consider, array_keys(drush_scan_directory($path, $file_pattern_to_search_for, $blacklist, 0, TRUE)));
  592. }
  593. }
  594. return $alias_files_to_consider;
  595. }
  596. /**
  597. * Traverses the alias search path and finds the specified alias record.
  598. *
  599. * @param $aliasname
  600. * The name of the alias without the leading '@' (i.e. '#name')
  601. * or NULL to load every alias found in every alias file.
  602. * @param $alias_path_context
  603. * When looking up a relative alias, the alias path context is
  604. * the primary alias that we will start our search from.
  605. * @return
  606. * An empty array if nothing was loaded. If $aliasname is
  607. * not null, then the array returned is the alias record for
  608. * $aliasname. If $aliasname is NULL, then the array returned
  609. * is a $kay => $value pair of alias names and alias records
  610. * loaded.
  611. */
  612. function _drush_sitealias_find_and_load_alias($aliasname, $alias_path_context = NULL) {
  613. // Special checking for '@sites' alias
  614. if ($aliasname == 'sites') {
  615. $drupal_root = NULL;
  616. if ($alias_path_context != null) {
  617. if (array_key_exists('root', $alias_path_context) && !array_key_exists('remote-host', $alias_path_context)) {
  618. $drupal_root = $alias_path_context['root'];
  619. }
  620. }
  621. else {
  622. $drupal_root = \Drush::bootstrapManager()->getRoot();
  623. }
  624. if (isset($drupal_root) && !is_array($drupal_root)) {
  625. drush_sitealias_create_sites_alias($drupal_root);
  626. }
  627. }
  628. $alias_files_to_consider = _drush_sitealias_find_alias_files($aliasname, $alias_path_context);
  629. return _drush_sitealias_find_and_load_alias_from_file($aliasname, $alias_files_to_consider);
  630. }
  631. function _drush_sitealias_find_and_load_alias_from_file($aliasname, $alias_files_to_consider) {
  632. $result = array();
  633. $result_names = array();
  634. // For every file that matches, check inside it for
  635. // an alias with a matching name.
  636. $recorded_files = array();
  637. foreach ($alias_files_to_consider as $filename) {
  638. if (file_exists($filename)) {
  639. $aliases = $options = array();
  640. // silently ignore files we can't include
  641. if ((@include $filename) === FALSE) {
  642. drush_log(dt('Cannot open alias file "!alias", ignoring.', array('!alias' => realpath($filename))), LogLevel::BOOTSTRAP);
  643. continue;
  644. }
  645. unset($options['site-aliases']); // maybe unnecessary
  646. // If $aliases are not set, but $options are, then define one alias named
  647. // after the first word of the file, before '.alias.drushrc.php.
  648. if (empty($aliases) && !empty($options)) {
  649. $this_alias_name = substr(basename($filename),0,strpos(basename($filename),'.'));
  650. $aliases[$this_alias_name] = $options;
  651. $options = array();
  652. }
  653. // If this is a group alias file, then make an
  654. // implicit alias from the group name that contains
  655. // a site-list of all of the aliases in the file
  656. $group_prefix = '';
  657. if (substr($filename, -20) == ".aliases.drushrc.php") {
  658. $group_name = basename($filename,".aliases.drushrc.php");
  659. $group_prefix = $group_name . '.';
  660. if (!empty($aliases) && !array_key_exists($group_name, $aliases)) {
  661. $alias_names = array();
  662. foreach (array_keys($aliases) as $one_alias) {
  663. $alias_names[] = "@$group_name.$one_alias";
  664. $aliases[$one_alias]['#name'] = "$group_name.$one_alias";
  665. $aliases[$one_alias]['#group'] = $group_name;
  666. $aliases["$group_name.$one_alias"] = $aliases[$one_alias];
  667. $aliases[$one_alias]["#hidden"] = TRUE;
  668. }
  669. $aliases[$group_name] = array('site-list' => implode(',', $alias_names), '#group' => $group_name, '#name' => $group_name);
  670. }
  671. }
  672. // Store only the named alias into the alias cache
  673. if ((isset($aliases)) && !empty($aliasname) && array_key_exists($aliasname, $aliases)) {
  674. drush_set_config_special_contexts($options); // maybe unnecessary
  675. $one_result = array_merge($options, $aliases[$aliasname]);
  676. $one_result['#file'] = $filename;
  677. if (!array_key_exists('#name', $one_result)) {
  678. $one_result['#name'] = $aliasname;
  679. }
  680. _drush_sitealias_initialize_alias_record($one_result);
  681. // If the alias name is exactly the same as a previous match, then
  682. // merge the two records together
  683. if (!empty($result) && ($result['#name'] == $one_result['#name'])) {
  684. $result = _sitealias_array_merge($result, $one_result);
  685. }
  686. // Add the name of the found record to the list of results
  687. else {
  688. $result_names[] = "@" . $one_result['#name'];
  689. $result = $one_result;
  690. }
  691. }
  692. }
  693. }
  694. // If there are multiple matches, then return a list of results.
  695. if (count($result_names) > 1) {
  696. $result = array('site-list' => $result_names);
  697. }
  698. return $result;
  699. }
  700. /**
  701. * Merges two site aliases.
  702. *
  703. * array_merge_recursive is too much; we only want to run
  704. * array_merge on the common top-level keys of the array.
  705. *
  706. * @param array $site_alias_a
  707. * A site alias array.
  708. * @param array $site_alias_b
  709. * A site alias array.
  710. * @return
  711. * A site alias array where the keys from $site_alias_a are overwritten by the
  712. * keys from $site_alias_b.
  713. */
  714. function _sitealias_array_merge($site_alias_a, $site_alias_b) {
  715. $result = $site_alias_a;
  716. foreach($site_alias_b as $key => $value) {
  717. if (is_array($value) && array_key_exists($key, $result)) {
  718. $result[$key] = array_merge($result[$key], $value);
  719. }
  720. else {
  721. $result[$key] = $value;
  722. }
  723. }
  724. return $result;
  725. }
  726. /**
  727. * Check to see if there is a 'parent' item in the alias; if there is,
  728. * then load the parent alias record and overlay the entries in the
  729. * current alias record on top of the items from the parent record.
  730. *
  731. * @param $aliases
  732. * An array of alias records that are modified in-place.
  733. */
  734. function _drush_sitealias_add_inherited_values(&$aliases) {
  735. foreach ($aliases as $alias_name => $alias_value) {
  736. // Prevent circular references from causing an infinite loop
  737. _drush_sitealias_cache_alias("@$alias_name", array());
  738. _drush_sitealias_add_inherited_values_to_record($alias_value);
  739. $aliases[$alias_name] = $alias_value;
  740. }
  741. }
  742. function _drush_sitealias_add_inherited_values_to_record(&$alias_value) {
  743. drush_command_invoke_all_ref('drush_sitealias_alter', $alias_value);
  744. if (isset($alias_value['parent'])) {
  745. drush_log(dt("Using deprecated 'parent' element '!parent' in '!name'.", array('!parent' => $alias_value['parent'], '!name' => $alias_value['#name'])), LogLevel::DEBUG);
  746. // Fetch and merge in each parent
  747. foreach (explode(',', $alias_value['parent']) as $parent) {
  748. $parent_record = drush_sitealias_get_record($parent);
  749. unset($parent_record['#name']);
  750. unset($parent_record['#file']);
  751. unset($parent_record['#hidden']);
  752. $array_based_keys = array_merge(drush_get_special_keys(), array('path-aliases'));
  753. foreach ($array_based_keys as $array_based_key) {
  754. if (isset($alias_value[$array_based_key]) && isset($parent_record[$array_based_key])) {
  755. $alias_value[$array_based_key] = array_merge($parent_record[$array_based_key], $alias_value[$array_based_key]);
  756. }
  757. }
  758. $alias_value = array_merge($parent_record, $alias_value);
  759. }
  760. }
  761. unset($alias_value['parent']);
  762. }
  763. /**
  764. * Add an empty record for the specified alias name
  765. *
  766. * @param $alias_name
  767. * The name of the alias, including the leading "@"
  768. */
  769. function _drush_sitealias_cache_alias($alias_name, $alias_record) {
  770. $cache =& drush_get_context('site-aliases');
  771. // If the alias already exists in the cache, then merge
  772. // the new alias with the existing alias
  773. if (array_key_exists($alias_name, $cache)) {
  774. $alias_record = array_merge($cache[$alias_name], $alias_record);
  775. }
  776. if (!isset($alias_record['#name'])) {
  777. $alias_record['#name'] = trim($alias_name, '@');
  778. }
  779. $cache[$alias_name] = $alias_record;
  780. // If the alias record points at a local site, make sure
  781. // that /drush, /sites/all/drush and the site folder for that site
  782. // are added to the alias path, so that other alias files
  783. // stored in those locations become searchable.
  784. if (!array_key_exists('remote-host', $alias_record) && !empty($alias_record['root'])) {
  785. drush_sitealias_add_to_alias_path($alias_record['root'] . '/drush');
  786. drush_sitealias_add_to_alias_path($alias_record['root'] . '/sites/all/drush');
  787. $site_dir = drush_sitealias_local_site_path($alias_record);
  788. if (isset($site_dir)) {
  789. drush_sitealias_add_to_alias_path($site_dir);
  790. }
  791. }
  792. }
  793. /**
  794. * If the alias record does not contain a 'databases' or 'db-url'
  795. * entry, then use backend invoke to look up the settings value
  796. * from the remote or local site. The 'db_url' form is preferred;
  797. * nothing is done if 'db_url' is not available (e.g. on a D7 site)
  798. *
  799. * @param $alias_record
  800. * The full alias record to populate with database settings
  801. */
  802. function drush_sitealias_add_db_url(&$alias_record) {
  803. if (!isset($alias_record['db-url']) && !isset($alias_record['databases']) && !isset($alias_record['site-list'])) {
  804. drush_sitealias_add_db_settings($alias_record);
  805. }
  806. if (!isset($alias_record['db-url']) && isset($alias_record['databases'])) {
  807. $alias_record['db-url'] = drush_sitealias_convert_databases_to_db_url($alias_record['databases']);
  808. }
  809. }
  810. /**
  811. * Drush still accepts --db-url format database specifications as
  812. * cli parameters; it is therefore useful to be able to convert
  813. * from a database record back to a db-url sometimes.
  814. */
  815. function drush_sitealias_convert_db_spec_to_db_url($db_spec) {
  816. $result = urlencode($db_spec["driver"]) . "://";
  817. if (isset($db_spec["username"])) {
  818. $result .= urlencode($db_spec["username"]);
  819. if (isset($db_spec["password"])) {
  820. $result .= ":" . urlencode($db_spec["password"]);
  821. }
  822. $result .= "@";
  823. }
  824. // Host is required, unless this is an sqlite db.
  825. if (isset($db_spec["host"])) {
  826. $result .= urlencode($db_spec["host"]);
  827. if (isset($db_spec["port"])) {
  828. $result .= ":" . urlencode($db_spec["port"]);
  829. }
  830. $result .= '/' . urlencode($db_spec["database"]);
  831. }
  832. else {
  833. // URL-encode the database, but convert slashes
  834. // back to their original form for readability.
  835. // This portion is the "path" of the URL, so it may
  836. // contain slashes. This is important for sqlite.
  837. $result .= str_replace("%2F", "/", urlencode(ltrim($db_spec["database"], '/')));
  838. }
  839. return $result;
  840. }
  841. /**
  842. * Create a db-url from the databases record.
  843. */
  844. function drush_sitealias_convert_databases_to_db_url($databases) {
  845. if ((count($databases) == 1) && isset($databases['default'])) {
  846. $result = drush_sitealias_convert_db_spec_to_db_url($databases['default']['default']);
  847. }
  848. else {
  849. foreach ($databases as $key => $db_info) {
  850. $result[$key] = drush_sitealias_convert_db_spec_to_db_url($db_info['default']);
  851. }
  852. }
  853. return $result;
  854. }
  855. /**
  856. * Return the databases record from the alias record
  857. *
  858. * @param $alias_record
  859. * A record returned from drush_sitealias_get_record
  860. * @returns
  861. * A databases record (always in D7 format) or NULL
  862. * if the databases record could not be found.
  863. */
  864. function sitealias_get_databases_from_record(&$alias_record) {
  865. $altered_record = drush_sitealias_add_db_settings($alias_record);
  866. return array_key_exists('databases', $alias_record) ? $alias_record['databases'] : NULL;
  867. }
  868. /**
  869. * Return the $db_spec record for the database associated with
  870. * the provided alias record. @see drush_sitealias_add_db_settings(),
  871. * which will be used to first add the database information to the
  872. * alias records, invoking sql-conf to look them up if necessary.
  873. *
  874. * The options 'database' and 'target' are used to specify which
  875. * specific database should be fetched from the database record;
  876. * they may appear in the alias definition, or may be taken from the
  877. * command line options. The values 'default' and 'default' are
  878. * used if these options are not specified in either location.
  879. *
  880. * Note that in the context of sql-sync, the site alias record will
  881. * be taken from one of the source or target aliases
  882. * (e.g. `drush sql-sync @source @target`), which will be overlayed with
  883. * any options that begin with 'source-' or 'target-', respectively.
  884. * Therefore, the commandline options 'source-database' and 'source-target'
  885. * (or 'target-database' and 'source-target') may also affect the operation
  886. * of this function.
  887. */
  888. function drush_sitealias_get_db_spec(&$alias_record, $default_to_self = FALSE, $prefix = '') {
  889. $db_spec = NULL;
  890. $databases = sitealias_get_databases_from_record($alias_record);
  891. if (isset($databases) && !empty($databases)) {
  892. $database = drush_sitealias_get_option($alias_record, 'database', 'default', $prefix);
  893. $target = drush_sitealias_get_option($alias_record, 'target', 'default', $prefix);
  894. if (array_key_exists($database, $databases) && array_key_exists($target, $databases[$database])) {
  895. $db_spec = $databases[$database][$target];
  896. }
  897. }
  898. elseif ($default_to_self) {
  899. $db_spec = _drush_sql_get_db_spec();
  900. }
  901. if (isset($db_spec)) {
  902. $remote_host = drush_sitealias_get_option($alias_record, 'remote-host', NULL, $prefix);
  903. if (!drush_is_local_host($remote_host)) {
  904. $db_spec['remote-host'] = $remote_host;
  905. $db_spec['port'] = drush_sitealias_get_option($alias_record, 'remote-port', (isset($db_spec['port']) ? $db_spec['port'] : NULL), $prefix);
  906. }
  907. }
  908. return $db_spec;
  909. }
  910. /**
  911. * If the alias record does not contain a 'databases' or 'db-url'
  912. * entry, then use backend invoke to look up the settings value
  913. * from the remote or local site. The 'databases' form is
  914. * preferred; 'db_url' will be converted to 'databases' if necessary.
  915. *
  916. * @param $alias_record
  917. * The full alias record to populate with database settings
  918. */
  919. function drush_sitealias_add_db_settings(&$alias_record) {
  920. $altered_record = FALSE;
  921. if (isset($alias_record['root'])) {
  922. // If the alias record does not have a defined 'databases' entry,
  923. // then we'll need to look one up
  924. if (!isset($alias_record['db-url']) && !isset($alias_record['databases']) && !isset($alias_record['site-list'])) {
  925. $values = drush_invoke_process($alias_record, "sql-conf", array(), array('all' => TRUE), array('integrate' => FALSE, 'override-simulated' => TRUE));
  926. if (is_array($values) && ($values['error_status'] == 0)) {
  927. $altered_record = TRUE;
  928. // If there are any special settings in the '@self' record returned by drush_invoke_process,
  929. // then add those into our altered record as well
  930. if (array_key_exists('self', $values)) {
  931. $alias_record = array_merge($values['self'], $alias_record);
  932. }
  933. drush_sitealias_cache_db_settings($alias_record, $values['object']);
  934. }
  935. }
  936. }
  937. return $altered_record;
  938. }
  939. function drush_sitealias_cache_db_settings(&$alias_record, $databases) {
  940. if (!empty($databases)) {
  941. $alias_record['databases'] = $databases;
  942. }
  943. // If the name is set, then re-cache the record after we fetch the databases
  944. if (array_key_exists('#name', $alias_record)) {
  945. $all_site_aliases =& drush_get_context('site-aliases');
  946. $all_site_aliases['@' . $alias_record['#name']] = $alias_record;
  947. // Check and see if this record is a copy of 'self'
  948. if (($alias_record['#name'] != 'self') && array_key_exists('@self', $all_site_aliases) && array_key_exists('#name', $all_site_aliases['@self']) && ($all_site_aliases['@self']['#name'] == $alias_record['#name'])) {
  949. $all_site_aliases['@self'] = $alias_record;
  950. }
  951. }
  952. }
  953. /**
  954. * Check to see if we have already bootstrapped to a site.
  955. */
  956. function drush_sitealias_is_bootstrapped_site($alias_record) {
  957. if (!isset($alias_record['remote-host']) && array_key_exists('root', $alias_record)) {
  958. $self_record = drush_sitealias_get_record("@self");
  959. if (empty($self_record) || !array_key_exists('root', $self_record)) {
  960. // TODO: If we have not bootstrapped to a site yet, we could
  961. // perhaps bootstrap to $alias_record here.
  962. return FALSE;
  963. }
  964. elseif(($alias_record['root'] == $self_record['root']) && ($alias_record['uri'] == $self_record['uri'])) {
  965. return TRUE;
  966. }
  967. }
  968. return FALSE;
  969. }
  970. /**
  971. * Determines whether a given site alias is for a remote site.
  972. *
  973. * @param string $alias
  974. * An alias name or site specification.
  975. *
  976. * @return bool
  977. * Returns TRUE if the alias refers to a remote site, FALSE if it does not, or NULL is unsure.
  978. */
  979. function drush_sitealias_is_remote_site($alias) {
  980. if (is_array($alias) && !empty($alias['remote-host'])) {
  981. return TRUE;
  982. }
  983. if (!is_string($alias) || !strlen($alias)) {
  984. return NULL;
  985. }
  986. $site_record = drush_sitealias_get_record($alias);
  987. if ($site_record) {
  988. if (!empty($site_record['remote-host'])) {
  989. return TRUE;
  990. }
  991. else {
  992. return FALSE;
  993. }
  994. }
  995. else {
  996. drush_set_error('Unrecognized site alias.');
  997. }
  998. }
  999. /**
  1000. * Get the name of the current bootstrapped site
  1001. */
  1002. function drush_sitealias_bootstrapped_site_name() {
  1003. $site_name = NULL;
  1004. $self_record = drush_sitealias_get_record('@self');
  1005. if (array_key_exists('#name', $self_record)) {
  1006. $site_name = $self_record['#name'];
  1007. }
  1008. if (!isset($site_name) || ($site_name == '@self')) {
  1009. $drupal_root = \Drush::bootstrapManager()->getRoot();
  1010. if (isset($drupal_root)) {
  1011. $drupal_uri = drush_get_context('DRUSH_SELECTED_URI', 'default');
  1012. $drupal_uri = str_replace('http://', '', $drupal_uri);
  1013. // TODO: Maybe use _drush_sitealias_find_local_alias_name?
  1014. $site_name = $drupal_root . '#' . $drupal_uri;
  1015. }
  1016. }
  1017. return $site_name;
  1018. }
  1019. /**
  1020. * If there are any path aliases (items beginning with "%") in the test
  1021. * string, then resolve them as path aliases and add them to the provided
  1022. * alias record.
  1023. *
  1024. * @param $alias_record
  1025. * The full alias record to use in path alias expansion
  1026. * @param $test_string
  1027. * A slash-separated list of path aliases to resolve
  1028. * e.g. "%files/%special".
  1029. */
  1030. function drush_sitealias_resolve_path_references(&$alias_record, $test_string = '') {
  1031. $path_aliases = array_key_exists('path-aliases', $alias_record) ? $alias_record['path-aliases'] : array();
  1032. // Convert the test string into an array of items, and
  1033. // from this make a comma-separated list of projects
  1034. // that we can pass to 'drush status'.
  1035. $test_array = explode('/', $test_string);
  1036. $project_array = array();
  1037. foreach($test_array as $one_item) {
  1038. if (!empty($one_item) && ($one_item[0] == '%') && (!array_key_exists($one_item,$path_aliases))) {
  1039. $project_array[] = substr($one_item,1);
  1040. }
  1041. }
  1042. $project_list = implode(',', $project_array);
  1043. if (!empty($project_array)) {
  1044. // Optimization: if we're already bootstrapped to the
  1045. // site specified by $alias_record, then we can just
  1046. // call _core_site_status_table() rather than use backend invoke.
  1047. if (drush_sitealias_is_bootstrapped_site($alias_record) && drush_has_boostrapped(DRUSH_BOOTSTRAP_DRUPAL_FULL)) {
  1048. $status_values = _core_site_status_table($project_list);
  1049. }
  1050. else {
  1051. $values = drush_invoke_process($alias_record, "core-status", array(), empty($project_list) ? array() : array('project' => $project_list), array('integrate' => FALSE, 'override-simulated' => TRUE));
  1052. $status_values = $values['object'];
  1053. }
  1054. if (isset($status_values['%paths'])) {
  1055. foreach ($status_values['%paths'] as $key => $path) {
  1056. $alias_record['path-aliases'][$key] = $path;
  1057. }
  1058. }
  1059. // If 'root' is not set in the alias, then fill it in from the status values.
  1060. if (!isset($alias_record['root']) && isset($status_values['root'])) {
  1061. $alias_record['root'] = $status_values['root'];
  1062. }
  1063. }
  1064. }
  1065. /**
  1066. * Given an alias record that is a site list (contains a 'site-list' entry),
  1067. * resolve all of the members of the site list and return them
  1068. * is an array of alias records.
  1069. *
  1070. * @param $alias_record
  1071. * The site list alias record array
  1072. * @return
  1073. * An array of individual site alias records
  1074. */
  1075. function drush_sitealias_resolve_sitelist($alias_record) {
  1076. $result_list = array();
  1077. if (isset($alias_record)) {
  1078. if (array_key_exists('site-list', $alias_record)) {
  1079. foreach ($alias_record['site-list'] as $sitespec) {
  1080. $one_result = drush_sitealias_get_record($sitespec);
  1081. $result_list = array_merge($result_list, drush_sitealias_resolve_sitelist($one_result));
  1082. }
  1083. }
  1084. elseif (array_key_exists('#name', $alias_record)) {
  1085. $result_list[$alias_record['#name']] = $alias_record;
  1086. }
  1087. }
  1088. return $result_list;
  1089. }
  1090. function _drush_sitelist_find_in_list($one_source, &$target) {
  1091. $result = FALSE;
  1092. foreach ($target as $key => $one_target) {
  1093. if(_drush_sitelist_check_site_records($one_source, $one_target)) {
  1094. $result = $one_target;
  1095. unset($target[$key]);
  1096. }
  1097. }
  1098. return $result;
  1099. }
  1100. function _drush_sitelist_check_site_records($source, $target) {
  1101. if ((array_key_exists('uri', $source)) && (array_key_exists('uri', $target)) && ($source['uri'] == $target['uri'])) {
  1102. return TRUE;
  1103. }
  1104. return FALSE;
  1105. }
  1106. /**
  1107. * Initialize an alias record; called as soon as the alias
  1108. * record is loaded from its alias file, before it is stored
  1109. * in the cache.
  1110. *
  1111. * @param alias_record
  1112. * The alias record to be initialized; parameter is modified in place.
  1113. */
  1114. function _drush_sitealias_initialize_alias_record(&$alias_record) {
  1115. // If there is a 'from-list' entry, then build a derived
  1116. // list based on the site list with the given name.
  1117. if (array_key_exists('from-list', $alias_record)) {
  1118. // danger of infinite loops... move to transient defaults?
  1119. $from_record = drush_sitealias_get_record($alias_record['from-list']);
  1120. $from_list = drush_sitealias_resolve_sitelist($from_record);
  1121. $derived_list = array();
  1122. foreach ($from_list as $one_record) {
  1123. $derived_record = _drush_sitealias_derive_record($one_record, $alias_record);
  1124. $derived_list[] = drush_sitealias_alias_record_to_spec($derived_record);
  1125. }
  1126. $alias_record = array();
  1127. if (!empty($derived_list)) {
  1128. $alias_record['site-list'] = $derived_list;
  1129. }
  1130. }
  1131. // If there is a 'site-search-path' entry, then build
  1132. // a 'site-list' entry from all of the sites that can be
  1133. // found in the search path.
  1134. if (array_key_exists('site-search-path', $alias_record)) {
  1135. // TODO: Is there any point in merging the sites from
  1136. // the search path with any sites already listed in the
  1137. // 'site-list' entry? For now we'll just overwrite.
  1138. $search_path = $alias_record['site-search-path'];
  1139. if (!is_array($search_path)) {
  1140. $search_path = explode(',', $search_path);
  1141. }
  1142. $found_sites = _drush_sitealias_find_local_sites($search_path);
  1143. $alias_record['site-list'] = $found_sites;
  1144. // The 'unordered-list' flag indicates that the order of the items in the site list is not stable.
  1145. $alias_record['unordered-list'] = '1';
  1146. // DEBUG: var_export($alias_record, FALSE);
  1147. }
  1148. if (array_key_exists('site-list', $alias_record)) {
  1149. if (!is_array($alias_record['site-list'])) {
  1150. $alias_record['site-list'] = explode(',', $alias_record['site-list']);
  1151. }
  1152. }
  1153. else {
  1154. if (isset($alias_record['root']) && !isset($alias_recort['uri'])) {
  1155. $alias_recort['uri'] = 'default';
  1156. }
  1157. }
  1158. }
  1159. /**
  1160. * Add "static" default values to the given alias record. The
  1161. * difference between a static default and a transient default is
  1162. * that static defaults -always- exist in the alias record, and
  1163. * they are cached, whereas transient defaults are only added
  1164. * if the given drush command explicitly adds them.
  1165. *
  1166. * @param alias_record
  1167. * An alias record with most values already filled in
  1168. */
  1169. function _drush_sitealias_add_static_defaults(&$alias_record) {
  1170. // If there is a 'db-url' entry but not 'databases' entry, then we will
  1171. // build 'databases' from 'db-url' so that drush commands that use aliases
  1172. // can always count on using a uniform 'databases' array.
  1173. if (isset($alias_record['db-url']) && !isset($alias_record['databases'])) {
  1174. $alias_record['databases'] = drush_sitealias_convert_db_from_db_url($alias_record['db-url']);
  1175. }
  1176. // Canonicalize paths.
  1177. if (!empty($alias_record['root'])) {
  1178. $alias_record['root'] = Path::canonicalize($alias_record['root']);
  1179. }
  1180. // Adjustments for aliases to drupal instances (as opposed to aliases that are site lists)
  1181. if (array_key_exists('uri', $alias_record)) {
  1182. // Make sure that there is always a 'path-aliases' array
  1183. if (!array_key_exists('path-aliases', $alias_record)) {
  1184. $alias_record['path-aliases'] = array();
  1185. }
  1186. // If there is a 'root' entry, then copy it to the '%root' path alias
  1187. if (isset($alias_record['root'])) {
  1188. $alias_record['path-aliases']['%root'] = $alias_record['root'];
  1189. }
  1190. }
  1191. }
  1192. function _drush_sitealias_derive_record($from_record, $modifying_record) {
  1193. $result = $from_record;
  1194. // If there is a 'remote-user' in the modifying record, copy it.
  1195. if (array_key_exists('remote-user', $modifying_record)) {
  1196. $result['remote-user'] = $from_record['remote_user'];
  1197. }
  1198. // If there is a 'remote-host', then:
  1199. // If it is empty, clear the remote host in the result record
  1200. // If it ends in '.', then prepend it to the remote host in the result record
  1201. // Otherwise, copy it to the result record
  1202. if (array_key_exists('remote-host', $modifying_record)) {
  1203. $remote_host_modifier = $modifying_record['remote-host'];
  1204. if(empty($remote_host_modifier)) {
  1205. unset($result['remote-host']);
  1206. unset($result['remote-user']);
  1207. }
  1208. elseif ($remote_host_modifier[strlen($remote_host_modifier)-1] == '.') {
  1209. $result['remote-host'] = $remote_host_modifier . $result['remote-host'];
  1210. }
  1211. else {
  1212. $result['remote-host'] = $remote_host_modifier;
  1213. }
  1214. }
  1215. // If there is a 'root', then:
  1216. // If it begins with '/', copy it to the result record
  1217. // Otherwise, append it to the result record
  1218. if (array_key_exists('root', $modifying_record)) {
  1219. $root_modifier = $modifying_record['root'];
  1220. if($root_modifier[0] == '/') {
  1221. $result['root'] = $root_modifier;
  1222. }
  1223. else {
  1224. $result['root'] = $result['root'] . '/' . $root_modifier;
  1225. }
  1226. }
  1227. // Poor man's realpath: take out the /../ with preg_replace.
  1228. // (realpath fails if the files in the path do not exist)
  1229. while(strpos($result['root'], '/../') !== FALSE) {
  1230. $result['root'] = preg_replace('/\w+\/\.\.\//', '', $result['root']);
  1231. }
  1232. // TODO: Should we allow the uri to be transformed?
  1233. // I think that if the uri does not match, then you should
  1234. // always build the list by hand, and not rely on '_drush_sitealias_derive_record'.
  1235. return $result;
  1236. }
  1237. /**
  1238. * Convert from an alias record to a site specification
  1239. *
  1240. * @param alias_record
  1241. * The full alias record to convert
  1242. *
  1243. * @param with_db
  1244. * True if the site specification should include a ?db-url term
  1245. *
  1246. * @return string
  1247. * The site specification
  1248. */
  1249. function drush_sitealias_alias_record_to_spec($alias_record, $with_db = false) {
  1250. $result = '';
  1251. // TODO: we should handle 'site-list' records too.
  1252. if (array_key_exists('site-list', $alias_record)) {
  1253. // TODO: we should actually expand the site list and recompose it
  1254. $result = implode(',', $alias_record['site-list']);
  1255. }
  1256. else {
  1257. // There should always be a uri
  1258. if (array_key_exists('uri', $alias_record)) {
  1259. $result = '#' . drush_sitealias_uri_to_site_dir($alias_record['uri'], drush_sitealias_get_root($alias_record));
  1260. }
  1261. // There should always be a root
  1262. if (array_key_exists('root', $alias_record)) {
  1263. $result = $alias_record['root'] . $result;
  1264. }
  1265. if (array_key_exists('remote-host', $alias_record)) {
  1266. $result = drush_remote_host($alias_record) . $result;
  1267. }
  1268. // Add the database info to the specification if desired
  1269. if ($with_db) {
  1270. // If db-url is not supplied, look it up from the remote
  1271. // or local site and add it to the site alias
  1272. if (!isset($alias_record['db-url'])) {
  1273. drush_sitealias_add_db_url($alias_record);
  1274. }
  1275. $result = $result . '?db-url=' . urlencode(is_array($alias_record['db-url']) ? $alias_record['db-url']['default'] : $alias_record['db-url']);
  1276. }
  1277. }
  1278. return $result;
  1279. }
  1280. /**
  1281. * Search for drupal installations in the search path.
  1282. *
  1283. * @param search_path
  1284. * An array of drupal root folders
  1285. *
  1286. * @return
  1287. * An array of site specifications (/path/to/root#sitename.com)
  1288. */
  1289. function _drush_sitealias_find_local_sites($search_path) {
  1290. $result = array();
  1291. foreach ($search_path as $a_drupal_root) {
  1292. $result = array_merge($result, _drush_find_local_sites_at_root($a_drupal_root));
  1293. }
  1294. return $result;
  1295. }
  1296. /**
  1297. * Return a list of all of the local sites at the specified drupal root.
  1298. */
  1299. function _drush_find_local_sites_at_root($a_drupal_root = '', $search_depth = 1) {
  1300. $site_list = array();
  1301. $base_path = (empty($a_drupal_root) ? drush_get_context('DRUSH_DRUPAL_ROOT') : $a_drupal_root );
  1302. if (!empty($base_path)) {
  1303. if (drush_valid_root($base_path)) {
  1304. // If $a_drupal_root is in fact a valid drupal root, then return
  1305. // all of the sites found inside the 'sites' folder of this drupal instance.
  1306. $site_list = _drush_find_local_sites_in_sites_folder($base_path);
  1307. }
  1308. else {
  1309. $bootstrap_files = drush_scan_directory($base_path, '/' . basename(DRUSH_DRUPAL_SIGNATURE) . '/' , array('.', '..', 'CVS', 'examples'), 0, drush_get_option('search-depth', $search_depth) + 1, 'filename', 1);
  1310. foreach ($bootstrap_files as $one_bootstrap => $info) {
  1311. $includes_dir = dirname($one_bootstrap);
  1312. if (basename($includes_dir) == basename(dirname(DRUSH_DRUPAL_SIGNATURE))) {
  1313. $drupal_root = dirname($includes_dir);
  1314. $site_list = array_merge(_drush_find_local_sites_in_sites_folder($drupal_root), $site_list);
  1315. }
  1316. }
  1317. }
  1318. }
  1319. return $site_list;
  1320. }
  1321. /**
  1322. * Return a list of all of the local sites at the specified 'sites' folder.
  1323. */
  1324. function _drush_find_local_sites_in_sites_folder($a_drupal_root) {
  1325. $site_list = array();
  1326. // If anyone searches for sites at a given root, then
  1327. // make sure that alias files stored at this root
  1328. // directory are included in the alias search path
  1329. drush_sitealias_add_to_alias_path($a_drupal_root);
  1330. $base_path = $a_drupal_root . '/sites';
  1331. // TODO: build a cache keyed off of $base_path (realpath($base_path)?),
  1332. // so that it is guarenteed that the lists returned will definitely be
  1333. // exactly the same should this routine be called twice with the same path.
  1334. $files = drush_scan_directory($base_path, '/settings\.php/', array('.', '..', 'CVS', 'all'), 0, 1, 'filename', 1);
  1335. foreach ($files as $filename => $info) {
  1336. if ($info->basename == 'settings.php') {
  1337. // First we'll resolve the realpath of the settings.php file,
  1338. // so that we get the correct drupal root when symlinks are in use.
  1339. $real_sitedir = dirname(realpath($filename));
  1340. $real_root = drush_locate_root($filename);
  1341. if ($real_root !== FALSE) {
  1342. $a_drupal_site = $real_root . '#' . basename($real_sitedir);
  1343. }
  1344. // If the symlink points to some folder outside of any drupal
  1345. // root, then we'll use the
  1346. else {
  1347. $uri = drush_sitealias_site_dir_from_filename($filename);
  1348. $a_drupal_site = $a_drupal_root . '#' . $uri;
  1349. }
  1350. // Add the site if it isn't already in the array
  1351. if (!in_array($a_drupal_site, $site_list)) {
  1352. $site_list[] = $a_drupal_site;
  1353. }
  1354. }
  1355. }
  1356. return $site_list;
  1357. }
  1358. function drush_sitealias_create_sites_alias($a_drupal_root = '') {
  1359. $sites_list = _drush_find_local_sites_at_root($a_drupal_root);
  1360. _drush_sitealias_cache_alias('@sites', array('site-list' => $sites_list));
  1361. }
  1362. /**
  1363. * Add "transient" default values to the given alias record. The
  1364. * difference between a static default and a transient default is
  1365. * that static defaults -always- exist in the alias record,
  1366. * whereas transient defaults are only added if the given drush
  1367. * command explicitly calls this function. The other advantage
  1368. * of transient defaults is that it is possible to differentiate
  1369. * between a default value and an unspecified value, since the
  1370. * transient defaults are not added until requested.
  1371. *
  1372. * Since transient defaults are not cached, you should avoid doing
  1373. * expensive operations here. To be safe, drush commands should
  1374. * avoid calling this function more than once.
  1375. *
  1376. * @param alias_record
  1377. * An alias record with most values already filled in
  1378. */
  1379. function _drush_sitealias_add_transient_defaults(&$alias_record) {
  1380. if (isset($alias_record['path-aliases'])) {
  1381. // Add the path to the drush folder to the path aliases as !drush
  1382. if (!array_key_exists('%drush', $alias_record['path-aliases'])) {
  1383. if (array_key_exists('%drush-script', $alias_record['path-aliases'])) {
  1384. $alias_record['path-aliases']['%drush'] = dirname($alias_record['path-aliases']['%drush-script']);
  1385. }
  1386. else {
  1387. $alias_record['path-aliases']['%drush'] = dirname(drush_find_drush());
  1388. }
  1389. }
  1390. // Add the path to the site folder to the path aliases as !site
  1391. if (!array_key_exists('%site', $alias_record['path-aliases']) && array_key_exists('uri', $alias_record)) {
  1392. $alias_record['path-aliases']['%site'] = 'sites/' . drush_sitealias_uri_to_site_dir($alias_record['uri'], drush_sitealias_get_root($alias_record)) . '/';
  1393. }
  1394. }
  1395. }
  1396. /**
  1397. * Find the name of a local alias record that has the specified
  1398. * root and uri.
  1399. */
  1400. function _drush_sitealias_find_local_alias_name($root, $uri) {
  1401. $result = '';
  1402. $all_site_aliases =& drush_get_context('site-aliases');
  1403. foreach ($all_site_aliases as $alias_name => $alias_values) {
  1404. if (!array_key_exists('remote-host', $alias_values) && array_key_exists('root', $alias_values) && array_key_exists('uri', $alias_values) && ($alias_name != '@self')) {
  1405. if (($root == $alias_values['root']) && ($uri == $alias_values['uri'])) {
  1406. $result = $alias_name;
  1407. }
  1408. }
  1409. }
  1410. return $result;
  1411. }
  1412. /**
  1413. * If '$alias' is the name of a folder in the sites folder of the given drupal
  1414. * root, then build an alias record for it
  1415. *
  1416. * @param alias
  1417. * The name of the site in the 'sites' folder to convert
  1418. * @return array
  1419. * An alias record, or empty if none found.
  1420. */
  1421. function _drush_sitealias_find_record_for_local_site($alias, $drupal_root = NULL) {
  1422. $alias_record = array();
  1423. // Clip off the leading '#' if it is there
  1424. if (substr($alias,0,1) == '#') {
  1425. $alias = substr($alias,1);
  1426. }
  1427. if (!isset($drupal_root)) {
  1428. $drupal_root = \Drush::bootstrapManager()->getRoot();
  1429. }
  1430. if (!empty($drupal_root)) {
  1431. $alias_dir = drush_sitealias_uri_to_site_dir($alias, $drupal_root);
  1432. $site_settings_file = $drupal_root . '/sites/' . $alias_dir . '/settings.php';
  1433. $alias_record = drush_sitealias_build_record_from_settings_file($site_settings_file, $alias, $drupal_root);
  1434. }
  1435. return $alias_record;
  1436. }
  1437. function drush_sitealias_build_record_from_settings_file($site_settings_file, $alias = null, $drupal_root = null) {
  1438. $alias_record = array();
  1439. if (file_exists($site_settings_file)) {
  1440. if (!isset($drupal_root)) {
  1441. $drupal_root = drush_locate_root($site_settings_file);
  1442. }
  1443. $alias_record['root'] = $drupal_root;
  1444. if (isset($alias)) {
  1445. $alias_record['uri'] = $alias;
  1446. }
  1447. else {
  1448. $alias_record['uri'] = _drush_sitealias_site_dir_to_uri(drush_sitealias_site_dir_from_filename($site_settings_file));
  1449. }
  1450. }
  1451. return $alias_record;
  1452. }
  1453. /**
  1454. * Pull the site directory from the path to settings.php
  1455. *
  1456. * @param site_settings_file
  1457. * path to settings.php
  1458. *
  1459. * @return string
  1460. * the site directory component of the path to settings.php
  1461. */
  1462. function drush_sitealias_site_dir_from_filename($site_settings_file) {
  1463. return basename(dirname($site_settings_file));
  1464. }
  1465. /**
  1466. * Convert from a URI to a site directory.
  1467. *
  1468. * @param uri
  1469. * A uri, such as http://domain.com:8080/drupal
  1470. * @return string
  1471. * A directory, such as domain.com.8080.drupal
  1472. */
  1473. function drush_sitealias_uri_to_site_dir($uri, $site_root = NULL) {
  1474. $uri = str_replace('http://', '', $uri);
  1475. $uri = str_replace('https://', '', $uri);
  1476. if (drush_is_windows()) {
  1477. // Handle absolute paths on windows
  1478. $uri = str_replace(array(':/', ':\\'), array('.', '.'), $uri);
  1479. }
  1480. $hostname = str_replace(array('/', ':', '\\'), array('.', '.', '.'), $uri);
  1481. // Check sites.php mappings
  1482. $site_dir = drush_site_dir_lookup_from_hostname($hostname, $site_root);
  1483. return $site_dir ? $site_dir : $hostname;
  1484. }
  1485. /**
  1486. * Convert from an old-style database URL to an array of database settings.
  1487. *
  1488. * @param db_url
  1489. * A Drupal 6 db url string to convert, or an array with a 'default' element.
  1490. * @return array
  1491. * An array of database values containing only the 'default' element of
  1492. * the db url. If the parse fails the array is empty.
  1493. */
  1494. function drush_convert_db_from_db_url($db_url) {
  1495. $db_spec = array();
  1496. if (is_array($db_url)) {
  1497. $db_url_default = $db_url['default'];
  1498. }
  1499. else {
  1500. $db_url_default = $db_url;
  1501. }
  1502. // If it's a sqlite database, pick the database path and we're done.
  1503. if (strpos($db_url_default, 'sqlite://') === 0) {
  1504. $db_spec = array(
  1505. 'driver' => 'sqlite',
  1506. 'database' => substr($db_url_default, strlen('sqlite://')),
  1507. );
  1508. }
  1509. else {
  1510. $url = parse_url($db_url_default);
  1511. if ($url) {
  1512. // Fill in defaults to prevent notices.
  1513. $url += array(
  1514. 'scheme' => NULL,
  1515. 'user' => NULL,
  1516. 'pass' => NULL,
  1517. 'host' => NULL,
  1518. 'port' => NULL,
  1519. 'path' => NULL,
  1520. );
  1521. $url = (object)array_map('urldecode', $url);
  1522. $db_spec = array(
  1523. 'driver' => $url->scheme == 'mysqli' ? 'mysql' : $url->scheme,
  1524. 'username' => $url->user,
  1525. 'password' => $url->pass,
  1526. 'host' => $url->host,
  1527. 'port' => $url->port,
  1528. 'database' => ltrim($url->path, '/'),
  1529. );
  1530. }
  1531. }
  1532. return $db_spec;
  1533. }
  1534. /**
  1535. * Convert from an old-style database URL to an array of database settings
  1536. *
  1537. * @param db_url
  1538. * A Drupal 6 db-url string to convert, or an array with multiple db-urls.
  1539. * @return array
  1540. * An array of database values.
  1541. */
  1542. function drush_sitealias_convert_db_from_db_url($db_url) {
  1543. $result = array();
  1544. if (!is_array($db_url)) {
  1545. $result = array('default' => array('default' => drush_convert_db_from_db_url($db_url)));
  1546. }
  1547. else {
  1548. foreach ($db_url as $one_name => $one_db_url) {
  1549. $result[$one_name] = array('default' => drush_convert_db_from_db_url($one_db_url));
  1550. }
  1551. }
  1552. return $result;
  1553. }
  1554. /**
  1555. * Utility function used by drush_get_alias; keys that start with
  1556. * '%' or '!' are path aliases, the rest are entries in the alias record.
  1557. */
  1558. function _drush_sitealias_set_record_element(&$alias_record, $key, $value) {
  1559. if ((substr($key,0,1) == '%') || (substr($key,0,1) == '!')) {
  1560. $alias_record['path-aliases'][$key] = $value;
  1561. }
  1562. elseif (!empty($key)) {
  1563. $alias_record[$key] = $value;
  1564. }
  1565. }
  1566. /**
  1567. * Looks up the specified alias record and calls through to
  1568. * drush_sitealias_set_alias_context, below.
  1569. *
  1570. * @param alias
  1571. * The name of the alias record
  1572. * @param prefix
  1573. * The prefix value to afix to the beginning of every
  1574. * key set.
  1575. * @return boolean
  1576. * TRUE is an alias was found and processed.
  1577. */
  1578. function _drush_sitealias_set_context_by_name($alias, $prefix = '') {
  1579. if ($alias) {
  1580. $site_alias_settings = drush_sitealias_get_record($alias);
  1581. if (!empty($site_alias_settings)) {
  1582. drush_sitealias_set_alias_context($site_alias_settings, $prefix);
  1583. drush_sitealias_cache_alias_by_path($site_alias_settings);
  1584. if (empty($prefix)) {
  1585. // Create an alias '@self'
  1586. // Allow 'uri' from the commandline to override
  1587. $drush_uri = drush_get_option(array('uri', 'l'), FALSE);
  1588. if ($drush_uri) {
  1589. $site_alias_settings['uri'] = $drush_uri;
  1590. }
  1591. _drush_sitealias_cache_alias('@self', $site_alias_settings);
  1592. // Change the selected site to match the new --root and --uri, if any were set.
  1593. _drush_preflight_root_uri();
  1594. }
  1595. return $site_alias_settings;
  1596. }
  1597. }
  1598. return array();
  1599. }
  1600. /**
  1601. * Given an alias record, overwrite its values with options
  1602. * from the command line and other drush contexts as specified
  1603. * by the provided prefix. For example, if the prefix is 'source-',
  1604. * then any option 'source-foo' will set the value 'foo' in the
  1605. * alias record.
  1606. */
  1607. function drush_sitealias_overlay_options($site_alias_record, $prefix) {
  1608. return array_merge($site_alias_record, drush_get_merged_prefixed_options($prefix));
  1609. }
  1610. /**
  1611. * First return an option set via drush_sitealias_overlay_options, if
  1612. * any, then fall back on "%" . $option from the path aliases.
  1613. */
  1614. function drush_sitealias_get_path_option($site_alias_record, $option, $default = NULL) {
  1615. if (isset($site_alias_record) && array_key_exists($option, $site_alias_record)) {
  1616. return $site_alias_record[$option];
  1617. }
  1618. if (isset($site_alias_record) && array_key_exists('path-aliases', $site_alias_record) && array_key_exists("%$option", $site_alias_record['path-aliases'])) {
  1619. return $site_alias_record['path-aliases']["%$option"];
  1620. }
  1621. else {
  1622. return drush_get_option($option, $default);
  1623. }
  1624. }
  1625. /**
  1626. * Given a site alias record, copy selected fields from it
  1627. * into the drush 'alias' context. The 'alias' context has
  1628. * lower precedence than the 'cli' context, so values
  1629. * set by an alias record can be overridden by command-line
  1630. * parameters.
  1631. *
  1632. * @param site_alias_settings
  1633. * An alias record
  1634. * @param prefix
  1635. * The prefix value to affix to the beginning of every
  1636. * key set. For example, if this function is called once with
  1637. * 'source-' and again with 'destination-' prefixes, then the
  1638. * source database records will be stored in 'source-databases',
  1639. * and the destination database records will be in
  1640. * 'destination-databases'.
  1641. */
  1642. function drush_sitealias_set_alias_context($site_alias_settings, $prefix = '') {
  1643. $options = drush_get_context('alias');
  1644. // There are some items that we should just skip
  1645. $skip_list = drush_get_special_keys();
  1646. // If 'php-options' are set in the alias, then we will force drush
  1647. // to redispatch via the remote dispatch mechanism even if the target is localhost.
  1648. if ((array_key_exists('php-options', $site_alias_settings) || array_key_exists('php', $site_alias_settings)) && !drush_get_context('DRUSH_BACKEND', FALSE)) {
  1649. if (!array_key_exists('remote-host', $site_alias_settings)) {
  1650. $site_alias_settings['remote-host'] = 'localhost';
  1651. }
  1652. }
  1653. // If 'php-options' are not set in the alias, then skip 'remote-host'
  1654. // and 'remote-user' if 'remote-host' is actually the local machine.
  1655. // This prevents drush from using the remote dispatch mechanism (the command
  1656. // is just run directly on the local machine, bootstrapping to the specified alias)
  1657. elseif (array_key_exists('remote-host', $site_alias_settings) && drush_is_local_host($site_alias_settings['remote-host'])) {
  1658. $skip_list[] = 'remote-host';
  1659. $skip_list[] = 'remote-user';
  1660. }
  1661. // If prefix is set, then copy from the 'prefix-' version
  1662. // of the drush special keys ('command-specific', 'path-aliases')
  1663. // into the ordinary version. This will allow us to set
  1664. // 'source-command-specific' options that will only apply when
  1665. // the alias is used as the source option for rsync or sql-sync.
  1666. if (!empty($prefix)) {
  1667. $special_contexts = drush_get_special_keys();
  1668. foreach ($special_contexts as $option_name) {
  1669. if (array_key_exists($prefix . $option_name, $site_alias_settings)) {
  1670. $site_alias_settings[$option_name] = array_key_exists($option_name, $site_alias_settings) ? array_merge($site_alias_settings[$option_name], $site_alias_settings[$prefix . $option_name]) : $site_alias_settings[$prefix . $option_name];
  1671. }
  1672. }
  1673. }
  1674. // Transfer all options from the site alias to the drush options
  1675. // in the 'alias' context.
  1676. foreach ($site_alias_settings as $key => $value) {
  1677. // Special handling for path aliases:
  1678. if ($key == "path-aliases") {
  1679. $path_aliases = $value;
  1680. foreach (array('%drush-script', '%dump', '%dump-dir', '%include') as $path_key) {
  1681. if (array_key_exists($path_key, $path_aliases)) {
  1682. // Evaluate the path value, and substitute any path references found.
  1683. // ex: '%dump-dir' => '%root/dumps' will store sql-dumps in the folder
  1684. // 'dumps' in the Drupal root folder for the site.
  1685. $evaluated_path = str_replace(array_keys($path_aliases), array_values($path_aliases), $path_aliases[$path_key]);
  1686. $options[$prefix . substr($path_key, 1)] = $evaluated_path;
  1687. }
  1688. }
  1689. }
  1690. // Special handling for command-specific
  1691. elseif ($key == "command-specific") {
  1692. $options[$key] = $value;
  1693. }
  1694. elseif (!in_array($key, $skip_list)) {
  1695. $options[$prefix . $key] = $value;
  1696. }
  1697. }
  1698. drush_set_config_options('alias', $options);
  1699. }
  1700. /**
  1701. * Call prior to drush_sitealias_evaluate_path to insure
  1702. * that any site-specific aliases associated with any
  1703. * local site in $path are defined.
  1704. */
  1705. function _drush_sitealias_preflight_path($path) {
  1706. $alias = NULL;
  1707. // Parse site aliases if there is a colon in the path
  1708. // We allow:
  1709. // @alias:/path
  1710. // machine.domain.com:/path
  1711. // machine:/path
  1712. // Note that paths in the form "c:/path" are converted to
  1713. // "/cygdrive/c/path" later; we do not want them to confuse
  1714. // us here, so we skip paths that start with a single character
  1715. // before the colon if we are running on Windows. Single-character
  1716. // machine names are allowed in Linux only.
  1717. $colon_pos = strpos($path, ':');
  1718. if ($colon_pos > (drush_is_windows("LOCAL") ? 1 : 0)) {
  1719. $alias = substr($path, 0, $colon_pos);
  1720. $path = substr($path, $colon_pos + 1);
  1721. $site_alias_settings = drush_sitealias_get_record($alias);
  1722. if (empty($site_alias_settings) && (substr($path,0,1) == '@')) {
  1723. return NULL;
  1724. }
  1725. $machine = $alias;
  1726. }
  1727. else {
  1728. $machine = '';
  1729. // if the path is a site alias or a local site...
  1730. $site_alias_settings = drush_sitealias_get_record($path);
  1731. if (empty($site_alias_settings) && (substr($path,0,1) == '@')) {
  1732. return NULL;
  1733. }
  1734. if (!empty($site_alias_settings) || drush_is_local_host($path)) {
  1735. $alias = $path;
  1736. $path = '';
  1737. }
  1738. }
  1739. return array('alias' => $alias, 'path' => $path, 'machine' => $machine);
  1740. }
  1741. /**
  1742. * Given a properly-escaped options string, replace any occurance of
  1743. * %files and so on embedded inside it with its corresponding path.
  1744. */
  1745. function drush_sitealias_evaluate_paths_in_options($option_string) {
  1746. $path_aliases = _core_path_aliases();
  1747. return str_replace(array_keys($path_aliases), array_values($path_aliases), $option_string);
  1748. }
  1749. /**
  1750. * Evaluate a path from its shorthand form to a literal path
  1751. * usable by rsync.
  1752. *
  1753. * A path is "machine:/path" or "machine:path" or "/path" or "path".
  1754. * 'machine' might instead be an alias record, or the name
  1755. * of a site in the 'sites' folder. 'path' might be (or contain)
  1756. * '%root' or some other path alias. This function will examine
  1757. * all components of the path and evaluate them as necessary to
  1758. * come to the final path.
  1759. *
  1760. * @param path
  1761. * The path to evaluate
  1762. * @param additional_options
  1763. * An array of options that overrides whatever was passed in on
  1764. * the command line (like the 'process' context, but only for
  1765. * the scope of this one call).
  1766. * @param local_only
  1767. * If TRUE, force an error if the provided path points to a remote
  1768. * machine.
  1769. * @param os
  1770. * This should be the local system os, unless evaluate path is
  1771. * being called for rsync, in which case it should be "CWRSYNC"
  1772. * if cwrsync is being used, or "rsync" to automatically select
  1773. * between "LOCAL" and "CWRSYNC" based on the platform.
  1774. * @return
  1775. * The site record for the machine specified in the path, if any,
  1776. * with the path to pass to rsync (including the machine specifier)
  1777. * in the 'evaluated-path' item.
  1778. */
  1779. function drush_sitealias_evaluate_path($path, &$additional_options, $local_only = FALSE, $os = NULL, $command_specific_prefix = '') {
  1780. $site_alias_settings = array();
  1781. $path_aliases = array();
  1782. $remote_user = '';
  1783. $preflight = _drush_sitealias_preflight_path($path);
  1784. if (!isset($preflight)) {
  1785. return NULL;
  1786. }
  1787. $alias = $preflight['alias'];
  1788. $path = $preflight['path'];
  1789. $machine = $preflight['machine'];
  1790. if (isset($alias)) {
  1791. // Note that the alias settings may have an 'os' component, but we do
  1792. // not want to use it here. The paths passed to rsync should always be
  1793. // escaped per the LOCAL rules, without regard to the remote platform type.
  1794. $site_alias_settings = drush_sitealias_get_record($alias);
  1795. if (!empty($command_specific_prefix)) {
  1796. drush_command_set_command_specific_options($command_specific_prefix);
  1797. drush_sitealias_command_default_options($site_alias_settings, $command_specific_prefix);
  1798. }
  1799. }
  1800. if (!empty($site_alias_settings)) {
  1801. if ($local_only && array_key_exists('remote-host', $site_alias_settings)) {
  1802. return drush_set_error('DRUSH_REMOTE_SITE_IN_LOCAL_CONTEXT', dt("A remote site alias was used in a context where only a local alias is appropriate."));
  1803. }
  1804. // Apply any options from this alias that might affect our rsync
  1805. drush_sitealias_set_alias_context($site_alias_settings);
  1806. // Use 'remote-host' from settings if available; otherwise site is local
  1807. if (drush_sitealias_is_remote_site($site_alias_settings)) {
  1808. $machine = drush_remote_host($site_alias_settings);
  1809. }
  1810. else {
  1811. $machine = '';
  1812. }
  1813. }
  1814. else {
  1815. // Strip the machine portion of the path if the
  1816. // alias points to the local machine.
  1817. if (drush_is_local_host($machine)) {
  1818. $machine = '';
  1819. }
  1820. else {
  1821. $machine = "$remote_user$machine";
  1822. }
  1823. }
  1824. // TOD: The code below is a little rube-goldberg-ish, and needs to be
  1825. // reworked. core-rsync will call this function twice: once to
  1826. // evaluate the destination, and then again to evaluate the source. Things
  1827. // get odd with --exclude-paths, especially in conjunction with command-specific
  1828. // and the --exclude-files option. @see testCommandSpecific()
  1829. // If the --exclude-other-sites option is specified, then
  1830. // convert that into --include-paths='%site' and --exclude-sites.
  1831. if (drush_get_option_override($additional_options, 'exclude-other-sites', FALSE) && !drush_get_context('exclude-other-sites-processed', FALSE)) {
  1832. $include_path_option = drush_get_option_override($additional_options, 'include-paths', '');
  1833. $additional_options['include-paths'] = '%site';
  1834. if (!empty($include_path_option)) {
  1835. // We use PATH_SEPARATOR here because we are later going to explicitly explode() this variable using PATH_SEPARATOR.
  1836. $additional_options['include-paths'] .= PATH_SEPARATOR . $include_path_option;
  1837. }
  1838. $additional_options['exclude-sites'] = TRUE;
  1839. drush_set_context('exclude-other-sites-processed', TRUE);
  1840. }
  1841. else {
  1842. unset($additional_options['include-paths']);
  1843. }
  1844. // If the --exclude-files option is specified, then
  1845. // convert that into --exclude-paths='%files'.
  1846. if (drush_get_option_override($additional_options, 'exclude-files', FALSE) && !drush_get_option_override($additional_options, 'exclude-files-processed', FALSE, 'process')) {
  1847. $exclude_path_option = drush_get_option_override($additional_options, 'exclude-paths', '');
  1848. $additional_options['exclude-paths'] = '%files';
  1849. if (!empty($exclude_path_option)) {
  1850. // We use PATH_SEPARATOR here because we are later going to explicitly explode() this variable using PATH_SEPARATOR.
  1851. $additional_options['exclude-paths'] .= PATH_SEPARATOR . $exclude_path_option;
  1852. }
  1853. $additional_options['exclude-files-processed'] = TRUE;
  1854. }
  1855. else {
  1856. unset($additional_options['exclude-paths']);
  1857. }
  1858. // If there was no site specification given, and the
  1859. // machine is local, then try to look
  1860. // up an alias record for the default drush site.
  1861. if (empty($site_alias_settings) && empty($machine)) {
  1862. $drush_uri = drush_get_context('DRUSH_SELECTED_URI', 'default');
  1863. $site_alias_settings = drush_sitealias_get_record($drush_uri);
  1864. }
  1865. // Always add transient defaults
  1866. _drush_sitealias_add_transient_defaults($site_alias_settings);
  1867. // The $resolve_path variable is used by drush_sitealias_resolve_path_references
  1868. // to test to see if there are any path references such as %site or %files
  1869. // in it, so that resolution is only done if the path alias is referenced.
  1870. // Therefore, we can concatenate without worrying too much about the structure of
  1871. // this variable's contents.
  1872. $include_path = drush_get_option_override($additional_options, 'include-paths', '');
  1873. $exclude_path = drush_get_option_override($additional_options, 'exclude-paths', '');
  1874. if (is_array($include_path)) {
  1875. $include_path = implode('/', $include_path);
  1876. }
  1877. if (is_array($exclude_path)) {
  1878. $include_path = implode('/', $exclude_path);
  1879. }
  1880. $resolve_path = "$path/$include_path/$exclude_path";
  1881. // Resolve path aliases such as %files, if any exist in the path
  1882. if (!empty($resolve_path)) {
  1883. drush_sitealias_resolve_path_references($site_alias_settings, $resolve_path);
  1884. }
  1885. if (array_key_exists('path-aliases', $site_alias_settings)) {
  1886. $path_aliases = $site_alias_settings['path-aliases'];
  1887. }
  1888. // Get the 'root' setting from the alias; if it does not
  1889. // exist, then get the root from the bootstrapped site.
  1890. if (array_key_exists('root', $site_alias_settings)) {
  1891. $drupal_root = $site_alias_settings['root'];
  1892. }
  1893. elseif (!drush_sitealias_is_remote_site($site_alias_settings)) {
  1894. drush_bootstrap_max(DRUSH_BOOTSTRAP_DRUPAL_SITE);
  1895. $drupal_root = drush_get_context('DRUSH_DRUPAL_ROOT');
  1896. }
  1897. if (empty($drupal_root)) {
  1898. $drupal_root = '';
  1899. }
  1900. else {
  1901. // Add a slash to the end of the drupal root, as below.
  1902. $drupal_root = drush_trim_path($drupal_root) . "/";
  1903. }
  1904. $full_path_aliases = $path_aliases;
  1905. foreach ($full_path_aliases as $key => $value) {
  1906. // Expand all relative path aliases to be based off of the Drupal root
  1907. if (!drush_is_absolute_path($value, "LOCAL") && ($key != '%root')) {
  1908. $full_path_aliases[$key] = $drupal_root . $value;
  1909. }
  1910. // We do not want slashes on the end of our path aliases.
  1911. $full_path_aliases[$key] = drush_trim_path($full_path_aliases[$key]);
  1912. }
  1913. // Fill in path aliases in the path, the include path and the exclude path.
  1914. $path = str_replace(array_keys($full_path_aliases), array_values($full_path_aliases), $path);
  1915. if (!empty($include_path)) {
  1916. drush_set_option('include-paths', str_replace(array_keys($path_aliases), array_values($path_aliases), $include_path));
  1917. }
  1918. if (!empty($exclude_path)) {
  1919. drush_set_option('exclude-paths', str_replace(array_keys($path_aliases), array_values($path_aliases), $exclude_path));
  1920. }
  1921. // Next make the rsync path, which includes the machine
  1922. // and path components together.
  1923. // First make empty paths or relative paths start from the drupal root.
  1924. if (empty($path) || (!drush_is_absolute_path($path, "LOCAL"))) {
  1925. $path = $drupal_root . $path;
  1926. }
  1927. // When calculating a path for use with rsync, we must correct
  1928. // absolute paths in the form c:\path when cwrsync is in use.
  1929. $path = drush_correct_absolute_path_for_exec($path, $os);
  1930. // If there is a $machine component, to the path, then
  1931. // add it to the beginning
  1932. $evaluated_path = drush_escapeshellarg($path, $os);
  1933. if (!empty($machine)) {
  1934. $evaluated_path = $machine . ':' . $evaluated_path;
  1935. }
  1936. //
  1937. // Add our result paths:
  1938. //
  1939. // evaluated-path: machine:/path
  1940. // server-component: machine
  1941. // path-component: :/path
  1942. // path: /path
  1943. // user-path: path (as specified in input parameter)
  1944. //
  1945. $site_alias_settings['evaluated-path'] = $evaluated_path;
  1946. if (!empty($machine)) {
  1947. $site_alias_settings['server-component'] = $machine;
  1948. }
  1949. $site_alias_settings['path-component'] = (!empty($path) ? ':' . $path : '');
  1950. $site_alias_settings['path'] = $path;
  1951. $site_alias_settings['user-path'] = $preflight['path'];
  1952. return $site_alias_settings;
  1953. }
  1954. /**
  1955. * Option keys used for site selection.
  1956. */
  1957. function drush_sitealias_site_selection_keys() {
  1958. return array('remote-host', 'remote-user', 'ssh-options', '#name', 'os');
  1959. }
  1960. function sitealias_find_local_drupal_root($site_list) {
  1961. $drupal_root = NULL;
  1962. foreach ($site_list as $site) {
  1963. if (($drupal_root == NULL) && (array_key_exists('root', $site) && !array_key_exists('remote-host', $site))) {
  1964. $drupal_root = $site['root'];
  1965. }
  1966. }
  1967. return $drupal_root;
  1968. }
  1969. /**
  1970. * Helper function to obtain the keys' names that need special handling in certain
  1971. * cases.
  1972. * @return
  1973. * A non-associative array containing the needed keys' names.
  1974. */
  1975. function drush_get_special_keys() {
  1976. $special_keys = array(
  1977. 'command-specific',
  1978. 'site-aliases',
  1979. );
  1980. return $special_keys;
  1981. }
  1982. /**
  1983. * Read the tmp file where the persistent site setting is stored.
  1984. *
  1985. * @return string
  1986. * A valid site specification.
  1987. */
  1988. function drush_sitealias_site_get() {
  1989. if (($filename = drush_sitealias_get_envar_filename()) && file_exists($filename)) {
  1990. $site = file_get_contents($filename);
  1991. return $site;
  1992. }
  1993. else {
  1994. return FALSE;
  1995. }
  1996. }
  1997. /**
  1998. * Un-set the currently use'd site alias.
  1999. */
  2000. function drush_sitealias_site_clear() {
  2001. if ($filename = drush_sitealias_get_envar_filename()) {
  2002. return drush_delete_dir($filename);
  2003. }
  2004. return FALSE;
  2005. }
  2006. /**
  2007. * Returns the filename for the file that stores the DRUPAL_SITE variable.
  2008. *
  2009. * @param string $filename_prefix
  2010. * An arbitrary string to prefix the filename with.
  2011. *
  2012. * @return string|false
  2013. * Returns the full path to temp file if possible, or FALSE if not.
  2014. */
  2015. function drush_sitealias_get_envar_filename($filename_prefix = 'drush-drupal-site-') {
  2016. $shell_pid = getenv('DRUSH_SHELL_PID');
  2017. if (!$shell_pid && function_exists('posix_getppid')) {
  2018. $shell_pid = posix_getppid();
  2019. }
  2020. if (!$shell_pid) {
  2021. return FALSE;
  2022. }
  2023. $tmp = getenv('TMPDIR') ? getenv('TMPDIR') : '/tmp';
  2024. $username = drush_get_username();
  2025. return "{$tmp}/drush-env-{$username}/{$filename_prefix}" . $shell_pid;
  2026. }
  2027. /**
  2028. * Cache the specified alias in the alias path cache. The
  2029. * alias path cache creates a lookup from the site folder
  2030. * (/path/to/drupal/sites/default) to the provided alias record.
  2031. *
  2032. * Only the name of the alias and the path to the file it
  2033. * is stored in is cached; when it is retrieved, it is
  2034. * loaded directly from the correct file.
  2035. */
  2036. function drush_sitealias_cache_alias_by_path($alias_record) {
  2037. if (!isset($alias_record['remote-host']) && isset($alias_record['root']) && isset($alias_record['uri']) && isset($alias_record['#name']) && isset($alias_record['#file'])) {
  2038. $path = drush_sitealias_local_site_path($alias_record);
  2039. if ($path) {
  2040. $cid = drush_get_cid('alias-path-', array(), array($path));
  2041. $alias_path_data = array(
  2042. '#name' => $alias_record['#name'],
  2043. '#file' => $alias_record['#file'],
  2044. );
  2045. drush_cache_set($cid, $alias_path_data);
  2046. }
  2047. }
  2048. }
  2049. /**
  2050. * Look for a defined alias that points to the specified
  2051. * site directory. The cache is tested first; if nothing
  2052. * is cached, then an exhaustive search is done for the
  2053. * specified site. If the exhaustive search returns a
  2054. * match, then it is cached.
  2055. *
  2056. * @param $path
  2057. * /path/to/drupal/sites/default
  2058. * @return
  2059. * An alias record for the provided path
  2060. */
  2061. function drush_sitealias_lookup_alias_by_path($path, $allow_best_match=FALSE) {
  2062. $result = drush_sitealias_quick_lookup_cached_alias_by_path($path);
  2063. $fallback = array();
  2064. if (empty($result)) {
  2065. $aliases = _drush_sitealias_find_and_load_all_aliases();
  2066. foreach ($aliases as $name => $alias_record) {
  2067. if (!isset($alias_record['remote-host']) && isset($alias_record['root']) && isset($alias_record['uri']) && isset($alias_record['#name']) && isset($alias_record['#file'])) {
  2068. if ($path == drush_sitealias_local_site_path($alias_record)) {
  2069. $result = $alias_record;
  2070. break;
  2071. }
  2072. if (substr($path, 0, strlen($alias_record['root'])) == $alias_record['root']) {
  2073. $fallback = $alias_record;
  2074. }
  2075. }
  2076. }
  2077. }
  2078. if (empty($result) && $allow_best_match) {
  2079. $result = $fallback;
  2080. }
  2081. if (!empty($result)) {
  2082. _drush_sitealias_add_inherited_values_to_record($result);
  2083. drush_sitealias_cache_alias_by_path($result);
  2084. }
  2085. return $result;
  2086. }
  2087. /**
  2088. * Look for a cached alias that points to the specified
  2089. * site directory. Nothing is returned if there is no
  2090. * matching cached alias.
  2091. *
  2092. * @param $path
  2093. * /path/to/drupal/sites/default
  2094. * @return
  2095. * An alias record for the provided path
  2096. */
  2097. function drush_sitealias_quick_lookup_cached_alias_by_path($path) {
  2098. $alias_record = array();
  2099. $cid = drush_get_cid('alias-path-', array(), array($path));
  2100. $alias_path_cache = drush_cache_get($cid);
  2101. if (isset($alias_path_cache->data)) {
  2102. $alias_name = $alias_path_cache->data['#name'];
  2103. $alias_file = $alias_path_cache->data['#file'];
  2104. $alias_record = _drush_sitealias_find_and_load_alias_from_file($alias_name, array($alias_file));
  2105. _drush_sitealias_add_inherited_values_to_record($alias_record);
  2106. $alias_record['#name'] = $alias_name;
  2107. }
  2108. return $alias_record;
  2109. }
  2110. /**
  2111. * Return the site root, if there is one in the record.
  2112. */
  2113. function drush_sitealias_get_root($alias_record) {
  2114. return array_key_exists('root', $alias_record) ? $alias_record['root'] : NULL;
  2115. }
  2116. /**
  2117. * Decide on which side to run a core-rsync.
  2118. *
  2119. * @param $source
  2120. * @param $destination
  2121. * @param $runner Where to run the rsync operation: 'destination', 'source',
  2122. * 'auto' ('destination' if both are remote, otherwise '@self') or FALSE (@self)
  2123. * @return mixed
  2124. */
  2125. function drush_get_runner($source, $destination, $runner = FALSE) {
  2126. if (is_string($source)) {
  2127. $source = drush_sitealias_get_record($site);
  2128. }
  2129. if (is_string($destination)) {
  2130. $destination = drush_sitealias_get_record($destination);
  2131. }
  2132. // If both sites are remote, and --runner=auto, then we'll use the destination site.
  2133. if (drush_sitealias_is_remote_site($source) && drush_sitealias_is_remote_site($destination)) {
  2134. if ($runner == 'auto') {
  2135. $runner = 'destination';
  2136. }
  2137. }
  2138. // If the user explicitly requests a remote site, then return the selected one.
  2139. if ($runner == 'destination') {
  2140. return "@" . $destination['#name'];
  2141. }
  2142. if ($runner == 'source') {
  2143. return "@" . $source['#name'];
  2144. }
  2145. // Default to running rsync locally. When in doubt, local is best, because
  2146. // we can always resolve aliases here.
  2147. return '@self';
  2148. }