Page MenuHomestyx hydra

No OneTemporary

diff --git a/src/applications/repository/storage/PhabricatorRepository.php b/src/applications/repository/storage/PhabricatorRepository.php
index 2257777b61..d82ec3b5bc 100644
--- a/src/applications/repository/storage/PhabricatorRepository.php
+++ b/src/applications/repository/storage/PhabricatorRepository.php
@@ -1,479 +1,549 @@
<?php
/*
* Copyright 2012 Facebook, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+/**
+ * @task uri Repository URI Management
+ */
final class PhabricatorRepository extends PhabricatorRepositoryDAO {
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';
protected $phid;
protected $name;
protected $callsign;
protected $uuid;
protected $versionControlSystem;
protected $details = array();
private $sshKeyfile;
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(
PhabricatorPHIDConstants::PHID_TYPE_REPO);
}
public function getDetail($key, $default = null) {
return idx($this->details, $key, $default);
}
public function setDetail($key, $value) {
$this->details[$key] = $value;
return $this;
}
public function getDiffusionBrowseURIForPath($path) {
$drequest = DiffusionRequest::newFromDictionary(
array(
'repository' => $this,
'path' => $path,
));
return $drequest->generateURI(
array(
'action' => 'browse',
));
}
- public function getRemoteURI() {
- $raw_uri = $this->getDetail('remote-uri');
- if (!$raw_uri) {
- return null;
- }
-
- if (strpos($raw_uri, '/') === 0) {
- // If the URI starts with a '/', it's an implicit file:// URI on the
- // local disk.
- $uri = new PhutilURI('file://'.$raw_uri);
- return (string)$uri;
- }
-
- $uri = new PhutilURI($raw_uri);
- if ($uri->getProtocol()) {
- if ($this->isSSHProtocol($uri->getProtocol())) {
- if ($this->getSSHLogin()) {
- $uri->setUser($this->getSSHLogin());
- }
- }
- return (string)$uri;
- }
-
- $uri = new PhutilGitURI($raw_uri);
- if ($uri->getDomain()) {
- if ($this->getSSHLogin()) {
- $uri->setUser($this->getSSHLogin());
- }
- return (string)$uri;
- }
-
- throw new Exception(
- "Repository remote URI '{$raw_uri}' could not be parsed!");
- }
-
public function getLocalPath() {
return $this->getDetail('local-path');
}
public function execRemoteCommand($pattern /* , $arg, ... */) {
$args = func_get_args();
$args = $this->formatRemoteCommand($args);
return call_user_func_array('exec_manual', $args);
}
public function execxRemoteCommand($pattern /* , $arg, ... */) {
$args = func_get_args();
$args = $this->formatRemoteCommand($args);
return call_user_func_array('execx', $args);
}
public function getRemoteCommandFuture($pattern /* , $arg, ... */) {
$args = func_get_args();
$args = $this->formatRemoteCommand($args);
return newv('ExecFuture', $args);
}
public function passthruRemoteCommand($pattern /* , $arg, ... */) {
$args = func_get_args();
$args = $this->formatRemoteCommand($args);
return call_user_func_array('phutil_passthru', $args);
}
public function execLocalCommand($pattern /* , $arg, ... */) {
$args = func_get_args();
$args = $this->formatLocalCommand($args);
return call_user_func_array('exec_manual', $args);
}
public function execxLocalCommand($pattern /* , $arg, ... */) {
$args = func_get_args();
$args = $this->formatLocalCommand($args);
return call_user_func_array('execx', $args);
}
public function getLocalCommandFuture($pattern /* , $arg, ... */) {
$args = func_get_args();
$args = $this->formatLocalCommand($args);
return newv('ExecFuture', $args);
}
public function passthruLocalCommand($pattern /* , $arg, ... */) {
$args = func_get_args();
$args = $this->formatLocalCommand($args);
return call_user_func_array('phutil_passthru', $args);
}
private function formatRemoteCommand(array $args) {
$pattern = $args[0];
$args = array_slice($args, 1);
if ($this->shouldUseSSH()) {
switch ($this->getVersionControlSystem()) {
case PhabricatorRepositoryType::REPOSITORY_TYPE_SVN:
$pattern = "SVN_SSH=%s svn --non-interactive {$pattern}";
array_unshift(
$args,
csprintf(
'ssh -l %s -i %s',
$this->getSSHLogin(),
$this->getSSHKeyfile()));
break;
case PhabricatorRepositoryType::REPOSITORY_TYPE_GIT:
$command = call_user_func_array(
'csprintf',
array_merge(
array(
"(ssh-add %s && git {$pattern})",
$this->getSSHKeyfile(),
),
$args));
$pattern = "ssh-agent sh -c %s";
$args = array($command);
break;
case PhabricatorRepositoryType::REPOSITORY_TYPE_MERCURIAL:
$pattern = "hg --config ui.ssh=%s {$pattern}";
array_unshift(
$args,
csprintf(
'ssh -l %s -i %s',
$this->getSSHLogin(),
$this->getSSHKeyfile()));
break;
default:
throw new Exception("Unrecognized version control system.");
}
} else if ($this->shouldUseHTTP()) {
switch ($this->getVersionControlSystem()) {
case PhabricatorRepositoryType::REPOSITORY_TYPE_SVN:
$pattern =
"svn ".
"--non-interactive ".
"--no-auth-cache ".
"--trust-server-cert ".
"--username %s ".
"--password %s ".
$pattern;
array_unshift(
$args,
$this->getDetail('http-login'),
$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 %s ".
"--password %s ".
$pattern;
array_unshift(
$args,
$this->getDetail('http-login'),
$this->getDetail('http-pass'));
break;
default:
throw new Exception(
"SVN protocol is SVN only.");
}
} else {
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("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 = "(cd %s && svn --non-interactive {$pattern})";
array_unshift($args, $this->getLocalPath());
break;
case PhabricatorRepositoryType::REPOSITORY_TYPE_GIT:
$pattern = "(cd %s && git {$pattern})";
array_unshift($args, $this->getLocalPath());
break;
case PhabricatorRepositoryType::REPOSITORY_TYPE_MERCURIAL:
$pattern = "(cd %s && HGPLAIN=1 hg {$pattern})";
array_unshift($args, $this->getLocalPath());
break;
default:
throw new Exception("Unrecognized version control system.");
}
array_unshift($args, $pattern);
return $args;
}
private 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 shouldUseSSH() {
- $uri = new PhutilURI($this->getRemoteURI());
- $protocol = $uri->getProtocol();
- if ($this->isSSHProtocol($protocol)) {
- return (bool)$this->getSSHKeyfile();
- } else {
- return false;
- }
- }
-
- public function shouldUseHTTP() {
- $uri = new PhutilURI($this->getRemoteURI());
- $protocol = $uri->getProtocol();
- if ($this->isHTTPProtocol($protocol)) {
- return (bool)$this->getDetail('http-login');
- } else {
- return false;
- }
- }
-
- public function shouldUseSVNProtocol() {
- $uri = new PhutilURI($this->getRemoteURI());
- $protocol = $uri->getProtocol();
- if ($this->isSVNProtocol($protocol)) {
- return (bool)$this->getDetail('http-login');
- } else {
- return false;
- }
- }
-
-
- public function getPublicRemoteURI() {
- $uri = new PhutilURI($this->getRemoteURI());
-
- // 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.
- $uri->setUser(null);
- $uri->setPass(null);
-
- return $uri;
- }
-
public function getURI() {
return '/diffusion/'.$this->getCallsign().'/';
}
- private function isSSHProtocol($protocol) {
- return ($protocol == 'ssh' || $protocol == 'svn+ssh');
- }
-
- private function isHTTPProtocol($protocol) {
- return ($protocol == 'http' || $protocol == 'https');
- }
-
- private function isSVNProtocol($protocol) {
- return ($protocol == 'svn');
- }
-
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());
}
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->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 static function loadAllByPHIDOrCallsign(array $names) {
$repositories = array();
foreach ($names as $name) {
$repo = id(new PhabricatorRepository())->loadOneWhere(
'phid = %s OR callsign = %s',
$name,
$name);
if (!$repo) {
throw new Exception(
"No repository with PHID or callsign '{$name}' exists!");
}
$repositories[$repo->getID()] = $repo;
}
return $repositories;
}
+/* -( 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->getURIObject();
+
+ // 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) {
+ $uri->setUser(null);
+ } else {
+ $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:PhutilURI}) or a git URI
+ * (returned as a @{class:PhutilGitURI}).
+ *
+ * @return wild A @{class:PhutilURI} or @{class:PhutilGitURI}.
+ * @task uri
+ */
+ private 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() {
+ $protocol = $this->getRemoteProtocol();
+ if ($this->isSSHProtocol($protocol)) {
+ return (bool)$this->getSSHKeyfile();
+ } else {
+ 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() {
+ $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() {
+ $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');
+ }
+
}
diff --git a/src/applications/repository/storage/__tests__/PhabricatorRepositoryTestCase.php b/src/applications/repository/storage/__tests__/PhabricatorRepositoryTestCase.php
index 6b8d3672b0..7456ed92e4 100644
--- a/src/applications/repository/storage/__tests__/PhabricatorRepositoryTestCase.php
+++ b/src/applications/repository/storage/__tests__/PhabricatorRepositoryTestCase.php
@@ -1,50 +1,74 @@
<?php
/*
* Copyright 2012 Facebook, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
final class PhabricatorRepositoryTestCase
extends PhabricatorTestCase {
+ public function testRepositoryURIProtocols() {
+ $tests = array(
+ '/path/to/repo' => 'file',
+ 'file:///path/to/repo' => 'file',
+ 'ssh://user@domain.com/path' => 'ssh',
+ 'git@example.com:path' => 'ssh',
+ 'git://git@example.com/path' => 'git',
+ 'svn+ssh://example.com/path' => 'svn+ssh',
+ 'https://example.com/repo/' => 'https',
+ 'http://example.com/' => 'http',
+ 'https://user@example.com/' => 'https',
+ );
+
+ foreach ($tests as $uri => $expect) {
+ $repository = new PhabricatorRepository();
+ $repository->setDetail('remote-uri', $uri);
+
+ $this->assertEqual(
+ $expect,
+ $repository->getRemoteProtocol(),
+ "Protocol for '{$uri}'.");
+ }
+ }
+
public function testBranchFilter() {
$git = PhabricatorRepositoryType::REPOSITORY_TYPE_GIT;
$repo = new PhabricatorRepository();
$repo->setVersionControlSystem($git);
$this->assertEqual(
true,
$repo->shouldTrackBranch('imaginary'),
'Track all branches by default.');
$repo->setDetail(
'branch-filter',
array(
'master' => true,
));
$this->assertEqual(
true,
$repo->shouldTrackBranch('master'),
'Track listed branches.');
$this->assertEqual(
false,
$repo->shouldTrackBranch('imaginary'),
'Do not track unlisted branches.');
}
}

File Metadata

Mime Type
text/x-diff
Expires
Sun, Jul 27, 3:52 PM (1 w, 7 h ago)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
185966
Default Alt Text
(20 KB)

Event Timeline