1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45 package org.eclipse.jgit.lib;
46
47 import static org.eclipse.jgit.transport.ReceiveCommand.Result.NOT_ATTEMPTED;
48 import static org.eclipse.jgit.transport.ReceiveCommand.Result.REJECTED_OTHER_REASON;
49
50 import java.io.IOException;
51 import java.text.MessageFormat;
52 import java.util.ArrayList;
53 import java.util.Arrays;
54 import java.util.Collection;
55 import java.util.Collections;
56 import java.util.HashSet;
57 import java.util.List;
58
59 import org.eclipse.jgit.internal.JGitText;
60 import org.eclipse.jgit.lib.RefUpdate.Result;
61 import org.eclipse.jgit.revwalk.RevWalk;
62 import org.eclipse.jgit.transport.PushCertificate;
63 import org.eclipse.jgit.transport.ReceiveCommand;
64
65
66
67
68
69
70
71 public class BatchRefUpdate {
72 private final RefDatabase refdb;
73
74
75 private final List<ReceiveCommand> commands;
76
77
78 private boolean allowNonFastForwards;
79
80
81 private PersonIdent refLogIdent;
82
83
84 private String refLogMessage;
85
86
87 private boolean refLogIncludeResult;
88
89
90 private PushCertificate pushCert;
91
92
93
94
95
96
97
98 protected BatchRefUpdate(RefDatabase refdb) {
99 this.refdb = refdb;
100 this.commands = new ArrayList<ReceiveCommand>();
101 }
102
103
104
105
106
107 public boolean isAllowNonFastForwards() {
108 return allowNonFastForwards;
109 }
110
111
112
113
114
115
116
117
118 public BatchRefUpdate setAllowNonFastForwards(boolean allow) {
119 allowNonFastForwards = allow;
120 return this;
121 }
122
123
124 public PersonIdent getRefLogIdent() {
125 return refLogIdent;
126 }
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141 public BatchRefUpdate setRefLogIdent(final PersonIdent pi) {
142 refLogIdent = pi;
143 return this;
144 }
145
146
147
148
149
150
151
152 public String getRefLogMessage() {
153 return refLogMessage;
154 }
155
156
157 public boolean isRefLogIncludingResult() {
158 return refLogIncludeResult;
159 }
160
161
162
163
164
165
166
167
168
169
170
171
172
173 public BatchRefUpdate setRefLogMessage(String msg, boolean appendStatus) {
174 if (msg == null && !appendStatus)
175 disableRefLog();
176 else if (msg == null && appendStatus) {
177 refLogMessage = "";
178 refLogIncludeResult = true;
179 } else {
180 refLogMessage = msg;
181 refLogIncludeResult = appendStatus;
182 }
183 return this;
184 }
185
186
187
188
189
190
191 public BatchRefUpdate disableRefLog() {
192 refLogMessage = null;
193 refLogIncludeResult = false;
194 return this;
195 }
196
197
198 public boolean isRefLogDisabled() {
199 return refLogMessage == null;
200 }
201
202
203
204
205
206
207
208
209
210
211
212 public void setPushCertificate(PushCertificate cert) {
213 pushCert = cert;
214 }
215
216
217
218
219
220
221
222
223
224
225 protected PushCertificate getPushCertificate() {
226 return pushCert;
227 }
228
229
230 public List<ReceiveCommand> getCommands() {
231 return Collections.unmodifiableList(commands);
232 }
233
234
235
236
237
238
239
240
241 public BatchRefUpdate addCommand(ReceiveCommand cmd) {
242 commands.add(cmd);
243 return this;
244 }
245
246
247
248
249
250
251
252
253 public BatchRefUpdate addCommand(ReceiveCommand... cmd) {
254 return addCommand(Arrays.asList(cmd));
255 }
256
257
258
259
260
261
262
263
264 public BatchRefUpdate addCommand(Collection<ReceiveCommand> cmd) {
265 commands.addAll(cmd);
266 return this;
267 }
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285 public void execute(RevWalk walk, ProgressMonitor monitor)
286 throws IOException {
287 monitor.beginTask(JGitText.get().updatingReferences, commands.size());
288 List<ReceiveCommand> commands2 = new ArrayList<ReceiveCommand>(
289 commands.size());
290 List<String> namesToCheck = new ArrayList<String>(commands.size());
291
292
293 for (ReceiveCommand cmd : commands) {
294 try {
295 if (cmd.getResult() == NOT_ATTEMPTED) {
296 cmd.updateType(walk);
297 switch (cmd.getType()) {
298 case CREATE:
299 namesToCheck.add(cmd.getRefName());
300 commands2.add(cmd);
301 break;
302 case UPDATE:
303 case UPDATE_NONFASTFORWARD:
304 commands2.add(cmd);
305 break;
306 case DELETE:
307 RefUpdate rud = newUpdate(cmd);
308 monitor.update(1);
309 cmd.setResult(rud.delete(walk));
310 }
311 }
312 } catch (IOException err) {
313 cmd.setResult(
314 REJECTED_OTHER_REASON,
315 MessageFormat.format(JGitText.get().lockError,
316 err.getMessage()));
317 }
318 }
319 if (!commands2.isEmpty()) {
320
321 Collection<String> takenNames = new HashSet<String>(refdb.getRefs(
322 RefDatabase.ALL).keySet());
323 Collection<String> takenPrefixes = getTakenPrefixes(takenNames);
324
325
326 for (ReceiveCommand cmd : commands2) {
327 try {
328 if (cmd.getResult() == NOT_ATTEMPTED) {
329 cmd.updateType(walk);
330 RefUpdate ru = newUpdate(cmd);
331 SWITCH: switch (cmd.getType()) {
332 case DELETE:
333
334 break;
335 case UPDATE:
336 case UPDATE_NONFASTFORWARD:
337 RefUpdate ruu = newUpdate(cmd);
338 cmd.setResult(ruu.update(walk));
339 break;
340 case CREATE:
341 for (String prefix : getPrefixes(cmd.getRefName())) {
342 if (takenNames.contains(prefix)) {
343 cmd.setResult(Result.LOCK_FAILURE);
344 break SWITCH;
345 }
346 }
347 if (takenPrefixes.contains(cmd.getRefName())) {
348 cmd.setResult(Result.LOCK_FAILURE);
349 break SWITCH;
350 }
351 ru.setCheckConflicting(false);
352 addRefToPrefixes(takenPrefixes, cmd.getRefName());
353 takenNames.add(cmd.getRefName());
354 cmd.setResult(ru.update(walk));
355 }
356 }
357 } catch (IOException err) {
358 cmd.setResult(REJECTED_OTHER_REASON, MessageFormat.format(
359 JGitText.get().lockError, err.getMessage()));
360 } finally {
361 monitor.update(1);
362 }
363 }
364 }
365 monitor.endTask();
366 }
367
368 private static Collection<String> getTakenPrefixes(
369 final Collection<String> names) {
370 Collection<String> ref = new HashSet<String>();
371 for (String name : names)
372 ref.addAll(getPrefixes(name));
373 return ref;
374 }
375
376 private static void addRefToPrefixes(Collection<String> prefixes,
377 String name) {
378 for (String prefix : getPrefixes(name)) {
379 prefixes.add(prefix);
380 }
381 }
382
383 static Collection<String> getPrefixes(String s) {
384 Collection<String> ret = new HashSet<String>();
385 int p1 = s.indexOf('/');
386 while (p1 > 0) {
387 ret.add(s.substring(0, p1));
388 p1 = s.indexOf('/', p1 + 1);
389 }
390 return ret;
391 }
392
393
394
395
396
397
398
399
400
401
402
403 protected RefUpdate newUpdate(ReceiveCommand cmd) throws IOException {
404 RefUpdate ru = refdb.newUpdate(cmd.getRefName(), false);
405 if (isRefLogDisabled())
406 ru.disableRefLog();
407 else {
408 ru.setRefLogIdent(refLogIdent);
409 ru.setRefLogMessage(refLogMessage, refLogIncludeResult);
410 }
411 ru.setPushCertificate(pushCert);
412 switch (cmd.getType()) {
413 case DELETE:
414 if (!ObjectId.zeroId().equals(cmd.getOldId()))
415 ru.setExpectedOldObjectId(cmd.getOldId());
416 ru.setForceUpdate(true);
417 return ru;
418
419 case CREATE:
420 case UPDATE:
421 case UPDATE_NONFASTFORWARD:
422 default:
423 ru.setForceUpdate(isAllowNonFastForwards());
424 ru.setExpectedOldObjectId(cmd.getOldId());
425 ru.setNewObjectId(cmd.getNewId());
426 return ru;
427 }
428 }
429
430 @Override
431 public String toString() {
432 StringBuilder r = new StringBuilder();
433 r.append(getClass().getSimpleName()).append('[');
434 if (commands.isEmpty())
435 return r.append(']').toString();
436
437 r.append('\n');
438 for (ReceiveCommand cmd : commands) {
439 r.append(" ");
440 r.append(cmd);
441 r.append(" (").append(cmd.getResult()).append(")\n");
442 }
443 return r.append(']').toString();
444 }
445 }