Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/phabricator
Path: blob/master/src/applications/diffusion/controller/DiffusionBlameController.php
12242 views
1
<?php
2
3
final class DiffusionBlameController 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
19
$blame = $this->loadBlame();
20
21
$identifiers = array_fuse($blame);
22
if ($identifiers) {
23
$commits = id(new DiffusionCommitQuery())
24
->setViewer($viewer)
25
->withRepository($repository)
26
->withIdentifiers($identifiers)
27
->needIdentities(true)
28
// See PHI1014. If identities haven't been built yet, we may need to
29
// fall back to raw commit data.
30
->needCommitData(true)
31
->execute();
32
$commits = mpull($commits, null, 'getCommitIdentifier');
33
} else {
34
$commits = array();
35
}
36
37
$commit_map = mpull($commits, 'getCommitIdentifier', 'getPHID');
38
39
$revision_map = DiffusionCommitRevisionQuery::loadRevisionMapForCommits(
40
$viewer,
41
$commits);
42
43
$base_href = (string)$drequest->generateURI(
44
array(
45
'action' => 'browse',
46
'stable' => true,
47
));
48
49
$skip_text = pht('Skip Past This Commit');
50
$skip_icon = id(new PHUIIconView())
51
->setIcon('fa-backward');
52
53
Javelin::initBehavior('phabricator-tooltips');
54
55
$handle_phids = array();
56
foreach ($commits as $commit) {
57
$handle_phids[] = $commit->getAuthorDisplayPHID();
58
}
59
60
foreach ($revision_map as $revisions) {
61
foreach ($revisions as $revision) {
62
$handle_phids[] = $revision->getAuthorPHID();
63
}
64
}
65
66
$handles = $viewer->loadHandles($handle_phids);
67
68
$map = array();
69
$epochs = array();
70
foreach ($identifiers as $identifier) {
71
$skip_href = $base_href.'?before='.$identifier;
72
73
$skip_link = javelin_tag(
74
'a',
75
array(
76
'href' => $skip_href,
77
'sigil' => 'has-tooltip',
78
'meta' => array(
79
'tip' => $skip_text,
80
'align' => 'E',
81
'size' => 300,
82
),
83
),
84
$skip_icon);
85
86
// We may not have a commit object for a given identifier if the commit
87
// has not imported yet.
88
89
// At time of writing, this can also happen if a line was part of the
90
// initial import: blame produces a "^abc123" identifier in Git, which
91
// doesn't correspond to a real commit.
92
93
$commit = idx($commits, $identifier);
94
95
$revision = null;
96
if ($commit) {
97
$revisions = idx($revision_map, $commit->getPHID());
98
99
// There may be multiple edges between this commit and revisions in the
100
// database. If there are, just pick one arbitrarily.
101
if ($revisions) {
102
$revision = head($revisions);
103
}
104
}
105
106
$author_phid = null;
107
108
if ($commit) {
109
$author_phid = $commit->getAuthorDisplayPHID();
110
}
111
112
if (!$author_phid) {
113
// This means we couldn't identify an author for the commit or the
114
// revision. We just render a blank for alignment.
115
$author_style = null;
116
$author_href = null;
117
$author_sigil = null;
118
$author_meta = null;
119
} else {
120
$author_src = $handles[$author_phid]->getImageURI();
121
$author_style = 'background-image: url('.$author_src.');';
122
$author_href = $handles[$author_phid]->getURI();
123
$author_sigil = 'has-tooltip';
124
$author_meta = array(
125
'tip' => $handles[$author_phid]->getName(),
126
'align' => 'E',
127
'size' => 'auto',
128
);
129
}
130
131
$author_link = javelin_tag(
132
$author_href ? 'a' : 'span',
133
array(
134
'class' => 'phabricator-source-blame-author',
135
'style' => $author_style,
136
'href' => $author_href,
137
'sigil' => $author_sigil,
138
'meta' => $author_meta,
139
));
140
141
if ($commit) {
142
$commit_link = javelin_tag(
143
'a',
144
array(
145
'href' => $commit->getURI(),
146
'sigil' => 'has-tooltip',
147
'meta' => array(
148
'tip' => $this->renderCommitTooltip($commit, $handles),
149
'align' => 'E',
150
'size' => 600,
151
),
152
),
153
$commit->getLocalName());
154
} else {
155
$commit_link = null;
156
}
157
158
$info = array(
159
$author_link,
160
$commit_link,
161
);
162
163
if ($revision) {
164
$revision_link = javelin_tag(
165
'a',
166
array(
167
'href' => $revision->getURI(),
168
'sigil' => 'has-tooltip',
169
'meta' => array(
170
'tip' => $this->renderRevisionTooltip($revision, $handles),
171
'align' => 'E',
172
'size' => 600,
173
),
174
),
175
$revision->getMonogram());
176
177
$info = array(
178
$info,
179
" \xC2\xB7 ",
180
$revision_link,
181
);
182
}
183
184
if ($commit) {
185
$epoch = $commit->getEpoch();
186
} else {
187
$epoch = 0;
188
}
189
190
$epochs[] = $epoch;
191
192
$data = array(
193
'skip' => $skip_link,
194
'info' => hsprintf('%s', $info),
195
'epoch' => $epoch,
196
);
197
198
$map[$identifier] = $data;
199
}
200
201
$epoch_min = min($epochs);
202
$epoch_max = max($epochs);
203
204
return id(new AphrontAjaxResponse())->setContent(
205
array(
206
'blame' => $blame,
207
'map' => $map,
208
'epoch' => array(
209
'min' => $epoch_min,
210
'max' => $epoch_max,
211
),
212
));
213
}
214
215
private function loadBlame() {
216
$drequest = $this->getDiffusionRequest();
217
218
$commit = $drequest->getCommit();
219
$path = $drequest->getPath();
220
221
$blame_timeout = 15;
222
223
$blame = $this->callConduitWithDiffusionRequest(
224
'diffusion.blame',
225
array(
226
'commit' => $commit,
227
'paths' => array($path),
228
'timeout' => $blame_timeout,
229
));
230
231
return idx($blame, $path, array());
232
}
233
234
private function renderRevisionTooltip(
235
DifferentialRevision $revision,
236
$handles) {
237
$viewer = $this->getViewer();
238
239
$date = phabricator_date($revision->getDateModified(), $viewer);
240
$monogram = $revision->getMonogram();
241
$title = $revision->getTitle();
242
$header = "{$monogram} {$title}";
243
244
$author = $handles[$revision->getAuthorPHID()]->getName();
245
246
return "{$header}\n{$date} \xC2\xB7 {$author}";
247
}
248
249
private function renderCommitTooltip(
250
PhabricatorRepositoryCommit $commit,
251
$handles) {
252
253
$viewer = $this->getViewer();
254
255
$date = phabricator_date($commit->getEpoch(), $viewer);
256
$summary = trim($commit->getSummary());
257
258
$author_phid = $commit->getAuthorPHID();
259
if ($author_phid && isset($handles[$author_phid])) {
260
$author_name = $handles[$author_phid]->getName();
261
} else {
262
$author_name = null;
263
}
264
265
if ($author_name) {
266
return "{$summary}\n{$date} \xC2\xB7 {$author_name}";
267
} else {
268
return "{$summary}\n{$date}";
269
}
270
}
271
272
}
273
274