Something went wrong. Try again.
@recaptime-dev's working patches + fork for Phorge, a community fork of Phabricator. (Upstream dev and stable branches are at upstream/main and upstream/stable respectively.) hq.recaptime.dev/wiki/Phorge
phorge phabricator
Something went wrong. Try again.
8.0 kB · 311 lines
PHP
at commit 2f95330c
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312<?php
abstract class DiffusionCommandEngine extends Phobject {
private $repository; private $protocol; private $credentialPHID; private $argv; private $passthru; private $connectAsDevice; private $sudoAsDaemon; private $uri;
public static function newCommandEngine(PhabricatorRepository $repository) { $engines = self::newCommandEngines();
foreach ($engines as $engine) { if ($engine->canBuildForRepository($repository)) { return id(clone $engine) ->setRepository($repository); } }
throw new Exception( pht( 'No registered command engine can build commands for this '. 'repository ("%s").', $repository->getDisplayName())); }
private static function newCommandEngines() { return id(new PhutilClassMapQuery()) ->setAncestorClass(__CLASS__) ->execute(); }
abstract protected function canBuildForRepository( PhabricatorRepository $repository);
abstract protected function newFormattedCommand($pattern, array $argv); abstract protected function newCustomEnvironment();
public function setRepository(PhabricatorRepository $repository) { $this->repository = $repository; return $this; }
public function getRepository() { return $this->repository; }
public function setURI(PhutilURI $uri) { $this->uri = $uri; $this->setProtocol($uri->getProtocol()); return $this; }
public function getURI() { return $this->uri; }
public function setProtocol($protocol) { $this->protocol = $protocol; return $this; }
public function getProtocol() { return $this->protocol; }
public function getDisplayProtocol() { return $this->getProtocol().'://'; }
public function setCredentialPHID($credential_phid) { $this->credentialPHID = $credential_phid; return $this; }
public function getCredentialPHID() { return $this->credentialPHID; }
public function setArgv(array $argv) { $this->argv = $argv; return $this; }
public function getArgv() { return $this->argv; }
public function setPassthru($passthru) { $this->passthru = $passthru; return $this; }
public function getPassthru() { return $this->passthru; }
public function setConnectAsDevice($connect_as_device) { $this->connectAsDevice = $connect_as_device; return $this; }
public function getConnectAsDevice() { return $this->connectAsDevice; }
public function setSudoAsDaemon($sudo_as_daemon) { $this->sudoAsDaemon = $sudo_as_daemon; return $this; }
public function getSudoAsDaemon() { return $this->sudoAsDaemon; }
protected function shouldAlwaysSudo() { return false; }
public function newFuture() { $argv = $this->newCommandArgv(); $env = $this->newCommandEnvironment(); $is_passthru = $this->getPassthru();
if ($this->getSudoAsDaemon() || $this->shouldAlwaysSudo()) { $command = call_user_func_array('csprintf', $argv); $command = PhabricatorDaemon::sudoCommandAsDaemonUser($command); $argv = array('%C', $command); }
if ($is_passthru) { $future = newv('PhutilExecPassthru', $argv); } else { $future = newv('ExecFuture', $argv); }
$future->setEnv($env);
// See T13108. By default, don't let any cluster command run indefinitely // to try to avoid cases where `git fetch` hangs for some reason and we're // left sitting with a held lock forever. $repository = $this->getRepository(); if (!$is_passthru) { $future->setTimeout($repository->getEffectiveCopyTimeLimit()); }
return $future; }
private function newCommandArgv() { $argv = $this->argv; $pattern = $argv[0]; $argv = array_slice($argv, 1);
list($pattern, $argv) = $this->newFormattedCommand($pattern, $argv);
return array_merge(array($pattern), $argv); }
private function newCommandEnvironment() { $env = $this->newCommonEnvironment() + $this->newCustomEnvironment(); foreach ($env as $key => $value) { if ($value === null) { unset($env[$key]); } } return $env; }
private function newCommonEnvironment() { $repository = $this->getRepository();
$env = array(); // NOTE: Force the language to "en_US.UTF-8", which overrides locale // settings. This makes stuff print in English instead of, e.g., French, // so we can parse the output of some commands, error messages, etc. $env['LANG'] = 'en_US.UTF-8';
// Propagate PHABRICATOR_ENV explicitly. For discussion, see T4155. $env['PHABRICATOR_ENV'] = PhabricatorEnv::getSelectedEnvironmentName();
$as_device = $this->getConnectAsDevice(); $credential_phid = $this->getCredentialPHID();
if ($as_device) { $device = AlmanacKeys::getLiveDevice(); if (!$device) { throw new Exception( pht( 'Attempting to build a repository command (for repository "%s") '. 'as device, but this host ("%s") is not configured as a cluster '. 'device.', $repository->getDisplayName(), php_uname('n'))); }
if ($credential_phid) { throw new Exception( pht( 'Attempting to build a repository command (for repository "%s"), '. 'but the CommandEngine is configured to connect as both the '. 'current cluster device ("%s") and with a specific credential '. '("%s"). These options are mutually exclusive. Connections must '. 'authenticate as one or the other, not both.', $repository->getDisplayName(), $device->getName(), $credential_phid)); } }
if ($this->isAnySSHProtocol()) { if ($credential_phid) { $env['PHABRICATOR_CREDENTIAL'] = $credential_phid; } if ($as_device) { $env['PHABRICATOR_AS_DEVICE'] = 1; } }
$env += $repository->getPassthroughEnvironmentalVariables();
return $env; }
public function isSSHProtocol() { return ($this->getProtocol() == 'ssh'); }
public function isSVNProtocol() { return ($this->getProtocol() == 'svn'); }
public function isSVNSSHProtocol() { return ($this->getProtocol() == 'svn+ssh'); }
public function isHTTPProtocol() { return ($this->getProtocol() == 'http'); }
public function isHTTPSProtocol() { return ($this->getProtocol() == 'https'); }
public function isAnyHTTPProtocol() { return ($this->isHTTPProtocol() || $this->isHTTPSProtocol()); }
public function isAnySSHProtocol() { return ($this->isSSHProtocol() || $this->isSVNSSHProtocol()); }
public function isCredentialSupported() { return ($this->getPassphraseProvidesCredentialType() !== null); }
public function isCredentialOptional() { if ($this->isAnySSHProtocol()) { return false; }
return true; }
public function getPassphraseCredentialLabel() { if ($this->isAnySSHProtocol()) { return pht('SSH Key'); }
if ($this->isAnyHTTPProtocol() || $this->isSVNProtocol()) { return pht('Password'); }
return null; }
public function getPassphraseDefaultCredentialType() { if ($this->isAnySSHProtocol()) { return PassphraseSSHPrivateKeyTextCredentialType::CREDENTIAL_TYPE; }
if ($this->isAnyHTTPProtocol() || $this->isSVNProtocol()) { return PassphrasePasswordCredentialType::CREDENTIAL_TYPE; }
return null; }
public function getPassphraseProvidesCredentialType() { if ($this->isAnySSHProtocol()) { return PassphraseSSHPrivateKeyCredentialType::PROVIDES_TYPE; }
if ($this->isAnyHTTPProtocol() || $this->isSVNProtocol()) { return PassphrasePasswordCredentialType::PROVIDES_TYPE; }
return null; }
protected function getSSHWrapper() { $root = dirname(phutil_get_library_root('phabricator')); return $root.'/bin/ssh-connect'; }
}