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