Page MenuHomestyx hydra

No OneTemporary

diff --git a/bin/ssh-connect b/bin/ssh-connect
new file mode 120000
index 0000000000..79f7c94d03
--- /dev/null
+++ b/bin/ssh-connect
@@ -0,0 +1 @@
+../scripts/ssh/ssh-connect.php
\ No newline at end of file
diff --git a/scripts/ssh/ssh-connect.php b/scripts/ssh/ssh-connect.php
new file mode 100755
index 0000000000..2f28778565
--- /dev/null
+++ b/scripts/ssh/ssh-connect.php
@@ -0,0 +1,71 @@
+#!/usr/bin/env php
+<?php
+
+// This is a wrapper script for Git, Mercurial, and Subversion. It primarily
+// serves to inject "-o StrictHostKeyChecking=no" into the SSH arguments.
+
+$root = dirname(dirname(dirname(__FILE__)));
+require_once $root.'/scripts/__init_script__.php';
+
+$target_name = getenv('PHABRICATOR_SSH_TARGET');
+if (!$target_name) {
+ throw new Exception(pht("No 'PHABRICATOR_SSH_TARGET' in environment!"));
+}
+
+$repository = id(new PhabricatorRepositoryQuery())
+ ->setViewer(PhabricatorUser::getOmnipotentUser())
+ ->withCallsigns(array($target_name))
+ ->executeOne();
+if (!$repository) {
+ throw new Exception(pht('No repository with callsign "%s"!', $target_name));
+}
+
+$pattern = array();
+$arguments = array();
+
+$pattern[] = 'ssh';
+
+$pattern[] = '-o';
+$pattern[] = 'StrictHostKeyChecking=no';
+
+$login = $repository->getSSHLogin();
+if (strlen($login)) {
+ $pattern[] = '-l';
+ $pattern[] = '%P';
+ $arguments[] = new PhutilOpaqueEnvelope($login);
+}
+
+$ssh_identity = null;
+
+$key = $repository->getDetail('ssh-key');
+$keyfile = $repository->getDetail('ssh-keyfile');
+if ($keyfile) {
+ $ssh_identity = $keyfile;
+} else if ($key) {
+ $tmpfile = new TempFile('phabricator-repository-ssh-key');
+ chmod($tmpfile, 0600);
+ Filesystem::writeFile($tmpfile, $key);
+ $ssh_identity = (string)$tmpfile;
+}
+
+if ($ssh_identity) {
+ $pattern[] = '-i';
+ $pattern[] = '%P';
+ $arguments[] = new PhutilOpaqueEnvelope($keyfile);
+}
+
+$pattern[] = '--';
+
+$passthru_args = array_slice($argv, 1);
+foreach ($passthru_args as $passthru_arg) {
+ $pattern[] = '%s';
+ $arguments[] = $passthru_arg;
+}
+
+$pattern = implode(' ', $pattern);
+array_unshift($arguments, $pattern);
+
+$err = newv('PhutilExecPassthru', $arguments)
+ ->execute();
+
+exit($err);
diff --git a/src/applications/repository/storage/PhabricatorRepository.php b/src/applications/repository/storage/PhabricatorRepository.php
index b2df31969e..859c9eff7d 100644
--- a/src/applications/repository/storage/PhabricatorRepository.php
+++ b/src/applications/repository/storage/PhabricatorRepository.php
@@ -1,975 +1,1004 @@
<?php
/**
* @task uri Repository URI Management
*/
final class PhabricatorRepository extends PhabricatorRepositoryDAO
implements
PhabricatorPolicyInterface,
PhabricatorFlaggableInterface,
PhabricatorMarkupInterface {
/**
* Shortest hash we'll recognize in raw "a829f32" form.
*/
const MINIMUM_UNQUALIFIED_HASH = 7;
/**
* Shortest hash we'll recognize in qualified "rXab7ef2f8" form.
*/
const MINIMUM_QUALIFIED_HASH = 5;
const TABLE_PATH = 'repository_path';
const TABLE_PATHCHANGE = 'repository_pathchange';
const TABLE_FILESYSTEM = 'repository_filesystem';
const TABLE_SUMMARY = 'repository_summary';
const TABLE_BADCOMMIT = 'repository_badcommit';
const TABLE_LINTMESSAGE = 'repository_lintmessage';
const SERVE_OFF = 'off';
const SERVE_READONLY = 'readonly';
const SERVE_READWRITE = 'readwrite';
protected $name;
protected $callsign;
protected $uuid;
protected $viewPolicy;
protected $editPolicy;
protected $pushPolicy;
protected $versionControlSystem;
protected $details = array();
private $sshKeyfile;
private $commitCount = self::ATTACHABLE;
private $mostRecentCommit = self::ATTACHABLE;
public static function initializeNewRepository(PhabricatorUser $actor) {
$app = id(new PhabricatorApplicationQuery())
->setViewer($actor)
->withClasses(array('PhabricatorApplicationDiffusion'))
->executeOne();
$view_policy = $app->getPolicy(DiffusionCapabilityDefaultView::CAPABILITY);
$edit_policy = $app->getPolicy(DiffusionCapabilityDefaultEdit::CAPABILITY);
$push_policy = $app->getPolicy(DiffusionCapabilityDefaultPush::CAPABILITY);
return id(new PhabricatorRepository())
->setViewPolicy($view_policy)
->setEditPolicy($edit_policy)
->setPushPolicy($push_policy);
}
public function getConfiguration() {
return array(
self::CONFIG_AUX_PHID => true,
self::CONFIG_SERIALIZATION => array(
'details' => self::SERIALIZATION_JSON,
),
) + parent::getConfiguration();
}
public function generatePHID() {
return PhabricatorPHID::generateNewPHID(
PhabricatorRepositoryPHIDTypeRepository::TYPECONST);
}
public function toDictionary() {
return array(
'name' => $this->getName(),
'phid' => $this->getPHID(),
'callsign' => $this->getCallsign(),
'vcs' => $this->getVersionControlSystem(),
'uri' => PhabricatorEnv::getProductionURI($this->getURI()),
'remoteURI' => (string)$this->getPublicRemoteURI(),
'tracking' => $this->getDetail('tracking-enabled'),
'description' => $this->getDetail('description'),
);
}
public function getDetail($key, $default = null) {
return idx($this->details, $key, $default);
}
public function getHumanReadableDetail($key, $default = null) {
$value = $this->getDetail($key, $default);
switch ($key) {
case 'branch-filter':
case 'close-commits-filter':
$value = array_keys($value);
$value = implode(', ', $value);
break;
}
return $value;
}
public function setDetail($key, $value) {
$this->details[$key] = $value;
return $this;
}
public function attachCommitCount($count) {
$this->commitCount = $count;
return $this;
}
public function getCommitCount() {
return $this->assertAttached($this->commitCount);
}
public function attachMostRecentCommit(
PhabricatorRepositoryCommit $commit = null) {
$this->mostRecentCommit = $commit;
return $this;
}
public function getMostRecentCommit() {
return $this->assertAttached($this->mostRecentCommit);
}
public function getDiffusionBrowseURIForPath(
PhabricatorUser $user,
$path,
$line = null,
$branch = null) {
$drequest = DiffusionRequest::newFromDictionary(
array(
'user' => $user,
'repository' => $this,
'path' => $path,
'branch' => $branch,
));
return $drequest->generateURI(
array(
'action' => 'browse',
'line' => $line,
));
}
public function getLocalPath() {
return $this->getDetail('local-path');
}
public function getSubversionBaseURI() {
$subpath = $this->getDetail('svn-subpath');
if (!strlen($subpath)) {
$subpath = null;
}
return $this->getSubversionPathURI($subpath);
}
public function getSubversionPathURI($path = null, $commit = null) {
$vcs = $this->getVersionControlSystem();
if ($vcs != PhabricatorRepositoryType::REPOSITORY_TYPE_SVN) {
throw new Exception("Not a subversion repository!");
}
if ($this->isHosted()) {
$uri = 'file://'.$this->getLocalPath();
} else {
$uri = $this->getDetail('remote-uri');
}
$uri = rtrim($uri, '/');
if (strlen($path)) {
$path = rawurlencode($path);
$path = str_replace('%2F', '/', $path);
$uri = $uri.'/'.ltrim($path, '/');
}
if ($path !== null || $commit !== null) {
$uri .= '@';
}
if ($commit !== null) {
$uri .= $commit;
}
return $uri;
}
+
+/* -( Remote Command Execution )------------------------------------------- */
+
+
public function execRemoteCommand($pattern /* , $arg, ... */) {
$args = func_get_args();
- $args = $this->formatRemoteCommand($args);
- return call_user_func_array('exec_manual', $args);
+ return $this->newRemoteCommandFuture($args)->resolve();
}
public function execxRemoteCommand($pattern /* , $arg, ... */) {
$args = func_get_args();
- $args = $this->formatRemoteCommand($args);
- return call_user_func_array('execx', $args);
+ return $this->newRemoteCommandFuture($args)->resolvex();
}
public function getRemoteCommandFuture($pattern /* , $arg, ... */) {
$args = func_get_args();
- $args = $this->formatRemoteCommand($args);
- return newv('ExecFuture', $args);
+ return $this->newRemoteCommandFuture($args);
}
public function passthruRemoteCommand($pattern /* , $arg, ... */) {
$args = func_get_args();
- $args = $this->formatRemoteCommand($args);
- return call_user_func_array('phutil_passthru', $args);
+ return $this->newRemoteCommandPassthru($args)->execute();
+ }
+
+ private function newRemoteCommandFuture(array $argv) {
+ $argv = $this->formatRemoteCommand($argv);
+ $future = newv('ExecFuture', $argv);
+ $future->setEnv($this->getRemoteCommandEnvironment());
+ return $future;
+ }
+
+ private function newRemoteCommandPassthru(array $argv) {
+ $argv = $this->formatRemoteCommand($argv);
+ $passthru = newv('PhutilExecPassthru', $argv);
+ $passthru->setEnv($this->getRemoteCommandEnvironment());
+ return $passthru;
}
- public function execLocalCommand($pattern /* , $arg, ... */) {
- $this->assertLocalExists();
+/* -( Local Command Execution )-------------------------------------------- */
+
+
+ public function execLocalCommand($pattern /* , $arg, ... */) {
$args = func_get_args();
- $args = $this->formatLocalCommand($args);
- return call_user_func_array('exec_manual', $args);
+ return $this->newLocalCommandFuture($args)->resolve();
}
public function execxLocalCommand($pattern /* , $arg, ... */) {
- $this->assertLocalExists();
-
$args = func_get_args();
- $args = $this->formatLocalCommand($args);
- return call_user_func_array('execx', $args);
+ return $this->newLocalCommandFuture($args)->resolvex();
}
public function getLocalCommandFuture($pattern /* , $arg, ... */) {
- $this->assertLocalExists();
-
$args = func_get_args();
- $args = $this->formatLocalCommand($args);
- return newv('ExecFuture', $args);
+ return $this->newLocalCommandFuture($args);
}
public function passthruLocalCommand($pattern /* , $arg, ... */) {
+ $args = func_get_args();
+ return $this->newLocalCommandPassthru($args)->execute();
+ }
+
+ private function newLocalCommandFuture(array $argv) {
$this->assertLocalExists();
- $args = func_get_args();
- $args = $this->formatLocalCommand($args);
- return call_user_func_array('phutil_passthru', $args);
+ $argv = $this->formatLocalCommand($argv);
+ $future = newv('ExecFuture', $argv);
+ $future->setEnv($this->getLocalCommandEnvironment());
+
+ if ($this->usesLocalWorkingCopy()) {
+ $future->setCWD($this->getLocalPath());
+ }
+
+ return $future;
}
+ private function newLocalCommandPassthru(array $argv) {
+ $this->assertLocalExists();
+
+ $argv = $this->formatLocalCommand($argv);
+ $future = newv('PhutilExecPassthru', $argv);
+ $future->setEnv($this->getLocalCommandEnvironment());
+
+ if ($this->usesLocalWorkingCopy()) {
+ $future->setCWD($this->getLocalPath());
+ }
+
+ return $future;
+ }
- private function formatRemoteCommand(array $args) {
- $pattern = $args[0];
- $args = array_slice($args, 1);
- $empty = $this->getEmptyReadableDirectoryPath();
+/* -( 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 "C", 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' => 'C',
+ );
+
+ 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("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_SSH_TARGET'] = $this->getCallsign();
switch ($this->getVersionControlSystem()) {
case PhabricatorRepositoryType::REPOSITORY_TYPE_SVN:
- $pattern = "SVN_SSH=%s svn --non-interactive {$pattern}";
- array_unshift(
- $args,
- csprintf(
- 'ssh -l %P -i %P',
- new PhutilOpaqueEnvelope($this->getSSHLogin()),
- new PhutilOpaqueEnvelope($this->getSSHKeyfile())));
+ // Force SVN to use `bin/ssh-connect`.
+ $env['SVN_SSH'] = $this->getSSHWrapper();
break;
case PhabricatorRepositoryType::REPOSITORY_TYPE_GIT:
- $command = call_user_func_array(
- 'csprintf',
- array_merge(
- array(
- "(ssh-add %P && HOME=%s git {$pattern})",
- new PhutilOpaqueEnvelope($this->getSSHKeyfile()),
- $empty,
- ),
- $args));
- $pattern = "ssh-agent sh -c %s";
- $args = array($command);
+ // Force Git to use `bin/ssh-connect`.
+ $env['GIT_SSH'] = $this->getSSHWrapper();
break;
case PhabricatorRepositoryType::REPOSITORY_TYPE_MERCURIAL:
- $pattern = "hg --config ui.ssh=%s {$pattern}";
- array_unshift(
- $args,
- csprintf(
- 'ssh -l %P -i %P',
- new PhutilOpaqueEnvelope($this->getSSHLogin()),
- new PhutilOpaqueEnvelope($this->getSSHKeyfile())));
+ // 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("Unrecognized version control system.");
}
- } else if ($this->shouldUseHTTP()) {
- switch ($this->getVersionControlSystem()) {
- case PhabricatorRepositoryType::REPOSITORY_TYPE_SVN:
+ }
+
+ 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()) {
$pattern =
"svn ".
"--non-interactive ".
"--no-auth-cache ".
"--trust-server-cert ".
"--username %P ".
"--password %P ".
$pattern;
array_unshift(
$args,
new PhutilOpaqueEnvelope($this->getDetail('http-login')),
new PhutilOpaqueEnvelope($this->getDetail('http-pass')));
- break;
- default:
- throw new Exception(
- "No support for HTTP Basic Auth in this version control system.");
- }
- } else if ($this->shouldUseSVNProtocol()) {
- switch ($this->getVersionControlSystem()) {
- case PhabricatorRepositoryType::REPOSITORY_TYPE_SVN:
- $pattern =
- "svn ".
- "--non-interactive ".
- "--no-auth-cache ".
- "--username %P ".
- "--password %P ".
- $pattern;
- array_unshift(
- $args,
- new PhutilOpaqueEnvelope($this->getDetail('http-login')),
- new PhutilOpaqueEnvelope($this->getDetail('http-pass')));
- break;
- default:
- throw new Exception(
- "SVN protocol is SVN only.");
- }
- } else {
- switch ($this->getVersionControlSystem()) {
- case PhabricatorRepositoryType::REPOSITORY_TYPE_SVN:
+ } else if ($this->shouldUseSVNProtocol()) {
+ $pattern =
+ "svn ".
+ "--non-interactive ".
+ "--no-auth-cache ".
+ "--username %P ".
+ "--password %P ".
+ $pattern;
+ array_unshift(
+ $args,
+ new PhutilOpaqueEnvelope($this->getDetail('http-login')),
+ new PhutilOpaqueEnvelope($this->getDetail('http-pass')));
+ } else {
$pattern = "svn --non-interactive {$pattern}";
- break;
- case PhabricatorRepositoryType::REPOSITORY_TYPE_GIT:
- $pattern = "HOME=%s git {$pattern}";
- array_unshift($args, $empty);
- break;
- case PhabricatorRepositoryType::REPOSITORY_TYPE_MERCURIAL:
+ }
+ 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("Unrecognized version control system.");
- }
+ }
+ break;
+ default:
+ throw new Exception("Unrecognized version control system.");
}
array_unshift($args, $pattern);
return $args;
}
private function formatLocalCommand(array $args) {
$pattern = $args[0];
$args = array_slice($args, 1);
- $empty = $this->getEmptyReadableDirectoryPath();
-
switch ($this->getVersionControlSystem()) {
case PhabricatorRepositoryType::REPOSITORY_TYPE_SVN:
- $pattern = "(cd %s && svn --non-interactive {$pattern})";
- array_unshift($args, $this->getLocalPath());
+ $pattern = "svn --non-interactive {$pattern}";
break;
case PhabricatorRepositoryType::REPOSITORY_TYPE_GIT:
- $pattern = "(cd %s && HOME=%s git {$pattern})";
- array_unshift($args, $this->getLocalPath(), $empty);
+ $pattern = "git {$pattern}";
break;
case PhabricatorRepositoryType::REPOSITORY_TYPE_MERCURIAL:
- $hgplain = (phutil_is_windows() ? "set HGPLAIN=1 &&" : "HGPLAIN=1");
- $pattern = "(cd %s && {$hgplain} hg {$pattern})";
- array_unshift($args, $this->getLocalPath());
+ $pattern = "hg {$pattern}";
break;
default:
throw new Exception("Unrecognized version control system.");
}
array_unshift($args, $pattern);
return $args;
}
- private function getEmptyReadableDirectoryPath() {
- // 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'));
- return $root.'/support/empty/';
- }
-
- private function getSSHLogin() {
+ public function getSSHLogin() {
return $this->getDetail('ssh-login');
}
- private function getSSHKeyfile() {
- if ($this->sshKeyfile === null) {
- $key = $this->getDetail('ssh-key');
- $keyfile = $this->getDetail('ssh-keyfile');
- if ($keyfile) {
- // Make sure we can read the file, that it exists, etc.
- Filesystem::readFile($keyfile);
- $this->sshKeyfile = $keyfile;
- } else if ($key) {
- $keyfile = new TempFile('phabricator-repository-ssh-key');
- chmod($keyfile, 0600);
- Filesystem::writeFile($keyfile, $key);
- $this->sshKeyfile = $keyfile;
- } else {
- $this->sshKeyfile = '';
- }
- }
-
- return (string)$this->sshKeyfile;
- }
-
public function getURI() {
return '/diffusion/'.$this->getCallsign().'/';
}
public function isTracked() {
return $this->getDetail('tracking-enabled', false);
}
public function getDefaultBranch() {
$default = $this->getDetail('default-branch');
if (strlen($default)) {
return $default;
}
$default_branches = array(
PhabricatorRepositoryType::REPOSITORY_TYPE_GIT => 'master',
PhabricatorRepositoryType::REPOSITORY_TYPE_MERCURIAL => 'default',
);
return idx($default_branches, $this->getVersionControlSystem());
}
public function getDefaultArcanistBranch() {
return coalesce($this->getDefaultBranch(), 'svn');
}
private function isBranchInFilter($branch, $filter_key) {
$vcs = $this->getVersionControlSystem();
$is_git = ($vcs == PhabricatorRepositoryType::REPOSITORY_TYPE_GIT);
$use_filter = ($is_git);
if ($use_filter) {
$filter = $this->getDetail($filter_key, array());
if ($filter && empty($filter[$branch])) {
return false;
}
}
// By default, all branches pass.
return true;
}
public function shouldTrackBranch($branch) {
return $this->isBranchInFilter($branch, 'branch-filter');
}
public function shouldAutocloseBranch($branch) {
if ($this->isImporting()) {
return false;
}
if ($this->getDetail('disable-autoclose', false)) {
return false;
}
return $this->isBranchInFilter($branch, 'close-commits-filter');
}
public function shouldAutocloseCommit(
PhabricatorRepositoryCommit $commit,
PhabricatorRepositoryCommitData $data) {
if ($this->getDetail('disable-autoclose', false)) {
return false;
}
switch ($this->getVersionControlSystem()) {
case PhabricatorRepositoryType::REPOSITORY_TYPE_SVN:
return true;
case PhabricatorRepositoryType::REPOSITORY_TYPE_GIT:
break;
case PhabricatorRepositoryType::REPOSITORY_TYPE_MERCURIAL:
return true;
default:
throw new Exception("Unrecognized version control system.");
}
$branches = $data->getCommitDetail('seenOnBranches', array());
foreach ($branches as $branch) {
if ($this->shouldAutocloseBranch($branch)) {
return true;
}
}
return false;
}
public function formatCommitName($commit_identifier) {
$vcs = $this->getVersionControlSystem();
$type_git = PhabricatorRepositoryType::REPOSITORY_TYPE_GIT;
$type_hg = PhabricatorRepositoryType::REPOSITORY_TYPE_MERCURIAL;
$is_git = ($vcs == $type_git);
$is_hg = ($vcs == $type_hg);
if ($is_git || $is_hg) {
$short_identifier = substr($commit_identifier, 0, 12);
} else {
$short_identifier = $commit_identifier;
}
return 'r'.$this->getCallsign().$short_identifier;
}
public function isImporting() {
return (bool)$this->getDetail('importing', false);
}
/* -( Repository URI Management )------------------------------------------ */
/**
* Get the remote URI for this repository.
*
* @return string
* @task uri
*/
public function getRemoteURI() {
return (string)$this->getRemoteURIObject();
}
/**
* Get the remote URI for this repository, without authentication information.
*
* @return string Repository URI.
* @task uri
*/
public function getPublicRemoteURI() {
$uri = $this->getRemoteURIObject();
// Make sure we don't leak anything if this repo is using HTTP Basic Auth
// with the credentials in the URI or something zany like that.
if ($uri instanceof PhutilGitURI) {
if (!$this->getDetail('show-user', false)) {
$uri->setUser(null);
}
} else {
if (!$this->getDetail('show-user', false)) {
$uri->setUser(null);
}
$uri->setPass(null);
}
return (string)$uri;
}
/**
* Get the protocol for the repository's remote.
*
* @return string Protocol, like "ssh" or "git".
* @task uri
*/
public function getRemoteProtocol() {
$uri = $this->getRemoteURIObject();
if ($uri instanceof PhutilGitURI) {
return 'ssh';
} else {
return $uri->getProtocol();
}
}
/**
* Get a parsed object representation of the repository's remote URI. This
* may be a normal URI (returned as a @{class@libphutil:PhutilURI}) or a git
* URI (returned as a @{class@libphutil:PhutilGitURI}).
*
* @return wild A @{class@libphutil:PhutilURI} or
* @{class@libphutil:PhutilGitURI}.
* @task uri
*/
public function getRemoteURIObject() {
$raw_uri = $this->getDetail('remote-uri');
if (!$raw_uri) {
return new PhutilURI('');
}
if (!strncmp($raw_uri, '/', 1)) {
return new PhutilURI('file://'.$raw_uri);
}
$uri = new PhutilURI($raw_uri);
if ($uri->getProtocol()) {
if ($this->isSSHProtocol($uri->getProtocol())) {
if ($this->getSSHLogin()) {
$uri->setUser($this->getSSHLogin());
}
}
return $uri;
}
$uri = new PhutilGitURI($raw_uri);
if ($uri->getDomain()) {
if ($this->getSSHLogin()) {
$uri->setUser($this->getSSHLogin());
}
return $uri;
}
throw new Exception("Remote URI '{$raw_uri}' could not be parsed!");
}
/**
* Determine if we should connect to the remote using SSH flags and
* credentials.
*
* @return bool True to use the SSH protocol.
* @task uri
*/
private function shouldUseSSH() {
if ($this->isHosted()) {
return false;
}
$protocol = $this->getRemoteProtocol();
if ($this->isSSHProtocol($protocol)) {
- return (bool)$this->getSSHKeyfile();
- } else {
- return false;
+ $key = $this->getDetail('ssh-key');
+ $keyfile = $this->getDetail('ssh-keyfile');
+ if ($key || $keyfile) {
+ return true;
+ }
}
+
+ return false;
}
/**
* Determine if we should connect to the remote using HTTP flags and
* credentials.
*
* @return bool True to use the HTTP protocol.
* @task uri
*/
private function shouldUseHTTP() {
if ($this->isHosted()) {
return false;
}
$protocol = $this->getRemoteProtocol();
if ($protocol == 'http' || $protocol == 'https') {
return (bool)$this->getDetail('http-login');
} else {
return false;
}
}
/**
* Determine if we should connect to the remote using SVN flags and
* credentials.
*
* @return bool True to use the SVN protocol.
* @task uri
*/
private function shouldUseSVNProtocol() {
if ($this->isHosted()) {
return false;
}
$protocol = $this->getRemoteProtocol();
if ($protocol == 'svn') {
return (bool)$this->getDetail('http-login');
} else {
return false;
}
}
/**
* Determine if a protocol is SSH or SSH-like.
*
* @param string A protocol string, like "http" or "ssh".
* @return bool True if the protocol is SSH-like.
* @task uri
*/
private function isSSHProtocol($protocol) {
return ($protocol == 'ssh' || $protocol == 'svn+ssh');
}
public function delete() {
$this->openTransaction();
$paths = id(new PhabricatorOwnersPath())
->loadAllWhere('repositoryPHID = %s', $this->getPHID());
foreach ($paths as $path) {
$path->delete();
}
$projects = id(new PhabricatorRepositoryArcanistProject())
->loadAllWhere('repositoryID = %d', $this->getID());
foreach ($projects as $project) {
// note each project deletes its PhabricatorRepositorySymbols
$project->delete();
}
$commits = id(new PhabricatorRepositoryCommit())
->loadAllWhere('repositoryID = %d', $this->getID());
foreach ($commits as $commit) {
// note PhabricatorRepositoryAuditRequests and
// PhabricatorRepositoryCommitData are deleted here too.
$commit->delete();
}
$conn_w = $this->establishConnection('w');
queryfx(
$conn_w,
'DELETE FROM %T WHERE repositoryID = %d',
self::TABLE_FILESYSTEM,
$this->getID());
queryfx(
$conn_w,
'DELETE FROM %T WHERE repositoryID = %d',
self::TABLE_PATHCHANGE,
$this->getID());
queryfx(
$conn_w,
'DELETE FROM %T WHERE repositoryID = %d',
self::TABLE_SUMMARY,
$this->getID());
$result = parent::delete();
$this->saveTransaction();
return $result;
}
public function isGit() {
$vcs = $this->getVersionControlSystem();
return ($vcs == PhabricatorRepositoryType::REPOSITORY_TYPE_GIT);
}
public function isSVN() {
$vcs = $this->getVersionControlSystem();
return ($vcs == PhabricatorRepositoryType::REPOSITORY_TYPE_SVN);
}
public function isHg() {
$vcs = $this->getVersionControlSystem();
return ($vcs == PhabricatorRepositoryType::REPOSITORY_TYPE_MERCURIAL);
}
public function isHosted() {
return (bool)$this->getDetail('hosting-enabled', false);
}
public function setHosted($enabled) {
return $this->setDetail('hosting-enabled', $enabled);
}
public function getServeOverHTTP() {
if ($this->isSVN()) {
return self::SERVE_OFF;
}
$serve = $this->getDetail('serve-over-http', self::SERVE_OFF);
return $this->normalizeServeConfigSetting($serve);
}
public function setServeOverHTTP($mode) {
return $this->setDetail('serve-over-http', $mode);
}
public function getServeOverSSH() {
$serve = $this->getDetail('serve-over-ssh', self::SERVE_OFF);
return $this->normalizeServeConfigSetting($serve);
}
public function setServeOverSSH($mode) {
return $this->setDetail('serve-over-ssh', $mode);
}
public static function getProtocolAvailabilityName($constant) {
switch ($constant) {
case self::SERVE_OFF:
return pht('Off');
case self::SERVE_READONLY:
return pht('Read Only');
case self::SERVE_READWRITE:
return pht('Read/Write');
default:
return pht('Unknown');
}
}
private function normalizeServeConfigSetting($value) {
switch ($value) {
case self::SERVE_OFF:
case self::SERVE_READONLY:
return $value;
case self::SERVE_READWRITE:
if ($this->isHosted()) {
return self::SERVE_READWRITE;
} else {
return self::SERVE_READONLY;
}
default:
return self::SERVE_OFF;
}
}
/**
* Raise more useful errors when there are basic filesystem problems.
*/
private function assertLocalExists() {
if (!$this->usesLocalWorkingCopy()) {
return;
}
$local = $this->getLocalPath();
Filesystem::assertExists($local);
Filesystem::assertIsDirectory($local);
Filesystem::assertReadable($local);
}
/**
* Determine if the working copy is bare or not. In Git, this corresponds
* to `--bare`. In Mercurial, `--noupdate`.
*/
public function isWorkingCopyBare() {
switch ($this->getVersionControlSystem()) {
case PhabricatorRepositoryType::REPOSITORY_TYPE_SVN:
case PhabricatorRepositoryType::REPOSITORY_TYPE_MERCURIAL:
return false;
case PhabricatorRepositoryType::REPOSITORY_TYPE_GIT:
$local = $this->getLocalPath();
if (Filesystem::pathExists($local.'/.git')) {
return false;
} else {
return true;
}
}
}
public function usesLocalWorkingCopy() {
switch ($this->getVersionControlSystem()) {
case PhabricatorRepositoryType::REPOSITORY_TYPE_SVN:
return $this->isHosted();
case PhabricatorRepositoryType::REPOSITORY_TYPE_GIT:
case PhabricatorRepositoryType::REPOSITORY_TYPE_MERCURIAL:
return true;
}
}
public function writeStatusMessage(
$status_type,
$status_code,
array $parameters = array()) {
$table = new PhabricatorRepositoryStatusMessage();
$conn_w = $table->establishConnection('w');
$table_name = $table->getTableName();
if ($status_code === null) {
queryfx(
$conn_w,
'DELETE FROM %T WHERE repositoryID = %d AND statusType = %s',
$table_name,
$this->getID(),
$status_type);
} else {
queryfx(
$conn_w,
'INSERT INTO %T
(repositoryID, statusType, statusCode, parameters, epoch)
VALUES (%d, %s, %s, %s, %d)
ON DUPLICATE KEY UPDATE
statusCode = VALUES(statusCode),
parameters = VALUES(parameters),
epoch = VALUES(epoch)',
$table_name,
$this->getID(),
$status_type,
$status_code,
json_encode($parameters),
time());
}
return $this;
}
/* -( PhabricatorPolicyInterface )----------------------------------------- */
public function getCapabilities() {
return array(
PhabricatorPolicyCapability::CAN_VIEW,
PhabricatorPolicyCapability::CAN_EDIT,
DiffusionCapabilityPush::CAPABILITY,
);
}
public function getPolicy($capability) {
switch ($capability) {
case PhabricatorPolicyCapability::CAN_VIEW:
return $this->getViewPolicy();
case PhabricatorPolicyCapability::CAN_EDIT:
return $this->getEditPolicy();
case DiffusionCapabilityPush::CAPABILITY:
return $this->getPushPolicy();
}
}
public function hasAutomaticCapability($capability, PhabricatorUser $user) {
return false;
}
public function describeAutomaticCapability($capability) {
return null;
}
/* -( PhabricatorMarkupInterface )----------------------------------------- */
public function getMarkupFieldKey($field) {
$hash = PhabricatorHash::digestForIndex($this->getMarkupText($field));
return "repo:{$hash}";
}
public function newMarkupEngine($field) {
return PhabricatorMarkupEngine::newMarkupEngine(array());
}
public function getMarkupText($field) {
return $this->getDetail('description');
}
public function didMarkupText(
$field,
$output,
PhutilMarkupEngine $engine) {
require_celerity_resource('phabricator-remarkup-css');
return phutil_tag(
'div',
array(
'class' => 'phabricator-remarkup',
),
$output);
}
public function shouldUseMarkupCache($field) {
return true;
}
}

File Metadata

Mime Type
text/x-diff
Expires
Fri, Oct 31, 8:11 AM (14 h, 15 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
312062
Default Alt Text
(35 KB)

Event Timeline