diff --git a/commands/core/docs.drush.inc b/commands/core/docs.drush.inc index 79cc42c2a4..c8467e331b 100644 --- a/commands/core/docs.drush.inc +++ b/commands/core/docs.drush.inc @@ -105,6 +105,14 @@ function docs_drush_command() { 'callback' => 'drush_print_file', 'callback arguments' => array($docs_dir . '/docs/shellscripts.html'), ); + $items['docs-shell-aliases'] = array( + 'description' => 'Overview on how to use drush shell aliases.', + 'hidden' => TRUE, + 'topic' => TRUE, + 'bootstrap' => DRUSH_BOOTSTRAP_DRUSH, + 'callback' => 'drush_print_file', + 'callback arguments' => array($docs_dir . '/docs/shellaliases.html'), + ); $items['docs-commands'] = array( 'description' => 'Overview on how to write drush commands.', 'hidden' => TRUE, diff --git a/docs/shellaliases.html b/docs/shellaliases.html new file mode 100644 index 0000000000..902e494158 --- /dev/null +++ b/docs/shellaliases.html @@ -0,0 +1,57 @@ +
+ See: https://git.wiki.kernel.org/index.php/Aliases#Advanced +
+A shell alias is defined in a drush configuration file +called drushrc.php. See `drush topic docs-configuration`. +There are two kinds of shell aliases: an alias whose value +begins with a '!' will execute the rest of the line as +bash commands. Aliases that do not start with a '!' will +be interpreted as Drush commands. + +
+ $options['shell-aliases']['pull'] = '!git pull'; // We've all done it. + $options['shell-aliases']['noncore'] = 'pm-list --no-core'; ++With the above two aliases defined, `drush pull` will then be +equivalent to `git pull`, and `drush nocore` will be equivalent +to `drush pm-list --no-core`. + +
+For example, given the following site alias: +
+ $aliases['dev'] = array ( + 'root' => '/path/to/drupal', + 'uri' => 'mysite.org', + '#peer' => '@stage', + ); ++The aliases below can be used to pull the database to a dev site +or push the code from the same site from/to its peer site (live or stage) +via `drush @dev site-pull` and `drush @dev site-push`. Note that these +aliases assume that the alias used defines an item named '#peer' +(as shown in the above alias) that names the live or stage site. + +
+ $options['shell-aliases']['pull-data'] = '!drush sql-sync {{#peer}} {{@target}} && drush rsync {{#peer}}:%files {{@target}}:%files', + $options['shell-aliases']['push-code'] = '!drush rsync {{@target}} {{#peer}} && drush {{#peer}} updatedb', ++If the user does not use these shell aliases with any site alias, then +an error will be returned and the script will not run. If you define +the site that you push to and pull from in the '#peer' value, though, +then these aliases can be used to quickly run combinations of drush sql-sync +and rsync commands on the "standard" peer site, reducing the risk of +typos that might send information in the wrong direction or to the wrong site. diff --git a/docs/shellscripts.html b/docs/shellscripts.html index 039237a7a4..f306885bc1 100644 --- a/docs/shellscripts.html +++ b/docs/shellscripts.html @@ -1,4 +1,4 @@ -
A drush shell script is any Unix shell script file that has its "execute" bit set (i.e., via `chmod +x myscript.drush`) diff --git a/drush.php b/drush.php index 1d99d49eb7..44d893feb7 100755 --- a/drush.php +++ b/drush.php @@ -51,12 +51,13 @@ function drush_main() { $return = ''; drush_bootstrap_to_phase(DRUSH_BOOTSTRAP_DRUSH); - // Process a remote command if 'remote-host' option is set. - $command_handled = drush_remote_command(); - if (!$command_handled) { - $return = _drush_bootstrap_and_dispatch(); + if (!drush_get_error()) { + // Process a remote command if 'remote-host' option is set. + $command_handled = drush_remote_command(); + if (!$command_handled) { + $return = _drush_bootstrap_and_dispatch(); + } } - drush_bootstrap_finish(); // After this point the drush_shutdown function will run, diff --git a/examples/example.aliases.drushrc.php b/examples/example.aliases.drushrc.php index 496b88d298..30f8ed5730 100644 --- a/examples/example.aliases.drushrc.php +++ b/examples/example.aliases.drushrc.php @@ -201,6 +201,10 @@ * command. In the example below, `--skip-tables-list=comments` whenever * the alias @live is the target of an sql-sync command, but comments will * be included if @live is the source for the sql-sync command. + * - '#peer': Settings that begin with a '#' are not used directly by Drush, and + * in fact are removed before making a backend invoke call (for example). These + * kinds of values are useful in conjunction with shell aliases. See + * `drush topic docs-shell-aliases` for more information on this. * Some examples appear below. Remove the leading hash signs to enable. */ #$aliases['stage'] = array( diff --git a/examples/example.drushrc.php b/examples/example.drushrc.php index 49cee9d98a..d89dc9179a 100644 --- a/examples/example.drushrc.php +++ b/examples/example.drushrc.php @@ -65,6 +65,8 @@ // Drush shell aliases act similar to git aliases. // See https://git.wiki.kernel.org/index.php/Aliases#Advanced. // For best success, define these in drushrc files located in #6-3 above. +// More information on shell aliases can be found in +// `drush topic docs-shell-aliases` # $options['shell-aliases']['pull'] = '!git pull'; // We've all done it. # $options['shell-aliases']['pulldb'] = '!git pull && drush updatedb'; # $options['shell-aliases']['noncore'] = 'pm-list --no-core'; diff --git a/includes/command.inc b/includes/command.inc index c65bcab712..59ad0e864c 100644 --- a/includes/command.inc +++ b/includes/command.inc @@ -1567,8 +1567,14 @@ function drush_shell_alias_replace() { } } $alias_value = str_replace(array_keys($alias_variables), array_values($alias_variables), $alias_value); - // Get rid of any unmatched replacements - $alias_value = preg_replace('/{{[%@#]*[a-z0-9.]*}}/i', '', $alias_value); + // Check for unmatched replacements + $matches = array(); + $match_result = preg_match('/{{[%@#]*[a-z0-9.]*}}/', $alias_value, $matches); + if ($match_result) { + $unmatched_replacements = implode(', ', $matches); + $unmatched_replacements = preg_replace('/[{}]/', '', $unmatched_replacements); + return drush_set_error('DRUSH_SHELL_ALIAS_UNMATCHED_REPLACEMENTS', dt('The shell alias @alias-name uses replacements "@unmatched". You must use this command with a site alias (e.g. `drush @myalias @alias-name ...`) that defines all of these variables.', array('@alias-name' => $first, '@unmatched' => $unmatched_replacements))); + } $alias_value = explode(' ', $alias_value); } drush_log(dt('Shell alias found: !key => !value', array('!key' => $first, '!value' => implode(' ', $alias_value))), 'debug'); diff --git a/includes/sitealias.inc b/includes/sitealias.inc index 503b8f622b..26bf7c449a 100644 --- a/includes/sitealias.inc +++ b/includes/sitealias.inc @@ -149,6 +149,7 @@ function drush_sitealias_get_record($alias) { * not intended to be called directly. */ function _drush_sitealias_get_record($alias, $alias_context = NULL) { + $alias_record = array(); // Before we do anything else, load $alias if it needs to be loaded _drush_sitealias_load_alias($alias, $alias_context); diff --git a/tests/shellAliasTest.php b/tests/shellAliasTest.php index 0bdfc70597..8dad72410f 100644 --- a/tests/shellAliasTest.php +++ b/tests/shellAliasTest.php @@ -17,6 +17,7 @@ static function setupBeforeClass() { \$options['shell-aliases'] = array( 'glopts' => 'topic core-global-options', 'pull' => '!git pull', + 'echosimple' => '!echo {{@target}}', 'echotest' => '!echo {{@target}} {{%root}} {{%mypath}}', 'compound-command' => '!cd {{%sandbox}} && pwd && touch mytest && ls mytest', ); @@ -93,18 +94,29 @@ public function testShellAliasBashRemote() { } /* - * Test shell aliases with replacements -- no alias. + * Test shell aliases with simple replacements -- no alias. */ - public function testShellAliasReplacementNoAlias() { + public function testShellAliasSimpleReplacement() { $options = array( 'config' => UNISH_SANDBOX, ); - $this->drush('echotest', array(), $options); + $this->drush('echosimple', array(), $options); $expected = "@none"; $output = $this->getOutput(); $this->assertEquals($expected, $output, 'Expected echo test returned "@none"'); } + /* + * Test shell aliases with complex replacements -- no alias. + */ + public function testShellAliasReplacementNoAlias() { + $options = array( + 'config' => UNISH_SANDBOX, + ); + // echo test has replacements that are not satisfied, so this is expected to return an error. + $this->drush('echotest', array(), $options, NULL, NULL, self::EXIT_ERROR); + } + /* * Test shell aliases with replacements -- alias. */