Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/phabricator
Path: blob/master/src/applications/diffusion/controller/DiffusionCompareController.php
12242 views
1
<?php
2
3
final class DiffusionCompareController extends DiffusionController {
4
5
public function shouldAllowPublic() {
6
return true;
7
}
8
9
public function handleRequest(AphrontRequest $request) {
10
$response = $this->loadDiffusionContext();
11
if ($response) {
12
return $response;
13
}
14
15
$viewer = $this->getViewer();
16
$drequest = $this->getDiffusionRequest();
17
$repository = $drequest->getRepository();
18
require_celerity_resource('diffusion-css');
19
20
if (!$repository->supportsBranchComparison()) {
21
return $this->newDialog()
22
->setTitle(pht('Not Supported'))
23
->appendParagraph(
24
pht(
25
'Branch comparison is not supported for this version control '.
26
'system.'))
27
->addCancelButton($this->getApplicationURI(), pht('Okay'));
28
}
29
30
$head_ref = $request->getStr('head');
31
$against_ref = $request->getStr('against');
32
33
$must_prompt = false;
34
if (!$request->isFormPost()) {
35
if (!strlen($head_ref)) {
36
$head_ref = $drequest->getSymbolicCommit();
37
if (!strlen($head_ref)) {
38
$head_ref = $drequest->getBranch();
39
}
40
}
41
42
if (!strlen($against_ref)) {
43
$default_branch = $repository->getDefaultBranch();
44
if ($default_branch != $head_ref) {
45
$against_ref = $default_branch;
46
47
// If we filled this in by default, we want to prompt the user to
48
// confirm that this is really what they want.
49
$must_prompt = true;
50
}
51
}
52
}
53
54
$refs = $drequest->resolveRefs(
55
array_filter(
56
array(
57
$head_ref,
58
$against_ref,
59
)));
60
61
$identical = false;
62
if ($head_ref === $against_ref) {
63
$identical = true;
64
} else {
65
if (count($refs) == 2) {
66
if ($refs[$head_ref] === $refs[$against_ref]) {
67
$identical = true;
68
}
69
}
70
}
71
72
if ($must_prompt || count($refs) != 2 || $identical) {
73
return $this->buildCompareDialog(
74
$head_ref,
75
$against_ref,
76
$refs,
77
$identical);
78
}
79
80
if ($request->isFormPost()) {
81
// Redirect to a stable URI that can be copy/pasted.
82
$compare_uri = $drequest->generateURI(
83
array(
84
'action' => 'compare',
85
'head' => $head_ref,
86
'against' => $against_ref,
87
));
88
89
return id(new AphrontRedirectResponse())->setURI($compare_uri);
90
}
91
92
$crumbs = $this->buildCrumbs(
93
array(
94
'view' => 'compare',
95
));
96
$crumbs->setBorder(true);
97
98
$pager = id(new PHUIPagerView())
99
->readFromRequest($request);
100
101
$history = null;
102
try {
103
$history_results = $this->callConduitWithDiffusionRequest(
104
'diffusion.historyquery',
105
array(
106
'commit' => $head_ref,
107
'against' => $against_ref,
108
'path' => $drequest->getPath(),
109
'offset' => $pager->getOffset(),
110
'limit' => $pager->getPageSize() + 1,
111
));
112
$history = DiffusionPathChange::newFromConduit(
113
$history_results['pathChanges']);
114
$history = $pager->sliceResults($history);
115
116
$history_view = $this->newHistoryView(
117
$history_results,
118
$history,
119
$pager,
120
$head_ref,
121
$against_ref);
122
123
} catch (Exception $ex) {
124
if ($repository->isImporting()) {
125
$history_view = $this->renderStatusMessage(
126
pht('Still Importing...'),
127
pht(
128
'This repository is still importing. History is not yet '.
129
'available.'));
130
} else {
131
$history_view = $this->renderStatusMessage(
132
pht('Unable to Retrieve History'),
133
$ex->getMessage());
134
}
135
}
136
137
$header = id(new PHUIHeaderView())
138
->setHeader(
139
pht(
140
'Changes on %s but not %s',
141
phutil_tag('em', array(), $head_ref),
142
phutil_tag('em', array(), $against_ref)));
143
144
$curtain = $this->buildCurtain($head_ref, $against_ref);
145
146
$column_view = id(new PHUITwoColumnView())
147
->setHeader($header)
148
->setCurtain($curtain)
149
->setMainColumn(
150
array(
151
$history_view,
152
));
153
154
return $this->newPage()
155
->setTitle(
156
array(
157
$repository->getName(),
158
$repository->getDisplayName(),
159
))
160
->setCrumbs($crumbs)
161
->appendChild($column_view);
162
}
163
164
private function buildCompareDialog(
165
$head_ref,
166
$against_ref,
167
array $resolved,
168
$identical) {
169
170
$viewer = $this->getViewer();
171
$request = $this->getRequest();
172
$drequest = $this->getDiffusionRequest();
173
$repository = $drequest->getRepository();
174
175
$e_head = null;
176
$e_against = null;
177
$errors = array();
178
if ($request->isFormPost()) {
179
if (!strlen($head_ref)) {
180
$e_head = pht('Required');
181
$errors[] = pht(
182
'You must provide two different commits to compare.');
183
} else if (!isset($resolved[$head_ref])) {
184
$e_head = pht('Not Found');
185
$errors[] = pht(
186
'Commit "%s" is not a valid commit in this repository.',
187
$head_ref);
188
}
189
190
if (!strlen($against_ref)) {
191
$e_against = pht('Required');
192
$errors[] = pht(
193
'You must provide two different commits to compare.');
194
} else if (!isset($resolved[$against_ref])) {
195
$e_against = pht('Not Found');
196
$errors[] = pht(
197
'Commit "%s" is not a valid commit in this repository.',
198
$against_ref);
199
}
200
201
if ($identical) {
202
$e_head = pht('Identical');
203
$e_against = pht('Identical');
204
$errors[] = pht(
205
'Both references identify the same commit. You can not compare a '.
206
'commit against itself.');
207
}
208
}
209
210
$form = id(new AphrontFormView())
211
->setViewer($viewer)
212
->appendControl(
213
id(new AphrontFormTextControl())
214
->setLabel(pht('Head'))
215
->setName('head')
216
->setError($e_head)
217
->setValue($head_ref))
218
->appendControl(
219
id(new AphrontFormTextControl())
220
->setLabel(pht('Against'))
221
->setName('against')
222
->setError($e_against)
223
->setValue($against_ref));
224
225
$cancel_uri = $repository->generateURI(
226
array(
227
'action' => 'browse',
228
));
229
230
return $this->newDialog()
231
->setTitle(pht('Compare Against'))
232
->setWidth(AphrontDialogView::WIDTH_FORM)
233
->setErrors($errors)
234
->appendForm($form)
235
->addSubmitButton(pht('Compare'))
236
->addCancelButton($cancel_uri, pht('Cancel'));
237
}
238
239
private function buildCurtain($head_ref, $against_ref) {
240
$viewer = $this->getViewer();
241
$request = $this->getRequest();
242
$drequest = $this->getDiffusionRequest();
243
$repository = $drequest->getRepository();
244
245
$curtain = $this->newCurtainView(null);
246
247
$reverse_uri = $drequest->generateURI(
248
array(
249
'action' => 'compare',
250
'head' => $against_ref,
251
'against' => $head_ref,
252
));
253
254
$curtain->addAction(
255
id(new PhabricatorActionView())
256
->setName(pht('Reverse Comparison'))
257
->setHref($reverse_uri)
258
->setIcon('fa-refresh'));
259
260
$compare_uri = $drequest->generateURI(
261
array(
262
'action' => 'compare',
263
'head' => $head_ref,
264
));
265
266
$curtain->addAction(
267
id(new PhabricatorActionView())
268
->setName(pht('Compare Against...'))
269
->setIcon('fa-code-fork')
270
->setWorkflow(true)
271
->setHref($compare_uri));
272
273
// TODO: Provide a "Show Diff" action.
274
275
return $curtain;
276
}
277
278
private function newHistoryView(
279
array $results,
280
array $history,
281
PHUIPagerView $pager,
282
$head_ref,
283
$against_ref) {
284
285
$request = $this->getRequest();
286
$viewer = $this->getViewer();
287
$drequest = $this->getDiffusionRequest();
288
289
if (!$history) {
290
return $this->renderStatusMessage(
291
pht('Up To Date'),
292
pht(
293
'There are no commits on %s that are not already on %s.',
294
phutil_tag('strong', array(), $head_ref),
295
phutil_tag('strong', array(), $against_ref)));
296
}
297
298
$history_view = id(new DiffusionCommitGraphView())
299
->setViewer($viewer)
300
->setDiffusionRequest($drequest)
301
->setHistory($history)
302
->setParents($results['parents'])
303
->setFilterParents(true)
304
->setIsHead(!$pager->getOffset())
305
->setIsTail(!$pager->getHasMorePages());
306
307
return $history_view;
308
}
309
}
310
311