Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/phabricator
Path: blob/master/src/applications/diffusion/conduit/DiffusionInternalGitRawDiffQueryConduitAPIMethod.php
12242 views
1
<?php
2
3
final class DiffusionInternalGitRawDiffQueryConduitAPIMethod
4
extends DiffusionQueryConduitAPIMethod {
5
6
public function isInternalAPI() {
7
return true;
8
}
9
10
public function getAPIMethodName() {
11
return 'diffusion.internal.gitrawdiffquery';
12
}
13
14
public function getMethodDescription() {
15
return pht('Internal method for getting raw diff information.');
16
}
17
18
protected function defineReturnType() {
19
return 'string';
20
}
21
22
protected function defineCustomParamTypes() {
23
return array(
24
'commit' => 'required string',
25
);
26
}
27
28
protected function getResult(ConduitAPIRequest $request) {
29
$drequest = $this->getDiffusionRequest();
30
$repository = $drequest->getRepository();
31
$commit = $request->getValue('commit');
32
33
if (!$repository->isGit()) {
34
throw new Exception(
35
pht(
36
'This API method can only be called on Git repositories.'));
37
}
38
39
// Check if the commit has parents. We're testing to see whether it is the
40
// first commit in history (in which case we must use "git log") or some
41
// other commit (in which case we can use "git diff"). We'd rather use
42
// "git diff" because it has the right behavior for merge commits, but
43
// it requires the commit to have a parent that we can diff against. The
44
// first commit doesn't, so "commit^" is not a valid ref.
45
list($parents) = $repository->execxLocalCommand(
46
'log -n1 %s %s --',
47
'--format=%P',
48
gitsprintf('%s', $commit));
49
$use_log = !strlen(trim($parents));
50
51
// First, get a fast raw diff without "--find-copies-harder". This flag
52
// produces better results for moves and copies, but is explosively slow
53
// for large changes to large repositories. See T10423.
54
$raw = $this->getRawDiff($repository, $commit, $use_log, false);
55
56
// If we got a normal-sized diff (no more than 100 modified files), we'll
57
// try using "--find-copies-harder" to improve the output. This improved
58
// output is mostly useful for small changes anyway.
59
$try_harder = (substr_count($raw, "\n") <= 100);
60
if ($try_harder) {
61
try {
62
$raw = $this->getRawDiff($repository, $commit, $use_log, true);
63
} catch (Exception $ex) {
64
// Just ignore any exception we hit, we'll use the fast output
65
// instead.
66
}
67
}
68
69
return $raw;
70
}
71
72
private function getRawDiff(
73
PhabricatorRepository $repository,
74
$commit,
75
$use_log,
76
$try_harder) {
77
78
$flags = array(
79
'-n1',
80
'-M',
81
'-C',
82
'-B',
83
'--raw',
84
'-t',
85
'--abbrev=40',
86
);
87
88
if ($try_harder) {
89
$flags[] = '--find-copies-harder';
90
}
91
92
if ($use_log) {
93
// This is the first commit so we need to use "log". We know it's not a
94
// merge commit because it couldn't be merging anything, so this is safe.
95
96
// NOTE: "--pretty=format: " is to disable diff output, we only want the
97
// part we get from "--raw".
98
$future = $repository->getLocalCommandFuture(
99
'log %Ls --pretty=format: %s --',
100
$flags,
101
gitsprintf('%s', $commit));
102
} else {
103
// Otherwise, we can use "diff", which will give us output for merges.
104
// We diff against the first parent, as this is generally the expectation
105
// and results in sensible behavior.
106
$future = $repository->getLocalCommandFuture(
107
'diff %Ls %s %s --',
108
$flags,
109
gitsprintf('%s^1', $commit),
110
gitsprintf('%s', $commit));
111
}
112
113
// Don't spend more than 30 seconds generating the slower output.
114
if ($try_harder) {
115
$future->setTimeout(30);
116
}
117
118
list($raw) = $future->resolvex();
119
120
return $raw;
121
}
122
123
}
124
125