Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Inject options from core:rsync and sql:sync alias parameters. #3075

Merged
merged 9 commits into from
Oct 19, 2017
2 changes: 1 addition & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
"psr/log": "~1.0",
"psy/psysh": "~0.6",
"league/container": "~2",
"consolidation/config": "^1.0.3",
"consolidation/config": "^1.0.5",
"consolidation/robo": "^1.1.4",
"symfony/config": "~2.2|^3",
"chi-teck/drupal-code-generator": "^1.17.3",
Expand Down
38 changes: 35 additions & 3 deletions examples/example.aliases.yml
Original file line number Diff line number Diff line change
Expand Up @@ -160,14 +160,16 @@
# if you set a 'remote-host' value, and your remote OS is Windows, if you
# do not set the 'OS' value, it will default to 'Linux' and could cause
# unintended consequences, particularly when running 'drush sql-sync'.
# - 'ssh-options': If the target requires special options, such as a non-
# - 'ssh': If the target requires special options, such as a non-
# standard port, alternative identity file, or alternative
# authentication method, ssh-options can contain a string of extra
# options that are used with the ssh command, eg "-p 100"
# authentication method, the `option` entry under the `ssh` item may
# contain a string of extra options that are used with the ssh command,
# e.g. "-p 100"
# - 'paths': An array of aliases for common rsync targets.
# Relative aliases are always taken from the Drupal root.
# - 'files': Path to 'files' directory. This will be looked up if not
# specified.
# - 'drush-script': Path to the remot Drush command.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Typo. :s/remot/remote/.

# - 'command': These options will only be set if the alias
# is used with the specified command. In the example below, the option
# `--no-dump` will be selected whenever the @stage alias
Expand All @@ -177,6 +179,36 @@
# - `drush sql-sync @live @stage`
# NOTE: Setting boolean options broke with Symfony 3. This will be fixed
# in a future release. See: https://github.com/drush-ops/drush/issues/2956
# - 'alias-parameters': These options will only be set if the alias is
# used as the specified parameter. `sql:sync` and `core:rsync` are the two
# core commands that use this entry. These commands both have `source`
# and `target` parameters.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can we add config-pull to this list?

#
# Complex example:
#
# @code
# # File: remote.alias.yml
# live:
# host: server.domain.com
# user: www-admin
# root: /other/path/to/drupal
# uri: http://example.com
# ssh:
# options: '-p 100'
# paths:
# drush-script: '/path/to/drush'
# command:
# site:
# install:
# options:
# admin-password: 'secret-secret'
# alias-parameters:
# target:
# core:
# rsnyc:
# options:
# excplude-paths: sites/default/files/private
# @endcode
#
# Altering aliases:
#
Expand Down
2 changes: 1 addition & 1 deletion isolation/composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
"php": ">=5.6.0",
"ext-dom": "*",
"psr/log": "~1.0",
"consolidation/config": "dev-master",
"consolidation/config": "^1.0.5",
"grasmash/yaml-expander": "^1.1.1",
"symfony/yaml": "~2.3|^3",
"symfony/var-dumper": "~2.7|^3",
Expand Down
3 changes: 3 additions & 0 deletions src/Application.php
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,9 @@ public function refineUriSelection($cwd)
return;
}
$selfAliasRecord = $this->aliasManager->getSelf();
if (!$selfAliasRecord->hasRoot()) {
return;
}
$uri = $selfAliasRecord->uri();

if (empty($uri)) {
Expand Down
74 changes: 53 additions & 21 deletions src/Commands/core/RsyncCommands.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,15 @@
use Drush\SiteAlias\SiteAliasManagerAwareInterface;
use Drush\SiteAlias\SiteAliasManagerAwareTrait;
use Drush\Backend\BackendPathEvaluator;
use Robo\Contract\ConfigAwareInterface;
use Robo\Common\ConfigAwareTrait;
use Drush\Config\ConfigLocator;
use Symfony\Component\Console\Event\ConsoleCommandEvent;

class RsyncCommands extends DrushCommands implements SiteAliasManagerAwareInterface
class RsyncCommands extends DrushCommands implements SiteAliasManagerAwareInterface, ConfigAwareInterface
{
use SiteAliasManagerAwareTrait;
use ConfigAwareTrait;

/**
* These are arguments after the aliases and paths have been evaluated.
Expand All @@ -21,7 +26,7 @@ class RsyncCommands extends DrushCommands implements SiteAliasManagerAwareInterf
/** @var HostPath */
public $sourceEvaluatedPath;
/** @var HostPath */
public $destinationEvaluatedPath;
public $targetEvaluatedPath;
/** @var BackendPathEvaluator */
protected $pathEvaluator;

Expand All @@ -37,7 +42,7 @@ public function __construct()
*
* @command core:rsync
* @param $source A site alias and optional path. See rsync documentation and example.aliases.yml.
* @param $destination A site alias and optional path. See rsync documentation and example.aliases.config.yml.',
* @param $target A site alias and optional path. See rsync documentation and example.aliases.config.yml.',
* @param $extra Additional parameters after the ssh statement.
* @optionset_ssh
* @option exclude-paths List of paths to exclude, seperated by : (Unix-based systems) or ; (Windows).
Expand All @@ -54,11 +59,11 @@ public function __construct()
* @aliases rsync,core-rsync
* @topics docs:aliases
*/
public function rsync($source, $destination, array $extra, $options = ['exclude-paths' => self::REQ, 'include-paths' => self::REQ, 'mode' => 'akz'])
public function rsync($source, $target, array $extra, $options = ['exclude-paths' => self::REQ, 'include-paths' => self::REQ, 'mode' => 'akz'])
{
// Prompt for confirmation. This is destructive.
if (!\Drush\Drush::simulate()) {
$this->output()->writeln(dt("You will delete files in !target and replace with data from !source", array('!source' => $this->sourceEvaluatedPath->fullyQualifiedPathPreservingTrailingSlash(), '!target' => $this->destinationEvaluatedPath->fullyQualifiedPath())));
$this->output()->writeln(dt("You will delete files in !target and replace with data from !source", array('!source' => $this->sourceEvaluatedPath->fullyQualifiedPathPreservingTrailingSlash(), '!target' => $this->targetEvaluatedPath->fullyQualifiedPath())));
if (!$this->io()->confirm(dt('Do you want to continue?'))) {
throw new UserAbortException();
}
Expand All @@ -67,16 +72,16 @@ public function rsync($source, $destination, array $extra, $options = ['exclude-
$rsync_options = $this->rsyncOptions($options);
$parameters = array_merge([$rsync_options], $extra);
$parameters[] = $this->sourceEvaluatedPath->fullyQualifiedPathPreservingTrailingSlash();
$parameters[] = $this->destinationEvaluatedPath->fullyQualifiedPath();
$parameters[] = $this->targetEvaluatedPath->fullyQualifiedPath();

$ssh_options = Drush::config()->get('ssh.options', '');
$exec = "rsync -e 'ssh $ssh_options'". ' '. implode(' ', array_filter($parameters));
$exec_result = drush_op_system($exec);

if ($exec_result == 0) {
drush_backend_set_result($this->destinationEvaluatedPath->fullyQualifiedPath());
drush_backend_set_result($this->targetEvaluatedPath->fullyQualifiedPath());
} else {
throw new \Exception(dt("Could not rsync from !source to !dest", array('!source' => $this->sourceEvaluatedPath->fullyQualifiedPathPreservingTrailingSlash(), '!dest' => $this->destinationEvaluatedPath->fullyQualifiedPath())));
throw new \Exception(dt("Could not rsync from !source to !dest", array('!source' => $this->sourceEvaluatedPath->fullyQualifiedPathPreservingTrailingSlash(), '!dest' => $this->targetEvaluatedPath->fullyQualifiedPath())));
}
}

Expand All @@ -90,7 +95,7 @@ public function rsyncOptions($options)
$inc_ex_path = explode(PATH_SEPARATOR, @$options[$include_exclude . '-paths']);
foreach ($inc_ex_path as $one_path_to_inc_ex) {
if (!empty($one_path_to_inc_ex)) {
$paths = ' --' . $include_exclude . '="' . $one_path_to_inc_ex . '"';
$paths .= ' --' . $include_exclude . '="' . $one_path_to_inc_ex . '"';
}
}
}
Expand All @@ -105,27 +110,54 @@ public function rsyncOptions($options)
}

/**
* Validate that passed aliases are valid.
* Evaluate the path aliases in the source and destination
* parameters. We do this in the pre-command-event so that
* we can set up the configuration object to include options
* from the source and target aliases, if any, so that these
* values may participate in configuration injection.
*
* @hook validate core-rsync
* @param \Consolidation\AnnotatedCommand\CommandData $commandData
* @hook command-event core:rsync
* @param ConsoleCommandEvent $event
* @throws \Exception
* @return void
*/
public function validate(CommandData $commandData)
public function preCommandEvent(ConsoleCommandEvent $event)
{
$destination = $commandData->input()->getArgument('destination');
$source = $commandData->input()->getArgument('source');
$input = $event->getInput();
$this->sourceEvaluatedPath = $this->injectAliasPathParameterOptions($input, 'source');
$this->targetEvaluatedPath = $this->injectAliasPathParameterOptions($input, 'target');
}

protected function injectAliasPathParameterOptions($input, $parameterName)
{
// The Drush configuration object is a ConfigOverlay; fetch the alias
// context, that already has the options et. al. from the
// site-selection alias ('drush @site rsync ...'), @self.
$aliasConfigContext = $this->getConfig()->getContext(ConfigLocator::ALIAS_CONTEXT);
$manager = $this->siteAliasManager();
$this->sourceEvaluatedPath = HostPath::create($manager, $source);
$this->destinationEvaluatedPath = HostPath::create($manager, $destination);

$this->pathEvaluator->evaluate($this->sourceEvaluatedPath);
$this->pathEvaluator->evaluate($this->destinationEvaluatedPath);
$aliasName = $input->getArgument($parameterName);
$evaluatedPath = HostPath::create($manager, $aliasName);
$this->pathEvaluator->evaluate($evaluatedPath);

// Inject the source and target alias records into the alias config context.
$evaluatedPath->getAliasRecord()->injectIntoConfig($aliasConfigContext, $parameterName);

if ($this->sourceEvaluatedPath->isRemote() && $this->destinationEvaluatedPath->isRemote()) {
$msg = dt("Cannot specify two remote aliases. Instead, use one of the following alternate options:\n\n `drush {source} rsync @self {target}`\n `drush {source} rsync @self {fulltarget}\n\nUse the second form if the site alias definitions are not available at {source}.", array('source' => $source, 'target' => $destination, 'fulltarget' => $this->destinationEvaluatedPath->fullyQualifiedPath()));
return $evaluatedPath;
}

/**
* Validate that passed aliases are valid.
*
* @hook validate core-rsync
* @param \Consolidation\AnnotatedCommand\CommandData $commandData
* @throws \Exception
* @return void
*/
public function validate(CommandData $commandData)
{
if ($this->sourceEvaluatedPath->isRemote() && $this->targetEvaluatedPath->isRemote()) {
$msg = dt("Cannot specify two remote aliases. Instead, use one of the following alternate options:\n\n `drush {source} rsync @self {target}`\n `drush {source} rsync @self {fulltarget}\n\nUse the second form if the site alias definitions are not available at {source}.", array('source' => $source, 'target' => $target, 'fulltarget' => $this->targetEvaluatedPath->fullyQualifiedPath()));
throw new \Exception($msg);
}
}
Expand Down
Loading