mirror of
https://we.phorge.it/source/arcanist.git
synced 2024-11-22 14:52:40 +01:00
Improve Arcanist Mercurial compatibility
Summary: - Use "hg parents" to figure out where outgoing changes originate from, not "~1", since that's a new feature in Mercurial. - Add "--style default" all over the place since hg config can override this (similar to the date config issues we saw in git). - Cache working copy status so we don't run full hg diffs like 30 times (similar to git/svn APIs). - Use full "--git" flag instead of rather cryptic "-g". Test Plan: Ran "arc diff" in my hg working copy, got the diff I expected. Reviewers: Makinde, aran, jungejason, nh, tuomaspelkonen Reviewed By: Makinde CC: aran, Makinde Differential Revision: 934
This commit is contained in:
parent
1c9746a46e
commit
9df1b8a4bd
1 changed files with 66 additions and 44 deletions
|
@ -69,22 +69,40 @@ class ArcanistMercurialAPI extends ArcanistRepositoryAPI {
|
||||||
public function getRelativeCommit() {
|
public function getRelativeCommit() {
|
||||||
if (empty($this->relativeCommit)) {
|
if (empty($this->relativeCommit)) {
|
||||||
list($stdout) = execx(
|
list($stdout) = execx(
|
||||||
'(cd %s && hg outgoing --branch `hg branch` --limit 1)',
|
'(cd %s && hg outgoing --branch `hg branch` --limit 1 --style default)',
|
||||||
$this->getPath());
|
$this->getPath());
|
||||||
$logs = $this->parseMercurialLog($stdout);
|
$logs = $this->parseMercurialLog($stdout);
|
||||||
if (!count($logs)) {
|
if (!count($logs)) {
|
||||||
throw new ArcanistUsageException("You have no outgoing changes!");
|
throw new ArcanistUsageException("You have no outgoing changes!");
|
||||||
}
|
}
|
||||||
$oldest_log = head($logs);
|
$oldest_log = head($logs);
|
||||||
|
$oldest_rev = $oldest_log['rev'];
|
||||||
|
|
||||||
$this->relativeCommit = $oldest_log['rev'].'~1';
|
// NOTE: The "^" and "~" syntaxes were only added in hg 1.9, which is new
|
||||||
|
// as of July 2011, so do this in a compatible way. Also, "hg log" and
|
||||||
|
// "hg outgoing" don't necessarily show parents (even if given an explicit
|
||||||
|
// template consisting of just the parents token) so we need to separately
|
||||||
|
// execute "hg parents".
|
||||||
|
|
||||||
|
list($stdout) = execx(
|
||||||
|
'(cd %s && hg parents --style default --rev %s)',
|
||||||
|
$this->getPath(),
|
||||||
|
$oldest_rev);
|
||||||
|
$parents_logs = $this->parseMercurialLog($stdout);
|
||||||
|
$first_parent = head($parents_logs);
|
||||||
|
if (!$first_parent) {
|
||||||
|
throw new ArcanistUsageException(
|
||||||
|
"Oldest outgoing change has no parent revision!");
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->relativeCommit = $first_parent['rev'];
|
||||||
}
|
}
|
||||||
return $this->relativeCommit;
|
return $this->relativeCommit;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getLocalCommitInformation() {
|
public function getLocalCommitInformation() {
|
||||||
list($info) = execx(
|
list($info) = execx(
|
||||||
'(cd %s && hg log --rev %s..%s --)',
|
'(cd %s && hg log --style default --rev %s..%s --)',
|
||||||
$this->getPath(),
|
$this->getPath(),
|
||||||
$this->getRelativeCommit(),
|
$this->getRelativeCommit(),
|
||||||
$this->getWorkingCopyRevision());
|
$this->getWorkingCopyRevision());
|
||||||
|
@ -128,57 +146,61 @@ class ArcanistMercurialAPI extends ArcanistRepositoryAPI {
|
||||||
|
|
||||||
public function getWorkingCopyStatus() {
|
public function getWorkingCopyStatus() {
|
||||||
|
|
||||||
// A reviewable revision spans multiple local commits in Mercurial, but
|
if (!isset($this->status)) {
|
||||||
// there is no way to get file change status across multiple commits, so
|
// A reviewable revision spans multiple local commits in Mercurial, but
|
||||||
// just take the entire diff and parse it to figure out what's changed.
|
// there is no way to get file change status across multiple commits, so
|
||||||
|
// just take the entire diff and parse it to figure out what's changed.
|
||||||
|
|
||||||
$diff = $this->getFullMercurialDiff();
|
$diff = $this->getFullMercurialDiff();
|
||||||
$parser = new ArcanistDiffParser();
|
$parser = new ArcanistDiffParser();
|
||||||
$changes = $parser->parseDiff($diff);
|
$changes = $parser->parseDiff($diff);
|
||||||
|
|
||||||
$status_map = array();
|
$status_map = array();
|
||||||
|
|
||||||
foreach ($changes as $change) {
|
foreach ($changes as $change) {
|
||||||
$flags = 0;
|
$flags = 0;
|
||||||
switch ($change->getType()) {
|
switch ($change->getType()) {
|
||||||
case ArcanistDiffChangeType::TYPE_ADD:
|
case ArcanistDiffChangeType::TYPE_ADD:
|
||||||
case ArcanistDiffChangeType::TYPE_MOVE_HERE:
|
case ArcanistDiffChangeType::TYPE_MOVE_HERE:
|
||||||
case ArcanistDiffChangeType::TYPE_COPY_HERE:
|
case ArcanistDiffChangeType::TYPE_COPY_HERE:
|
||||||
$flags |= self::FLAG_ADDED;
|
$flags |= self::FLAG_ADDED;
|
||||||
break;
|
break;
|
||||||
case ArcanistDiffChangeType::TYPE_CHANGE:
|
case ArcanistDiffChangeType::TYPE_CHANGE:
|
||||||
case ArcanistDiffChangeType::TYPE_COPY_AWAY: // Check for changes?
|
case ArcanistDiffChangeType::TYPE_COPY_AWAY: // Check for changes?
|
||||||
$flags |= self::FLAG_MODIFIED;
|
$flags |= self::FLAG_MODIFIED;
|
||||||
break;
|
break;
|
||||||
case ArcanistDiffChangeType::TYPE_DELETE:
|
case ArcanistDiffChangeType::TYPE_DELETE:
|
||||||
case ArcanistDiffChangeType::TYPE_MOVE_AWAY:
|
case ArcanistDiffChangeType::TYPE_MOVE_AWAY:
|
||||||
case ArcanistDiffChangeType::TYPE_MULTICOPY:
|
case ArcanistDiffChangeType::TYPE_MULTICOPY:
|
||||||
$flags |= self::FLAG_DELETED;
|
$flags |= self::FLAG_DELETED;
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
$status_map[$change->getCurrentPath()] = $flags;
|
||||||
}
|
}
|
||||||
$status_map[$change->getCurrentPath()] = $flags;
|
|
||||||
|
list($stdout) = execx(
|
||||||
|
'(cd %s && hg status)',
|
||||||
|
$this->getPath());
|
||||||
|
|
||||||
|
$working_status = $this->parseMercurialStatus($stdout);
|
||||||
|
foreach ($working_status as $path => $status) {
|
||||||
|
$status |= self::FLAG_UNCOMMITTED;
|
||||||
|
if (!empty($status_map[$path])) {
|
||||||
|
$status_map[$path] |= $status;
|
||||||
|
} else {
|
||||||
|
$status_map[$path] = $status;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->status = $status_map;
|
||||||
}
|
}
|
||||||
|
|
||||||
list($stdout) = execx(
|
return $this->status;
|
||||||
'(cd %s && hg status)',
|
|
||||||
$this->getPath());
|
|
||||||
|
|
||||||
$working_status = $this->parseMercurialStatus($stdout);
|
|
||||||
foreach ($working_status as $path => $status) {
|
|
||||||
$status |= self::FLAG_UNCOMMITTED;
|
|
||||||
if (!empty($status_map[$path])) {
|
|
||||||
$status_map[$path] |= $status;
|
|
||||||
} else {
|
|
||||||
$status_map[$path] = $status;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return $status_map;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private function getDiffOptions() {
|
private function getDiffOptions() {
|
||||||
$options = array(
|
$options = array(
|
||||||
'-g',
|
'--git',
|
||||||
'-U'.$this->getDiffLinesOfContext(),
|
'-U'.$this->getDiffLinesOfContext(),
|
||||||
);
|
);
|
||||||
return implode(' ', $options);
|
return implode(' ', $options);
|
||||||
|
|
Loading…
Reference in a new issue