mirror of
https://we.phorge.it/source/phorge.git
synced 2024-11-25 16:22:43 +01:00
Further correct and disambigutate ref selectors passed to Git on the CLI
Summary: Ref T13589. In D21510, not every ref selector got touched, and this isn't a valid construction in Git: ``` $ git ls-tree ... -- '' ``` Thus: - Disambiguate more (all?) ref selectors. - Correct the construction of "git ls-tree" when there is no path. - Clean some stuff up: make the construction of some flags and arguments more explicit, get rid of a needless "%C", prefer "%Ls" over acrobatics, etc. Test Plan: Browsed/updated a local Git repository. (This change is somewhat difficult to test exhaustively, as evidenced by the "ls-tree" issue in D21510.) Maniphest Tasks: T13589 Differential Revision: https://secure.phabricator.com/D21511
This commit is contained in:
parent
ea9cb0b625
commit
0e28105ff7
15 changed files with 103 additions and 67 deletions
|
@ -35,22 +35,26 @@ final class DiffusionBrowseQueryConduitAPIMethod
|
||||||
protected function getGitResult(ConduitAPIRequest $request) {
|
protected function getGitResult(ConduitAPIRequest $request) {
|
||||||
$drequest = $this->getDiffusionRequest();
|
$drequest = $this->getDiffusionRequest();
|
||||||
$repository = $drequest->getRepository();
|
$repository = $drequest->getRepository();
|
||||||
|
|
||||||
$path = $request->getValue('path');
|
$path = $request->getValue('path');
|
||||||
|
if (!strlen($path)) {
|
||||||
|
$path = null;
|
||||||
|
}
|
||||||
|
|
||||||
$commit = $request->getValue('commit');
|
$commit = $request->getValue('commit');
|
||||||
$offset = (int)$request->getValue('offset');
|
$offset = (int)$request->getValue('offset');
|
||||||
$limit = (int)$request->getValue('limit');
|
$limit = (int)$request->getValue('limit');
|
||||||
$result = $this->getEmptyResultSet();
|
$result = $this->getEmptyResultSet();
|
||||||
|
|
||||||
if ($path == '') {
|
if ($path === null) {
|
||||||
// Fast path to improve the performance of the repository view; we know
|
// Fast path to improve the performance of the repository view; we know
|
||||||
// the root is always a tree at any commit and always exists.
|
// the root is always a tree at any commit and always exists.
|
||||||
$stdout = 'tree';
|
$stdout = 'tree';
|
||||||
} else {
|
} else {
|
||||||
try {
|
try {
|
||||||
list($stdout) = $repository->execxLocalCommand(
|
list($stdout) = $repository->execxLocalCommand(
|
||||||
'cat-file -t -- %s:%s',
|
'cat-file -t -- %s',
|
||||||
$commit,
|
sprintf('%s:%s', $commit, $path));
|
||||||
$path);
|
|
||||||
} catch (CommandException $e) {
|
} catch (CommandException $e) {
|
||||||
// The "cat-file" command may fail if the path legitimately does not
|
// The "cat-file" command may fail if the path legitimately does not
|
||||||
// exist, but it may also fail if the path is a submodule. This can
|
// exist, but it may also fail if the path is a submodule. This can
|
||||||
|
@ -121,14 +125,20 @@ final class DiffusionBrowseQueryConduitAPIMethod
|
||||||
return $result;
|
return $result;
|
||||||
}
|
}
|
||||||
|
|
||||||
list($stdout) = $repository->execxLocalCommand(
|
if ($path === null) {
|
||||||
'ls-tree -z -l %s -- %s',
|
list($stdout) = $repository->execxLocalCommand(
|
||||||
gitsprintf('%s', $commit),
|
'ls-tree -z -l %s --',
|
||||||
$path);
|
gitsprintf('%s', $commit));
|
||||||
|
} else {
|
||||||
|
list($stdout) = $repository->execxLocalCommand(
|
||||||
|
'ls-tree -z -l %s -- %s',
|
||||||
|
gitsprintf('%s', $commit),
|
||||||
|
$path);
|
||||||
|
}
|
||||||
|
|
||||||
$submodules = array();
|
$submodules = array();
|
||||||
|
|
||||||
if (strlen($path)) {
|
if ($path !== null) {
|
||||||
$prefix = rtrim($path, '/').'/';
|
$prefix = rtrim($path, '/').'/';
|
||||||
} else {
|
} else {
|
||||||
$prefix = '';
|
$prefix = '';
|
||||||
|
@ -226,8 +236,8 @@ final class DiffusionBrowseQueryConduitAPIMethod
|
||||||
$dict[$key] = $value;
|
$dict[$key] = $value;
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach ($submodules as $path) {
|
foreach ($submodules as $submodule_path) {
|
||||||
$full_path = $path->getFullPath();
|
$full_path = $submodule_path->getFullPath();
|
||||||
$key = 'submodule.'.$full_path.'.url';
|
$key = 'submodule.'.$full_path.'.url';
|
||||||
if (isset($dict[$key])) {
|
if (isset($dict[$key])) {
|
||||||
$path->setExternalURI($dict[$key]);
|
$path->setExternalURI($dict[$key]);
|
||||||
|
|
|
@ -45,7 +45,12 @@ final class DiffusionHistoryQueryConduitAPIMethod
|
||||||
$repository = $drequest->getRepository();
|
$repository = $drequest->getRepository();
|
||||||
$commit_hash = $request->getValue('commit');
|
$commit_hash = $request->getValue('commit');
|
||||||
$against_hash = $request->getValue('against');
|
$against_hash = $request->getValue('against');
|
||||||
|
|
||||||
$path = $request->getValue('path');
|
$path = $request->getValue('path');
|
||||||
|
if (!strlen($path)) {
|
||||||
|
$path = null;
|
||||||
|
}
|
||||||
|
|
||||||
$offset = $request->getValue('offset');
|
$offset = $request->getValue('offset');
|
||||||
$limit = $request->getValue('limit');
|
$limit = $request->getValue('limit');
|
||||||
|
|
||||||
|
@ -55,18 +60,27 @@ final class DiffusionHistoryQueryConduitAPIMethod
|
||||||
$commit_range = $commit_hash;
|
$commit_range = $commit_hash;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$argv = array();
|
||||||
|
|
||||||
|
$argv[] = '--skip';
|
||||||
|
$argv[] = $offset;
|
||||||
|
|
||||||
|
$argv[] = '--max-count';
|
||||||
|
$argv[] = $limit;
|
||||||
|
|
||||||
|
$argv[] = '--format=%H:%P';
|
||||||
|
|
||||||
|
$argv[] = gitsprintf('%s', $commit_range);
|
||||||
|
|
||||||
|
$argv[] = '--';
|
||||||
|
|
||||||
|
if ($path !== null) {
|
||||||
|
$argv[] = $path;
|
||||||
|
}
|
||||||
|
|
||||||
list($stdout) = $repository->execxLocalCommand(
|
list($stdout) = $repository->execxLocalCommand(
|
||||||
'log '.
|
'log %Ls',
|
||||||
'--skip=%d '.
|
$argv);
|
||||||
'-n %d '.
|
|
||||||
'--pretty=format:%s '.
|
|
||||||
'%s -- %C',
|
|
||||||
$offset,
|
|
||||||
$limit,
|
|
||||||
'%H:%P',
|
|
||||||
gitsprintf('%s', $commit_range),
|
|
||||||
// Git omits merge commits if the path is provided, even if it is empty.
|
|
||||||
(strlen($path) ? csprintf('%s', $path) : ''));
|
|
||||||
|
|
||||||
$lines = explode("\n", trim($stdout));
|
$lines = explode("\n", trim($stdout));
|
||||||
$lines = array_filter($lines);
|
$lines = array_filter($lines);
|
||||||
|
|
|
@ -43,9 +43,9 @@ final class DiffusionInternalGitRawDiffQueryConduitAPIMethod
|
||||||
// it requires the commit to have a parent that we can diff against. The
|
// it requires the commit to have a parent that we can diff against. The
|
||||||
// first commit doesn't, so "commit^" is not a valid ref.
|
// first commit doesn't, so "commit^" is not a valid ref.
|
||||||
list($parents) = $repository->execxLocalCommand(
|
list($parents) = $repository->execxLocalCommand(
|
||||||
'log -n1 --format=%s %s',
|
'log -n1 %s %s --',
|
||||||
'%P',
|
'--format=%P',
|
||||||
$commit);
|
gitsprintf('%s', $commit));
|
||||||
$use_log = !strlen(trim($parents));
|
$use_log = !strlen(trim($parents));
|
||||||
|
|
||||||
// First, get a fast raw diff without "--find-copies-harder". This flag
|
// First, get a fast raw diff without "--find-copies-harder". This flag
|
||||||
|
@ -96,18 +96,18 @@ final class DiffusionInternalGitRawDiffQueryConduitAPIMethod
|
||||||
// NOTE: "--pretty=format: " is to disable diff output, we only want the
|
// NOTE: "--pretty=format: " is to disable diff output, we only want the
|
||||||
// part we get from "--raw".
|
// part we get from "--raw".
|
||||||
$future = $repository->getLocalCommandFuture(
|
$future = $repository->getLocalCommandFuture(
|
||||||
'log %Ls --pretty=format: %s',
|
'log %Ls --pretty=format: %s --',
|
||||||
$flags,
|
$flags,
|
||||||
$commit);
|
gitsprintf('%s', $commit));
|
||||||
} else {
|
} else {
|
||||||
// Otherwise, we can use "diff", which will give us output for merges.
|
// Otherwise, we can use "diff", which will give us output for merges.
|
||||||
// We diff against the first parent, as this is generally the expectation
|
// We diff against the first parent, as this is generally the expectation
|
||||||
// and results in sensible behavior.
|
// and results in sensible behavior.
|
||||||
$future = $repository->getLocalCommandFuture(
|
$future = $repository->getLocalCommandFuture(
|
||||||
'diff %Ls %s^1 %s',
|
'diff %Ls %s %s --',
|
||||||
$flags,
|
$flags,
|
||||||
$commit,
|
gitsprintf('%s^1', $commit),
|
||||||
$commit);
|
gitsprintf('%s', $commit));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Don't spend more than 30 seconds generating the slower output.
|
// Don't spend more than 30 seconds generating the slower output.
|
||||||
|
|
|
@ -33,7 +33,8 @@ final class DiffusionLastModifiedQueryConduitAPIMethod
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
list($hash) = $repository->execxLocalCommand(
|
list($hash) = $repository->execxLocalCommand(
|
||||||
'log -n1 --format=%%H %s -- %s',
|
'log -n1 %s %s -- %s',
|
||||||
|
'--format=%H',
|
||||||
gitsprintf('%s', $commit),
|
gitsprintf('%s', $commit),
|
||||||
$path);
|
$path);
|
||||||
$results[$path] = trim($hash);
|
$results[$path] = trim($hash);
|
||||||
|
|
|
@ -35,8 +35,8 @@ final class DiffusionMergedCommitsQueryConduitAPIMethod
|
||||||
$limit = $this->getLimit($request);
|
$limit = $this->getLimit($request);
|
||||||
|
|
||||||
list($parents) = $repository->execxLocalCommand(
|
list($parents) = $repository->execxLocalCommand(
|
||||||
'log -n 1 --format=%s %s --',
|
'log -n 1 %s %s --',
|
||||||
'%P',
|
'--format=%P',
|
||||||
gitsprintf('%s', $commit));
|
gitsprintf('%s', $commit));
|
||||||
|
|
||||||
$parents = preg_split('/\s+/', trim($parents));
|
$parents = preg_split('/\s+/', trim($parents));
|
||||||
|
@ -50,10 +50,10 @@ final class DiffusionMergedCommitsQueryConduitAPIMethod
|
||||||
|
|
||||||
$first_parent = head($parents);
|
$first_parent = head($parents);
|
||||||
list($logs) = $repository->execxLocalCommand(
|
list($logs) = $repository->execxLocalCommand(
|
||||||
'log -n %d --format=%s %s %s --',
|
'log -n %d %s %s %s --',
|
||||||
// NOTE: "+ 1" accounts for the merge commit itself.
|
// NOTE: "+ 1" accounts for the merge commit itself.
|
||||||
$limit + 1,
|
$limit + 1,
|
||||||
'%H',
|
'--format=%H',
|
||||||
gitsprintf('%s', $commit),
|
gitsprintf('%s', $commit),
|
||||||
gitsprintf('%s', '^'.$first_parent));
|
gitsprintf('%s', '^'.$first_parent));
|
||||||
|
|
||||||
|
|
|
@ -28,9 +28,9 @@ final class DiffusionRefsQueryConduitAPIMethod
|
||||||
$commit = $request->getValue('commit');
|
$commit = $request->getValue('commit');
|
||||||
|
|
||||||
list($stdout) = $repository->execxLocalCommand(
|
list($stdout) = $repository->execxLocalCommand(
|
||||||
'log --format=%s -n 1 %s --',
|
'log -n 1 %s %s --',
|
||||||
'%d',
|
'--format=%d',
|
||||||
$commit);
|
gitsprintf('%s', $commit));
|
||||||
|
|
||||||
// %d, gives a weird output format
|
// %d, gives a weird output format
|
||||||
// similar to (remote/one, remote/two, remote/three)
|
// similar to (remote/one, remote/two, remote/three)
|
||||||
|
|
|
@ -608,9 +608,9 @@ final class DiffusionCommitHookEngine extends Phobject {
|
||||||
// repository. Particularly, this will cover the cases of a new branch, a
|
// repository. Particularly, this will cover the cases of a new branch, a
|
||||||
// completely moved tag, etc.
|
// completely moved tag, etc.
|
||||||
$futures[$key] = $this->getRepository()->getLocalCommandFuture(
|
$futures[$key] = $this->getRepository()->getLocalCommandFuture(
|
||||||
'log --format=%s %s --not --all',
|
'log %s %s --not --all --',
|
||||||
'%H',
|
'--format=%H',
|
||||||
$ref_update->getRefNew());
|
gitsprintf('%s', $ref_update->getRefNew()));
|
||||||
}
|
}
|
||||||
|
|
||||||
$content_updates = array();
|
$content_updates = array();
|
||||||
|
|
|
@ -10,9 +10,8 @@ final class DiffusionGitFileContentQuery extends DiffusionFileContentQuery {
|
||||||
$commit = $drequest->getCommit();
|
$commit = $drequest->getCommit();
|
||||||
|
|
||||||
return $repository->getLocalCommandFuture(
|
return $repository->getLocalCommandFuture(
|
||||||
'cat-file blob -- %s:%s',
|
'cat-file blob -- %s',
|
||||||
$commit,
|
sprintf('%s:%s', $commit, $path));
|
||||||
$path);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -55,12 +55,15 @@ final class DiffusionLowLevelCommitQuery
|
||||||
$split_body = true;
|
$split_body = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Even though we pass --encoding here, git doesn't always succeed, so
|
$argv = array();
|
||||||
// we try a little harder, since git *does* tell us what the actual encoding
|
|
||||||
// is correctly (unless it doesn't; encoding is sometimes empty).
|
$argv[] = '-n';
|
||||||
list($info) = $repository->execxLocalCommand(
|
$argv[] = '1';
|
||||||
'log -n 1 --encoding=%s --format=%s %s --',
|
|
||||||
'UTF-8',
|
$argv[] = '--encoding=UTF-8';
|
||||||
|
|
||||||
|
$argv[] = sprintf(
|
||||||
|
'--format=%s',
|
||||||
implode(
|
implode(
|
||||||
'%x00',
|
'%x00',
|
||||||
array(
|
array(
|
||||||
|
@ -78,8 +81,15 @@ final class DiffusionLowLevelCommitQuery
|
||||||
// so include an explicit terminator: this makes sure the exact
|
// so include an explicit terminator: this makes sure the exact
|
||||||
// body text is surrounded by "\0" characters.
|
// body text is surrounded by "\0" characters.
|
||||||
'~',
|
'~',
|
||||||
)),
|
)));
|
||||||
$this->identifier);
|
|
||||||
|
// Even though we pass --encoding here, git doesn't always succeed, so
|
||||||
|
// we try a little harder, since git *does* tell us what the actual encoding
|
||||||
|
// is correctly (unless it doesn't; encoding is sometimes empty).
|
||||||
|
list($info) = $repository->execxLocalCommand(
|
||||||
|
'log -n 1 %Ls %s --',
|
||||||
|
$argv,
|
||||||
|
gitsprintf('%s', $this->identifier));
|
||||||
|
|
||||||
$parts = explode("\0", $info);
|
$parts = explode("\0", $info);
|
||||||
$encoding = array_shift($parts);
|
$encoding = array_shift($parts);
|
||||||
|
|
|
@ -33,7 +33,7 @@ final class DiffusionLowLevelFilesizeQuery
|
||||||
|
|
||||||
$paths_future = $repository->getLocalCommandFuture(
|
$paths_future = $repository->getLocalCommandFuture(
|
||||||
'diff-tree -z -r --no-commit-id %s --',
|
'diff-tree -z -r --no-commit-id %s --',
|
||||||
$identifier);
|
gitsprintf('%s', $identifier));
|
||||||
|
|
||||||
// With "-z" we get "<fields>\0<filename>\0" for each line. Process the
|
// With "-z" we get "<fields>\0<filename>\0" for each line. Process the
|
||||||
// delimited text as "<fields>, <filename>" pairs.
|
// delimited text as "<fields>, <filename>" pairs.
|
||||||
|
|
|
@ -37,8 +37,8 @@ final class DiffusionLowLevelParentsQuery
|
||||||
$repository = $this->getRepository();
|
$repository = $this->getRepository();
|
||||||
|
|
||||||
list($stdout) = $repository->execxLocalCommand(
|
list($stdout) = $repository->execxLocalCommand(
|
||||||
'log -n 1 --format=%s %s --',
|
'log -n 1 %s %s --',
|
||||||
'%P',
|
'--format=%P',
|
||||||
gitsprintf('%s', $this->identifier));
|
gitsprintf('%s', $this->identifier));
|
||||||
|
|
||||||
return preg_split('/\s+/', trim($stdout));
|
return preg_split('/\s+/', trim($stdout));
|
||||||
|
|
|
@ -23,8 +23,8 @@ final class DiffusionGitRawDiffQuery extends DiffusionRawDiffQuery {
|
||||||
// Check if this is the root commit by seeing if it has parents, since
|
// Check if this is the root commit by seeing if it has parents, since
|
||||||
// `git diff X^ X` does not work if "X" is the initial commit.
|
// `git diff X^ X` does not work if "X" is the initial commit.
|
||||||
list($parents) = $repository->execxLocalCommand(
|
list($parents) = $repository->execxLocalCommand(
|
||||||
'log -n 1 --format=%s %s --',
|
'log -n 1 %s --',
|
||||||
'%P',
|
'--format=%P',
|
||||||
gitsprintf('%s', $commit));
|
gitsprintf('%s', $commit));
|
||||||
|
|
||||||
if (strlen(trim($parents))) {
|
if (strlen(trim($parents))) {
|
||||||
|
|
|
@ -19,13 +19,13 @@ final class PhabricatorGitGraphStream
|
||||||
|
|
||||||
if ($start_commit !== null) {
|
if ($start_commit !== null) {
|
||||||
$future = $repository->getLocalCommandFuture(
|
$future = $repository->getLocalCommandFuture(
|
||||||
'log --format=%s %s --',
|
'log %s %s --',
|
||||||
'%H%x01%P%x01%ct',
|
'--format=%H%x01%P%x01%ct',
|
||||||
$start_commit);
|
gitsprintf('%s', $start_commit));
|
||||||
} else {
|
} else {
|
||||||
$future = $repository->getLocalCommandFuture(
|
$future = $repository->getLocalCommandFuture(
|
||||||
'log --format=%s --all --',
|
'log %s --all --',
|
||||||
'%H%x01%P%x01%ct');
|
'--format=%H%x01%P%x01%ct');
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->iterator = new LinesOfALargeExecFuture($future);
|
$this->iterator = new LinesOfALargeExecFuture($future);
|
||||||
|
|
|
@ -483,17 +483,17 @@ final class PhabricatorRepositoryRefEngine
|
||||||
$ref_list = implode("\n", $ref_list)."\n";
|
$ref_list = implode("\n", $ref_list)."\n";
|
||||||
|
|
||||||
$future = $this->getRepository()->getLocalCommandFuture(
|
$future = $this->getRepository()->getLocalCommandFuture(
|
||||||
'log --format=%s --stdin',
|
'log %s --stdin --',
|
||||||
'%H');
|
'--format=%H');
|
||||||
|
|
||||||
list($stdout) = $future
|
list($stdout) = $future
|
||||||
->write($ref_list)
|
->write($ref_list)
|
||||||
->resolvex();
|
->resolvex();
|
||||||
} else {
|
} else {
|
||||||
list($stdout) = $this->getRepository()->execxLocalCommand(
|
list($stdout) = $this->getRepository()->execxLocalCommand(
|
||||||
'log --format=%s %s',
|
'log %s %s --',
|
||||||
'%H',
|
'--format=%H',
|
||||||
$new_head);
|
gitsprintf('%s', $new_head));
|
||||||
}
|
}
|
||||||
|
|
||||||
$stdout = trim($stdout);
|
$stdout = trim($stdout);
|
||||||
|
|
|
@ -4,6 +4,8 @@ final class PhabricatorWorkingCopyDiscoveryTestCase
|
||||||
extends PhabricatorWorkingCopyTestCase {
|
extends PhabricatorWorkingCopyTestCase {
|
||||||
|
|
||||||
public function testSubversionCommitDiscovery() {
|
public function testSubversionCommitDiscovery() {
|
||||||
|
$this->requireBinaryForTest('svn');
|
||||||
|
|
||||||
$refs = $this->discoverRefs('ST');
|
$refs = $this->discoverRefs('ST');
|
||||||
$this->assertEqual(
|
$this->assertEqual(
|
||||||
array(
|
array(
|
||||||
|
|
Loading…
Reference in a new issue