Page MenuHomePhabricator

D15752.id37958.diff
No OneTemporary

D15752.id37958.diff

diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php
--- a/src/__phutil_library_map__.php
+++ b/src/__phutil_library_map__.php
@@ -570,6 +570,8 @@
'DiffusionCachedResolveRefsQuery' => 'applications/diffusion/query/DiffusionCachedResolveRefsQuery.php',
'DiffusionChangeController' => 'applications/diffusion/controller/DiffusionChangeController.php',
'DiffusionChangeHeraldFieldGroup' => 'applications/diffusion/herald/DiffusionChangeHeraldFieldGroup.php',
+ 'DiffusionCommandEngine' => 'applications/diffusion/protocol/DiffusionCommandEngine.php',
+ 'DiffusionCommandEngineTestCase' => 'applications/diffusion/protocol/__tests__/DiffusionCommandEngineTestCase.php',
'DiffusionCommitAffectedFilesHeraldField' => 'applications/diffusion/herald/DiffusionCommitAffectedFilesHeraldField.php',
'DiffusionCommitAuthorHeraldField' => 'applications/diffusion/herald/DiffusionCommitAuthorHeraldField.php',
'DiffusionCommitAutocloseHeraldField' => 'applications/diffusion/herald/DiffusionCommitAutocloseHeraldField.php',
@@ -634,6 +636,7 @@
'DiffusionGitBlameQuery' => 'applications/diffusion/query/blame/DiffusionGitBlameQuery.php',
'DiffusionGitBranch' => 'applications/diffusion/data/DiffusionGitBranch.php',
'DiffusionGitBranchTestCase' => 'applications/diffusion/data/__tests__/DiffusionGitBranchTestCase.php',
+ 'DiffusionGitCommandEngine' => 'applications/diffusion/protocol/DiffusionGitCommandEngine.php',
'DiffusionGitFileContentQuery' => 'applications/diffusion/query/filecontent/DiffusionGitFileContentQuery.php',
'DiffusionGitLFSAuthenticateWorkflow' => 'applications/diffusion/gitlfs/DiffusionGitLFSAuthenticateWorkflow.php',
'DiffusionGitLFSResponse' => 'applications/diffusion/response/DiffusionGitLFSResponse.php',
@@ -667,6 +670,7 @@
'DiffusionLowLevelQuery' => 'applications/diffusion/query/lowlevel/DiffusionLowLevelQuery.php',
'DiffusionLowLevelResolveRefsQuery' => 'applications/diffusion/query/lowlevel/DiffusionLowLevelResolveRefsQuery.php',
'DiffusionMercurialBlameQuery' => 'applications/diffusion/query/blame/DiffusionMercurialBlameQuery.php',
+ 'DiffusionMercurialCommandEngine' => 'applications/diffusion/protocol/DiffusionMercurialCommandEngine.php',
'DiffusionMercurialFileContentQuery' => 'applications/diffusion/query/filecontent/DiffusionMercurialFileContentQuery.php',
'DiffusionMercurialRawDiffQuery' => 'applications/diffusion/query/rawdiff/DiffusionMercurialRawDiffQuery.php',
'DiffusionMercurialRequest' => 'applications/diffusion/request/DiffusionMercurialRequest.php',
@@ -788,6 +792,7 @@
'DiffusionServeController' => 'applications/diffusion/controller/DiffusionServeController.php',
'DiffusionSetPasswordSettingsPanel' => 'applications/diffusion/panel/DiffusionSetPasswordSettingsPanel.php',
'DiffusionSetupException' => 'applications/diffusion/exception/DiffusionSetupException.php',
+ 'DiffusionSubversionCommandEngine' => 'applications/diffusion/protocol/DiffusionSubversionCommandEngine.php',
'DiffusionSubversionSSHWorkflow' => 'applications/diffusion/ssh/DiffusionSubversionSSHWorkflow.php',
'DiffusionSubversionServeSSHWorkflow' => 'applications/diffusion/ssh/DiffusionSubversionServeSSHWorkflow.php',
'DiffusionSubversionWireProtocol' => 'applications/diffusion/protocol/DiffusionSubversionWireProtocol.php',
@@ -4771,6 +4776,8 @@
'DiffusionCachedResolveRefsQuery' => 'DiffusionLowLevelQuery',
'DiffusionChangeController' => 'DiffusionController',
'DiffusionChangeHeraldFieldGroup' => 'HeraldFieldGroup',
+ 'DiffusionCommandEngine' => 'Phobject',
+ 'DiffusionCommandEngineTestCase' => 'PhabricatorTestCase',
'DiffusionCommitAffectedFilesHeraldField' => 'DiffusionCommitHeraldField',
'DiffusionCommitAuthorHeraldField' => 'DiffusionCommitHeraldField',
'DiffusionCommitAutocloseHeraldField' => 'DiffusionCommitHeraldField',
@@ -4835,6 +4842,7 @@
'DiffusionGitBlameQuery' => 'DiffusionBlameQuery',
'DiffusionGitBranch' => 'Phobject',
'DiffusionGitBranchTestCase' => 'PhabricatorTestCase',
+ 'DiffusionGitCommandEngine' => 'DiffusionCommandEngine',
'DiffusionGitFileContentQuery' => 'DiffusionFileContentQuery',
'DiffusionGitLFSAuthenticateWorkflow' => 'DiffusionGitSSHWorkflow',
'DiffusionGitLFSResponse' => 'AphrontResponse',
@@ -4868,6 +4876,7 @@
'DiffusionLowLevelQuery' => 'Phobject',
'DiffusionLowLevelResolveRefsQuery' => 'DiffusionLowLevelQuery',
'DiffusionMercurialBlameQuery' => 'DiffusionBlameQuery',
+ 'DiffusionMercurialCommandEngine' => 'DiffusionCommandEngine',
'DiffusionMercurialFileContentQuery' => 'DiffusionFileContentQuery',
'DiffusionMercurialRawDiffQuery' => 'DiffusionRawDiffQuery',
'DiffusionMercurialRequest' => 'DiffusionRequest',
@@ -4989,6 +4998,7 @@
'DiffusionServeController' => 'DiffusionController',
'DiffusionSetPasswordSettingsPanel' => 'PhabricatorSettingsPanel',
'DiffusionSetupException' => 'Exception',
+ 'DiffusionSubversionCommandEngine' => 'DiffusionCommandEngine',
'DiffusionSubversionSSHWorkflow' => 'DiffusionSSHWorkflow',
'DiffusionSubversionServeSSHWorkflow' => 'DiffusionSubversionSSHWorkflow',
'DiffusionSubversionWireProtocol' => 'Phobject',
diff --git a/src/applications/diffusion/conduit/DiffusionHistoryQueryConduitAPIMethod.php b/src/applications/diffusion/conduit/DiffusionHistoryQueryConduitAPIMethod.php
--- a/src/applications/diffusion/conduit/DiffusionHistoryQueryConduitAPIMethod.php
+++ b/src/applications/diffusion/conduit/DiffusionHistoryQueryConduitAPIMethod.php
@@ -131,7 +131,8 @@
hgsprintf('reverse(ancestors(%s))', $commit_hash),
$path_arg);
- $stdout = PhabricatorRepository::filterMercurialDebugOutput($stdout);
+ $stdout = DiffusionMercurialCommandEngine::filterMercurialDebugOutput(
+ $stdout);
$lines = explode("\n", trim($stdout));
$lines = array_slice($lines, $offset);
diff --git a/src/applications/diffusion/protocol/DiffusionCommandEngine.php b/src/applications/diffusion/protocol/DiffusionCommandEngine.php
new file mode 100644
--- /dev/null
+++ b/src/applications/diffusion/protocol/DiffusionCommandEngine.php
@@ -0,0 +1,173 @@
+<?php
+
+abstract class DiffusionCommandEngine extends Phobject {
+
+ private $repository;
+ private $protocol;
+ private $credentialPHID;
+ private $argv;
+ private $passthru;
+
+ 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 setProtocol($protocol) {
+ $this->protocol = $protocol;
+ return $this;
+ }
+
+ public function getProtocol() {
+ return $this->protocol;
+ }
+
+ 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 newFuture() {
+ $argv = $this->newCommandArgv();
+ $env = $this->newCommandEnvironment();
+
+ if ($this->getPassthru()) {
+ $future = newv('PhutilExecPassthru', $argv);
+ } else {
+ $future = newv('ExecFuture', $argv);
+ }
+
+ $future->setEnv($env);
+
+ 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() {
+ $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();
+
+ if ($this->isAnySSHProtocol()) {
+ $credential_phid = $this->getCredentialPHID();
+ if ($credential_phid) {
+ $env['PHABRICATOR_CREDENTIAL'] = $credential_phid;
+ }
+ }
+
+ return $env;
+ }
+
+ protected function isSSHProtocol() {
+ return ($this->getProtocol() == 'ssh');
+ }
+
+ protected function isSVNProtocol() {
+ return ($this->getProtocol() == 'svn');
+ }
+
+ protected function isSVNSSHProtocol() {
+ return ($this->getProtocol() == 'svn+ssh');
+ }
+
+ protected function isHTTPProtocol() {
+ return ($this->getProtocol() == 'http');
+ }
+
+ protected function isHTTPSProtocol() {
+ return ($this->getProtocol() == 'https');
+ }
+
+ protected function isAnyHTTPProtocol() {
+ return ($this->isHTTPProtocol() || $this->isHTTPSProtocol());
+ }
+
+ protected function isAnySSHProtocol() {
+ return ($this->isSSHProtocol() || $this->isSVNSSHProtocol());
+ }
+
+ protected function getSSHWrapper() {
+ $root = dirname(phutil_get_library_root('phabricator'));
+ return $root.'/bin/ssh-connect';
+ }
+
+}
diff --git a/src/applications/diffusion/protocol/DiffusionGitCommandEngine.php b/src/applications/diffusion/protocol/DiffusionGitCommandEngine.php
new file mode 100644
--- /dev/null
+++ b/src/applications/diffusion/protocol/DiffusionGitCommandEngine.php
@@ -0,0 +1,37 @@
+<?php
+
+final class DiffusionGitCommandEngine
+ extends DiffusionCommandEngine {
+
+ protected function canBuildForRepository(
+ PhabricatorRepository $repository) {
+ return $repository->isGit();
+ }
+
+ protected function newFormattedCommand($pattern, array $argv) {
+ $pattern = "git {$pattern}";
+ return array($pattern, $argv);
+ }
+
+ protected function newCustomEnvironment() {
+ $env = array();
+
+ // NOTE: See T2965. Some time after Git 1.7.5.4, Git started fataling if
+ // it can not read $HOME. For many users, $HOME points at /root (this
+ // seems to be a default result of Apache setup). Instead, explicitly
+ // point $HOME at a readable, empty directory so that Git looks for the
+ // config file it's after, fails to locate it, and moves on. This is
+ // really silly, but seems like the least damaging approach to
+ // mitigating the issue.
+
+ $root = dirname(phutil_get_library_root('phabricator'));
+ $env['HOME'] = $root.'/support/empty/';
+
+ if ($this->isAnySSHProtocol()) {
+ $env['GIT_SSH'] = $this->getSSHWrapper();
+ }
+
+ return $env;
+ }
+
+}
diff --git a/src/applications/diffusion/protocol/DiffusionMercurialCommandEngine.php b/src/applications/diffusion/protocol/DiffusionMercurialCommandEngine.php
new file mode 100644
--- /dev/null
+++ b/src/applications/diffusion/protocol/DiffusionMercurialCommandEngine.php
@@ -0,0 +1,70 @@
+<?php
+
+final class DiffusionMercurialCommandEngine
+ extends DiffusionCommandEngine {
+
+ protected function canBuildForRepository(
+ PhabricatorRepository $repository) {
+ return $repository->isHg();
+ }
+
+ protected function newFormattedCommand($pattern, array $argv) {
+ $args = array();
+
+ if ($this->isAnySSHProtocol()) {
+ $pattern = "hg --config ui.ssh=%s {$pattern}";
+ $args[] = $this->getSSHWrapper();
+ } else {
+ $pattern = "hg {$pattern}";
+ }
+
+ return array($pattern, array_merge($args, $argv));
+ }
+
+ protected function newCustomEnvironment() {
+ $env = array();
+
+ // NOTE: This overrides certain configuration, extensions, and settings
+ // which make Mercurial commands do random unusual things.
+ $env['HGPLAIN'] = 1;
+
+ return $env;
+ }
+
+ /**
+ * Sanitize output of an `hg` command invoked with the `--debug` flag to make
+ * it usable.
+ *
+ * @param string Output from `hg --debug ...`
+ * @return string Usable output.
+ */
+ public static function filterMercurialDebugOutput($stdout) {
+ // When hg commands are run with `--debug` and some config file isn't
+ // trusted, Mercurial prints out a warning to stdout, twice, after Feb 2011.
+ //
+ // http://selenic.com/pipermail/mercurial-devel/2011-February/028541.html
+ //
+ // After Jan 2015, it may also fail to write to a revision branch cache.
+
+ $ignore = array(
+ 'ignoring untrusted configuration option',
+ "couldn't write revision branch cache:",
+ );
+
+ foreach ($ignore as $key => $pattern) {
+ $ignore[$key] = preg_quote($pattern, '/');
+ }
+
+ $ignore = '('.implode('|', $ignore).')';
+
+ $lines = preg_split('/(?<=\n)/', $stdout);
+ $regex = '/'.$ignore.'.*\n$/';
+
+ foreach ($lines as $key => $line) {
+ $lines[$key] = preg_replace($regex, '', $line);
+ }
+
+ return implode('', $lines);
+ }
+
+}
diff --git a/src/applications/diffusion/protocol/DiffusionSubversionCommandEngine.php b/src/applications/diffusion/protocol/DiffusionSubversionCommandEngine.php
new file mode 100644
--- /dev/null
+++ b/src/applications/diffusion/protocol/DiffusionSubversionCommandEngine.php
@@ -0,0 +1,54 @@
+<?php
+
+final class DiffusionSubversionCommandEngine
+ extends DiffusionCommandEngine {
+
+ protected function canBuildForRepository(
+ PhabricatorRepository $repository) {
+ return $repository->isSVN();
+ }
+
+ protected function newFormattedCommand($pattern, array $argv) {
+ $flags = array();
+ $args = array();
+
+ $flags[] = '--non-interactive';
+
+ if ($this->isAnyHTTPProtocol() || $this->isSVNProtocol()) {
+ $flags[] = '--no-auth-cache';
+
+ if ($this->isAnyHTTPProtocol()) {
+ $flags[] = '--trust-server-cert';
+ }
+
+ $credential_phid = $this->getCredentialPHID();
+ if ($credential_phid) {
+ $key = PassphrasePasswordKey::loadFromPHID(
+ $credential_phid,
+ PhabricatorUser::getOmnipotentUser());
+
+ $flags[] = '--username %P';
+ $args[] = $key->getUsernameEnvelope();
+
+ $flags[] = '--password %P';
+ $args[] = $key->getPasswordEnvelope();
+ }
+ }
+
+ $flags = implode(' ', $flags);
+ $pattern = "svn {$flags} {$pattern}";
+
+ return array($pattern, array_merge($args, $argv));
+ }
+
+ protected function newCustomEnvironment() {
+ $env = array();
+
+ if ($this->isAnySSHProtocol()) {
+ $env['SVN_SSH'] = $this->getSSHWrapper();
+ }
+
+ return $env;
+ }
+
+}
diff --git a/src/applications/diffusion/protocol/__tests__/DiffusionCommandEngineTestCase.php b/src/applications/diffusion/protocol/__tests__/DiffusionCommandEngineTestCase.php
new file mode 100644
--- /dev/null
+++ b/src/applications/diffusion/protocol/__tests__/DiffusionCommandEngineTestCase.php
@@ -0,0 +1,155 @@
+<?php
+
+final class DiffusionCommandEngineTestCase extends PhabricatorTestCase {
+
+ public function testCommandEngine() {
+ $type_git = PhabricatorRepositoryType::REPOSITORY_TYPE_GIT;
+ $type_hg = PhabricatorRepositoryType::REPOSITORY_TYPE_MERCURIAL;
+ $type_svn = PhabricatorRepositoryType::REPOSITORY_TYPE_SVN;
+
+ $root = dirname(phutil_get_library_root('phabricator'));
+ $ssh_wrapper = $root.'/bin/ssh-connect';
+ $home = $root.'/support/empty/';
+
+
+ // Plain commands.
+
+ $this->assertCommandEngineFormat(
+ 'git xyz',
+ array(
+ 'LANG' => 'en_US.UTF-8',
+ 'HOME' => $home,
+ ),
+ array(
+ 'vcs' => $type_git,
+ 'argv' => 'xyz',
+ ));
+
+ $this->assertCommandEngineFormat(
+ 'hg xyz',
+ array(
+ 'LANG' => 'en_US.UTF-8',
+ 'HGPLAIN' => '1',
+ ),
+ array(
+ 'vcs' => $type_hg,
+ 'argv' => 'xyz',
+ ));
+
+ $this->assertCommandEngineFormat(
+ 'svn --non-interactive xyz',
+ array(
+ 'LANG' => 'en_US.UTF-8',
+ ),
+ array(
+ 'vcs' => $type_svn,
+ 'argv' => 'xyz',
+ ));
+
+
+ // Commands with SSH.
+
+ $this->assertCommandEngineFormat(
+ 'git xyz',
+ array(
+ 'LANG' => 'en_US.UTF-8',
+ 'HOME' => $home,
+ 'GIT_SSH' => $ssh_wrapper,
+ ),
+ array(
+ 'vcs' => $type_git,
+ 'argv' => 'xyz',
+ 'protocol' => 'ssh',
+ ));
+
+ $this->assertCommandEngineFormat(
+ (string)csprintf('hg --config ui.ssh=%s xyz', $ssh_wrapper),
+ array(
+ 'LANG' => 'en_US.UTF-8',
+ 'HGPLAIN' => '1',
+ ),
+ array(
+ 'vcs' => $type_hg,
+ 'argv' => 'xyz',
+ 'protocol' => 'ssh',
+ ));
+
+ $this->assertCommandEngineFormat(
+ 'svn --non-interactive xyz',
+ array(
+ 'LANG' => 'en_US.UTF-8',
+ 'SVN_SSH' => $ssh_wrapper,
+ ),
+ array(
+ 'vcs' => $type_svn,
+ 'argv' => 'xyz',
+ 'protocol' => 'ssh',
+ ));
+
+
+ // Commands with HTTP.
+
+ $this->assertCommandEngineFormat(
+ 'git xyz',
+ array(
+ 'LANG' => 'en_US.UTF-8',
+ 'HOME' => $home,
+ ),
+ array(
+ 'vcs' => $type_git,
+ 'argv' => 'xyz',
+ 'protocol' => 'https',
+ ));
+
+ $this->assertCommandEngineFormat(
+ 'hg xyz',
+ array(
+ 'LANG' => 'en_US.UTF-8',
+ 'HGPLAIN' => '1',
+ ),
+ array(
+ 'vcs' => $type_hg,
+ 'argv' => 'xyz',
+ 'protocol' => 'https',
+ ));
+
+ $this->assertCommandEngineFormat(
+ 'svn --non-interactive --no-auth-cache --trust-server-cert xyz',
+ array(
+ 'LANG' => 'en_US.UTF-8',
+ ),
+ array(
+ 'vcs' => $type_svn,
+ 'argv' => 'xyz',
+ 'protocol' => 'https',
+ ));
+ }
+
+ private function assertCommandEngineFormat(
+ $command,
+ array $env,
+ array $inputs) {
+
+ $repository = id(new PhabricatorRepository())
+ ->setVersionControlSystem($inputs['vcs']);
+
+ $future = DiffusionCommandEngine::newCommandEngine($repository)
+ ->setArgv((array)$inputs['argv'])
+ ->setProtocol(idx($inputs, 'protocol'))
+ ->newFuture();
+
+ $command_string = $future->getCommand();
+
+ $actual_command = $command_string->getUnmaskedString();
+ $this->assertEqual($command, $actual_command);
+
+ $actual_environment = $future->getEnv();
+
+ $compare_environment = array_select_keys(
+ $actual_environment,
+ array_keys($env));
+
+ $this->assertEqual($env, $compare_environment);
+ }
+
+}
diff --git a/src/applications/diffusion/query/lowlevel/DiffusionLowLevelParentsQuery.php b/src/applications/diffusion/query/lowlevel/DiffusionLowLevelParentsQuery.php
--- a/src/applications/diffusion/query/lowlevel/DiffusionLowLevelParentsQuery.php
+++ b/src/applications/diffusion/query/lowlevel/DiffusionLowLevelParentsQuery.php
@@ -50,7 +50,9 @@
list($stdout) = $repository->execxLocalCommand(
'log --debug --limit 1 --template={parents} --rev %s',
$this->identifier);
- $stdout = PhabricatorRepository::filterMercurialDebugOutput($stdout);
+
+ $stdout = DiffusionMercurialCommandEngine::filterMercurialDebugOutput(
+ $stdout);
$hashes = preg_split('/\s+/', trim($stdout));
foreach ($hashes as $key => $value) {
diff --git a/src/applications/repository/storage/PhabricatorRepository.php b/src/applications/repository/storage/PhabricatorRepository.php
--- a/src/applications/repository/storage/PhabricatorRepository.php
+++ b/src/applications/repository/storage/PhabricatorRepository.php
@@ -487,19 +487,22 @@
}
private function newRemoteCommandFuture(array $argv) {
- $argv = $this->formatRemoteCommand($argv);
- $future = newv('ExecFuture', $argv);
- $future->setEnv($this->getRemoteCommandEnvironment());
- return $future;
+ return $this->newRemoteCommandEngine($argv)
+ ->newFuture();
}
private function newRemoteCommandPassthru(array $argv) {
- $argv = $this->formatRemoteCommand($argv);
- $passthru = newv('PhutilExecPassthru', $argv);
- $passthru->setEnv($this->getRemoteCommandEnvironment());
- return $passthru;
+ return $this->newRemoteCommandEngine($argv)
+ ->setPassthru(true)
+ ->newFuture();
}
+ private function newRemoteCommandEngine(array $argv) {
+ return DiffusionCommandEngine::newCommandEngine($this)
+ ->setArgv($argv)
+ ->setCredentialPHID($this->getCredentialPHID())
+ ->setProtocol($this->getRemoteProtocol());
+ }
/* -( Local Command Execution )-------------------------------------------- */
@@ -527,9 +530,9 @@
private function newLocalCommandFuture(array $argv) {
$this->assertLocalExists();
- $argv = $this->formatLocalCommand($argv);
- $future = newv('ExecFuture', $argv);
- $future->setEnv($this->getLocalCommandEnvironment());
+ $future = DiffusionCommandEngine::newCommandEngine($this)
+ ->setArgv($argv)
+ ->newFuture();
if ($this->usesLocalWorkingCopy()) {
$future->setCWD($this->getLocalPath());
@@ -541,9 +544,10 @@
private function newLocalCommandPassthru(array $argv) {
$this->assertLocalExists();
- $argv = $this->formatLocalCommand($argv);
- $future = newv('PhutilExecPassthru', $argv);
- $future->setEnv($this->getLocalCommandEnvironment());
+ $future = DiffusionCommandEngine::newCommandEngine($this)
+ ->setArgv($argv)
+ ->setPassthru(true)
+ ->newFuture();
if ($this->usesLocalWorkingCopy()) {
$future->setCWD($this->getLocalPath());
@@ -552,199 +556,6 @@
return $future;
}
-
-/* -( Command Infrastructure )--------------------------------------------- */
-
-
- private function getSSHWrapper() {
- $root = dirname(phutil_get_library_root('phabricator'));
- return $root.'/bin/ssh-connect';
- }
-
- private function getCommonCommandEnvironment() {
- $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.
- 'LANG' => 'en_US.UTF-8',
-
- // Propagate PHABRICATOR_ENV explicitly. For discussion, see T4155.
- 'PHABRICATOR_ENV' => PhabricatorEnv::getSelectedEnvironmentName(),
- );
-
- switch ($this->getVersionControlSystem()) {
- case PhabricatorRepositoryType::REPOSITORY_TYPE_SVN:
- break;
- case PhabricatorRepositoryType::REPOSITORY_TYPE_GIT:
- // NOTE: See T2965. Some time after Git 1.7.5.4, Git started fataling if
- // it can not read $HOME. For many users, $HOME points at /root (this
- // seems to be a default result of Apache setup). Instead, explicitly
- // point $HOME at a readable, empty directory so that Git looks for the
- // config file it's after, fails to locate it, and moves on. This is
- // really silly, but seems like the least damaging approach to
- // mitigating the issue.
-
- $root = dirname(phutil_get_library_root('phabricator'));
- $env['HOME'] = $root.'/support/empty/';
- break;
- case PhabricatorRepositoryType::REPOSITORY_TYPE_MERCURIAL:
- // NOTE: This overrides certain configuration, extensions, and settings
- // which make Mercurial commands do random unusual things.
- $env['HGPLAIN'] = 1;
- break;
- default:
- throw new Exception(pht('Unrecognized version control system.'));
- }
-
- return $env;
- }
-
- private function getLocalCommandEnvironment() {
- return $this->getCommonCommandEnvironment();
- }
-
- private function getRemoteCommandEnvironment() {
- $env = $this->getCommonCommandEnvironment();
-
- if ($this->shouldUseSSH()) {
- // NOTE: This is read by `bin/ssh-connect`, and tells it which credentials
- // to use.
- $env['PHABRICATOR_CREDENTIAL'] = $this->getCredentialPHID();
- switch ($this->getVersionControlSystem()) {
- case PhabricatorRepositoryType::REPOSITORY_TYPE_SVN:
- // Force SVN to use `bin/ssh-connect`.
- $env['SVN_SSH'] = $this->getSSHWrapper();
- break;
- case PhabricatorRepositoryType::REPOSITORY_TYPE_GIT:
- // Force Git to use `bin/ssh-connect`.
- $env['GIT_SSH'] = $this->getSSHWrapper();
- break;
- case PhabricatorRepositoryType::REPOSITORY_TYPE_MERCURIAL:
- // We force Mercurial through `bin/ssh-connect` too, but it uses a
- // command-line flag instead of an environmental variable.
- break;
- default:
- throw new Exception(pht('Unrecognized version control system.'));
- }
- }
-
- return $env;
- }
-
- private function formatRemoteCommand(array $args) {
- $pattern = $args[0];
- $args = array_slice($args, 1);
-
- switch ($this->getVersionControlSystem()) {
- case PhabricatorRepositoryType::REPOSITORY_TYPE_SVN:
- if ($this->shouldUseHTTP() || $this->shouldUseSVNProtocol()) {
- $flags = array();
- $flag_args = array();
- $flags[] = '--non-interactive';
- $flags[] = '--no-auth-cache';
- if ($this->shouldUseHTTP()) {
- $flags[] = '--trust-server-cert';
- }
-
- $credential_phid = $this->getCredentialPHID();
- if ($credential_phid) {
- $key = PassphrasePasswordKey::loadFromPHID(
- $credential_phid,
- PhabricatorUser::getOmnipotentUser());
- $flags[] = '--username %P';
- $flags[] = '--password %P';
- $flag_args[] = $key->getUsernameEnvelope();
- $flag_args[] = $key->getPasswordEnvelope();
- }
-
- $flags = implode(' ', $flags);
- $pattern = "svn {$flags} {$pattern}";
- $args = array_mergev(array($flag_args, $args));
- } else {
- $pattern = "svn --non-interactive {$pattern}";
- }
- break;
- case PhabricatorRepositoryType::REPOSITORY_TYPE_GIT:
- $pattern = "git {$pattern}";
- break;
- case PhabricatorRepositoryType::REPOSITORY_TYPE_MERCURIAL:
- if ($this->shouldUseSSH()) {
- $pattern = "hg --config ui.ssh=%s {$pattern}";
- array_unshift(
- $args,
- $this->getSSHWrapper());
- } else {
- $pattern = "hg {$pattern}";
- }
- break;
- default:
- throw new Exception(pht('Unrecognized version control system.'));
- }
-
- array_unshift($args, $pattern);
-
- return $args;
- }
-
- private function formatLocalCommand(array $args) {
- $pattern = $args[0];
- $args = array_slice($args, 1);
-
- switch ($this->getVersionControlSystem()) {
- case PhabricatorRepositoryType::REPOSITORY_TYPE_SVN:
- $pattern = "svn --non-interactive {$pattern}";
- break;
- case PhabricatorRepositoryType::REPOSITORY_TYPE_GIT:
- $pattern = "git {$pattern}";
- break;
- case PhabricatorRepositoryType::REPOSITORY_TYPE_MERCURIAL:
- $pattern = "hg {$pattern}";
- break;
- default:
- throw new Exception(pht('Unrecognized version control system.'));
- }
-
- array_unshift($args, $pattern);
-
- return $args;
- }
-
- /**
- * Sanitize output of an `hg` command invoked with the `--debug` flag to make
- * it usable.
- *
- * @param string Output from `hg --debug ...`
- * @return string Usable output.
- */
- public static function filterMercurialDebugOutput($stdout) {
- // When hg commands are run with `--debug` and some config file isn't
- // trusted, Mercurial prints out a warning to stdout, twice, after Feb 2011.
- //
- // http://selenic.com/pipermail/mercurial-devel/2011-February/028541.html
- //
- // After Jan 2015, it may also fail to write to a revision branch cache.
-
- $ignore = array(
- 'ignoring untrusted configuration option',
- "couldn't write revision branch cache:",
- );
-
- foreach ($ignore as $key => $pattern) {
- $ignore[$key] = preg_quote($pattern, '/');
- }
-
- $ignore = '('.implode('|', $ignore).')';
-
- $lines = preg_split('/(?<=\n)/', $stdout);
- $regex = '/'.$ignore.'.*\n$/';
-
- foreach ($lines as $key => $line) {
- $lines[$key] = preg_replace($regex, '', $line);
- }
-
- return implode('', $lines);
- }
-
public function getURI() {
$callsign = $this->getCallsign();
if (strlen($callsign)) {
diff --git a/src/applications/repository/storage/__tests__/PhabricatorRepositoryTestCase.php b/src/applications/repository/storage/__tests__/PhabricatorRepositoryTestCase.php
--- a/src/applications/repository/storage/__tests__/PhabricatorRepositoryTestCase.php
+++ b/src/applications/repository/storage/__tests__/PhabricatorRepositoryTestCase.php
@@ -147,7 +147,8 @@
);
foreach ($map as $input => $expect) {
- $actual = PhabricatorRepository::filterMercurialDebugOutput($input);
+ $actual = DiffusionMercurialCommandEngine::filterMercurialDebugOutput(
+ $input);
$this->assertEqual($expect, $actual, $input);
}
}

File Metadata

Mime Type
text/plain
Expires
Mar 24 2025, 12:23 PM (4 w, 4 d ago)
Storage Engine
blob
Storage Format
Encrypted (AES-256-CBC)
Storage Handle
7228493
Default Alt Text
D15752.id37958.diff (29 KB)

Event Timeline