/
ProcessManager.php
178 lines (156 loc) · 7.12 KB
/
ProcessManager.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
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
<?php
declare(strict_types=1);
namespace Drush\SiteAlias;
use Consolidation\SiteAlias\SiteAliasInterface;
use Consolidation\SiteProcess\ProcessBase;
use Consolidation\SiteProcess\ProcessManager as ConsolidationProcessManager;
use Consolidation\SiteProcess\SiteProcess;
use Drush\Drush;
use Drush\Style\DrushStyle;
use Symfony\Component\Filesystem\Path;
use Symfony\Component\Process\Process;
/**
* The Drush ProcessManager adds a few Drush-specific service methods.
*/
class ProcessManager extends ConsolidationProcessManager
{
protected $drupalFinder;
public function setDrupalFinder($drupalFinder): void
{
$this->drupalFinder = $drupalFinder;
}
public function getDrupalFinder()
{
return $this->drupalFinder;
}
/**
* Run a Drush command on a site alias (or @self).
*/
public function drush(SiteAliasInterface $siteAlias, string $command, array $args = [], array $options = [], array $options_double_dash = []): ProcessBase
{
array_unshift($args, $command);
return $this->drushSiteProcess($siteAlias, $args, $options, $options_double_dash);
}
/**
* drushSiteProcess should be avoided in favor of the drush method above.
*
* @internal drushSiteProcess exists specifically for use by the RedispatchHook,
* which does not have specific knowledge about which argument is the command.
*/
public function drushSiteProcess(SiteAliasInterface $siteAlias, array $args = [], array $options = [], array $options_double_dash = []): ProcessBase
{
$drushScript = $this->drushScript($siteAlias);
// Fill in the root and URI from the site alias, if the caller
// did not already provide them in $options.
if ($siteAlias->has('uri')) {
$options += [ 'uri' => $siteAlias->uri(), ];
}
// Include the --root parameter only if calling a global Drush.
// This is deprecated in Drush 12, and will be removed in Drush 13.
if ($siteAlias->hasRoot() && ($drushScript == "drush")) {
$options += [ 'root' => $siteAlias->root(), ];
}
// The executable is always 'drush' (at some path or another)
array_unshift($args, $drushScript);
return $this->siteProcess($siteAlias, $args, $options, $options_double_dash);
}
/**
* Determine the path to Drush to use
*/
public function drushScript(SiteAliasInterface $siteAlias)
{
$defaultDrushScript = 'drush';
// If the site alias has 'paths.drush-script', always use that.
if ($siteAlias->has('paths.drush-script')) {
return $siteAlias->get('paths.drush-script');
}
// A remote site / container et. al.,
if ($this->hasTransport($siteAlias)) {
if ($siteAlias->hasRoot()) {
return Path::join($siteAlias->root(), $this->relativePathToVendorBinDrush());
}
// Fallback to the 'drush' in the $PATH.
return $defaultDrushScript;
}
// If the target is a local Drupal site that has a vendor/bin/drush,
// then use that.
if ($siteAlias->hasRoot()) {
$localDrushScript = Path::join($siteAlias->root(), $this->relativePathToVendorBinDrush());
if (file_exists($localDrushScript)) {
return $localDrushScript;
}
}
// Otherwise, use the path to the version of Drush that is running
// right now (if available).
return $this->getConfig()->get('runtime.drush-script', $defaultDrushScript);
}
/**
* Return the relative path to 'vendor/bin/drush' from the Drupal root.
*/
protected function relativePathToVendorBinDrush()
{
// https://getcomposer.org/doc/articles/vendor-binaries.md#finding-the-composer-bin-dir-from-a-binary
$vendorBin = $GLOBALS['_composer_bin_dir'] ?? Path::join($this->getDrupalFinder()->getVendorDir(), 'bin');
$drupalRoot = $this->getDrupalFinder()->getDrupalRoot();
$relativeVendorBin = Path::makeRelative($vendorBin, $drupalRoot);
return Path::join($relativeVendorBin, 'drush');
}
/**
* @inheritdoc
*
* Use Drush::drush() or ProcessManager::drush() instead of this method
* when calling Drush.
*/
public function siteProcess(SiteAliasInterface $siteAlias, $args = [], $options = [], $optionsPassedAsArgs = []): ProcessBase
{
$process = parent::siteProcess($siteAlias, $args, $options, $optionsPassedAsArgs);
return $this->configureProcess($process);
}
/**
* Run a bash fragment locally.
*
* The timeout parameter on this method doesn't work. It exists for compatibility with parent.
* Call this method to get a Process and then call setters as needed.
*
* @param array $commandline The command line to run with arguments as separate items in an array
* @param string|null $cwd The working directory or null to use the working dir of the current PHP process
* @param array|null $env The environment variables or null to use the same environment as the current PHP process
* @param mixed|null $input The input as stream resource, scalar or \Traversable, or null for no input
* @param int|float|null $timeout The timeout in seconds or null to disable
*
* A wrapper around Symfony Process.
*/
public function process($commandline, $cwd = null, array $env = null, $input = null, $timeout = 60): ProcessBase
{
$process = parent::process($commandline, $cwd, $env, $input, $timeout);
return $this->configureProcess($process);
}
/**
* Create a Process instance from a commandline string.
* @param string $command The commandline string to run
* @param string|null $cwd The working directory or null to use the working dir of the current PHP process
* @param array|null $env The environment variables or null to use the same environment as the current PHP process
* @param mixed|null $input The input as stream resource, scalar or \Traversable, or null for no input
* @param int|float|null $timeout The timeout in seconds or null to disable
*/
public function shell($command, $cwd = null, array $env = null, $input = null, $timeout = 60): ProcessBase
{
$process = parent::shell($command, $cwd, $env, $input, $timeout);
return $this->configureProcess($process);
}
/**
* configureProcess sets up a process object so that it is ready to use.
*/
protected static function configureProcess(ProcessBase $process): ProcessBase
{
$process->setSimulated(Drush::simulate());
$process->setVerbose(Drush::verbose());
// Don't let sub-process inherit the verbosity of its parent https://github.com/symfony/console/blob/3.4/Application.php#L970-L972
putenv('SHELL_VERBOSITY');
unset($_ENV['SHELL_VERBOSITY'], $_SERVER['SHELL_VERBOSITY']);
$process->setLogger(Drush::logger());
$process->setRealtimeOutput(new DrushStyle(Drush::input(), Drush::output()));
$process->setTimeout(Drush::getTimeout());
return $process;
}
}