1
0
Fork 0
mirror of https://we.phorge.it/source/phorge.git synced 2024-12-19 20:10:55 +01:00

Return Diffusion diffs through Files, not directly over Conduit

Summary:
Fixes T10423. Ref T11524. This changes `diffusion.rawdiffquery` to return a file PHID instead of a blob of data.

This is better in general, but particularly better for huge diffs (as in T10423) and diffs with non-utf8 data (as in T10423).

Test Plan:
  - Used `bin/differential extract` to extract a latin1 diff, got a clean diff.
  - Used `bin/repository reparse --herald` to rerun herald on a latin1 diff, got a clean result.
  - Pushed latin1 diffs to test commit hooks.
  - Triggered the the too large / too slow logic.
  - Viewed latin1 diffs in Diffusion.
  - Used "blame past this change" in Diffusion to hit the `before` logic.

Reviewers: chad

Reviewed By: chad

Subscribers: eadler

Maniphest Tasks: T10423, T11524

Differential Revision: https://secure.phabricator.com/D16460
This commit is contained in:
epriestley 2016-08-26 09:37:53 -07:00
parent 771579496f
commit c55de86f0e
18 changed files with 163 additions and 158 deletions

View file

@ -5260,7 +5260,7 @@ phutil_register_library_map(array(
'DiffusionQueryCommitsConduitAPIMethod' => 'DiffusionConduitAPIMethod', 'DiffusionQueryCommitsConduitAPIMethod' => 'DiffusionConduitAPIMethod',
'DiffusionQueryConduitAPIMethod' => 'DiffusionConduitAPIMethod', 'DiffusionQueryConduitAPIMethod' => 'DiffusionConduitAPIMethod',
'DiffusionQueryPathsConduitAPIMethod' => 'DiffusionQueryConduitAPIMethod', 'DiffusionQueryPathsConduitAPIMethod' => 'DiffusionQueryConduitAPIMethod',
'DiffusionRawDiffQuery' => 'DiffusionQuery', 'DiffusionRawDiffQuery' => 'DiffusionFileFutureQuery',
'DiffusionRawDiffQueryConduitAPIMethod' => 'DiffusionQueryConduitAPIMethod', 'DiffusionRawDiffQueryConduitAPIMethod' => 'DiffusionQueryConduitAPIMethod',
'DiffusionReadmeView' => 'DiffusionView', 'DiffusionReadmeView' => 'DiffusionView',
'DiffusionRefDatasource' => 'PhabricatorTypeaheadDatasource', 'DiffusionRefDatasource' => 'PhabricatorTypeaheadDatasource',

View file

@ -36,7 +36,7 @@ final class DifferentialDiffExtractionEngine extends Phobject {
'repository' => $repository, 'repository' => $repository,
)); ));
$raw_diff = DiffusionQuery::callConduitWithDiffusionRequest( $diff_info = DiffusionQuery::callConduitWithDiffusionRequest(
$viewer, $viewer,
$drequest, $drequest,
'diffusion.rawdiffquery', 'diffusion.rawdiffquery',
@ -44,6 +44,21 @@ final class DifferentialDiffExtractionEngine extends Phobject {
'commit' => $identifier, 'commit' => $identifier,
)); ));
$file_phid = $diff_info['filePHID'];
$diff_file = id(new PhabricatorFileQuery())
->setViewer($viewer)
->withPHIDs(array($file_phid))
->executeOne();
if (!$diff_file) {
throw new Exception(
pht(
'Failed to load file ("%s") returned by "%s".',
$file_phid,
'diffusion.rawdiffquery'));
}
$raw_diff = $diff_file->loadFileData();
// TODO: Support adds, deletes and moves under SVN. // TODO: Support adds, deletes and moves under SVN.
if (strlen($raw_diff)) { if (strlen($raw_diff)) {
$changes = id(new ArcanistDiffParser())->parseDiff($raw_diff); $changes = id(new ArcanistDiffParser())->parseDiff($raw_diff);

View file

@ -262,7 +262,7 @@ final class DiffusionLintSaveRunner extends Phobject {
$query = DiffusionFileContentQuery::newFromDiffusionRequest($drequest); $query = DiffusionFileContentQuery::newFromDiffusionRequest($drequest);
$queries[$path] = $query; $queries[$path] = $query;
$futures[$path] = $query->getFileContentFuture(); $futures[$path] = new ImmediateFuture($query->executeInline());
} }
$authors = array(); $authors = array();

View file

@ -207,7 +207,7 @@ final class DiffusionDiffQueryConduitAPIMethod
$raw_query = DiffusionRawDiffQuery::newFromDiffusionRequest($drequest) $raw_query = DiffusionRawDiffQuery::newFromDiffusionRequest($drequest)
->setAnchorCommit($effective_commit); ->setAnchorCommit($effective_commit);
$raw_diff = $raw_query->loadRawDiff(); $raw_diff = $raw_query->executeInline();
if (!$raw_diff) { if (!$raw_diff) {
return $this->getEmptyResult(2); return $this->getEmptyResult(2);
} }

View file

@ -21,39 +21,27 @@ final class DiffusionRawDiffQueryConduitAPIMethod
return array( return array(
'commit' => 'required string', 'commit' => 'required string',
'path' => 'optional string', 'path' => 'optional string',
'timeout' => 'optional int',
'byteLimit' => 'optional int',
'linesOfContext' => 'optional int', 'linesOfContext' => 'optional int',
'againstCommit' => 'optional string', 'againstCommit' => 'optional string',
); ) + DiffusionFileFutureQuery::getConduitParameters();
} }
protected function getResult(ConduitAPIRequest $request) { protected function getResult(ConduitAPIRequest $request) {
$drequest = $this->getDiffusionRequest(); $drequest = $this->getDiffusionRequest();
$raw_query = DiffusionRawDiffQuery::newFromDiffusionRequest($drequest); $query = DiffusionRawDiffQuery::newFromDiffusionRequest($drequest);
$timeout = $request->getValue('timeout');
if ($timeout !== null) {
$raw_query->setTimeout($timeout);
}
$lines_of_context = $request->getValue('linesOfContext'); $lines_of_context = $request->getValue('linesOfContext');
if ($lines_of_context !== null) { if ($lines_of_context !== null) {
$raw_query->setLinesOfContext($lines_of_context); $query->setLinesOfContext($lines_of_context);
} }
$against_commit = $request->getValue('againstCommit'); $against_commit = $request->getValue('againstCommit');
if ($against_commit !== null) { if ($against_commit !== null) {
$raw_query->setAgainstCommit($against_commit); $query->setAgainstCommit($against_commit);
} }
$byte_limit = $request->getValue('byteLimit'); return $query->respondToConduitRequest($request);
if ($byte_limit !== null) {
$raw_query->setByteLimit($byte_limit);
}
return $raw_query->loadRawDiff();
} }
} }

View file

@ -1527,19 +1527,36 @@ final class DiffusionBrowseController extends DiffusionController {
private function getBeforeLineNumber($target_commit) { private function getBeforeLineNumber($target_commit) {
$drequest = $this->getDiffusionRequest(); $drequest = $this->getDiffusionRequest();
$viewer = $this->getViewer();
$line = $drequest->getLine(); $line = $drequest->getLine();
if (!$line) { if (!$line) {
return null; return null;
} }
$raw_diff = $this->callConduitWithDiffusionRequest( $diff_info = $this->callConduitWithDiffusionRequest(
'diffusion.rawdiffquery', 'diffusion.rawdiffquery',
array( array(
'commit' => $drequest->getCommit(), 'commit' => $drequest->getCommit(),
'path' => $drequest->getPath(), 'path' => $drequest->getPath(),
'againstCommit' => $target_commit, 'againstCommit' => $target_commit,
)); ));
$file_phid = $diff_info['filePHID'];
$file = id(new PhabricatorFileQuery())
->setViewer($viewer)
->withPHIDs(array($file_phid))
->executeOne();
if (!$file) {
throw new Exception(
pht(
'Failed to load file ("%s") returned by "%s".',
$file_phid,
'diffusion.rawdiffquery.'));
}
$raw_diff = $file->loadFileData();
$old_line = 0; $old_line = 0;
$new_line = 0; $new_line = 0;

View file

@ -1027,24 +1027,26 @@ final class DiffusionCommitController extends DiffusionController {
} }
private function buildRawDiffResponse(DiffusionRequest $drequest) { private function buildRawDiffResponse(DiffusionRequest $drequest) {
$raw_diff = $this->callConduitWithDiffusionRequest( $diff_info = $this->callConduitWithDiffusionRequest(
'diffusion.rawdiffquery', 'diffusion.rawdiffquery',
array( array(
'commit' => $drequest->getCommit(), 'commit' => $drequest->getCommit(),
'path' => $drequest->getPath(), 'path' => $drequest->getPath(),
)); ));
$file = PhabricatorFile::buildFromFileDataOrHash( $file_phid = $diff_info['filePHID'];
$raw_diff,
array(
'name' => $drequest->getCommit().'.diff',
'ttl' => (60 * 60 * 24),
'viewPolicy' => PhabricatorPolicies::POLICY_NOONE,
));
$unguarded = AphrontWriteGuard::beginScopedUnguardedWrites(); $file = id(new PhabricatorFileQuery())
$file->attachToObject($drequest->getRepository()->getPHID()); ->setViewer($this->getViewer())
unset($unguarded); ->withPHIDs(array($file_phid))
->executeOne();
if (!$file) {
throw new Exception(
pht(
'Failed to load file ("%s") returned by "%s".',
$file_phid,
'diffusion.rawdiffquery'));
}
return $file->getRedirectResponse(); return $file->getRedirectResponse();
} }

View file

@ -1095,7 +1095,7 @@ final class DiffusionCommitHookEngine extends Phobject {
->setTimeout($time_limit) ->setTimeout($time_limit)
->setByteLimit($byte_limit) ->setByteLimit($byte_limit)
->setLinesOfContext(0) ->setLinesOfContext(0)
->loadRawDiff(); ->executeInline();
break; break;
case PhabricatorRepositoryType::REPOSITORY_TYPE_SVN: case PhabricatorRepositoryType::REPOSITORY_TYPE_SVN:
// TODO: This diff has 3 lines of context, which produces slightly // TODO: This diff has 3 lines of context, which produces slightly

View file

@ -204,25 +204,50 @@ final class HeraldCommitAdapter
} }
private function loadCommitDiff() { private function loadCommitDiff() {
$byte_limit = self::getEnormousByteLimit(); $viewer = PhabricatorUser::getOmnipotentUser();
$raw = $this->callConduit( $byte_limit = self::getEnormousByteLimit();
$time_limit = self::getEnormousTimeLimit();
$diff_info = $this->callConduit(
'diffusion.rawdiffquery', 'diffusion.rawdiffquery',
array( array(
'commit' => $this->commit->getCommitIdentifier(), 'commit' => $this->commit->getCommitIdentifier(),
'timeout' => self::getEnormousTimeLimit(), 'timeout' => $time_limit,
'byteLimit' => $byte_limit, 'byteLimit' => $byte_limit,
'linesOfContext' => 0, 'linesOfContext' => 0,
)); ));
if (strlen($raw) >= $byte_limit) { if ($diff_info['tooHuge']) {
throw new Exception( throw new Exception(
pht( pht(
'The raw text of this change is enormous (larger than %d bytes). '. 'The raw text of this change is enormous (larger than %s byte(s)). '.
'Herald can not process it.', 'Herald can not process it.',
$byte_limit)); new PhutilNumber($byte_limit)));
} }
if ($diff_info['tooSlow']) {
throw new Exception(
pht(
'The raw text of this change took too long to process (longer '.
'than %s second(s)). Herald can not process it.',
new PhutilNumber($time_limit)));
}
$file_phid = $diff_info['filePHID'];
$diff_file = id(new PhabricatorFileQuery())
->setViewer($viewer)
->withPHIDs(array($file_phid))
->executeOne();
if (!$diff_file) {
throw new Exception(
pht(
'Failed to load diff ("%s") for this change.',
$file_phid));
}
$raw = $diff_file->loadFileData();
$parser = new ArcanistDiffParser(); $parser = new ArcanistDiffParser();
$changes = $parser->parseDiff($raw); $changes = $parser->parseDiff($raw);

View file

@ -42,7 +42,7 @@ abstract class DiffusionFileFutureQuery
return $this->didHitTimeLimit; return $this->didHitTimeLimit;
} }
abstract protected function getFileContentFuture(); abstract protected function newQueryFuture();
final public function respondToConduitRequest(ConduitAPIRequest $request) { final public function respondToConduitRequest(ConduitAPIRequest $request) {
$drequest = $this->getRequest(); $drequest = $this->getRequest();
@ -82,13 +82,13 @@ abstract class DiffusionFileFutureQuery
} }
final public function executeInline() { final public function executeInline() {
$future = $this->getFileContentFuture(); $future = $this->newConfiguredQueryFuture();
list($stdout) = $future->resolvex(); list($stdout) = $future->resolvex();
return $future; return $stdout;
} }
final protected function executeQuery() { final protected function executeQuery() {
$future = $this->newConfiguredFileContentFuture(); $future = $this->newQueryFuture();
$drequest = $this->getRequest(); $drequest = $this->getRequest();
@ -134,8 +134,8 @@ abstract class DiffusionFileFutureQuery
return $file; return $file;
} }
private function newConfiguredFileContentFuture() { private function newConfiguredQueryFuture() {
$future = $this->getFileContentFuture(); $future = $this->newQueryFuture();
if ($this->getTimeout()) { if ($this->getTimeout()) {
$future->setTimeout($this->getTimeout()); $future->setTimeout($this->getTimeout());
@ -149,5 +149,4 @@ abstract class DiffusionFileFutureQuery
return $future; return $future;
} }
} }

View file

@ -2,7 +2,7 @@
final class DiffusionGitFileContentQuery extends DiffusionFileContentQuery { final class DiffusionGitFileContentQuery extends DiffusionFileContentQuery {
protected function getFileContentFuture() { protected function newQueryFuture() {
$drequest = $this->getRequest(); $drequest = $this->getRequest();
$repository = $drequest->getRepository(); $repository = $drequest->getRepository();

View file

@ -3,7 +3,7 @@
final class DiffusionMercurialFileContentQuery final class DiffusionMercurialFileContentQuery
extends DiffusionFileContentQuery { extends DiffusionFileContentQuery {
protected function getFileContentFuture() { protected function newQueryFuture() {
$drequest = $this->getRequest(); $drequest = $this->getRequest();
$repository = $drequest->getRepository(); $repository = $drequest->getRepository();

View file

@ -2,7 +2,7 @@
final class DiffusionSvnFileContentQuery extends DiffusionFileContentQuery { final class DiffusionSvnFileContentQuery extends DiffusionFileContentQuery {
protected function getFileContentFuture() { protected function newQueryFuture() {
$drequest = $this->getRequest(); $drequest = $this->getRequest();
$repository = $drequest->getRepository(); $repository = $drequest->getRepository();

View file

@ -2,7 +2,7 @@
final class DiffusionGitRawDiffQuery extends DiffusionRawDiffQuery { final class DiffusionGitRawDiffQuery extends DiffusionRawDiffQuery {
protected function executeQuery() { protected function newQueryFuture() {
$drequest = $this->getRequest(); $drequest = $this->getRequest();
$repository = $drequest->getRepository(); $repository = $drequest->getRepository();
@ -17,54 +17,34 @@ final class DiffusionGitRawDiffQuery extends DiffusionRawDiffQuery {
'--dst-prefix=b/', '--dst-prefix=b/',
'-U'.(int)$this->getLinesOfContext(), '-U'.(int)$this->getLinesOfContext(),
); );
$options = implode(' ', $options);
$against = $this->getAgainstCommit(); $against = $this->getAgainstCommit();
if ($against === null) { if ($against === null) {
$against = $commit.'^'; // 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.
list($parents) = $repository->execxLocalCommand(
'log --format=%s %s --',
'%P',
$commit);
if (strlen(trim($parents))) {
$against = $commit.'^';
} else {
$against = ArcanistGitAPI::GIT_MAGIC_ROOT_COMMIT;
}
} }
// If there's no path, get the entire raw diff. $path = $drequest->getPath();
$path = nonempty($drequest->getPath(), '.'); if (!strlen($path)) {
$path = '.';
}
$future = $repository->getLocalCommandFuture( return $repository->getLocalCommandFuture(
'diff %C %s %s -- %s', 'diff %Ls %s %s -- %s',
$options, $options,
$against, $against,
$commit, $commit,
$path); $path);
$this->configureFuture($future);
try {
list($raw_diff) = $future->resolvex();
} catch (CommandException $ex) {
// Check if this is the root commit by seeing if it has parents.
list($parents) = $repository->execxLocalCommand(
'log --format=%s %s --',
'%P', // "parents"
$commit);
if (strlen(trim($parents))) {
throw $ex;
}
// No parents means we're looking at the root revision. Diff against
// the empty tree hash instead, since there is no parent so "^" does
// not work. See ArcanistGitAPI for more discussion.
$future = $repository->getLocalCommandFuture(
'diff %C %s %s -- %s',
$options,
ArcanistGitAPI::GIT_MAGIC_ROOT_COMMIT,
$commit,
$drequest->getPath());
$this->configureFuture($future);
list($raw_diff) = $future->resolvex();
}
return $raw_diff;
} }
} }

View file

@ -2,11 +2,7 @@
final class DiffusionMercurialRawDiffQuery extends DiffusionRawDiffQuery { final class DiffusionMercurialRawDiffQuery extends DiffusionRawDiffQuery {
protected function executeQuery() { protected function newQueryFuture() {
return $this->executeRawDiffCommand();
}
protected function executeRawDiffCommand() {
$drequest = $this->getRequest(); $drequest = $this->getRequest();
$repository = $drequest->getRepository(); $repository = $drequest->getRepository();
@ -30,11 +26,7 @@ final class DiffusionMercurialRawDiffQuery extends DiffusionRawDiffQuery {
$commit, $commit,
$path); $path);
$this->configureFuture($future); return $future;
list($raw_diff) = $future->resolvex();
return $raw_diff;
} }
} }

View file

@ -1,40 +1,17 @@
<?php <?php
abstract class DiffusionRawDiffQuery extends DiffusionQuery { abstract class DiffusionRawDiffQuery
extends DiffusionFileFutureQuery {
private $timeout;
private $linesOfContext = 65535; private $linesOfContext = 65535;
private $anchorCommit; private $anchorCommit;
private $againstCommit; private $againstCommit;
private $byteLimit;
final public static function newFromDiffusionRequest( final public static function newFromDiffusionRequest(
DiffusionRequest $request) { DiffusionRequest $request) {
return parent::newQueryObject(__CLASS__, $request); return parent::newQueryObject(__CLASS__, $request);
} }
final public function loadRawDiff() {
return $this->executeQuery();
}
final public function setTimeout($timeout) {
$this->timeout = $timeout;
return $this;
}
final public function getTimeout() {
return $this->timeout;
}
public function setByteLimit($byte_limit) {
$this->byteLimit = $byte_limit;
return $this;
}
public function getByteLimit() {
return $this->byteLimit;
}
final public function setLinesOfContext($lines_of_context) { final public function setLinesOfContext($lines_of_context) {
$this->linesOfContext = $lines_of_context; $this->linesOfContext = $lines_of_context;
return $this; return $this;
@ -66,15 +43,4 @@ abstract class DiffusionRawDiffQuery extends DiffusionQuery {
return $this->getRequest()->getStableCommit(); return $this->getRequest()->getStableCommit();
} }
protected function configureFuture(ExecFuture $future) {
if ($this->getTimeout()) {
$future->setTimeout($this->getTimeout());
}
if ($this->getByteLimit()) {
$future->setStdoutSizeLimit($this->getByteLimit());
$future->setStderrSizeLimit($this->getByteLimit());
}
}
} }

View file

@ -2,7 +2,7 @@
final class DiffusionSvnRawDiffQuery extends DiffusionRawDiffQuery { final class DiffusionSvnRawDiffQuery extends DiffusionRawDiffQuery {
protected function executeQuery() { protected function newQueryFuture() {
$drequest = $this->getRequest(); $drequest = $this->getRequest();
$repository = $drequest->getRepository(); $repository = $drequest->getRepository();
@ -22,10 +22,7 @@ final class DiffusionSvnRawDiffQuery extends DiffusionRawDiffQuery {
$commit, $commit,
$repository->getSubversionPathURI($drequest->getPath())); $repository->getSubversionPathURI($drequest->getPath()));
$this->configureFuture($future); return $future;
list($raw_diff) = $future->resolvex();
return $raw_diff;
} }
} }

View file

@ -105,40 +105,64 @@ final class PhabricatorRepositoryCommitHeraldWorker
private function loadRawPatchText( private function loadRawPatchText(
PhabricatorRepository $repository, PhabricatorRepository $repository,
PhabricatorRepositoryCommit $commit) { PhabricatorRepositoryCommit $commit) {
$viewer = PhabricatorUser::getOmnipotentUser();
$identifier = $commit->getCommitIdentifier();
$drequest = DiffusionRequest::newFromDictionary( $drequest = DiffusionRequest::newFromDictionary(
array( array(
'user' => PhabricatorUser::getOmnipotentUser(), 'user' => $viewer,
'repository' => $repository, 'repository' => $repository,
'commit' => $commit->getCommitIdentifier(),
)); ));
$raw_query = DiffusionRawDiffQuery::newFromDiffusionRequest($drequest);
$raw_query->setLinesOfContext(3);
$time_key = 'metamta.diffusion.time-limit'; $time_key = 'metamta.diffusion.time-limit';
$byte_key = 'metamta.diffusion.byte-limit'; $byte_key = 'metamta.diffusion.byte-limit';
$time_limit = PhabricatorEnv::getEnvConfig($time_key); $time_limit = PhabricatorEnv::getEnvConfig($time_key);
$byte_limit = PhabricatorEnv::getEnvConfig($byte_key); $byte_limit = PhabricatorEnv::getEnvConfig($byte_key);
if ($time_limit) { $diff_info = DiffusionQuery::callConduitWithDiffusionRequest(
$raw_query->setTimeout($time_limit); $viewer,
$drequest,
'diffusion.rawdiffquery',
array(
'commit' => $identifier,
'linesOfContext' => 3,
'timeout' => $time_limit,
'byteLimit' => $byte_limit,
));
if ($diff_info['tooSlow']) {
throw new Exception(
pht(
'Patch generation took longer than configured limit ("%s") of '.
'%s second(s).',
$time_key,
new PhutilNumber($time_limit)));
} }
$raw_diff = $raw_query->loadRawDiff(); if ($diff_info['tooHuge']) {
$size = strlen($raw_diff);
if ($byte_limit && $size > $byte_limit) {
$pretty_size = phutil_format_bytes($size);
$pretty_limit = phutil_format_bytes($byte_limit); $pretty_limit = phutil_format_bytes($byte_limit);
throw new Exception(pht( throw new Exception(
'Patch size of %s exceeds configured byte size limit (%s) of %s.', pht(
$pretty_size, 'Patch size exceeds configured byte size limit ("%s") of %s.',
$byte_key, $byte_key,
$pretty_limit)); $pretty_limit));
} }
return $raw_diff; $file_phid = $diff_info['filePHID'];
$file = id(new PhabricatorFileQuery())
->setViewer($viewer)
->withPHIDs(array($file_phid))
->executeOne();
if (!$file) {
throw new Exception(
pht(
'Failed to load file ("%s") returned by "%s".',
$file_phid,
'diffusion.rawdiffquery'));
}
return $file->loadFileData();
} }
} }