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.internal.ketch;
45
46 import static java.util.concurrent.TimeUnit.MILLISECONDS;
47 import static java.util.concurrent.TimeUnit.SECONDS;
48 import static org.eclipse.jgit.internal.ketch.Proposal.State.EXECUTED;
49 import static org.eclipse.jgit.internal.ketch.Proposal.State.QUEUED;
50 import static org.eclipse.jgit.transport.ReceiveCommand.Result.NOT_ATTEMPTED;
51 import static org.eclipse.jgit.transport.ReceiveCommand.Result.REJECTED_OTHER_REASON;
52
53 import java.io.IOException;
54 import java.util.Collection;
55
56 import org.eclipse.jgit.internal.JGitText;
57 import org.eclipse.jgit.transport.PreReceiveHook;
58 import org.eclipse.jgit.transport.ProgressSpinner;
59 import org.eclipse.jgit.transport.ReceiveCommand;
60 import org.eclipse.jgit.transport.ReceivePack;
61 import org.slf4j.Logger;
62 import org.slf4j.LoggerFactory;
63
64
65
66
67
68
69
70
71
72 public class KetchPreReceive implements PreReceiveHook {
73 private static final Logger log = LoggerFactory.getLogger(KetchPreReceive.class);
74
75 private final KetchLeader leader;
76
77
78
79
80
81
82
83
84 public KetchPreReceive(KetchLeader leader) {
85 this.leader = leader;
86 }
87
88
89 @Override
90 public void onPreReceive(ReceivePack rp, Collection<ReceiveCommand> cmds) {
91 cmds = ReceiveCommand.filter(cmds, NOT_ATTEMPTED);
92 if (cmds.isEmpty()) {
93 return;
94 }
95
96 try {
97 Proposal proposal = new Proposal(rp.getRevWalk(), cmds)
98 .setPushCertificate(rp.getPushCertificate())
99 .setAuthor(rp.getRefLogIdent())
100 .setMessage("push");
101 leader.queueProposal(proposal);
102 if (proposal.isDone()) {
103
104 return;
105 }
106
107 ProgressSpinner spinner = new ProgressSpinner(
108 rp.getMessageOutputStream());
109 if (proposal.getState() == QUEUED) {
110 waitForQueue(proposal, spinner);
111 }
112 if (!proposal.isDone()) {
113 waitForPropose(proposal, spinner);
114 }
115 } catch (IOException | InterruptedException e) {
116 String msg = JGitText.get().transactionAborted;
117 for (ReceiveCommand cmd : cmds) {
118 if (cmd.getResult() == NOT_ATTEMPTED) {
119 cmd.setResult(REJECTED_OTHER_REASON, msg);
120 }
121 }
122 log.error(msg, e);
123 }
124 }
125
126 private void waitForQueue(Proposal proposal, ProgressSpinner spinner)
127 throws InterruptedException {
128 spinner.beginTask(KetchText.get().waitingForQueue, 1, SECONDS);
129 while (!proposal.awaitStateChange(QUEUED, 250, MILLISECONDS)) {
130 spinner.update();
131 }
132 switch (proposal.getState()) {
133 case RUNNING:
134 default:
135 spinner.endTask(KetchText.get().starting);
136 break;
137
138 case EXECUTED:
139 spinner.endTask(KetchText.get().accepted);
140 break;
141
142 case ABORTED:
143 spinner.endTask(KetchText.get().failed);
144 break;
145 }
146 }
147
148 private void waitForPropose(Proposal proposal, ProgressSpinner spinner)
149 throws InterruptedException {
150 spinner.beginTask(KetchText.get().proposingUpdates, 2, SECONDS);
151 while (!proposal.await(250, MILLISECONDS)) {
152 spinner.update();
153 }
154 spinner.endTask(proposal.getState() == EXECUTED
155 ? KetchText.get().accepted
156 : KetchText.get().failed);
157 }
158 }