Skip to content
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
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