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