Page MenuHomestyx hydra

No OneTemporary

diff --git a/src/applications/config/check/PhabricatorBinariesSetupCheck.php b/src/applications/config/check/PhabricatorBinariesSetupCheck.php
index cf3c87f480..5b8f93346c 100644
--- a/src/applications/config/check/PhabricatorBinariesSetupCheck.php
+++ b/src/applications/config/check/PhabricatorBinariesSetupCheck.php
@@ -1,263 +1,257 @@
<?php
final class PhabricatorBinariesSetupCheck extends PhabricatorSetupCheck {
public function getDefaultGroup() {
return self::GROUP_OTHER;
}
protected function executeChecks() {
if (phutil_is_windows()) {
$bin_name = 'where';
} else {
$bin_name = 'which';
}
if (!Filesystem::binaryExists($bin_name)) {
$message = pht(
"Without '%s', Phabricator can not test for the availability ".
"of other binaries.",
$bin_name);
$this->raiseWarning($bin_name, $message);
// We need to return here if we can't find the 'which' / 'where' binary
// because the other tests won't be valid.
return;
}
if (!Filesystem::binaryExists('diff')) {
$message = pht(
"Without '%s', Phabricator will not be able to generate or render ".
"diffs in multiple applications.",
'diff');
$this->raiseWarning('diff', $message);
} else {
$tmp_a = new TempFile();
$tmp_b = new TempFile();
$tmp_c = new TempFile();
Filesystem::writeFile($tmp_a, 'A');
Filesystem::writeFile($tmp_b, 'A');
Filesystem::writeFile($tmp_c, 'B');
list($err) = exec_manual('diff %s %s', $tmp_a, $tmp_b);
if ($err) {
$this->newIssue('bin.diff.same')
->setName(pht("Unexpected '%s' Behavior", 'diff'))
->setMessage(
pht(
"The '%s' binary on this system has unexpected behavior: ".
"it was expected to exit without an error code when passed ".
"identical files, but exited with code %d.",
'diff',
$err));
}
list($err) = exec_manual('diff %s %s', $tmp_a, $tmp_c);
if (!$err) {
$this->newIssue('bin.diff.diff')
->setName(pht("Unexpected 'diff' Behavior"))
->setMessage(
pht(
"The '%s' binary on this system has unexpected behavior: ".
"it was expected to exit with a nonzero error code when passed ".
"differing files, but did not.",
'diff'));
}
}
$table = new PhabricatorRepository();
$vcses = queryfx_all(
$table->establishConnection('r'),
'SELECT DISTINCT versionControlSystem FROM %T',
$table->getTableName());
foreach ($vcses as $vcs) {
switch ($vcs['versionControlSystem']) {
case PhabricatorRepositoryType::REPOSITORY_TYPE_GIT:
$binary = 'git';
break;
case PhabricatorRepositoryType::REPOSITORY_TYPE_SVN:
$binary = 'svn';
break;
case PhabricatorRepositoryType::REPOSITORY_TYPE_MERCURIAL:
$binary = 'hg';
break;
default:
$binary = null;
break;
}
if (!$binary) {
continue;
}
if (!Filesystem::binaryExists($binary)) {
$message = pht(
'You have at least one repository configured which uses this '.
'version control system. It will not work without the VCS binary.');
$this->raiseWarning($binary, $message);
continue;
}
$version = PhutilBinaryAnalyzer::getForBinary($binary)
->getBinaryVersion();
switch ($vcs['versionControlSystem']) {
case PhabricatorRepositoryType::REPOSITORY_TYPE_GIT:
$bad_versions = array();
break;
case PhabricatorRepositoryType::REPOSITORY_TYPE_SVN:
$bad_versions = array(
// We need 1.5 for "--depth", see T7228.
'< 1.5' => pht(
'The minimum supported version of Subversion is 1.5, which '.
'was released in 2008.'),
'= 1.7.1' => pht(
'This version of Subversion has a bug where `%s` does not work '.
'for files added in rN (Subversion issue #2873), fixed in 1.7.2.',
'svn diff -c N'),
);
break;
case PhabricatorRepositoryType::REPOSITORY_TYPE_MERCURIAL:
$bad_versions = array(
- // We need 1.9 for HTTP cloning, see T3046.
- '< 1.9' => pht(
- 'The minimum supported version of Mercurial is 1.9, which was '.
- 'released in 2011.'),
- '= 2.1' => pht(
- 'This version of Mercurial returns a bad exit code '.
- 'after a successful pull.'),
- '= 2.2' => pht(
- 'This version of Mercurial has a significant memory leak, fixed '.
- 'in 2.2.1. Pushing fails with this version as well; see %s.',
- 'T3046#54922'),
+ // We need 2.4 for utilizing `{p1node}` keyword in templates, see
+ // D21679 and D21681.
+ '< 2.4' => pht(
+ 'The minimum supported version of Mercurial is 2.4, which was '.
+ 'released in 2012.'),
);
break;
}
if ($version === null) {
$this->raiseUnknownVersionWarning($binary);
} else {
$version_details = array();
foreach ($bad_versions as $spec => $details) {
list($operator, $bad_version) = explode(' ', $spec, 2);
$is_bad = version_compare($version, $bad_version, $operator);
if ($is_bad) {
$version_details[] = pht(
'(%s%s) %s',
$operator,
$bad_version,
$details);
}
}
if ($version_details) {
$this->raiseBadVersionWarning(
$binary,
$version,
$version_details);
}
}
}
}
private function raiseWarning($bin, $message) {
if (phutil_is_windows()) {
$preamble = pht(
"The '%s' binary could not be found. Set the webserver's %s ".
"environmental variable to include the directory where it resides, or ".
"add that directory to '%s' in the Phabricator configuration.",
$bin,
'PATH',
'environment.append-paths');
} else {
$preamble = pht(
"The '%s' binary could not be found. Symlink it into '%s', or set the ".
"webserver's %s environmental variable to include the directory where ".
"it resides, or add that directory to '%s' in the Phabricator ".
"configuration.",
$bin,
'phabricator/support/bin/',
'PATH',
'environment.append-paths');
}
$this->newIssue('bin.'.$bin)
->setShortName(pht("'%s' Missing", $bin))
->setName(pht("Missing '%s' Binary", $bin))
->setSummary(
pht("The '%s' binary could not be located or executed.", $bin))
->setMessage($preamble.' '.$message)
->addPhabricatorConfig('environment.append-paths');
}
private function raiseUnknownVersionWarning($binary) {
$summary = pht(
'Unable to determine the version number of "%s".',
$binary);
$message = pht(
'Unable to determine the version number of "%s". Usually, this means '.
'the program changed its version format string recently and Phabricator '.
'does not know how to parse the new one yet, but might indicate that '.
'you have a very old (or broken) binary.'.
"\n\n".
'Because we can not determine the version number, checks against '.
'minimum and known-bad versions will be skipped, so we might fail '.
'to detect an incompatible binary.'.
"\n\n".
'You may be able to resolve this issue by updating Phabricator, since '.
'a newer version of Phabricator is likely to be able to parse the '.
'newer version string.'.
"\n\n".
'If updating Phabricator does not fix this, you can report the issue '.
'to the upstream so we can adjust the parser.'.
"\n\n".
'If you are confident you have a recent version of "%s" installed and '.
'working correctly, it is usually safe to ignore this warning.',
$binary,
$binary);
$this->newIssue('bin.'.$binary.'.unknown-version')
->setShortName(pht("Unknown '%s' Version", $binary))
->setName(pht("Unknown '%s' Version", $binary))
->setSummary($summary)
->setMessage($message)
->addLink(
PhabricatorEnv::getDoclink('Contributing Bug Reports'),
pht('Report this Issue to the Upstream'));
}
private function raiseBadVersionWarning($binary, $version, array $problems) {
$summary = pht(
'This server has a known bad version of "%s".',
$binary);
$message = array();
$message[] = pht(
'This server has a known bad version of "%s" installed ("%s"). This '.
'version is not supported, or contains important bugs or security '.
'vulnerabilities which are fixed in a newer version.',
$binary,
$version);
$message[] = pht('You should upgrade this software.');
$message[] = pht('The known issues with this old version are:');
foreach ($problems as $problem) {
$message[] = $problem;
}
$message = implode("\n\n", $message);
$this->newIssue("bin.{$binary}.bad-version")
->setName(pht('Unsupported/Insecure "%s" Version', $binary))
->setSummary($summary)
->setMessage($message);
}
}
diff --git a/src/applications/diffusion/conduit/DiffusionHistoryQueryConduitAPIMethod.php b/src/applications/diffusion/conduit/DiffusionHistoryQueryConduitAPIMethod.php
index 5fa74d2e28..a7e9494a80 100644
--- a/src/applications/diffusion/conduit/DiffusionHistoryQueryConduitAPIMethod.php
+++ b/src/applications/diffusion/conduit/DiffusionHistoryQueryConduitAPIMethod.php
@@ -1,309 +1,296 @@
<?php
final class DiffusionHistoryQueryConduitAPIMethod
extends DiffusionQueryConduitAPIMethod {
private $parents = array();
public function getAPIMethodName() {
return 'diffusion.historyquery';
}
public function getMethodDescription() {
return pht(
'Returns history information for a repository at a specific '.
'commit and path.');
}
protected function defineReturnType() {
return 'array';
}
protected function defineCustomParamTypes() {
return array(
'commit' => 'required string',
'against' => 'optional string',
'path' => 'required string',
'offset' => 'required int',
'limit' => 'required int',
'needDirectChanges' => 'optional bool',
'needChildChanges' => 'optional bool',
);
}
protected function getResult(ConduitAPIRequest $request) {
$path_changes = parent::getResult($request);
return array(
'pathChanges' => mpull($path_changes, 'toDictionary'),
'parents' => $this->parents,
);
}
protected function getGitResult(ConduitAPIRequest $request) {
$drequest = $this->getDiffusionRequest();
$repository = $drequest->getRepository();
$commit_hash = $request->getValue('commit');
$against_hash = $request->getValue('against');
$path = $request->getValue('path');
if (!strlen($path)) {
$path = null;
}
$offset = $request->getValue('offset');
$limit = $request->getValue('limit');
if (strlen($against_hash)) {
$commit_range = "${against_hash}..${commit_hash}";
} else {
$commit_range = $commit_hash;
}
$argv = array();
$argv[] = '--skip';
$argv[] = $offset;
$argv[] = '--max-count';
$argv[] = $limit;
$argv[] = '--format=%H:%P';
$argv[] = gitsprintf('%s', $commit_range);
$argv[] = '--';
if ($path !== null) {
$argv[] = $path;
}
list($stdout) = $repository->execxLocalCommand(
'log %Ls',
$argv);
$lines = explode("\n", trim($stdout));
$lines = array_filter($lines);
$hash_list = array();
$parent_map = array();
foreach ($lines as $line) {
list($hash, $parents) = explode(':', $line);
$hash_list[] = $hash;
$parent_map[$hash] = preg_split('/\s+/', $parents);
}
$this->parents = $parent_map;
if (!$hash_list) {
return array();
}
return DiffusionQuery::loadHistoryForCommitIdentifiers(
$hash_list,
$drequest);
}
protected function getMercurialResult(ConduitAPIRequest $request) {
$drequest = $this->getDiffusionRequest();
$repository = $drequest->getRepository();
$commit_hash = $request->getValue('commit');
$path = $request->getValue('path');
$offset = $request->getValue('offset');
$limit = $request->getValue('limit');
$path = DiffusionPathIDQuery::normalizePath($path);
$path = ltrim($path, '/');
// NOTE: Older versions of Mercurial give different results for these
// commands (see T1268):
//
// $ hg log -- ''
// $ hg log
//
// All versions of Mercurial give different results for these commands
// (merge commits are excluded with the "." version):
//
// $ hg log -- .
// $ hg log
//
// If we don't have a path component in the query, omit it from the command
// entirely to avoid these inconsistencies.
// NOTE: When viewing the history of a file, we don't use "-b", because
// Mercurial stops history at the branchpoint but we're interested in all
// ancestors. When viewing history of a branch, we do use "-b", and thus
// stop history (this is more consistent with the Mercurial worldview of
// branches).
+ $path_args = array();
if (strlen($path)) {
- $path_arg = csprintf('%s', $path);
+ $path_args[] = $path;
$revset_arg = hgsprintf(
'reverse(ancestors(%s))',
$commit_hash);
} else {
- $path_arg = '';
$revset_arg = hgsprintf(
'reverse(ancestors(%s)) and branch(%s)',
$drequest->getBranch(),
$commit_hash);
}
+ $hg_analyzer = PhutilBinaryAnalyzer::getForBinary('hg');
+ if ($hg_analyzer->isMercurialTemplatePnodeAvailable()) {
+ $hg_log_template = '{node} {p1.node} {p2.node}\\n';
+ } else {
+ $hg_log_template = '{node} {p1node} {p2node}\\n';
+ }
+
list($stdout) = $repository->execxLocalCommand(
- 'log --debug --template %s --limit %d --rev %s -- %C',
- '{node};{parents}\\n',
+ 'log --template %s --limit %d --rev %s -- %Ls',
+ $hg_log_template,
($offset + $limit), // No '--skip' in Mercurial.
$revset_arg,
- $path_arg);
+ $path_args);
- $stdout = DiffusionMercurialCommandEngine::filterMercurialDebugOutput(
- $stdout);
$lines = explode("\n", trim($stdout));
$lines = array_slice($lines, $offset);
$hash_list = array();
$parent_map = array();
$last = null;
foreach (array_reverse($lines) as $line) {
- // In the event additional log output is included in future mercurial
- // updates, if the line does not contain any semi-colon then log it and
- // ignore it.
- if (strpos($line, ';') === false) {
- phlog(pht(
- 'Unexpected output from mercurial "log --debug" command: %s',
- $line));
- continue;
- }
- list($hash, $parents) = explode(';', $line);
- $parents = trim($parents);
- if (!$parents) {
- if ($last === null) {
- $parent_map[$hash] = array('...');
- } else {
- $parent_map[$hash] = array($last);
- }
- } else {
- $parents = preg_split('/\s+/', $parents);
- foreach ($parents as $parent) {
- list($plocal, $phash) = explode(':', $parent);
- if (!preg_match('/^0+$/', $phash)) {
- $parent_map[$hash][] = $phash;
- }
- }
- // This may happen for the zeroth commit in repository, both hashes
- // are "000000000...".
- if (empty($parent_map[$hash])) {
- $parent_map[$hash] = array('...');
+ $parts = explode(' ', trim($line));
+ $hash = $parts[0];
+ $parents = array_slice($parts, 1, 2);
+ foreach ($parents as $parent) {
+ if (!preg_match('/^0+\z/', $parent)) {
+ $parent_map[$hash][] = $parent;
}
}
+ // This may happen for the zeroth commit in repository, both hashes
+ // are "000000000...".
+ if (empty($parent_map[$hash])) {
+ $parent_map[$hash] = array('...');
+ }
// The rendering code expects the first commit to be "mainline", like
// Git. Flip the order so it does the right thing.
$parent_map[$hash] = array_reverse($parent_map[$hash]);
$hash_list[] = $hash;
$last = $hash;
}
$hash_list = array_reverse($hash_list);
$this->parents = array_reverse($parent_map, true);
return DiffusionQuery::loadHistoryForCommitIdentifiers(
$hash_list,
$drequest);
}
protected function getSVNResult(ConduitAPIRequest $request) {
$drequest = $this->getDiffusionRequest();
$repository = $drequest->getRepository();
$commit = $request->getValue('commit');
$path = $request->getValue('path');
$offset = $request->getValue('offset');
$limit = $request->getValue('limit');
$need_direct_changes = $request->getValue('needDirectChanges');
$need_child_changes = $request->getValue('needChildChanges');
$conn_r = $repository->establishConnection('r');
$paths = queryfx_all(
$conn_r,
'SELECT id, path FROM %T WHERE pathHash IN (%Ls)',
PhabricatorRepository::TABLE_PATH,
array(md5('/'.trim($path, '/'))));
$paths = ipull($paths, 'id', 'path');
$path_id = idx($paths, '/'.trim($path, '/'));
if (!$path_id) {
return array();
}
$filter_query = qsprintf($conn_r, '');
if ($need_direct_changes) {
if ($need_child_changes) {
$filter_query = qsprintf(
$conn_r,
'AND (isDirect = 1 OR changeType = %s)',
DifferentialChangeType::TYPE_CHILD);
} else {
$filter_query = qsprintf(
$conn_r,
'AND (isDirect = 1)');
}
}
$history_data = queryfx_all(
$conn_r,
'SELECT * FROM %T WHERE repositoryID = %d AND pathID = %d
AND commitSequence <= %d
%Q
ORDER BY commitSequence DESC
LIMIT %d, %d',
PhabricatorRepository::TABLE_PATHCHANGE,
$repository->getID(),
$path_id,
$commit ? $commit : 0x7FFFFFFF,
$filter_query,
$offset,
$limit);
$commits = array();
$commit_data = array();
$commit_ids = ipull($history_data, 'commitID');
if ($commit_ids) {
$commits = id(new PhabricatorRepositoryCommit())->loadAllWhere(
'id IN (%Ld)',
$commit_ids);
if ($commits) {
$commit_data = id(new PhabricatorRepositoryCommitData())->loadAllWhere(
'commitID in (%Ld)',
$commit_ids);
$commit_data = mpull($commit_data, null, 'getCommitID');
}
}
$history = array();
foreach ($history_data as $row) {
$item = new DiffusionPathChange();
$commit = idx($commits, $row['commitID']);
if ($commit) {
$item->setCommit($commit);
$item->setCommitIdentifier($commit->getCommitIdentifier());
$data = idx($commit_data, $commit->getID());
if ($data) {
$item->setCommitData($data);
}
}
$item->setChangeType($row['changeType']);
$item->setFileType($row['fileType']);
$history[] = $item;
}
return $history;
}
}
diff --git a/src/applications/diffusion/protocol/__tests__/DiffusionMercurialCommandEngineTests.php b/src/applications/diffusion/protocol/__tests__/DiffusionMercurialCommandEngineTests.php
index e89125c5d9..3ec09008cf 100644
--- a/src/applications/diffusion/protocol/__tests__/DiffusionMercurialCommandEngineTests.php
+++ b/src/applications/diffusion/protocol/__tests__/DiffusionMercurialCommandEngineTests.php
@@ -1,42 +1,89 @@
<?php
final class DiffusionMercurialCommandEngineTests extends PhabricatorTestCase {
public function testFilteringDebugOutput() {
+ $map = array(
+ '' => '',
+
+ "quack\n" => "quack\n",
+
+ "ignoring untrusted configuration option x.y = z\nquack\n" =>
+ "quack\n",
+
+ "ignoring untrusted configuration option x.y = z\n".
+ "ignoring untrusted configuration option x.y = z\n".
+ "quack\n" =>
+ "quack\n",
+
+ "ignoring untrusted configuration option x.y = z\n".
+ "ignoring untrusted configuration option x.y = z\n".
+ "ignoring untrusted configuration option x.y = z\n".
+ "quack\n" =>
+ "quack\n",
+
+ "quack\n".
+ "ignoring untrusted configuration option x.y = z\n".
+ "ignoring untrusted configuration option x.y = z\n".
+ "ignoring untrusted configuration option x.y = z\n" =>
+ "quack\n",
+
+ "ignoring untrusted configuration option x.y = z\n".
+ "ignoring untrusted configuration option x.y = z\n".
+ "duck\n".
+ "ignoring untrusted configuration option x.y = z\n".
+ "ignoring untrusted configuration option x.y = z\n".
+ "bread\n".
+ "ignoring untrusted configuration option x.y = z\n".
+ "quack\n" =>
+ "duck\nbread\nquack\n",
+
+ "ignoring untrusted configuration option x.y = z\n".
+ "duckignoring untrusted configuration option x.y = z\n".
+ "quack" =>
+ 'duckquack',
+ );
+
+ foreach ($map as $input => $expect) {
+ $actual = DiffusionMercurialCommandEngine::filterMercurialDebugOutput(
+ $input);
+ $this->assertEqual($expect, $actual, $input);
+ }
+
// Output that should be filtered out from the results
$output =
"ignoring untrusted configuration option\n".
"couldn't write revision branch cache:\n".
"couldn't write branch cache: blah blah blah\n".
"invalid branchheads cache\n".
"invalid branch cache (served): tip differs\n".
"starting pager for command 'log'\n".
"updated patterns: ".
".hglf/project/src/a/b/c/SomeClass.java, ".
"project/src/a/b/c/SomeClass.java\n".
"no terminfo entry for sitm\n";
$filtered_output =
DiffusionMercurialCommandEngine::filterMercurialDebugOutput($output);
$this->assertEqual('', $filtered_output);
// The output that should make it through the filtering
$output =
"0b33a9e5ceedba14b03214f743957357d7bb46a9;694".
":8b39f63eb209dd2bdfd4bd3d0721a9e38d75a6d3".
"-1:0000000000000000000000000000000000000000\n".
"8b39f63eb209dd2bdfd4bd3d0721a9e38d75a6d3;693".
":165bce9ce4ccc97024ba19ed5a22f6a066fa6844".
"-1:0000000000000000000000000000000000000000\n".
"165bce9ce4ccc97024ba19ed5a22f6a066fa6844;692:".
"2337bc9e3cf212b3b386b5197801b1c81db64920".
"-1:0000000000000000000000000000000000000000\n";
$filtered_output =
DiffusionMercurialCommandEngine::filterMercurialDebugOutput($output);
$this->assertEqual($output, $filtered_output);
}
}
diff --git a/src/applications/diffusion/query/blame/DiffusionMercurialBlameQuery.php b/src/applications/diffusion/query/blame/DiffusionMercurialBlameQuery.php
index 60eeb31c4f..5fa9c39f73 100644
--- a/src/applications/diffusion/query/blame/DiffusionMercurialBlameQuery.php
+++ b/src/applications/diffusion/query/blame/DiffusionMercurialBlameQuery.php
@@ -1,36 +1,66 @@
<?php
final class DiffusionMercurialBlameQuery extends DiffusionBlameQuery {
protected function newBlameFuture(DiffusionRequest $request, $path) {
$repository = $request->getRepository();
$commit = $request->getCommit();
- // NOTE: We're using "--debug" to make "--changeset" give us the full
- // commit hashes.
+ // NOTE: Using "--template" or "--debug" to get the full commit hashes.
+ $hg_analyzer = PhutilBinaryAnalyzer::getForBinary('hg');
+ if ($hg_analyzer->isMercurialAnnotateTemplatesAvailable()) {
+ // See `hg help annotate --verbose` for more info on the template format.
+ // Use array of arguments so the template line does not need wrapped in
+ // quotes.
+ $template = array(
+ '--template',
+ "{lines % '{node}: {line}'}",
+ );
+ } else {
+ $template = array(
+ '--debug',
+ '--changeset',
+ );
+ }
return $repository->getLocalCommandFuture(
- 'annotate --debug --changeset --rev %s -- %s',
+ 'annotate %Ls --rev %s -- %s',
+ $template,
$commit,
$path);
}
protected function resolveBlameFuture(ExecFuture $future) {
list($err, $stdout) = $future->resolve();
if ($err) {
return null;
}
$result = array();
$lines = phutil_split_lines($stdout);
foreach ($lines as $line) {
+ // If the `--debug` flag was used above instead of `--template` then
+ // there's a good change additional output was included which is not
+ // relevant to the information we want. It should be safe to call this
+ // regardless of whether we used `--debug` or `--template` so there isn't
+ // a need to track which argument was used.
+ $line = DiffusionMercurialCommandEngine::filterMercurialDebugOutput(
+ $line);
+
+ // Just in case new versions of Mercurial add arbitrary output when using
+ // the `--debug`, do a quick sanity check that this line is formatted in
+ // a way we're expecting.
+ if (strpos($line, ':') === false) {
+ phlog(pht('Unexpected output from hg annotate: %s', $line));
+ continue;
+ }
list($commit) = explode(':', $line, 2);
$result[] = $commit;
}
return $result;
}
}
diff --git a/src/applications/diffusion/query/lowlevel/DiffusionLowLevelParentsQuery.php b/src/applications/diffusion/query/lowlevel/DiffusionLowLevelParentsQuery.php
index 193f45a029..9e6c2425cb 100644
--- a/src/applications/diffusion/query/lowlevel/DiffusionLowLevelParentsQuery.php
+++ b/src/applications/diffusion/query/lowlevel/DiffusionLowLevelParentsQuery.php
@@ -1,99 +1,99 @@
<?php
final class DiffusionLowLevelParentsQuery
extends DiffusionLowLevelQuery {
private $identifier;
public function withIdentifier($identifier) {
$this->identifier = $identifier;
return $this;
}
protected function executeQuery() {
if (!strlen($this->identifier)) {
throw new PhutilInvalidStateException('withIdentifier');
}
$type = $this->getRepository()->getVersionControlSystem();
switch ($type) {
case PhabricatorRepositoryType::REPOSITORY_TYPE_GIT:
$result = $this->loadGitParents();
break;
case PhabricatorRepositoryType::REPOSITORY_TYPE_MERCURIAL:
$result = $this->loadMercurialParents();
break;
case PhabricatorRepositoryType::REPOSITORY_TYPE_SVN:
$result = $this->loadSubversionParents();
break;
default:
throw new Exception(pht('Unsupported repository type "%s"!', $type));
}
return $result;
}
private function loadGitParents() {
$repository = $this->getRepository();
list($stdout) = $repository->execxLocalCommand(
'log -n 1 %s %s --',
'--format=%P',
gitsprintf('%s', $this->identifier));
return preg_split('/\s+/', trim($stdout));
}
private function loadMercurialParents() {
$repository = $this->getRepository();
+ $hg_analyzer = PhutilBinaryAnalyzer::getForBinary('hg');
+ if ($hg_analyzer->isMercurialTemplatePnodeAvailable()) {
+ $hg_log_template = '{p1.node} {p2.node}';
+ } else {
+ $hg_log_template = '{p1node} {p2node}';
+ }
+
list($stdout) = $repository->execxLocalCommand(
- 'log --debug --limit 1 --template={parents} --rev %s',
+ 'log --limit 1 --template %s --rev %s',
+ $hg_log_template,
$this->identifier);
- $stdout = DiffusionMercurialCommandEngine::filterMercurialDebugOutput(
- $stdout);
-
$hashes = preg_split('/\s+/', trim($stdout));
foreach ($hashes as $key => $value) {
- // Mercurial parents look like "23:ad9f769d6f786fad9f76d9a" -- we want
- // to strip out the local rev part.
- list($local, $global) = explode(':', $value);
- $hashes[$key] = $global;
-
- // With --debug we get 40-character hashes but also get the "000000..."
- // hash for missing parents; ignore it.
- if (preg_match('/^0+$/', $global)) {
+ // We get 40-character hashes but also get the "000000..." hash for
+ // missing parents; ignore it.
+ if (preg_match('/^0+\z/', $value)) {
unset($hashes[$key]);
}
}
return $hashes;
}
private function loadSubversionParents() {
$repository = $this->getRepository();
$identifier = $this->identifier;
$refs = id(new DiffusionCachedResolveRefsQuery())
->setRepository($repository)
->withRefs(array($identifier))
->execute();
if (!$refs) {
throw new Exception(
pht(
'No commit "%s" in this repository.',
$identifier));
}
$n = (int)$identifier;
if ($n > 1) {
$ids = array($n - 1);
} else {
$ids = array();
}
return $ids;
}
}
diff --git a/src/applications/repository/storage/__tests__/PhabricatorRepositoryTestCase.php b/src/applications/repository/storage/__tests__/PhabricatorRepositoryTestCase.php
index ea83aa9d56..ca755bbaee 100644
--- a/src/applications/repository/storage/__tests__/PhabricatorRepositoryTestCase.php
+++ b/src/applications/repository/storage/__tests__/PhabricatorRepositoryTestCase.php
@@ -1,219 +1,170 @@
<?php
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(),
pht("Protocol for '%s'.", $uri));
}
}
public function testBranchFilter() {
$git = PhabricatorRepositoryType::REPOSITORY_TYPE_GIT;
$repo = new PhabricatorRepository();
$repo->setVersionControlSystem($git);
$this->assertTrue(
$repo->shouldTrackBranch('imaginary'),
pht('Track all branches by default.'));
$repo->setTrackOnlyRules(array('master'));
$this->assertTrue(
$repo->shouldTrackBranch('master'),
pht('Track listed branches.'));
$this->assertFalse(
$repo->shouldTrackBranch('imaginary'),
pht('Do not track unlisted branches.'));
}
public function testSubversionPathInfo() {
$svn = PhabricatorRepositoryType::REPOSITORY_TYPE_SVN;
$repo = new PhabricatorRepository();
$repo->setVersionControlSystem($svn);
$repo->setDetail('remote-uri', 'http://svn.example.com/repo');
$this->assertEqual(
'http://svn.example.com/repo',
$repo->getSubversionPathURI());
$repo->setDetail('remote-uri', 'http://svn.example.com/repo/');
$this->assertEqual(
'http://svn.example.com/repo',
$repo->getSubversionPathURI());
$repo->setDetail('hosting-enabled', true);
$repo->setLocalPath('/var/repo/SVN');
$this->assertEqual(
'file:///var/repo/SVN',
$repo->getSubversionPathURI());
$repo->setLocalPath('/var/repo/SVN/');
$this->assertEqual(
'file:///var/repo/SVN',
$repo->getSubversionPathURI());
$this->assertEqual(
'file:///var/repo/SVN/a@',
$repo->getSubversionPathURI('a'));
$this->assertEqual(
'file:///var/repo/SVN/a@1',
$repo->getSubversionPathURI('a', 1));
$this->assertEqual(
'file:///var/repo/SVN/%3F@22',
$repo->getSubversionPathURI('?', 22));
$repo->setDetail('svn-subpath', 'quack/trunk/');
$this->assertEqual(
'file:///var/repo/SVN/quack/trunk/@',
$repo->getSubversionBaseURI());
$this->assertEqual(
'file:///var/repo/SVN/quack/trunk/@HEAD',
$repo->getSubversionBaseURI('HEAD'));
}
- public function testFilterMercurialDebugOutput() {
- $map = array(
- '' => '',
-
- "quack\n" => "quack\n",
-
- "ignoring untrusted configuration option x.y = z\nquack\n" =>
- "quack\n",
-
- "ignoring untrusted configuration option x.y = z\n".
- "ignoring untrusted configuration option x.y = z\n".
- "quack\n" =>
- "quack\n",
-
- "ignoring untrusted configuration option x.y = z\n".
- "ignoring untrusted configuration option x.y = z\n".
- "ignoring untrusted configuration option x.y = z\n".
- "quack\n" =>
- "quack\n",
-
- "quack\n".
- "ignoring untrusted configuration option x.y = z\n".
- "ignoring untrusted configuration option x.y = z\n".
- "ignoring untrusted configuration option x.y = z\n" =>
- "quack\n",
-
- "ignoring untrusted configuration option x.y = z\n".
- "ignoring untrusted configuration option x.y = z\n".
- "duck\n".
- "ignoring untrusted configuration option x.y = z\n".
- "ignoring untrusted configuration option x.y = z\n".
- "bread\n".
- "ignoring untrusted configuration option x.y = z\n".
- "quack\n" =>
- "duck\nbread\nquack\n",
-
- "ignoring untrusted configuration option x.y = z\n".
- "duckignoring untrusted configuration option x.y = z\n".
- "quack" =>
- 'duckquack',
- );
-
- foreach ($map as $input => $expect) {
- $actual = DiffusionMercurialCommandEngine::filterMercurialDebugOutput(
- $input);
- $this->assertEqual($expect, $actual, $input);
- }
- }
-
public function testRepositoryShortNameValidation() {
$good = array(
'sensible-repository',
'AReasonableName',
'ACRONYM-project',
'sol-123',
'46-helixes',
'node.io',
'internet.com',
'www.internet-site.com.repository',
'with_under-scores',
// Can't win them all.
'A-_._-_._-_._-_._-_._-_._-1',
// 64-character names are fine.
str_repeat('a', 64),
);
$poor = array(
'',
'1',
'.',
'-_-',
'AAAA',
'..',
'a/b',
'../../etc/passwd',
'/',
'!',
'@',
'ca$hmoney',
'repo with spaces',
'hyphen-',
'-ated',
'_underscores_',
'yes!',
'quack.git',
'git.git',
'.git.git.git',
// 65-character names are no good.
str_repeat('a', 65),
);
foreach ($good as $nice_name) {
$actual = PhabricatorRepository::isValidRepositorySlug($nice_name);
$this->assertEqual(
true,
$actual,
pht(
'Expected "%s" to be a valid repository short name.',
$nice_name));
}
foreach ($poor as $poor_name) {
$actual = PhabricatorRepository::isValidRepositorySlug($poor_name);
$this->assertEqual(
false,
$actual,
pht(
'Expected "%s" to be rejected as an invalid repository '.
'short name.',
$poor_name));
}
}
}

File Metadata

Mime Type
text/x-diff
Expires
Wed, Nov 26, 7:40 PM (18 h, 27 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
420200
Default Alt Text
(35 KB)

Event Timeline