-
-
Notifications
You must be signed in to change notification settings - Fork 1.1k
/
RedispatchHook.php
139 lines (122 loc) · 4.87 KB
/
RedispatchHook.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
<?php
namespace Drush\Runtime;
use Consolidation\AnnotatedCommand\AnnotationData;
use Consolidation\AnnotatedCommand\Hooks\InitializeHookInterface;
use Consolidation\SiteAlias\SiteAlias;
use Consolidation\SiteAlias\SiteAliasManagerAwareInterface;
use Consolidation\SiteAlias\SiteAliasManagerAwareTrait;
use Consolidation\SiteProcess\ProcessManager;
use Consolidation\SiteProcess\Util\Tty;
use Drush\Drush;
use Drush\Log\LogLevel;
use Drush\Config\ConfigAwareTrait;
use Robo\Contract\ConfigAwareInterface;
use Symfony\Component\Console\Input\InputInterface;
use Drush\Utils\TerminalUtils;
/**
* The RedispatchHook is installed as an init hook that runs before
* all commands. If the commandline contains an alias or a site specification
* that points at a remote machine, then we will stop execution of the
* current command and instead run the command remotely.
*/
class RedispatchHook implements InitializeHookInterface, ConfigAwareInterface, SiteAliasManagerAwareInterface
{
use ConfigAwareTrait;
use SiteAliasManagerAwareTrait;
/** @var ProcessManager */
protected $processManager;
public function __construct(ProcessManager $processManager)
{
$this->processManager = $processManager;
}
/**
* Check to see if it is necessary to redispatch to a remote site.
* We do not redispatch to local sites here; usually, local sites may
* simply be selected and require no redispatch. When a local redispatch
* is needed, it happens in the RedispatchToSiteLocal class.
*
* @param InputInterface $input
* @param AnnotationData $annotationData
*/
public function initialize(InputInterface $input, AnnotationData $annotationData)
{
// See drush_preflight_command_dispatch; also needed are:
// - redispatch to a different site-local Drush on same system
// - site-list handling (REMOVED)
// These redispatches need to be done regardless of the presence
// of a @handle-remote-commands annotation.
// If the command has the @handle-remote-commands annotation, then
// short-circuit redispatches to remote hosts.
if ($annotationData->has('handle-remote-commands')) {
return;
}
return $this->redispatchIfRemote($input);
}
/**
* Check to see if the target of the command is remote. Call redispatch
* if it is.
*
* @param InputInterface $input
*/
public function redispatchIfRemote(InputInterface $input)
{
$aliasRecord = $this->siteAliasManager()->getSelf();
// Determine if this is a remote command.
if ($this->processManager->hasTransport($aliasRecord)) {
return $this->redispatch($input);
}
}
/**
* Called from RemoteCommandProxy::execute() to run remote commands.
*
* @param InputInterface $input
*/
public function redispatch(InputInterface $input)
{
// Get the command arguments, and shift off the Drush command.
$redispatchArgs = $this->getConfig()->get('runtime.argv');
$drush_path = array_shift($redispatchArgs);
$command_name = $this->getConfig()->get('runtime.command');
Drush::logger()->debug('Redispatch hook {command}', ['command' => $command_name]);
// Remove argument patterns that should not be propagated
$redispatchArgs = $this->alterArgsForRedispatch($redispatchArgs);
// The options the user provided on the commandline will be included
// in $redispatchArgs.
$redispatchOptions = [];
$aliasRecord = $this->siteAliasManager()->getSelf();
$process = $this->processManager->drushSiteProcess($aliasRecord, $redispatchArgs, $redispatchOptions);
if (!Tty::isTtySupported()) {
$process->setInput(STDIN);
} else {
$process->setTty($this->getConfig()->get('ssh.tty', $input->isInteractive()));
}
$process->mustRun($process->showRealtime());
return $this->exitEarly($process->getExitCode());
}
/**
* Remove anything that is not necessary for the remote side.
* At the moment this is limited to configuration options
* provided via -D.
*/
protected function alterArgsForRedispatch(array $redispatchArgs): array
{
return array_filter($redispatchArgs, function ($item) {
return strpos($item, '-D') !== 0;
});
}
/**
* Abort the current execution without causing distress to our
* shutdown handler.
*
* @param int $exit_code.
*/
protected function exitEarly(int $exit_code): void
{
Drush::logger()->debug('Redispatch hook exit early');
// Note that RemoteCommandProxy::execute() is expecting that
// the redispatch() method will not return, so that will need
// to be altered if this behavior is changed.
Runtime::setCompleted();
exit($exit_code);
}
}