84d7890bd2bf664fdba306650a4a6fd03ad668cb
[yaffs-website] / vendor / drush / drush / src / Runtime / RedispatchHook.php
1 <?php
2
3 namespace Drush\Runtime;
4
5 use Consolidation\AnnotatedCommand\Hooks\InitializeHookInterface;
6 use Drush\Drush;
7 use Robo\Contract\ConfigAwareInterface;
8 use Symfony\Component\Console\Input\InputInterface;
9 use Consolidation\AnnotatedCommand\AnnotationData;
10 use Drush\Log\LogLevel;
11 use Robo\Common\ConfigAwareTrait;
12
13 /**
14  * The RedispatchHook is installed as an init hook that runs before
15  * all commands. If the commandline contains an alias or a site specification
16  * that points at a remote machine, then we will stop execution of the
17  * current command and instead run the command remotely.
18  */
19 class RedispatchHook implements InitializeHookInterface, ConfigAwareInterface
20 {
21     use ConfigAwareTrait;
22
23     /**
24      * Check to see if it is necessary to redispatch to a remote site.
25      * We do not redispatch to local sites here; usually, local sites may
26      * simply be selected and require no redispatch. When a local redispatch
27      * is needed, it happens in the RedispatchToSiteLocal class.
28      *
29      * @param InputInterface $input
30      * @param AnnotationData $annotationData
31      */
32     public function initialize(InputInterface $input, AnnotationData $annotationData)
33     {
34         // See drush_preflight_command_dispatch; also needed are:
35         //   - redispatch to a different site-local Drush on same system
36         //   - site-list handling (REMOVED)
37         // These redispatches need to be done regardless of the presence
38         // of a @handle-remote-commands annotation.
39
40         // If the command has the @handle-remote-commands annotation, then
41         // short-circuit redispatches to remote hosts.
42         if ($annotationData->has('handle-remote-commands')) {
43             return;
44         }
45         return $this->redispatchIfRemote($input);
46     }
47
48     /**
49      * Check to see if the target of the command is remote. Call redispatch
50      * if it is.
51      *
52      * @param InputInterface $input
53      */
54     public function redispatchIfRemote(InputInterface $input)
55     {
56         // Determine if this is a remote command.
57         // n.b. 'hasOption' only means that the option definition exists, so don't use that here.
58         $root = $input->getOption('remote-host');
59         if (!empty($root)) {
60             return $this->redispatch($input);
61         }
62     }
63
64     /**
65      * Called from RemoteCommandProxy::execute() to run remote commands.
66      *
67      * @param InputInterface $input
68      */
69     public function redispatch(InputInterface $input)
70     {
71         $remote_host = $input->getOption('remote-host');
72         $remote_user = $input->getOption('remote-user');
73
74         // Get the command arguments, and shift off the Drush command.
75         $redispatchArgs = Drush::config()->get('runtime.argv');
76         $drush_path = array_shift($redispatchArgs);
77         $command_name = array_shift($redispatchArgs);
78
79         Drush::logger()->debug('Redispatch hook {command}', ['command' => $command_name]);
80
81         // Remove argument patterns that should not be propagated
82         $redispatchArgs = $this->alterArgsForRedispatch($redispatchArgs);
83
84         // The options the user provided on the commandline will be included
85         // in $redispatchArgs.
86         $redispatchOptions = [];
87
88         // n.b. Defining the 'backend' flag here causes failed execution in the
89         // non-interactive case, even if 'backend' is set to 'false'.
90         $backend_options = [
91             'drush-script' => $this->getConfig()->get('paths.drush-script', null),
92             'remote-host' => $remote_host,
93             'remote-user' => $remote_user,
94             'additional-global-options' => [],
95             'interactive' => true,
96         ];
97         if ($input->isInteractive()) {
98             $backend_options['#tty'] = true;
99             $backend_options['interactive'] = true;
100         }
101
102         $invocations = [
103             [
104                 'command' => $command_name,
105                 'args' => $redispatchArgs,
106             ],
107         ];
108         $common_backend_options = [];
109         $default_command = null;
110         $default_site = [
111             'remote-host' => $remote_host,
112             'remote-user' => $remote_user,
113             'root' => $input->getOption('root'),
114             'uri' => $input->getOption('uri'),
115         ];
116         $context = null;
117
118         $values = drush_backend_invoke_concurrent(
119             $invocations,
120             $redispatchOptions,
121             $backend_options,
122             $default_command,
123             $default_site,
124             $context
125         );
126
127         return $this->exitEarly($values);
128     }
129
130     /**
131      * Remove anything that is not necessary for the remote side.
132      * At the moment this is limited to configuration options
133      * provided via -D.
134      *
135      * @param array $redispatchArgs
136      */
137     protected function alterArgsForRedispatch($redispatchArgs)
138     {
139         return array_filter($redispatchArgs, function ($item) {
140             return strpos($item, '-D') !== 0;
141         });
142     }
143
144     /**
145      * Abort the current execution without causing distress to our
146      * shutdown handler.
147      *
148      * @param array $values The results from backend invoke.
149      */
150     protected function exitEarly($values)
151     {
152         Drush::logger()->log(LogLevel::DEBUG, 'Redispatch hook exit early');
153
154         // TODO: This is how Drush exits from redispatch commands today;
155         // perhaps this could be somewhat improved, though.
156         // Note that RemoteCommandProxy::execute() is expecting that
157         // the redispatch() method will not return, so that will need
158         // to be altered if this behavior is changed.
159         drush_set_context('DRUSH_EXECUTION_COMPLETED', true);
160         exit($values['error_status']);
161     }
162 }