1
0
Fork 0
mirror of https://we.phorge.it/source/arcanist.git synced 2024-09-20 00:49:11 +02:00

Use execxLocal() for ArcanistGitAPI

Summary:
  - This is simpler and reuses more code than doing "(cd %s && ...)" every time.
  - If we have an issue like HGPLAIN, we have one place to fix it now.
  - On Windows, the construct "(cd %s && ...)" does not mean what we'd like it to.

Test Plan: Ran "arc diff" in a git repo with this change.

Reviewers: btrahan, Makinde

Reviewed By: Makinde

CC: aran, epriestley

Maniphest Tasks: T124

Differential Revision: https://secure.phabricator.com/D1761
This commit is contained in:
epriestley 2012-03-02 16:47:34 -08:00
parent 77262c0cff
commit 075c4f84d4
5 changed files with 98 additions and 102 deletions

View file

@ -52,7 +52,7 @@ final class BranchInfo {
$name_sha1_map = mpull($branches, 'getSha1', 'getName');
$commits_list = $api->multigetCommitMessages(
array_unique(array_values($name_sha1_map)),
"%%ct%%n%%an%%n%%s%%n%%b"); //don't ask
"%ct%n%an%n%s%n%b");
foreach ($branches as $branch) {
$sha1 = $name_sha1_map[$branch->getName()];
$branch->setSha1($sha1);

View file

@ -180,4 +180,16 @@ abstract class ArcanistRepositoryAPI {
throw new ArcanistCapabilityNotSupportedException($this);
}
public function execxLocal($pattern /*, ... */) {
$args = func_get_args();
return $this->buildLocalFuture($args)->resolvex();
}
public function execManualLocal($pattern /*, ... */) {
$args = func_get_args();
return $this->buildLocalFuture($args)->resolve();
}
abstract protected function buildLocalFuture(array $argv);
}

View file

@ -38,6 +38,16 @@ final class ArcanistGitAPI extends ArcanistRepositoryAPI {
return new ArcanistGitAPI($root);
}
protected function buildLocalFuture(array $argv) {
$argv[0] = 'git '.$argv[0];
$future = newv('ExecFuture', $argv);
$future->setCWD($this->getPath());
return $future;
}
public function getSourceControlSystemName() {
return 'git';
}
@ -65,9 +75,8 @@ final class ArcanistGitAPI extends ArcanistRepositoryAPI {
$against = $this->getRelativeCommit().'..HEAD';
}
list($info) = execx(
'(cd %s && git log %s --format=%s --)',
$this->getPath(),
list($info) = $this->execxLocal(
'log %s --format=%s --',
$against,
'%H%x00%T%x00%P%x00%at%x00%an%x00%s');
@ -94,13 +103,9 @@ final class ArcanistGitAPI extends ArcanistRepositoryAPI {
public function getRelativeCommit() {
if ($this->relativeCommit === null) {
list($err) = exec_manual(
'(cd %s; git rev-parse --verify HEAD^)',
$this->getPath());
list($err) = $this->execManualLocal('rev-parse --verify HEAD^');
if ($err) {
list($err) = exec_manual(
'(cd %s; git rev-parse --verify HEAD)',
$this->getPath());
list($err) = $this->execManualLocal('rev-parse --verify HEAD');
if ($err) {
$this->repositoryHasNoCommits = true;
}
@ -142,18 +147,16 @@ final class ArcanistGitAPI extends ArcanistRepositoryAPI {
public function getFullGitDiff() {
$options = $this->getDiffFullOptions();
list($stdout) = execx(
"(cd %s; git diff {$options} %s --)",
$this->getPath(),
list($stdout) = $this->execxLocal(
"diff {$options} %s --",
$this->getRelativeCommit());
return $stdout;
}
public function getRawDiffText($path) {
$options = $this->getDiffFullOptions();
list($stdout) = execx(
"(cd %s; git diff {$options} %s -- %s)",
$this->getPath(),
list($stdout) = $this->execxLocal(
"diff {$options} %s -- %s",
$this->getRelativeCommit(),
$path);
return $stdout;
@ -165,9 +168,7 @@ final class ArcanistGitAPI extends ArcanistRepositoryAPI {
// $ git rev-parse --abbrev-ref `git symbolic-ref HEAD`
//
// But that may fail if you're not on a branch.
list($stdout) = execx(
'(cd %s; git branch)',
$this->getPath());
list($stdout) = $this->execxLocal('branch');
$matches = null;
if (preg_match('/^\* (.+)$/m', $stdout, $matches)) {
@ -188,32 +189,27 @@ final class ArcanistGitAPI extends ArcanistRepositoryAPI {
return '';
} else if ($relative == self::GIT_MAGIC_ROOT_COMMIT) {
// First commit.
list($stdout) = execx(
'(cd %s; git log --format=medium HEAD)',
$this->getPath());
list($stdout) = $this->execxLocal('log --format=medium HEAD');
} else {
// 2..N commits.
list($stdout) = execx(
'(cd %s; git log --first-parent --format=medium %s..HEAD)',
$this->getPath(),
list($stdout) = $this->execxLocal(
'log --first-parent --format=medium %s..HEAD',
$this->getRelativeCommit());
}
return $stdout;
}
public function getGitHistoryLog() {
list($stdout) = execx(
'(cd %s; git log --format=medium -n%d %s)',
$this->getPath(),
list($stdout) = $this->execxLocal(
'log --format=medium -n%d %s',
self::SEARCH_LENGTH_FOR_PARENT_REVISIONS,
$this->getRelativeCommit());
return $stdout;
}
public function getSourceControlBaseRevision() {
list($stdout) = execx(
'(cd %s; git rev-parse %s)',
$this->getPath(),
list($stdout) = $this->execxLocal(
'rev-parse %s',
$this->getRelativeCommit());
return rtrim($stdout, "\n");
}
@ -228,9 +224,8 @@ final class ArcanistGitAPI extends ArcanistRepositoryAPI {
} else {
$flags = '';
}
list($stdout) = execx(
'(cd %s; git rev-parse %s HEAD)',
$this->getPath(),
list($stdout) = $this->execxLocal(
'rev-parse %s HEAD',
$flags);
return rtrim($stdout, "\n");
}
@ -243,31 +238,35 @@ final class ArcanistGitAPI extends ArcanistRepositoryAPI {
// -- parallelize these slow cpu bound git calls.
// Find committed changes.
$committed_future = new ExecFuture(
"(cd %s; git diff {$options} --raw %s --)",
$this->getPath(),
$this->getRelativeCommit());
$committed_future = $this->buildLocalFuture(
array(
"diff {$options} --raw %s --",
$this->getRelativeCommit(),
));
// Find uncommitted changes.
$uncommitted_future = new ExecFuture(
"(cd %s; git diff {$options} --raw %s --)",
$this->getPath(),
$this->repositoryHasNoCommits
? self::GIT_MAGIC_ROOT_COMMIT
: 'HEAD');
$uncommitted_future = $this->buildLocalFuture(
array(
"diff {$options} --raw %s --",
$this->repositoryHasNoCommits
? self::GIT_MAGIC_ROOT_COMMIT
: 'HEAD',
));
// Untracked files
$untracked_future = new ExecFuture(
'(cd %s; git ls-files --others --exclude-standard)',
$this->getPath());
$untracked_future = $this->buildLocalFuture(
array(
'ls-files --others --exclude-standard',
));
// TODO: This doesn't list unstaged adds. It's not clear how to get that
// list other than "git status --porcelain" and then parsing it. :/
// Unstaged changes
$unstaged_future = new ExecFuture(
'(cd %s; git ls-files -m)',
$this->getPath());
$unstaged_future = $this->buildLocalFuture(
array(
'ls-files -m',
));
$futures = array(
$committed_future,
@ -320,17 +319,15 @@ final class ArcanistGitAPI extends ArcanistRepositoryAPI {
}
public function amendGitHeadCommit($message) {
execx(
'(cd %s; git commit --amend --allow-empty --message %s)',
$this->getPath(),
$this->execxLocal(
'commit --amend --allow-empty --message %s',
$message);
}
public function getPreReceiveHookStatus($old_ref, $new_ref) {
$options = $this->getDiffBaseOptions();
list($stdout) = execx(
"(cd %s && git diff {$options} --raw %s %s --)",
$this->getPath(),
list($stdout) = $this->execxLocal(
"diff {$options} --raw %s %s --",
$old_ref,
$new_ref);
return $this->parseGitStatus($stdout, $full = true);
@ -376,9 +373,8 @@ final class ArcanistGitAPI extends ArcanistRepositoryAPI {
public function getBlame($path) {
// TODO: 'git blame' supports --porcelain and we should probably use it.
list($stdout) = execx(
'(cd %s; git blame --date=iso -w -M %s -- %s)',
$this->getPath(),
list($stdout) = $this->execxLocal(
'blame --date=iso -w -M %s -- %s',
$this->getRelativeCommit(),
$path);
@ -454,9 +450,8 @@ final class ArcanistGitAPI extends ArcanistRepositoryAPI {
// and treat it as though it as a file containing a list of other files,
// which is silly.
list($stdout) = execx(
'(cd %s && git ls-tree %s -- %s)',
$this->getPath(),
list($stdout) = $this->execxLocal(
'ls-tree %s -- %s',
$revision,
$path);
@ -472,9 +467,8 @@ final class ArcanistGitAPI extends ArcanistRepositoryAPI {
return null;
}
list($stdout) = execx(
'(cd %s && git cat-file blob %s)',
$this->getPath(),
list($stdout) = $this->execxLocal(
'cat-file blob %s',
$info[$path]['ref']);
return $stdout;
}
@ -485,8 +479,7 @@ final class ArcanistGitAPI extends ArcanistRepositoryAPI {
* @return array where each element is a triple ('name', 'sha1', 'current')
*/
public function getAllBranches() {
list($branch_info) = execx(
'cd %s && git branch --no-color', $this->getPath());
list($branch_info) = $this->execxLocal('branch --no-color');
$lines = explode("\n", trim($branch_info));
$result = array();
foreach ($lines as $line) {
@ -506,10 +499,8 @@ final class ArcanistGitAPI extends ArcanistRepositoryAPI {
$all_names = ipull($result, 'name');
// Calling 'git branch' first and then 'git rev-parse' is way faster than
// 'git branch -v' for some reason.
list($sha1s_string) = execx(
"cd %s && git rev-parse %Ls",
$this->path,
$all_names);
list($sha1s_string) = $this->execxLocal('rev-parse %Ls', $all_names);
$sha1_map = array_combine($all_names, explode("\n", trim($sha1s_string)));
foreach ($result as &$branch) {
$branch['sha1'] = $sha1_map[$branch['name']];
@ -525,30 +516,25 @@ final class ArcanistGitAPI extends ArcanistRepositoryAPI {
* @param string $format the format to show messages in
*/
public function multigetCommitMessages($revs, $format) {
$delimiter = "%%x00";
$revs_list = implode(' ', $revs);
$show_command =
"git show -s --pretty=\"format:$format$delimiter\" $revs_list";
list($commits_string) = execx(
"cd %s && $show_command",
$this->getPath());
list($commits_string) = $this->execxLocal(
"show -s --pretty='format:'%s%s %Ls",
$format,
'%x00',
$revs);
$commits_list = array_slice(explode("\0", $commits_string), 0, -1);
$commits_list = array_combine($revs, $commits_list);
return $commits_list;
}
public function getRepositoryOwner() {
list($owner) = execx(
'cd %s && git config --get user.name',
$this->getPath());
list($owner) = $this->execxLocal('config --get user.name');
return trim($owner);
}
public function getWorkingCopyRevision() {
list($stdout) = execx(
'(cd %s; git rev-parse %s)',
$this->getPath(),
'HEAD');
list($stdout) = $this->execxLocal('rev-parse HEAD');
return rtrim($stdout, "\n");
}
@ -567,9 +553,8 @@ final class ArcanistGitAPI extends ArcanistRepositoryAPI {
if ($base == ArcanistGitAPI::GIT_MAGIC_ROOT_COMMIT) {
$merge_base = $base;
} else {
list($err, $merge_base) = exec_manual(
'(cd %s; git merge-base %s HEAD)',
$this->getPath(),
list($err, $merge_base) = $this->execManualLocal(
'merge-base %s HEAD',
$base);
if ($err) {
throw new ArcanistUsageException(
@ -614,9 +599,8 @@ final class ArcanistGitAPI extends ArcanistRepositoryAPI {
}
public function getCommitMessageForRevision($rev) {
list($message) = execx(
'(cd %s && git log -n1 %s)',
$this->getPath(),
list($message) = $this->execxLocal(
'log -n1 %s',
$rev);
$parser = new ArcanistDiffParser();
return head($parser->parseDiff($message));

View file

@ -29,17 +29,7 @@ final class ArcanistMercurialAPI extends ArcanistRepositoryAPI {
private $workingCopyRevision;
private $localCommitInfo;
public function execxLocal($pattern /*, ... */) {
$args = func_get_args();
return $this->buildLocalFuture($args)->resolvex();
}
public function execManualLocal($pattern /*, ... */) {
$args = func_get_args();
return $this->buildLocalFuture($args)->resolve();
}
private function buildLocalFuture(array $argv) {
protected function buildLocalFuture(array $argv) {
// Mercurial has a "defaults" feature which basically breaks automation by
// allowing the user to add random flags to any command. This feature is

View file

@ -36,6 +36,16 @@ final class ArcanistSubversionAPI extends ArcanistRepositoryAPI {
return 'svn';
}
protected function buildLocalFuture(array $argv) {
$argv[0] = 'svn '.$argv[0];
$future = newv('ExecFuture', $argv);
$future->setCWD($this->getPath());
return $future;
}
public function hasMergeConflicts() {
foreach ($this->getSVNStatus() as $path => $mask) {
if ($mask & self::FLAG_CONFLICT) {