Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/phabricator
Path: blob/master/src/applications/diffusion/protocol/DiffusionCommandEngine.php
12242 views
1
<?php
2
3
abstract class DiffusionCommandEngine extends Phobject {
4
5
private $repository;
6
private $protocol;
7
private $credentialPHID;
8
private $argv;
9
private $passthru;
10
private $connectAsDevice;
11
private $sudoAsDaemon;
12
private $uri;
13
14
public static function newCommandEngine(PhabricatorRepository $repository) {
15
$engines = self::newCommandEngines();
16
17
foreach ($engines as $engine) {
18
if ($engine->canBuildForRepository($repository)) {
19
return id(clone $engine)
20
->setRepository($repository);
21
}
22
}
23
24
throw new Exception(
25
pht(
26
'No registered command engine can build commands for this '.
27
'repository ("%s").',
28
$repository->getDisplayName()));
29
}
30
31
private static function newCommandEngines() {
32
return id(new PhutilClassMapQuery())
33
->setAncestorClass(__CLASS__)
34
->execute();
35
}
36
37
abstract protected function canBuildForRepository(
38
PhabricatorRepository $repository);
39
40
abstract protected function newFormattedCommand($pattern, array $argv);
41
abstract protected function newCustomEnvironment();
42
43
public function setRepository(PhabricatorRepository $repository) {
44
$this->repository = $repository;
45
return $this;
46
}
47
48
public function getRepository() {
49
return $this->repository;
50
}
51
52
public function setURI(PhutilURI $uri) {
53
$this->uri = $uri;
54
$this->setProtocol($uri->getProtocol());
55
return $this;
56
}
57
58
public function getURI() {
59
return $this->uri;
60
}
61
62
public function setProtocol($protocol) {
63
$this->protocol = $protocol;
64
return $this;
65
}
66
67
public function getProtocol() {
68
return $this->protocol;
69
}
70
71
public function getDisplayProtocol() {
72
return $this->getProtocol().'://';
73
}
74
75
public function setCredentialPHID($credential_phid) {
76
$this->credentialPHID = $credential_phid;
77
return $this;
78
}
79
80
public function getCredentialPHID() {
81
return $this->credentialPHID;
82
}
83
84
public function setArgv(array $argv) {
85
$this->argv = $argv;
86
return $this;
87
}
88
89
public function getArgv() {
90
return $this->argv;
91
}
92
93
public function setPassthru($passthru) {
94
$this->passthru = $passthru;
95
return $this;
96
}
97
98
public function getPassthru() {
99
return $this->passthru;
100
}
101
102
public function setConnectAsDevice($connect_as_device) {
103
$this->connectAsDevice = $connect_as_device;
104
return $this;
105
}
106
107
public function getConnectAsDevice() {
108
return $this->connectAsDevice;
109
}
110
111
public function setSudoAsDaemon($sudo_as_daemon) {
112
$this->sudoAsDaemon = $sudo_as_daemon;
113
return $this;
114
}
115
116
public function getSudoAsDaemon() {
117
return $this->sudoAsDaemon;
118
}
119
120
protected function shouldAlwaysSudo() {
121
return false;
122
}
123
124
public function newFuture() {
125
$argv = $this->newCommandArgv();
126
$env = $this->newCommandEnvironment();
127
$is_passthru = $this->getPassthru();
128
129
if ($this->getSudoAsDaemon() || $this->shouldAlwaysSudo()) {
130
$command = call_user_func_array('csprintf', $argv);
131
$command = PhabricatorDaemon::sudoCommandAsDaemonUser($command);
132
$argv = array('%C', $command);
133
}
134
135
if ($is_passthru) {
136
$future = newv('PhutilExecPassthru', $argv);
137
} else {
138
$future = newv('ExecFuture', $argv);
139
}
140
141
$future->setEnv($env);
142
143
// See T13108. By default, don't let any cluster command run indefinitely
144
// to try to avoid cases where `git fetch` hangs for some reason and we're
145
// left sitting with a held lock forever.
146
$repository = $this->getRepository();
147
if (!$is_passthru) {
148
$future->setTimeout($repository->getEffectiveCopyTimeLimit());
149
}
150
151
return $future;
152
}
153
154
private function newCommandArgv() {
155
$argv = $this->argv;
156
$pattern = $argv[0];
157
$argv = array_slice($argv, 1);
158
159
list($pattern, $argv) = $this->newFormattedCommand($pattern, $argv);
160
161
return array_merge(array($pattern), $argv);
162
}
163
164
private function newCommandEnvironment() {
165
$env = $this->newCommonEnvironment() + $this->newCustomEnvironment();
166
foreach ($env as $key => $value) {
167
if ($value === null) {
168
unset($env[$key]);
169
}
170
}
171
return $env;
172
}
173
174
private function newCommonEnvironment() {
175
$repository = $this->getRepository();
176
177
$env = array();
178
// NOTE: Force the language to "en_US.UTF-8", which overrides locale
179
// settings. This makes stuff print in English instead of, e.g., French,
180
// so we can parse the output of some commands, error messages, etc.
181
$env['LANG'] = 'en_US.UTF-8';
182
183
// Propagate PHABRICATOR_ENV explicitly. For discussion, see T4155.
184
$env['PHABRICATOR_ENV'] = PhabricatorEnv::getSelectedEnvironmentName();
185
186
$as_device = $this->getConnectAsDevice();
187
$credential_phid = $this->getCredentialPHID();
188
189
if ($as_device) {
190
$device = AlmanacKeys::getLiveDevice();
191
if (!$device) {
192
throw new Exception(
193
pht(
194
'Attempting to build a repository command (for repository "%s") '.
195
'as device, but this host ("%s") is not configured as a cluster '.
196
'device.',
197
$repository->getDisplayName(),
198
php_uname('n')));
199
}
200
201
if ($credential_phid) {
202
throw new Exception(
203
pht(
204
'Attempting to build a repository command (for repository "%s"), '.
205
'but the CommandEngine is configured to connect as both the '.
206
'current cluster device ("%s") and with a specific credential '.
207
'("%s"). These options are mutually exclusive. Connections must '.
208
'authenticate as one or the other, not both.',
209
$repository->getDisplayName(),
210
$device->getName(),
211
$credential_phid));
212
}
213
}
214
215
216
if ($this->isAnySSHProtocol()) {
217
if ($credential_phid) {
218
$env['PHABRICATOR_CREDENTIAL'] = $credential_phid;
219
}
220
if ($as_device) {
221
$env['PHABRICATOR_AS_DEVICE'] = 1;
222
}
223
}
224
225
$env += $repository->getPassthroughEnvironmentalVariables();
226
227
return $env;
228
}
229
230
public function isSSHProtocol() {
231
return ($this->getProtocol() == 'ssh');
232
}
233
234
public function isSVNProtocol() {
235
return ($this->getProtocol() == 'svn');
236
}
237
238
public function isSVNSSHProtocol() {
239
return ($this->getProtocol() == 'svn+ssh');
240
}
241
242
public function isHTTPProtocol() {
243
return ($this->getProtocol() == 'http');
244
}
245
246
public function isHTTPSProtocol() {
247
return ($this->getProtocol() == 'https');
248
}
249
250
public function isAnyHTTPProtocol() {
251
return ($this->isHTTPProtocol() || $this->isHTTPSProtocol());
252
}
253
254
public function isAnySSHProtocol() {
255
return ($this->isSSHProtocol() || $this->isSVNSSHProtocol());
256
}
257
258
public function isCredentialSupported() {
259
return ($this->getPassphraseProvidesCredentialType() !== null);
260
}
261
262
public function isCredentialOptional() {
263
if ($this->isAnySSHProtocol()) {
264
return false;
265
}
266
267
return true;
268
}
269
270
public function getPassphraseCredentialLabel() {
271
if ($this->isAnySSHProtocol()) {
272
return pht('SSH Key');
273
}
274
275
if ($this->isAnyHTTPProtocol() || $this->isSVNProtocol()) {
276
return pht('Password');
277
}
278
279
return null;
280
}
281
282
public function getPassphraseDefaultCredentialType() {
283
if ($this->isAnySSHProtocol()) {
284
return PassphraseSSHPrivateKeyTextCredentialType::CREDENTIAL_TYPE;
285
}
286
287
if ($this->isAnyHTTPProtocol() || $this->isSVNProtocol()) {
288
return PassphrasePasswordCredentialType::CREDENTIAL_TYPE;
289
}
290
291
return null;
292
}
293
294
public function getPassphraseProvidesCredentialType() {
295
if ($this->isAnySSHProtocol()) {
296
return PassphraseSSHPrivateKeyCredentialType::PROVIDES_TYPE;
297
}
298
299
if ($this->isAnyHTTPProtocol() || $this->isSVNProtocol()) {
300
return PassphrasePasswordCredentialType::PROVIDES_TYPE;
301
}
302
303
return null;
304
}
305
306
protected function getSSHWrapper() {
307
$root = dirname(phutil_get_library_root('phabricator'));
308
return $root.'/bin/ssh-connect';
309
}
310
311
}
312
313