Path: blob/master/src/applications/diffusion/conduit/DiffusionInternalGitRawDiffQueryConduitAPIMethod.php
12242 views
<?php12final class DiffusionInternalGitRawDiffQueryConduitAPIMethod3extends DiffusionQueryConduitAPIMethod {45public function isInternalAPI() {6return true;7}89public function getAPIMethodName() {10return 'diffusion.internal.gitrawdiffquery';11}1213public function getMethodDescription() {14return pht('Internal method for getting raw diff information.');15}1617protected function defineReturnType() {18return 'string';19}2021protected function defineCustomParamTypes() {22return array(23'commit' => 'required string',24);25}2627protected function getResult(ConduitAPIRequest $request) {28$drequest = $this->getDiffusionRequest();29$repository = $drequest->getRepository();30$commit = $request->getValue('commit');3132if (!$repository->isGit()) {33throw new Exception(34pht(35'This API method can only be called on Git repositories.'));36}3738// Check if the commit has parents. We're testing to see whether it is the39// first commit in history (in which case we must use "git log") or some40// other commit (in which case we can use "git diff"). We'd rather use41// "git diff" because it has the right behavior for merge commits, but42// it requires the commit to have a parent that we can diff against. The43// first commit doesn't, so "commit^" is not a valid ref.44list($parents) = $repository->execxLocalCommand(45'log -n1 %s %s --',46'--format=%P',47gitsprintf('%s', $commit));48$use_log = !strlen(trim($parents));4950// First, get a fast raw diff without "--find-copies-harder". This flag51// produces better results for moves and copies, but is explosively slow52// for large changes to large repositories. See T10423.53$raw = $this->getRawDiff($repository, $commit, $use_log, false);5455// If we got a normal-sized diff (no more than 100 modified files), we'll56// try using "--find-copies-harder" to improve the output. This improved57// output is mostly useful for small changes anyway.58$try_harder = (substr_count($raw, "\n") <= 100);59if ($try_harder) {60try {61$raw = $this->getRawDiff($repository, $commit, $use_log, true);62} catch (Exception $ex) {63// Just ignore any exception we hit, we'll use the fast output64// instead.65}66}6768return $raw;69}7071private function getRawDiff(72PhabricatorRepository $repository,73$commit,74$use_log,75$try_harder) {7677$flags = array(78'-n1',79'-M',80'-C',81'-B',82'--raw',83'-t',84'--abbrev=40',85);8687if ($try_harder) {88$flags[] = '--find-copies-harder';89}9091if ($use_log) {92// This is the first commit so we need to use "log". We know it's not a93// merge commit because it couldn't be merging anything, so this is safe.9495// NOTE: "--pretty=format: " is to disable diff output, we only want the96// part we get from "--raw".97$future = $repository->getLocalCommandFuture(98'log %Ls --pretty=format: %s --',99$flags,100gitsprintf('%s', $commit));101} else {102// Otherwise, we can use "diff", which will give us output for merges.103// We diff against the first parent, as this is generally the expectation104// and results in sensible behavior.105$future = $repository->getLocalCommandFuture(106'diff %Ls %s %s --',107$flags,108gitsprintf('%s^1', $commit),109gitsprintf('%s', $commit));110}111112// Don't spend more than 30 seconds generating the slower output.113if ($try_harder) {114$future->setTimeout(30);115}116117list($raw) = $future->resolvex();118119return $raw;120}121122}123124125