1
2
3
4
5
6
7
8
9
10
11 package org.eclipse.jgit.transport;
12
13 import static org.eclipse.jgit.transport.ReceiveCommand.Result.NOT_ATTEMPTED;
14 import static org.eclipse.jgit.transport.ReceiveCommand.Result.REJECTED_OTHER_REASON;
15
16 import java.io.IOException;
17 import java.text.MessageFormat;
18 import java.util.ArrayList;
19 import java.util.Collection;
20 import java.util.List;
21
22 import org.eclipse.jgit.annotations.NonNull;
23 import org.eclipse.jgit.annotations.Nullable;
24 import org.eclipse.jgit.internal.JGitText;
25 import org.eclipse.jgit.lib.AnyObjectId;
26 import org.eclipse.jgit.lib.ObjectId;
27 import org.eclipse.jgit.lib.Ref;
28 import org.eclipse.jgit.lib.RefUpdate;
29 import org.eclipse.jgit.revwalk.RevCommit;
30 import org.eclipse.jgit.revwalk.RevObject;
31 import org.eclipse.jgit.revwalk.RevWalk;
32
33
34
35
36
37
38
39
40 public class ReceiveCommand {
41
42 public enum Type {
43
44 CREATE,
45
46
47
48
49
50
51
52 UPDATE,
53
54
55
56
57
58
59
60
61 UPDATE_NONFASTFORWARD,
62
63
64 DELETE;
65 }
66
67
68 public enum Result {
69
70 NOT_ATTEMPTED,
71
72
73 REJECTED_NOCREATE,
74
75
76 REJECTED_NODELETE,
77
78
79 REJECTED_NONFASTFORWARD,
80
81
82 REJECTED_CURRENT_BRANCH,
83
84
85
86
87
88
89
90
91 REJECTED_MISSING_OBJECT,
92
93
94 REJECTED_OTHER_REASON,
95
96
97 LOCK_FAILURE,
98
99
100 OK;
101 }
102
103
104
105
106
107
108
109
110
111
112
113
114 public static List<ReceiveCommand> filter(Iterable<ReceiveCommand> in,
115 Result want) {
116 List<ReceiveCommand> r;
117 if (in instanceof Collection)
118 r = new ArrayList<>(((Collection<?>) in).size());
119 else
120 r = new ArrayList<>();
121 for (ReceiveCommand cmd : in) {
122 if (cmd.getResult() == want)
123 r.add(cmd);
124 }
125 return r;
126 }
127
128
129
130
131
132
133
134
135
136
137
138
139 public static List<ReceiveCommand> filter(List<ReceiveCommand> commands,
140 Result want) {
141 return filter((Iterable<ReceiveCommand>) commands, want);
142 }
143
144
145
146
147
148
149
150
151
152
153
154
155
156 public static void abort(Iterable<ReceiveCommand> commands) {
157 for (ReceiveCommand c : commands) {
158 if (c.getResult() == NOT_ATTEMPTED) {
159 c.setResult(REJECTED_OTHER_REASON,
160 JGitText.get().transactionAborted);
161 }
162 }
163 }
164
165
166
167
168
169
170
171
172
173
174 public static boolean isTransactionAborted(ReceiveCommand cmd) {
175 return cmd.getResult() == REJECTED_OTHER_REASON
176 && cmd.getMessage().equals(JGitText.get().transactionAborted);
177 }
178
179
180
181
182
183
184
185
186
187
188
189
190
191 public static ReceiveCommand link(@NonNull ObjectId oldId,
192 @NonNull String newTarget, @NonNull String name) {
193 return new ReceiveCommand(oldId, newTarget, name);
194 }
195
196
197
198
199
200
201
202
203
204
205
206
207
208 public static ReceiveCommand link(@Nullable String oldTarget,
209 @NonNull String newTarget, @NonNull String name) {
210 return new ReceiveCommand(oldTarget, newTarget, name);
211 }
212
213
214
215
216
217
218
219
220
221
222
223
224
225 public static ReceiveCommand unlink(@NonNull String oldTarget,
226 @NonNull ObjectId newId, @NonNull String name) {
227 return new ReceiveCommand(oldTarget, newId, name);
228 }
229
230 private final ObjectId oldId;
231
232 private final String oldSymref;
233
234 private final ObjectId newId;
235
236 private final String newSymref;
237
238 private final String name;
239
240 private Type type;
241
242 private boolean typeIsCorrect;
243
244 private Ref ref;
245
246 private Result status = Result.NOT_ATTEMPTED;
247
248 private String message;
249
250 private boolean customRefLog;
251
252 private String refLogMessage;
253
254 private boolean refLogIncludeResult;
255
256 private Boolean forceRefLog;
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273 public ReceiveCommand(final ObjectId oldId, final ObjectId newId,
274 final String name) {
275 if (oldId == null) {
276 throw new IllegalArgumentException(
277 JGitText.get().oldIdMustNotBeNull);
278 }
279 if (newId == null) {
280 throw new IllegalArgumentException(
281 JGitText.get().newIdMustNotBeNull);
282 }
283 if (name == null || name.isEmpty()) {
284 throw new IllegalArgumentException(
285 JGitText.get().nameMustNotBeNullOrEmpty);
286 }
287 this.oldId = oldId;
288 this.oldSymref = null;
289 this.newId = newId;
290 this.newSymref = null;
291 this.name = name;
292
293 type = Type.UPDATE;
294 if (ObjectId.zeroId().equals(oldId)) {
295 type = Type.CREATE;
296 }
297 if (ObjectId.zeroId().equals(newId)) {
298 type = Type.DELETE;
299 }
300 }
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325 public ReceiveCommand(final ObjectId oldId, final ObjectId newId,
326 final String name, final Type type) {
327 if (oldId == null) {
328 throw new IllegalArgumentException(
329 JGitText.get().oldIdMustNotBeNull);
330 }
331 if (newId == null) {
332 throw new IllegalArgumentException(
333 JGitText.get().newIdMustNotBeNull);
334 }
335 if (name == null || name.isEmpty()) {
336 throw new IllegalArgumentException(
337 JGitText.get().nameMustNotBeNullOrEmpty);
338 }
339 this.oldId = oldId;
340 this.oldSymref = null;
341 this.newId = newId;
342 this.newSymref = null;
343 this.name = name;
344 switch (type) {
345 case CREATE:
346 if (!ObjectId.zeroId().equals(oldId)) {
347 throw new IllegalArgumentException(
348 JGitText.get().createRequiresZeroOldId);
349 }
350 break;
351 case DELETE:
352 if (!ObjectId.zeroId().equals(newId)) {
353 throw new IllegalArgumentException(
354 JGitText.get().deleteRequiresZeroNewId);
355 }
356 break;
357 case UPDATE:
358 case UPDATE_NONFASTFORWARD:
359 if (ObjectId.zeroId().equals(newId)
360 || ObjectId.zeroId().equals(oldId)) {
361 throw new IllegalArgumentException(
362 JGitText.get().updateRequiresOldIdAndNewId);
363 }
364 break;
365 default:
366 throw new IllegalStateException(
367 JGitText.get().enumValueNotSupported0);
368 }
369 this.type = type;
370 }
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385 private ReceiveCommand(ObjectId oldId, String newSymref, String name) {
386 if (oldId == null) {
387 throw new IllegalArgumentException(
388 JGitText.get().oldIdMustNotBeNull);
389 }
390 if (name == null || name.isEmpty()) {
391 throw new IllegalArgumentException(
392 JGitText.get().nameMustNotBeNullOrEmpty);
393 }
394 this.oldId = oldId;
395 this.oldSymref = null;
396 this.newId = ObjectId.zeroId();
397 this.newSymref = newSymref;
398 this.name = name;
399 if (AnyObjectId.isEqual(ObjectId.zeroId(), oldId)) {
400 type = Type.CREATE;
401 } else if (newSymref != null) {
402 type = Type.UPDATE;
403 } else {
404 type = Type.DELETE;
405 }
406 typeIsCorrect = true;
407 }
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422 private ReceiveCommand(String oldSymref, ObjectId newId, String name) {
423 if (newId == null) {
424 throw new IllegalArgumentException(
425 JGitText.get().newIdMustNotBeNull);
426 }
427 if (name == null || name.isEmpty()) {
428 throw new IllegalArgumentException(
429 JGitText.get().nameMustNotBeNullOrEmpty);
430 }
431 this.oldId = ObjectId.zeroId();
432 this.oldSymref = oldSymref;
433 this.newId = newId;
434 this.newSymref = null;
435 this.name = name;
436 if (oldSymref == null) {
437 type = Type.CREATE;
438 } else if (!AnyObjectId.isEqual(ObjectId.zeroId(), newId)) {
439 type = Type.UPDATE;
440 } else {
441 type = Type.DELETE;
442 }
443 typeIsCorrect = true;
444 }
445
446
447
448
449
450
451
452
453
454
455
456
457
458 private ReceiveCommand(@Nullable String oldTarget, String newTarget, String name) {
459 if (name == null || name.isEmpty()) {
460 throw new IllegalArgumentException(
461 JGitText.get().nameMustNotBeNullOrEmpty);
462 }
463 this.oldId = ObjectId.zeroId();
464 this.oldSymref = oldTarget;
465 this.newId = ObjectId.zeroId();
466 this.newSymref = newTarget;
467 this.name = name;
468 if (oldTarget == null) {
469 if (newTarget == null) {
470 throw new IllegalArgumentException(
471 JGitText.get().bothRefTargetsMustNotBeNull);
472 }
473 type = Type.CREATE;
474 } else if (newTarget != null) {
475 type = Type.UPDATE;
476 } else {
477 type = Type.DELETE;
478 }
479 typeIsCorrect = true;
480 }
481
482
483
484
485
486
487 public ObjectId getOldId() {
488 return oldId;
489 }
490
491
492
493
494
495
496
497 @Nullable
498 public String getOldSymref() {
499 return oldSymref;
500 }
501
502
503
504
505
506
507 public ObjectId getNewId() {
508 return newId;
509 }
510
511
512
513
514
515
516
517 @Nullable
518 public String getNewSymref() {
519 return newSymref;
520 }
521
522
523
524
525
526
527 public String getRefName() {
528 return name;
529 }
530
531
532
533
534
535
536 public Type getType() {
537 return type;
538 }
539
540
541
542
543
544
545 public Ref getRef() {
546 return ref;
547 }
548
549
550
551
552
553
554 public Result getResult() {
555 return status;
556 }
557
558
559
560
561
562
563 public String getMessage() {
564 return message;
565 }
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581 public void setRefLogMessage(String msg, boolean appendStatus) {
582 customRefLog = true;
583 if (msg == null && !appendStatus) {
584 disableRefLog();
585 } else if (msg == null && appendStatus) {
586 refLogMessage = "";
587 refLogIncludeResult = true;
588 } else {
589 refLogMessage = msg;
590 refLogIncludeResult = appendStatus;
591 }
592 }
593
594
595
596
597
598
599
600
601 public void disableRefLog() {
602 customRefLog = true;
603 refLogMessage = null;
604 refLogIncludeResult = false;
605 }
606
607
608
609
610
611
612
613 public void setForceRefLog(boolean force) {
614 forceRefLog = Boolean.valueOf(force);
615 }
616
617
618
619
620
621
622
623
624
625
626
627
628 public boolean hasCustomRefLog() {
629 return customRefLog;
630 }
631
632
633
634
635
636
637
638 public boolean isRefLogDisabled() {
639 return refLogMessage == null;
640 }
641
642
643
644
645
646
647
648
649 @Nullable
650 public String getRefLogMessage() {
651 return refLogMessage;
652 }
653
654
655
656
657
658
659
660
661 public boolean isRefLogIncludingResult() {
662 return refLogIncludeResult;
663 }
664
665
666
667
668
669
670
671
672 @Nullable
673 public Boolean isForceRefLog() {
674 return forceRefLog;
675 }
676
677
678
679
680
681
682
683 public void setResult(Result s) {
684 setResult(s, null);
685 }
686
687
688
689
690
691
692
693
694
695 public void setResult(Result s, String m) {
696 status = s;
697 message = m;
698 }
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717 public void updateType(RevWalk walk) throws IOException {
718 if (typeIsCorrect)
719 return;
720 if (type == Type.UPDATE && !AnyObjectId.isEqual(oldId, newId)) {
721 RevObject o = walk.parseAny(oldId);
722 RevObject n = walk.parseAny(newId);
723 if (!(o instanceof RevCommit)
724 || !(n instanceof RevCommit)
725 || !walk.isMergedInto((RevCommit) o, (RevCommit) n))
726 setType(Type.UPDATE_NONFASTFORWARD);
727 }
728 typeIsCorrect = true;
729 }
730
731
732
733
734
735
736
737
738
739
740 public void execute(ReceivePack rp) {
741 try {
742 String expTarget = getOldSymref();
743 boolean detach = getNewSymref() != null
744 || (type == Type.DELETE && expTarget != null);
745 RefUpdate ru = rp.getRepository().updateRef(getRefName(), detach);
746 if (expTarget != null) {
747 if (!ru.getRef().isSymbolic() || !ru.getRef().getTarget()
748 .getName().equals(expTarget)) {
749 setResult(Result.LOCK_FAILURE);
750 return;
751 }
752 }
753
754 ru.setRefLogIdent(rp.getRefLogIdent());
755 ru.setRefLogMessage(refLogMessage, refLogIncludeResult);
756 switch (getType()) {
757 case DELETE:
758 if (!ObjectId.zeroId().equals(getOldId())) {
759
760
761
762
763 ru.setExpectedOldObjectId(getOldId());
764 }
765 ru.setForceUpdate(true);
766 setResult(ru.delete(rp.getRevWalk()));
767 break;
768
769 case CREATE:
770 case UPDATE:
771 case UPDATE_NONFASTFORWARD:
772 ru.setForceUpdate(rp.isAllowNonFastForwards());
773 ru.setExpectedOldObjectId(getOldId());
774 ru.setRefLogMessage("push", true);
775 if (getNewSymref() != null) {
776 setResult(ru.link(getNewSymref()));
777 } else {
778 ru.setNewObjectId(getNewId());
779 setResult(ru.update(rp.getRevWalk()));
780 }
781 break;
782 }
783 } catch (IOException err) {
784 reject(err);
785 }
786 }
787
788 void setRef(Ref r) {
789 ref = r;
790 }
791
792 void setType(Type t) {
793 type = t;
794 }
795
796 void setTypeFastForwardUpdate() {
797 type = Type.UPDATE;
798 typeIsCorrect = true;
799 }
800
801
802
803
804
805
806
807 public void setResult(RefUpdate.Result r) {
808 switch (r) {
809 case NOT_ATTEMPTED:
810 setResult(Result.NOT_ATTEMPTED);
811 break;
812
813 case LOCK_FAILURE:
814 case IO_FAILURE:
815 setResult(Result.LOCK_FAILURE);
816 break;
817
818 case NO_CHANGE:
819 case NEW:
820 case FORCED:
821 case FAST_FORWARD:
822 setResult(Result.OK);
823 break;
824
825 case REJECTED:
826 setResult(Result.REJECTED_NONFASTFORWARD);
827 break;
828
829 case REJECTED_CURRENT_BRANCH:
830 setResult(Result.REJECTED_CURRENT_BRANCH);
831 break;
832
833 case REJECTED_MISSING_OBJECT:
834 setResult(Result.REJECTED_MISSING_OBJECT);
835 break;
836
837 case REJECTED_OTHER_REASON:
838 setResult(Result.REJECTED_OTHER_REASON);
839 break;
840
841 default:
842 setResult(Result.REJECTED_OTHER_REASON, r.name());
843 break;
844 }
845 }
846
847 void reject(IOException err) {
848 setResult(Result.REJECTED_OTHER_REASON, MessageFormat.format(
849 JGitText.get().lockError, err.getMessage()));
850 }
851
852
853 @SuppressWarnings("nls")
854 @Override
855 public String toString() {
856 return getType().name() + ": " + getOldId().name() + " "
857 + getNewId().name() + " " + getRefName();
858 }
859 }