1
0
Fork 0
mirror of https://we.phorge.it/source/arcanist.git synced 2024-11-21 22:32:41 +01:00

Add a "CommitSymbolRef" for resolving symbolic commits into stable commit hashes

Summary:
Ref T13490. Frequently, we know the symbolic name of a commit (like "master") but need the immutable identifier for it (the commit hash).

Provide a Ref and Query for doing this lookup.

Test Plan: Ran `arc inspect symbol(...)` with various symbols, saw appropriate resolutions, nulls, or errors.

Maniphest Tasks: T13490

Differential Revision: https://secure.phabricator.com/D21090
This commit is contained in:
epriestley 2020-04-11 15:27:41 -07:00
parent 92be6df0eb
commit 4cc05c377d
5 changed files with 187 additions and 0 deletions

View file

@ -104,6 +104,8 @@ phutil_register_library_map(array(
'ArcanistCommentStyleXHPASTLinterRuleTestCase' => 'lint/linter/xhpast/rules/__tests__/ArcanistCommentStyleXHPASTLinterRuleTestCase.php',
'ArcanistCommitRef' => 'ref/ArcanistCommitRef.php',
'ArcanistCommitRefInspector' => 'inspector/ArcanistCommitRefInspector.php',
'ArcanistCommitSymbolRef' => 'ref/commitsymbol/ArcanistCommitSymbolRef.php',
'ArcanistCommitSymbolRefInspector' => 'ref/commitsymbol/ArcanistCommitSymbolRefInspector.php',
'ArcanistCommitUpstreamHardpointQuery' => 'query/ArcanistCommitUpstreamHardpointQuery.php',
'ArcanistCommitWorkflow' => 'workflow/ArcanistCommitWorkflow.php',
'ArcanistCompilerLintRenderer' => 'lint/renderer/ArcanistCompilerLintRenderer.php',
@ -206,6 +208,7 @@ phutil_register_library_map(array(
'ArcanistGetConfigWorkflow' => 'workflow/ArcanistGetConfigWorkflow.php',
'ArcanistGitAPI' => 'repository/api/ArcanistGitAPI.php',
'ArcanistGitCommitMessageHardpointQuery' => 'query/ArcanistGitCommitMessageHardpointQuery.php',
'ArcanistGitCommitSymbolCommitHardpointQuery' => 'ref/commitsymbol/ArcanistGitCommitSymbolCommitHardpointQuery.php',
'ArcanistGitLandEngine' => 'land/ArcanistGitLandEngine.php',
'ArcanistGitUpstreamPath' => 'repository/api/ArcanistGitUpstreamPath.php',
'ArcanistGitWorkingCopy' => 'workingcopy/ArcanistGitWorkingCopy.php',
@ -1066,6 +1069,8 @@ phutil_register_library_map(array(
'ArcanistCommentStyleXHPASTLinterRuleTestCase' => 'ArcanistXHPASTLinterRuleTestCase',
'ArcanistCommitRef' => 'ArcanistRef',
'ArcanistCommitRefInspector' => 'ArcanistRefInspector',
'ArcanistCommitSymbolRef' => 'ArcanistRef',
'ArcanistCommitSymbolRefInspector' => 'ArcanistRefInspector',
'ArcanistCommitUpstreamHardpointQuery' => 'ArcanistWorkflowHardpointQuery',
'ArcanistCommitWorkflow' => 'ArcanistWorkflow',
'ArcanistCompilerLintRenderer' => 'ArcanistLintRenderer',
@ -1168,6 +1173,7 @@ phutil_register_library_map(array(
'ArcanistGetConfigWorkflow' => 'ArcanistWorkflow',
'ArcanistGitAPI' => 'ArcanistRepositoryAPI',
'ArcanistGitCommitMessageHardpointQuery' => 'ArcanistWorkflowGitHardpointQuery',
'ArcanistGitCommitSymbolCommitHardpointQuery' => 'ArcanistWorkflowGitHardpointQuery',
'ArcanistGitLandEngine' => 'ArcanistLandEngine',
'ArcanistGitUpstreamPath' => 'Phobject',
'ArcanistGitWorkingCopy' => 'ArcanistWorkingCopy',

View file

@ -0,0 +1,37 @@
<?php
final class ArcanistCommitSymbolRef
extends ArcanistRef {
private $symbol;
const HARDPOINT_COMMIT = 'ref.commit-symbol';
public function getRefDisplayName() {
return pht('Commit Symbol "%s"', $this->getSymbol());
}
protected function newHardpoints() {
return array(
$this->newHardpoint(self::HARDPOINT_COMMIT),
);
}
public function setSymbol($symbol) {
$this->symbol = $symbol;
return $this;
}
public function getSymbol() {
return $this->symbol;
}
public function attachCommit(ArcanistCommitRef $commit) {
return $this->attachHardpoint(self::HARDPOINT_COMMIT, $commit);
}
public function getCommit() {
return $this->getHardpoint(self::HARDPOINT_COMMIT);
}
}

View file

@ -0,0 +1,22 @@
<?php
final class ArcanistCommitSymbolRefInspector
extends ArcanistRefInspector {
public function getInspectFunctionName() {
return 'symbol';
}
public function newInspectRef(array $argv) {
if (count($argv) !== 1) {
throw new PhutilArgumentUsageException(
pht(
'Expected exactly one argument to "symbol(...)" with a '.
'commit symbol.'));
}
return id(new ArcanistCommitSymbolRef())
->setSymbol($argv[0]);
}
}

View file

@ -0,0 +1,92 @@
<?php
final class ArcanistGitCommitSymbolCommitHardpointQuery
extends ArcanistWorkflowGitHardpointQuery {
public function getHardpoints() {
return array(
ArcanistCommitSymbolRef::HARDPOINT_COMMIT,
);
}
protected function canLoadRef(ArcanistRef $ref) {
return ($ref instanceof ArcanistCommitSymbolRef);
}
public function loadHardpoint(array $refs, $hardpoint) {
$symbol_map = array();
foreach ($refs as $key => $ref) {
$symbol_map[$key] = $ref->getSymbol();
}
$symbol_set = array_fuse($symbol_map);
foreach ($symbol_set as $symbol) {
$this->validateSymbol($symbol);
}
$api = $this->getRepositoryAPI();
$symbol_list = implode("\n", $symbol_set);
$future = $api->newFuture('cat-file --batch-check --')
->write($symbol_list);
list($stdout) = (yield $this->yieldFuture($future));
$lines = phutil_split_lines($stdout, $retain_endings = false);
if (count($lines) !== count($symbol_set)) {
throw new Exception(
pht(
'Execution of "git cat-file --batch-check" emitted an unexpected '.
'number of lines, expected %s but got %s.',
phutil_count($symbol_set),
phutil_count($lines)));
}
$hash_map = array();
$pairs = array_combine($symbol_set, $lines);
foreach ($pairs as $symbol => $line) {
$parts = explode(' ', $line, 3);
if (count($parts) < 2) {
throw new Exception(
pht(
'Execution of "git cat-file --batch-check" emitted an '.
'unexpected line ("%s").',
$line));
}
list($hash, $type) = $parts;
// NOTE: For now, symbols which map to tags (which, in turn, map to
// commits) are ignored here.
if ($type !== 'commit') {
$hash_map[$symbol] = null;
continue;
}
$hash_map[$symbol] = $hash;
}
$results = array();
foreach ($symbol_map as $key => $symbol) {
$results[$key] = $hash_map[$symbol];
}
yield $this->yieldMap($results);
}
private function validateSymbol($symbol) {
if (strpos($symbol, "\n") !== false) {
throw new Exception(
pht(
'Commit symbol "%s" contains a newline. This is not a valid '.
'character in a Git commit symbol.',
addcslashes($symbol, "\\\n")));
}
}
}

View file

@ -673,6 +673,36 @@ abstract class ArcanistRepositoryAPI extends Phobject {
return new ArcanistBranchRef();
}
final public function getCurrentCommitRef() {
$commit_hash = $this->newCurrentCommitHash();
return $this->newCommitRef()
->setCommitHash($commit_hash);
}
protected function newCurrentCommitRef() {
$commit_hash = $this->newCurrentCommitHash();
return $this->newCommitRefForSymbol($commit_hash);
}
protected function newCommitRefForSymbol() {
throw new ArcanistCapabilityNotSupportedException($this);
}
protected function newCurrentCommitHash() {
throw new ArcanistCapabilityNotSupportedException($this);
}
final public function getCurrentWorkingCopyStateRef() {
return $this->newCurrentWorkingCopyStateRef();
}
protected function newCurrentWorkingCopyStateRef() {
$commit_ref = $this->getCurrentCommitRef();
return id(new ArcanistWorkingCopyStateRef())
->setCommitRef($commit_ref);
}
final public function newFuture($pattern /* , ... */) {
$args = func_get_args();
return $this->buildLocalFuture($args)