Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/phabricator
Path: blob/master/src/applications/diffusion/conduit/DiffusionDiffQueryConduitAPIMethod.php
12242 views
1
<?php
2
3
final class DiffusionDiffQueryConduitAPIMethod
4
extends DiffusionQueryConduitAPIMethod {
5
6
private $effectiveCommit;
7
8
public function getAPIMethodName() {
9
return 'diffusion.diffquery';
10
}
11
12
public function getMethodDescription() {
13
return pht(
14
'Get diff information from a repository for a specific path at an '.
15
'(optional) commit.');
16
}
17
18
protected function defineReturnType() {
19
return 'array';
20
}
21
22
protected function defineCustomParamTypes() {
23
return array(
24
'path' => 'required string',
25
'commit' => 'optional string',
26
);
27
}
28
29
protected function getResult(ConduitAPIRequest $request) {
30
$result = parent::getResult($request);
31
32
return array(
33
'changes' => mpull($result, 'toDictionary'),
34
'effectiveCommit' => $this->getEffectiveCommit($request),
35
);
36
}
37
38
protected function getGitResult(ConduitAPIRequest $request) {
39
return $this->getGitOrMercurialResult($request);
40
}
41
42
protected function getMercurialResult(ConduitAPIRequest $request) {
43
return $this->getGitOrMercurialResult($request);
44
}
45
46
/**
47
* NOTE: We have to work particularly hard for SVN as compared to other VCS.
48
* That's okay but means this shares little code with the other VCS.
49
*/
50
protected function getSVNResult(ConduitAPIRequest $request) {
51
$drequest = $this->getDiffusionRequest();
52
$repository = $drequest->getRepository();
53
54
$effective_commit = $this->getEffectiveCommit($request);
55
if (!$effective_commit) {
56
return $this->getEmptyResult();
57
}
58
59
$drequest = clone $drequest;
60
$drequest->updateSymbolicCommit($effective_commit);
61
62
$path_change_query = DiffusionPathChangeQuery::newFromDiffusionRequest(
63
$drequest);
64
$path_changes = $path_change_query->loadChanges();
65
66
$path = null;
67
foreach ($path_changes as $change) {
68
if ($change->getPath() == $drequest->getPath()) {
69
$path = $change;
70
}
71
}
72
73
if (!$path) {
74
return $this->getEmptyResult();
75
}
76
77
$change_type = $path->getChangeType();
78
switch ($change_type) {
79
case DifferentialChangeType::TYPE_MULTICOPY:
80
case DifferentialChangeType::TYPE_DELETE:
81
if ($path->getTargetPath()) {
82
$old = array(
83
$path->getTargetPath(),
84
$path->getTargetCommitIdentifier(),
85
);
86
} else {
87
$old = array($path->getPath(), $path->getCommitIdentifier() - 1);
88
}
89
$old_name = $path->getPath();
90
$new_name = '';
91
$new = null;
92
break;
93
case DifferentialChangeType::TYPE_ADD:
94
$old = null;
95
$new = array($path->getPath(), $path->getCommitIdentifier());
96
$old_name = '';
97
$new_name = $path->getPath();
98
break;
99
case DifferentialChangeType::TYPE_MOVE_HERE:
100
case DifferentialChangeType::TYPE_COPY_HERE:
101
$old = array(
102
$path->getTargetPath(),
103
$path->getTargetCommitIdentifier(),
104
);
105
$new = array($path->getPath(), $path->getCommitIdentifier());
106
$old_name = $path->getTargetPath();
107
$new_name = $path->getPath();
108
break;
109
case DifferentialChangeType::TYPE_MOVE_AWAY:
110
$old = array(
111
$path->getPath(),
112
$path->getCommitIdentifier() - 1,
113
);
114
$old_name = $path->getPath();
115
$new_name = null;
116
$new = null;
117
break;
118
default:
119
$old = array($path->getPath(), $path->getCommitIdentifier() - 1);
120
$new = array($path->getPath(), $path->getCommitIdentifier());
121
$old_name = $path->getPath();
122
$new_name = $path->getPath();
123
break;
124
}
125
126
$futures = array(
127
'old' => $this->buildSVNContentFuture($old),
128
'new' => $this->buildSVNContentFuture($new),
129
);
130
$futures = array_filter($futures);
131
132
foreach (new FutureIterator($futures) as $key => $future) {
133
$stdout = '';
134
try {
135
list($stdout) = $future->resolvex();
136
} catch (CommandException $e) {
137
if ($path->getFileType() != DifferentialChangeType::FILE_DIRECTORY) {
138
throw $e;
139
}
140
}
141
$futures[$key] = $stdout;
142
}
143
144
$old_data = idx($futures, 'old', '');
145
$new_data = idx($futures, 'new', '');
146
147
$engine = new PhabricatorDifferenceEngine();
148
$engine->setOldName($old_name);
149
$engine->setNewName($new_name);
150
$raw_diff = $engine->generateRawDiffFromFileContent($old_data, $new_data);
151
152
$arcanist_changes = DiffusionPathChange::convertToArcanistChanges(
153
$path_changes);
154
155
$parser = $this->getDefaultParser();
156
$parser->setChanges($arcanist_changes);
157
$parser->forcePath($path->getPath());
158
$changes = $parser->parseDiff($raw_diff);
159
160
$change = $changes[$path->getPath()];
161
162
return array($change);
163
}
164
165
private function getEffectiveCommit(ConduitAPIRequest $request) {
166
if ($this->effectiveCommit === null) {
167
$drequest = $this->getDiffusionRequest();
168
169
$path = $drequest->getPath();
170
$result = DiffusionQuery::callConduitWithDiffusionRequest(
171
$request->getUser(),
172
$drequest,
173
'diffusion.lastmodifiedquery',
174
array(
175
'paths' => array($path => $drequest->getStableCommit()),
176
));
177
178
$this->effectiveCommit = idx($result, $path);
179
}
180
181
return $this->effectiveCommit;
182
}
183
184
private function buildSVNContentFuture($spec) {
185
if (!$spec) {
186
return null;
187
}
188
189
$drequest = $this->getDiffusionRequest();
190
$repository = $drequest->getRepository();
191
192
list($ref, $rev) = $spec;
193
return $repository->getRemoteCommandFuture(
194
'cat %s',
195
$repository->getSubversionPathURI($ref, $rev));
196
}
197
198
private function getGitOrMercurialResult(ConduitAPIRequest $request) {
199
$drequest = $this->getDiffusionRequest();
200
$repository = $drequest->getRepository();
201
202
$effective_commit = $this->getEffectiveCommit($request);
203
if (!$effective_commit) {
204
return $this->getEmptyResult();
205
}
206
207
$raw_query = DiffusionRawDiffQuery::newFromDiffusionRequest($drequest)
208
->setAnchorCommit($effective_commit);
209
210
$raw_diff = $raw_query->executeInline();
211
if (!$raw_diff) {
212
return $this->getEmptyResult();
213
}
214
215
$parser = $this->getDefaultParser();
216
$changes = $parser->parseDiff($raw_diff);
217
218
return $changes;
219
}
220
221
private function getDefaultParser() {
222
$drequest = $this->getDiffusionRequest();
223
$repository = $drequest->getRepository();
224
225
$parser = new ArcanistDiffParser();
226
$try_encoding = $repository->getDetail('encoding');
227
if ($try_encoding) {
228
$parser->setTryEncoding($try_encoding);
229
}
230
$parser->setDetectBinaryFiles(true);
231
232
return $parser;
233
}
234
235
private function getEmptyResult() {
236
return array();
237
}
238
239
}
240
241