Page MenuHomePhabricator

D18842.diff
No OneTemporary

D18842.diff

diff --git a/src/repository/api/ArcanistGitAPI.php b/src/repository/api/ArcanistGitAPI.php
--- a/src/repository/api/ArcanistGitAPI.php
+++ b/src/repository/api/ArcanistGitAPI.php
@@ -52,8 +52,12 @@
}
public function getGitVersion() {
- list($stdout) = $this->execxLocal('--version');
- return rtrim(str_replace('git version ', '', $stdout));
+ static $version = null;
+ if ($version === null) {
+ list($stdout) = $this->execxLocal('--version');
+ $version = rtrim(str_replace('git version ', '', $stdout));
+ }
+ return $version;
}
public function getMetadataPath() {
@@ -645,8 +649,70 @@
return $this->executeSVNFindRev($hash, 'SVN');
}
+ private function buildUncommittedStatusViaStatus() {
+ $status = $this->buildLocalFuture(
+ array(
+ 'status --porcelain=2 -z',
+ ));
+ list($stdout) = $status->resolvex();
+
+ $result = new PhutilArrayWithDefaultValue();
+ $parts = explode("\0", $stdout);
+ while (count($parts) > 1) {
+ $entry = array_shift($parts);
+ $entry_parts = explode(' ', $entry);
+ if ($entry_parts[0] == '1') {
+ $path = $entry_parts[8];
+ } else if ($entry_parts[0] == '2') {
+ $path = $entry_parts[9];
+ } else if ($entry_parts[0] == 'u') {
+ $path = $entry_parts[10];
+ } else if ($entry_parts[0] == '?') {
+ $result[$entry_parts[1]] = self::FLAG_UNTRACKED;
+ continue;
+ }
+
+ $result[$path] |= self::FLAG_UNCOMMITTED;
+ $index_state = substr($entry_parts[1], 0, 1);
+ $working_state = substr($entry_parts[1], 1, 1);
+ if ($index_state == 'A') {
+ $result[$path] |= self::FLAG_ADDED;
+ } else if ($index_state == 'M') {
+ $result[$path] |= self::FLAG_MODIFIED;
+ } else if ($index_state == 'D') {
+ $result[$path] |= self::FLAG_DELETED;
+ }
+ if ($working_state != '.') {
+ $result[$path] |= self::FLAG_UNSTAGED;
+ if ($index_state == '.') {
+ if ($working_state == 'A') {
+ $result[$path] |= self::FLAG_ADDED;
+ } else if ($working_state == 'M') {
+ $result[$path] |= self::FLAG_MODIFIED;
+ } else if ($working_state == 'D') {
+ $result[$path] |= self::FLAG_DELETED;
+ }
+ }
+ }
+ $submodule_tracked = substr($entry_parts[2], 2, 1);
+ $submodule_untracked = substr($entry_parts[2], 3, 1);
+ if ($submodule_tracked == 'M' || $submodule_untracked == 'U') {
+ $result[$path] |= self::FLAG_EXTERNALS;
+ }
+
+ if ($entry_parts[0] == '2') {
+ $result[array_shift($parts)] = $result[$path] | self::FLAG_DELETED;
+ $result[$path] |= self::FLAG_ADDED;
+ }
+ }
+ return $result->toArray();
+ }
protected function buildUncommittedStatus() {
+ if (version_compare($this->getGitVersion(), '2.11.0', '>=')) {
+ return $this->buildUncommittedStatusViaStatus();
+ }
+
$diff_options = $this->getDiffBaseOptions();
if ($this->repositoryHasNoCommits) {
@@ -719,7 +785,7 @@
protected function buildCommitRangeStatus() {
list($stdout, $stderr) = $this->execxLocal(
- 'diff %C --raw %s --',
+ 'diff %C --raw %s HEAD --',
$this->getDiffBaseOptions(),
$this->getBaseCommit());
diff --git a/src/repository/api/ArcanistMercurialAPI.php b/src/repository/api/ArcanistMercurialAPI.php
--- a/src/repository/api/ArcanistMercurialAPI.php
+++ b/src/repository/api/ArcanistMercurialAPI.php
@@ -372,41 +372,18 @@
}
protected function buildCommitRangeStatus() {
- // TODO: Possibly we should use "hg status --rev X --rev ." for this
- // instead, but we must run "hg diff" later anyway in most cases, so
- // building and caching it shouldn't hurt us.
+ list($stdout) = $this->execxLocal(
+ 'status --rev %s --rev tip',
+ $this->getBaseCommit());
- $diff = $this->getFullMercurialDiff();
- if (!$diff) {
- return array();
- }
+ $results = new PhutilArrayWithDefaultValue();
- $parser = new ArcanistDiffParser();
- $changes = $parser->parseDiff($diff);
-
- $status_map = array();
- foreach ($changes as $change) {
- $flags = 0;
- switch ($change->getType()) {
- case ArcanistDiffChangeType::TYPE_ADD:
- case ArcanistDiffChangeType::TYPE_MOVE_HERE:
- case ArcanistDiffChangeType::TYPE_COPY_HERE:
- $flags |= self::FLAG_ADDED;
- break;
- case ArcanistDiffChangeType::TYPE_CHANGE:
- case ArcanistDiffChangeType::TYPE_COPY_AWAY: // Check for changes?
- $flags |= self::FLAG_MODIFIED;
- break;
- case ArcanistDiffChangeType::TYPE_DELETE:
- case ArcanistDiffChangeType::TYPE_MOVE_AWAY:
- case ArcanistDiffChangeType::TYPE_MULTICOPY:
- $flags |= self::FLAG_DELETED;
- break;
- }
- $status_map[$change->getCurrentPath()] = $flags;
+ $working_status = ArcanistMercurialParser::parseMercurialStatus($stdout);
+ foreach ($working_status as $path => $mask) {
+ $results[$path] |= $mask;
}
- return $status_map;
+ return $results->toArray();
}
protected function didReloadWorkingCopy() {
diff --git a/src/repository/api/ArcanistSubversionAPI.php b/src/repository/api/ArcanistSubversionAPI.php
--- a/src/repository/api/ArcanistSubversionAPI.php
+++ b/src/repository/api/ArcanistSubversionAPI.php
@@ -45,9 +45,9 @@
}
protected function buildCommitRangeStatus() {
- // In SVN, the commit range is always "uncommitted changes", so these
- // statuses are equivalent.
- return $this->getUncommittedStatus();
+ // In SVN, there are never any previous commits in the range -- it is all in
+ // the uncommitted status.
+ return array();
}
protected function buildUncommittedStatus() {
diff --git a/src/repository/api/__tests__/ArcanistRepositoryAPIStateTestCase.php b/src/repository/api/__tests__/ArcanistRepositoryAPIStateTestCase.php
--- a/src/repository/api/__tests__/ArcanistRepositoryAPIStateTestCase.php
+++ b/src/repository/api/__tests__/ArcanistRepositoryAPIStateTestCase.php
@@ -56,6 +56,16 @@
}
private function assertCorrectState($test, ArcanistRepositoryAPI $api) {
+ if ($api instanceof ArcanistGitAPI) {
+ $version = $api->getGitVersion();
+ if (version_compare($version, '2.11.0', '<')) {
+ // Behavior differs slightly on older versions of git; rather than code
+ // both variants, skip the tests in the presence of such a git.
+ $this->assertSkipped(pht('Behavior differs slightly on git < 2.11.0'));
+ return;
+ }
+ }
+
$f_mod = ArcanistRepositoryAPI::FLAG_MODIFIED;
$f_add = ArcanistRepositoryAPI::FLAG_ADDED;
$f_del = ArcanistRepositoryAPI::FLAG_DELETED;
@@ -70,7 +80,22 @@
switch ($test) {
case 'svn_basic.svn.tgz':
- $expect = array(
+ $expect_uncommitted = array(
+ 'ADDED' => $f_add,
+ 'COPIED_TO' => $f_add,
+ 'DELETED' => $f_del,
+ 'MODIFIED' => $f_mod,
+ 'MOVED' => $f_del,
+ 'MOVED_TO' => $f_add,
+ 'PROPCHANGE' => $f_mod,
+ 'UNTRACKED' => $f_unt,
+ );
+ $this->assertEqual($expect_uncommitted, $api->getUncommittedStatus());
+
+ $expect_range = array();
+ $this->assertEqual($expect_range, $api->getCommitRangeStatus());
+
+ $expect_working = array(
'ADDED' => $f_add,
'COPIED_TO' => $f_add,
'DELETED' => $f_del,
@@ -80,8 +105,7 @@
'PROPCHANGE' => $f_mod,
'UNTRACKED' => $f_unt,
);
- $this->assertEqual($expect, $api->getUncommittedStatus());
- $this->assertEqual($expect, $api->getCommitRangeStatus());
+ $this->assertEqual($expect_working, $api->getWorkingCopyStatus());
break;
case 'git_basic.git.tgz':
$expect_uncommitted = array(
@@ -96,10 +120,19 @@
'ADDED' => $f_add,
'DELETED' => $f_del,
'MODIFIED' => $f_mod,
- 'UNCOMMITTED' => $f_add,
'UNSTAGED' => $f_add,
);
$this->assertEqual($expect_range, $api->getCommitRangeStatus());
+
+ $expect_working = array(
+ 'ADDED' => $f_add,
+ 'DELETED' => $f_del,
+ 'MODIFIED' => $f_mod,
+ 'UNCOMMITTED' => $f_add | $f_unc,
+ 'UNSTAGED' => $f_add | $f_mod | $f_uns | $f_unc,
+ 'UNTRACKED' => $f_unt,
+ );
+ $this->assertEqual($expect_working, $api->getWorkingCopyStatus());
break;
case 'git_submodules_dirty.git.tgz':
$expect_uncommitted = array(
@@ -107,19 +140,19 @@
'added/' => $f_unt,
'deleted' => $f_del | $f_uns | $f_unc,
'modified-commit' => $f_mod | $f_uns | $f_unc,
- 'modified-commit-dirty' => $f_mod | $f_uns | $f_unc,
- 'modified-dirty' => $f_ext | $f_uns | $f_unc,
+ 'modified-commit-dirty' => $f_ext | $f_mod | $f_uns | $f_unc,
+ 'modified-dirty' => $f_ext | $f_mod | $f_uns | $f_unc,
);
$this->assertEqual($expect_uncommitted, $api->getUncommittedStatus());
break;
case 'git_submodules_staged.git.tgz':
$expect_uncommitted = array(
- '.gitmodules' => $f_mod | $f_uns | $f_unc,
+ '.gitmodules' => $f_mod | $f_unc,
'added' => $f_add | $f_unc,
'deleted' => $f_del | $f_unc,
'modified-commit' => $f_mod | $f_unc,
- 'modified-commit-dirty' => $f_mod | $f_uns | $f_unc,
- 'modified-dirty' => $f_ext | $f_uns | $f_unc,
+ 'modified-commit-dirty' => $f_ext | $f_mod | $f_uns | $f_unc,
+ 'modified-dirty' => $f_ext | $f_mod | $f_uns | $f_unc,
);
$this->assertEqual($expect_uncommitted, $api->getUncommittedStatus());
break;
@@ -137,6 +170,15 @@
'UNCOMMITTED' => $f_add,
);
$this->assertEqual($expect_range, $api->getCommitRangeStatus());
+
+ $expect_working = array(
+ 'ADDED' => $f_add,
+ 'DELETED' => $f_del,
+ 'MODIFIED' => $f_mod,
+ 'UNCOMMITTED' => $f_add | $f_mod | $f_unc,
+ 'UNTRACKED' => $f_unt,
+ );
+ $this->assertEqual($expect_working, $api->getWorkingCopyStatus());
break;
default:
throw new Exception(

File Metadata

Mime Type
text/plain
Expires
Fri, May 24, 3:56 AM (3 w, 2 d ago)
Storage Engine
blob
Storage Format
Encrypted (AES-256-CBC)
Storage Handle
6288806
Default Alt Text
D18842.diff (10 KB)

Event Timeline