1
0
Fork 0
mirror of https://we.phorge.it/source/arcanist.git synced 2024-12-26 07:20:56 +01:00

Add 'arc which', and

ArcanistRepositoryAPI->loadWorkingCopyDifferentialRevisions()

Summary:
  - See T787.
  - @cpiro has an immediate use case for this, which is ##arc amend --revision
`arc which --id` --show master## for "git merge --autosquash" or similar.
  - For T614, we need this to choose "--create" vs "--update".
  - Other workflows should also use this to improve how often we automatically
get things right, particularly in Mercurial and SVN.

Test Plan:
Ran "arc which" in SVN, Git and HG working copies with various flags;
results seemed reasonable.

Reviewers: btrahan, cpiro, jungejason

Reviewed By: btrahan

CC: aran, epriestley

Maniphest Tasks: T787

Differential Revision: https://secure.phabricator.com/D1478
This commit is contained in:
epriestley 2012-01-24 08:07:38 -08:00
parent 03a9c516ea
commit 3ee01bacac
8 changed files with 248 additions and 2 deletions

View file

@ -95,6 +95,7 @@ phutil_register_library_map(array(
'ArcanistUploadWorkflow' => 'workflow/upload',
'ArcanistUsageException' => 'exception/usage',
'ArcanistUserAbortException' => 'exception/usage/userabort',
'ArcanistWhichWorkflow' => 'workflow/which',
'ArcanistWorkingCopyIdentity' => 'workingcopyidentity',
'ArcanistXHPASTLintNamingHook' => 'lint/linter/xhpast/naminghook',
'ArcanistXHPASTLinter' => 'lint/linter/xhpast',
@ -166,6 +167,7 @@ phutil_register_library_map(array(
'ArcanistUnitWorkflow' => 'ArcanistBaseWorkflow',
'ArcanistUploadWorkflow' => 'ArcanistBaseWorkflow',
'ArcanistUserAbortException' => 'ArcanistUsageException',
'ArcanistWhichWorkflow' => 'ArcanistBaseWorkflow',
'ArcanistXHPASTLinter' => 'ArcanistLinter',
'ArcanistXHPASTLinterTestCase' => 'ArcanistLinterTestCase',
'ComprehensiveLintEngine' => 'ArcanistLintEngine',

View file

@ -154,6 +154,9 @@ abstract class ArcanistRepositoryAPI {
abstract public function getSourceControlBaseRevision();
abstract public function supportsRelativeLocalCommits();
abstract public function getWorkingCopyRevision();
abstract public function loadWorkingCopyDifferentialRevisions(
ConduitClient $conduit,
array $query);
public function getCommitMessageForRevision($revision) {
throw new ArcanistCapabilityNotSupportedException($this);

View file

@ -619,4 +619,62 @@ class ArcanistGitAPI extends ArcanistRepositoryAPI {
return head($parser->parseDiff($message));
}
public function loadWorkingCopyDifferentialRevisions(
ConduitClient $conduit,
array $query) {
$messages = $this->getGitCommitLog();
if (!strlen($messages)) {
return array();
}
$parser = new ArcanistDiffParser();
$messages = $parser->parseDiff($messages);
// First, try to find revisions by explicit revision IDs in commit messages.
$revision_ids = array();
foreach ($messages as $message) {
$object = ArcanistDifferentialCommitMessage::newFromRawCorpus(
$message->getMetadata('message'));
if ($object->getRevisionID()) {
$revision_ids[] = $object->getRevisionID();
}
}
if ($revision_ids) {
$results = $conduit->callMethodSynchronous(
'differential.query',
$query + array(
'ids' => $revision_ids,
));
return $results;
}
// If we didn't succeed, try to find revisions by hash.
$hashes = array();
foreach ($this->getLocalCommitInformation() as $commit) {
$hashes[] = array('gtcm', $commit['commit']);
$hashes[] = array('gttr', $commit['tree']);
}
$results = $conduit->callMethodSynchronous(
'differential.query',
$query + array(
'commitHashes' => $hashes,
));
if ($results) {
return $results;
}
// If we still didn't succeed, try to find revisions by branch name.
$results = $conduit->callMethodSynchronous(
'differential.query',
$query + array(
'branches' => array($this->getBranchName()),
));
return $results;
}
}

View file

@ -6,6 +6,7 @@
phutil_require_module('arcanist', 'differential/commitmessage');
phutil_require_module('arcanist', 'exception/usage');
phutil_require_module('arcanist', 'parser/diff');
phutil_require_module('arcanist', 'repository/api/base');

View file

@ -45,11 +45,11 @@ class ArcanistMercurialAPI extends ArcanistRepositoryAPI {
}
public function getBranchName() {
// TODO: I have nearly no idea how hg local branches work.
// TODO: I have nearly no idea how hg branches work.
list($stdout) = execx(
'(cd %s && hg branch)',
$this->getPath());
return $stdout;
return trim($stdout);
}
public function setRelativeCommit($commit) {
@ -374,4 +374,34 @@ class ArcanistMercurialAPI extends ArcanistRepositoryAPI {
"'hg push' or by printing and faxing it).";
}
public function loadWorkingCopyDifferentialRevisions(
ConduitClient $conduit,
array $query) {
// Try to find revisions by hash.
$hashes = array();
foreach ($this->getLocalCommitInformation() as $commit) {
$hashes[] = array('hgcm', $commit['rev']);
}
$results = $conduit->callMethodSynchronous(
'differential.query',
$query + array(
'commitHashes' => $hashes,
));
if ($results) {
return $results;
}
// If we still didn't succeed, try to find revisions by branch name.
$results = $conduit->callMethodSynchronous(
'differential.query',
$query + array(
'branches' => array($this->getBranchName()),
));
return $results;
}
}

View file

@ -506,4 +506,24 @@ EODIFF;
return "Done.";
}
public function loadWorkingCopyDifferentialRevisions(
ConduitClient $conduit,
array $query) {
// We don't have much to go on in SVN, look for revisions that came from
// this directory.
$results = $conduit->callMethodSynchronous(
'differential.query',
$query);
foreach ($results as $key => $result) {
if ($result['sourcePath'] != $this->getPath()) {
unset($results[$key]);
}
}
return $results;
}
}

View file

@ -0,0 +1,116 @@
<?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.
*/
/**
* Show which revision or revisions are in the working copy.
*
* @group workflow
*/
class ArcanistWhichWorkflow extends ArcanistBaseWorkflow {
public function getCommandHelp() {
return phutil_console_format(<<<EOTEXT
**which** (svn)
**which** [commit] (hg, git)
Supports: svn, git, hg
Shows which revision is in the working copy (or which revisions, if
more than one matches).
EOTEXT
);
}
public function requiresConduit() {
return true;
}
public function requiresRepositoryAPI() {
return true;
}
public function requiresAuthentication() {
return true;
}
public function getArguments() {
return array(
'any-author' => array(
'help' => "Show revisions by any author, not just you.",
),
'any-status' => array(
'help' => "Show committed and abandoned revisions.",
),
'id' => array(
'help' => "If exactly one revision matches, print it to stdout. ".
"Otherwise, exit with an error. Intended for scripts.",
),
'*' => 'commit',
);
}
public function run() {
$repository_api = $this->getRepositoryAPI();
$commit = $this->getArgument('commit');
if (count($commit)) {
if (!$repository_api->supportsRelativeLocalCommits()) {
throw new ArcanistUsageException(
"This version control system does not support relative commits.");
} else {
$repository_api->parseRelativeLocalCommit($commit);
}
}
$any_author = $this->getArgument('any-author');
$any_status = $this->getArgument('any-status');
$query = array(
'authors' => $any_author
? null
: array($this->getUserPHID()),
'status' => $any_status
? 'status-any'
: 'status-open',
);
$revisions = $repository_api->loadWorkingCopyDifferentialRevisions(
$this->getConduit(),
$query);
if (empty($revisions)) {
$this->writeStatusMessage("No matching revisions.\n");
return 1;
}
if ($this->getArgument('id')) {
if (count($revisions) == 1) {
echo idx(head($revisions), 'id');
return 0;
} else {
$this->writeStatusMessage("More than one matching revision.\n");
return 1;
}
}
foreach ($revisions as $revision) {
echo 'D'.$revision['id'].' '.$revision['title']."\n";
}
return 0;
}
}

View file

@ -0,0 +1,16 @@
<?php
/**
* This file is automatically generated. Lint this module to rebuild it.
* @generated
*/
phutil_require_module('arcanist', 'exception/usage');
phutil_require_module('arcanist', 'workflow/base');
phutil_require_module('phutil', 'console');
phutil_require_module('phutil', 'utils');
phutil_require_source('ArcanistWhichWorkflow.php');