diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php index bfba62e253..465108ac7c 100644 --- a/src/__phutil_library_map__.php +++ b/src/__phutil_library_map__.php @@ -528,6 +528,8 @@ phutil_register_library_map(array( 'DiffusionAuditorsAddAuditorsHeraldAction' => 'applications/diffusion/herald/DiffusionAuditorsAddAuditorsHeraldAction.php', 'DiffusionAuditorsAddSelfHeraldAction' => 'applications/diffusion/herald/DiffusionAuditorsAddSelfHeraldAction.php', 'DiffusionAuditorsHeraldAction' => 'applications/diffusion/herald/DiffusionAuditorsHeraldAction.php', + 'DiffusionBlameConduitAPIMethod' => 'applications/diffusion/conduit/DiffusionBlameConduitAPIMethod.php', + 'DiffusionBlameQuery' => 'applications/diffusion/query/blame/DiffusionBlameQuery.php', 'DiffusionBlockHeraldAction' => 'applications/diffusion/herald/DiffusionBlockHeraldAction.php', 'DiffusionBranchQueryConduitAPIMethod' => 'applications/diffusion/conduit/DiffusionBranchQueryConduitAPIMethod.php', 'DiffusionBranchTableController' => 'applications/diffusion/controller/DiffusionBranchTableController.php', @@ -601,6 +603,7 @@ phutil_register_library_map(array( 'DiffusionFindSymbolsConduitAPIMethod' => 'applications/diffusion/conduit/DiffusionFindSymbolsConduitAPIMethod.php', 'DiffusionGetLintMessagesConduitAPIMethod' => 'applications/diffusion/conduit/DiffusionGetLintMessagesConduitAPIMethod.php', 'DiffusionGetRecentCommitsByPathConduitAPIMethod' => 'applications/diffusion/conduit/DiffusionGetRecentCommitsByPathConduitAPIMethod.php', + 'DiffusionGitBlameQuery' => 'applications/diffusion/query/blame/DiffusionGitBlameQuery.php', 'DiffusionGitBranch' => 'applications/diffusion/data/DiffusionGitBranch.php', 'DiffusionGitBranchTestCase' => 'applications/diffusion/data/__tests__/DiffusionGitBranchTestCase.php', 'DiffusionGitFileContentQuery' => 'applications/diffusion/query/filecontent/DiffusionGitFileContentQuery.php', @@ -632,6 +635,7 @@ phutil_register_library_map(array( 'DiffusionLowLevelParentsQuery' => 'applications/diffusion/query/lowlevel/DiffusionLowLevelParentsQuery.php', 'DiffusionLowLevelQuery' => 'applications/diffusion/query/lowlevel/DiffusionLowLevelQuery.php', 'DiffusionLowLevelResolveRefsQuery' => 'applications/diffusion/query/lowlevel/DiffusionLowLevelResolveRefsQuery.php', + 'DiffusionMercurialBlameQuery' => 'applications/diffusion/query/blame/DiffusionMercurialBlameQuery.php', 'DiffusionMercurialFileContentQuery' => 'applications/diffusion/query/filecontent/DiffusionMercurialFileContentQuery.php', 'DiffusionMercurialRawDiffQuery' => 'applications/diffusion/query/rawdiff/DiffusionMercurialRawDiffQuery.php', 'DiffusionMercurialRequest' => 'applications/diffusion/request/DiffusionMercurialRequest.php', @@ -743,6 +747,7 @@ phutil_register_library_map(array( 'DiffusionSubversionServeSSHWorkflow' => 'applications/diffusion/ssh/DiffusionSubversionServeSSHWorkflow.php', 'DiffusionSubversionWireProtocol' => 'applications/diffusion/protocol/DiffusionSubversionWireProtocol.php', 'DiffusionSubversionWireProtocolTestCase' => 'applications/diffusion/protocol/__tests__/DiffusionSubversionWireProtocolTestCase.php', + 'DiffusionSvnBlameQuery' => 'applications/diffusion/query/blame/DiffusionSvnBlameQuery.php', 'DiffusionSvnFileContentQuery' => 'applications/diffusion/query/filecontent/DiffusionSvnFileContentQuery.php', 'DiffusionSvnRawDiffQuery' => 'applications/diffusion/query/rawdiff/DiffusionSvnRawDiffQuery.php', 'DiffusionSvnRequest' => 'applications/diffusion/request/DiffusionSvnRequest.php', @@ -4493,6 +4498,8 @@ phutil_register_library_map(array( 'DiffusionAuditorsAddAuditorsHeraldAction' => 'DiffusionAuditorsHeraldAction', 'DiffusionAuditorsAddSelfHeraldAction' => 'DiffusionAuditorsHeraldAction', 'DiffusionAuditorsHeraldAction' => 'HeraldAction', + 'DiffusionBlameConduitAPIMethod' => 'DiffusionQueryConduitAPIMethod', + 'DiffusionBlameQuery' => 'DiffusionQuery', 'DiffusionBlockHeraldAction' => 'HeraldAction', 'DiffusionBranchQueryConduitAPIMethod' => 'DiffusionQueryConduitAPIMethod', 'DiffusionBranchTableController' => 'DiffusionController', @@ -4566,6 +4573,7 @@ phutil_register_library_map(array( 'DiffusionFindSymbolsConduitAPIMethod' => 'DiffusionConduitAPIMethod', 'DiffusionGetLintMessagesConduitAPIMethod' => 'DiffusionConduitAPIMethod', 'DiffusionGetRecentCommitsByPathConduitAPIMethod' => 'DiffusionConduitAPIMethod', + 'DiffusionGitBlameQuery' => 'DiffusionBlameQuery', 'DiffusionGitBranch' => 'Phobject', 'DiffusionGitBranchTestCase' => 'PhabricatorTestCase', 'DiffusionGitFileContentQuery' => 'DiffusionFileContentQuery', @@ -4597,6 +4605,7 @@ phutil_register_library_map(array( 'DiffusionLowLevelParentsQuery' => 'DiffusionLowLevelQuery', 'DiffusionLowLevelQuery' => 'Phobject', 'DiffusionLowLevelResolveRefsQuery' => 'DiffusionLowLevelQuery', + 'DiffusionMercurialBlameQuery' => 'DiffusionBlameQuery', 'DiffusionMercurialFileContentQuery' => 'DiffusionFileContentQuery', 'DiffusionMercurialRawDiffQuery' => 'DiffusionRawDiffQuery', 'DiffusionMercurialRequest' => 'DiffusionRequest', @@ -4708,6 +4717,7 @@ phutil_register_library_map(array( 'DiffusionSubversionServeSSHWorkflow' => 'DiffusionSubversionSSHWorkflow', 'DiffusionSubversionWireProtocol' => 'Phobject', 'DiffusionSubversionWireProtocolTestCase' => 'PhabricatorTestCase', + 'DiffusionSvnBlameQuery' => 'DiffusionBlameQuery', 'DiffusionSvnFileContentQuery' => 'DiffusionFileContentQuery', 'DiffusionSvnRawDiffQuery' => 'DiffusionRawDiffQuery', 'DiffusionSvnRequest' => 'DiffusionRequest', diff --git a/src/applications/diffusion/conduit/DiffusionBlameConduitAPIMethod.php b/src/applications/diffusion/conduit/DiffusionBlameConduitAPIMethod.php new file mode 100644 index 0000000000..7cbb379039 --- /dev/null +++ b/src/applications/diffusion/conduit/DiffusionBlameConduitAPIMethod.php @@ -0,0 +1,44 @@ +'; + } + + protected function defineCustomParamTypes() { + return array( + 'paths' => 'required list', + 'commit' => 'required string', + 'timeout' => 'optional int', + ); + } + + protected function getResult(ConduitAPIRequest $request) { + $drequest = $this->getDiffusionRequest(); + + $paths = $request->getValue('paths'); + + $blame_query = DiffusionBlameQuery::newFromDiffusionRequest($drequest) + ->setPaths($paths); + + $timeout = $request->getValue('timeout'); + if ($timeout) { + $blame_query->setTimeout($timeout); + } + + $blame = $blame_query->execute(); + + return $blame; + } + +} diff --git a/src/applications/diffusion/conduit/DiffusionQueryConduitAPIMethod.php b/src/applications/diffusion/conduit/DiffusionQueryConduitAPIMethod.php index 4b3eb6721f..21e8da485f 100644 --- a/src/applications/diffusion/conduit/DiffusionQueryConduitAPIMethod.php +++ b/src/applications/diffusion/conduit/DiffusionQueryConduitAPIMethod.php @@ -110,6 +110,13 @@ abstract class DiffusionQueryConduitAPIMethod 'commit' => $request->getValue('commit'), )); + if (!$drequest) { + throw new Exception( + pht( + 'Repository "%s" is not a valid repository.', + $identifier)); + } + // Figure out whether we're going to handle this request on this device, // or proxy it to another node in the cluster. diff --git a/src/applications/diffusion/query/blame/DiffusionBlameQuery.php b/src/applications/diffusion/query/blame/DiffusionBlameQuery.php new file mode 100644 index 0000000000..6d83020dd2 --- /dev/null +++ b/src/applications/diffusion/query/blame/DiffusionBlameQuery.php @@ -0,0 +1,69 @@ +timeout = $timeout; + return $this; + } + + public function getTimeout() { + return $this->timeout; + } + + public function setPaths(array $paths) { + $this->paths = $paths; + return $this; + } + + public function getPaths() { + return $this->paths; + } + + abstract protected function newBlameFuture(DiffusionRequest $request, $path); + + abstract protected function resolveBlameFuture(ExecFuture $future); + + final public static function newFromDiffusionRequest( + DiffusionRequest $request) { + return parent::newQueryObject(__CLASS__, $request); + } + + final protected function executeQuery() { + $paths = $this->getPaths(); + $request = $this->getRequest(); + $timeout = $this->getTimeout(); + + $futures = array(); + foreach ($paths as $path) { + $future = $this->newBlameFuture($request, $path); + + if ($timeout) { + $future->setTimeout($timeout); + } + + $futures[$path] = $future; + } + + + $blame = array(); + + if ($futures) { + $futures = id(new FutureIterator($futures)) + ->limit(4); + + foreach ($futures as $path => $future) { + $path_blame = $this->resolveBlameFuture($future); + if ($path_blame !== null) { + $blame[$path] = $path_blame; + } + } + } + + return $blame; + } + +} diff --git a/src/applications/diffusion/query/blame/DiffusionGitBlameQuery.php b/src/applications/diffusion/query/blame/DiffusionGitBlameQuery.php new file mode 100644 index 0000000000..f98cc645a7 --- /dev/null +++ b/src/applications/diffusion/query/blame/DiffusionGitBlameQuery.php @@ -0,0 +1,34 @@ +getRepository(); + + $commit = $request->getCommit(); + + return $repository->getLocalCommandFuture( + '--no-pager blame -s -l %s -- %s', + $commit, + $path); + } + + protected function resolveBlameFuture(ExecFuture $future) { + list($err, $stdout) = $future->resolve(); + + if ($err) { + return null; + } + + $result = array(); + + $lines = phutil_split_lines($stdout); + foreach ($lines as $line) { + list($commit) = explode(' ', $line, 2); + $result[] = $commit; + } + + return $result; + } + +} diff --git a/src/applications/diffusion/query/blame/DiffusionMercurialBlameQuery.php b/src/applications/diffusion/query/blame/DiffusionMercurialBlameQuery.php new file mode 100644 index 0000000000..60eeb31c4f --- /dev/null +++ b/src/applications/diffusion/query/blame/DiffusionMercurialBlameQuery.php @@ -0,0 +1,36 @@ +getRepository(); + $commit = $request->getCommit(); + + // NOTE: We're using "--debug" to make "--changeset" give us the full + // commit hashes. + + return $repository->getLocalCommandFuture( + 'annotate --debug --changeset --rev %s -- %s', + $commit, + $path); + } + + protected function resolveBlameFuture(ExecFuture $future) { + list($err, $stdout) = $future->resolve(); + + if ($err) { + return null; + } + + $result = array(); + + $lines = phutil_split_lines($stdout); + foreach ($lines as $line) { + list($commit) = explode(':', $line, 2); + $result[] = $commit; + } + + return $result; + } + +} diff --git a/src/applications/diffusion/query/blame/DiffusionSvnBlameQuery.php b/src/applications/diffusion/query/blame/DiffusionSvnBlameQuery.php new file mode 100644 index 0000000000..afa99e2bb3 --- /dev/null +++ b/src/applications/diffusion/query/blame/DiffusionSvnBlameQuery.php @@ -0,0 +1,36 @@ +getRepository(); + $commit = $request->getCommit(); + + return $repository->getRemoteCommandFuture( + 'blame --force %s', + $repository->getSubversionPathURI($path, $commit)); + } + + protected function resolveBlameFuture(ExecFuture $future) { + list($err, $stdout) = $future->resolve(); + + if ($err) { + return null; + } + + $result = array(); + $matches = null; + + $lines = phutil_split_lines($stdout); + foreach ($lines as $line) { + if (preg_match('/^\s*(\d+)/', $line, $matches)) { + $result[] = (int)$matches[1]; + } else { + $result[] = null; + } + } + + return $result; + } + +}