1
2
3
4
5
6
7
8
9
10
11 package org.eclipse.jgit.internal.ketch;
12
13 import static java.util.concurrent.TimeUnit.MILLISECONDS;
14 import static java.util.concurrent.TimeUnit.SECONDS;
15 import static org.eclipse.jgit.internal.ketch.Proposal.State.EXECUTED;
16 import static org.eclipse.jgit.internal.ketch.Proposal.State.QUEUED;
17 import static org.eclipse.jgit.transport.ReceiveCommand.Result.NOT_ATTEMPTED;
18 import static org.eclipse.jgit.transport.ReceiveCommand.Result.REJECTED_OTHER_REASON;
19
20 import java.io.IOException;
21 import java.util.Collection;
22
23 import org.eclipse.jgit.internal.JGitText;
24 import org.eclipse.jgit.transport.PreReceiveHook;
25 import org.eclipse.jgit.transport.ProgressSpinner;
26 import org.eclipse.jgit.transport.ReceiveCommand;
27 import org.eclipse.jgit.transport.ReceivePack;
28 import org.slf4j.Logger;
29 import org.slf4j.LoggerFactory;
30
31
32
33
34
35
36
37
38
39 public class KetchPreReceive implements PreReceiveHook {
40 private static final Logger log = LoggerFactory.getLogger(KetchPreReceive.class);
41
42 private final KetchLeader leader;
43
44
45
46
47
48
49
50
51 public KetchPreReceive(KetchLeader leader) {
52 this.leader = leader;
53 }
54
55
56 @Override
57 public void onPreReceive(ReceivePack rp, Collection<ReceiveCommand> cmds) {
58 cmds = ReceiveCommand.filter(cmds, NOT_ATTEMPTED);
59 if (cmds.isEmpty()) {
60 return;
61 }
62
63 try {
64 Proposal proposal = new Proposal(rp.getRevWalk(), cmds)
65 .setPushCertificate(rp.getPushCertificate())
66 .setAuthor(rp.getRefLogIdent())
67 .setMessage("push");
68 leader.queueProposal(proposal);
69 if (proposal.isDone()) {
70
71 return;
72 }
73
74 ProgressSpinner spinner = new ProgressSpinner(
75 rp.getMessageOutputStream());
76 if (proposal.getState() == QUEUED) {
77 waitForQueue(proposal, spinner);
78 }
79 if (!proposal.isDone()) {
80 waitForPropose(proposal, spinner);
81 }
82 } catch (IOException | InterruptedException e) {
83 String msg = JGitText.get().transactionAborted;
84 for (ReceiveCommand cmd : cmds) {
85 if (cmd.getResult() == NOT_ATTEMPTED) {
86 cmd.setResult(REJECTED_OTHER_REASON, msg);
87 }
88 }
89 log.error(msg, e);
90 }
91 }
92
93 private void waitForQueue(Proposal proposal, ProgressSpinner spinner)
94 throws InterruptedException {
95 spinner.beginTask(KetchText.get().waitingForQueue, 1, SECONDS);
96 while (!proposal.awaitStateChange(QUEUED, 250, MILLISECONDS)) {
97 spinner.update();
98 }
99 switch (proposal.getState()) {
100 case RUNNING:
101 default:
102 spinner.endTask(KetchText.get().starting);
103 break;
104
105 case EXECUTED:
106 spinner.endTask(KetchText.get().accepted);
107 break;
108
109 case ABORTED:
110 spinner.endTask(KetchText.get().failed);
111 break;
112 }
113 }
114
115 private void waitForPropose(Proposal proposal, ProgressSpinner spinner)
116 throws InterruptedException {
117 spinner.beginTask(KetchText.get().proposingUpdates, 2, SECONDS);
118 while (!proposal.await(250, MILLISECONDS)) {
119 spinner.update();
120 }
121 spinner.endTask(proposal.getState() == EXECUTED
122 ? KetchText.get().accepted
123 : KetchText.get().failed);
124 }
125 }