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.GitProtocolConstants.CAPABILITY_ATOMIC;
47 import static org.eclipse.jgit.transport.GitProtocolConstants.CAPABILITY_PUSH_OPTIONS;
48 import static org.eclipse.jgit.transport.GitProtocolConstants.CAPABILITY_REPORT_STATUS;
49
50 import java.io.IOException;
51 import java.io.InputStream;
52 import java.io.OutputStream;
53 import java.util.ArrayList;
54 import java.util.Collections;
55 import java.util.List;
56
57 import org.eclipse.jgit.annotations.Nullable;
58 import org.eclipse.jgit.errors.UnpackException;
59 import org.eclipse.jgit.lib.ConfigConstants;
60 import org.eclipse.jgit.lib.Constants;
61 import org.eclipse.jgit.lib.NullProgressMonitor;
62 import org.eclipse.jgit.lib.Repository;
63 import org.eclipse.jgit.transport.ReceiveCommand.Result;
64 import org.eclipse.jgit.transport.RefAdvertiser.PacketLineOutRefAdvertiser;
65
66
67
68
69 public class ReceivePack extends BaseReceivePack {
70
71 private PreReceiveHook preReceive;
72
73
74 private PostReceiveHook postReceive;
75
76
77 private boolean reportStatus;
78
79 private boolean echoCommandFailures;
80
81
82 private boolean usePushOptions;
83 private List<String> pushOptions;
84
85
86
87
88
89
90
91 public ReceivePack(final Repository into) {
92 super(into);
93 preReceive = PreReceiveHook.NULL;
94 postReceive = PostReceiveHook.NULL;
95 }
96
97
98
99
100
101
102
103 @Nullable
104 public List<String> getPushOptions() {
105 if (isAllowPushOptions() && usePushOptions) {
106 return Collections.unmodifiableList(pushOptions);
107 }
108
109
110
111
112 return null;
113 }
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128 public void setPushOptions(@Nullable List<String> options) {
129 usePushOptions = options != null;
130 pushOptions = options;
131 }
132
133
134 public PreReceiveHook getPreReceiveHook() {
135 return preReceive;
136 }
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152 public void setPreReceiveHook(final PreReceiveHook h) {
153 preReceive = h != null ? h : PreReceiveHook.NULL;
154 }
155
156
157 public PostReceiveHook getPostReceiveHook() {
158 return postReceive;
159 }
160
161
162
163
164
165
166
167
168
169
170
171 public void setPostReceiveHook(final PostReceiveHook h) {
172 postReceive = h != null ? h : PostReceiveHook.NULL;
173 }
174
175
176
177
178
179
180
181
182 public void setEchoCommandFailures(boolean echo) {
183 echoCommandFailures = echo;
184 }
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204 public void receive(final InputStream input, final OutputStream output,
205 final OutputStream messages) throws IOException {
206 init(input, output, messages);
207 try {
208 service();
209 } finally {
210 try {
211 close();
212 } finally {
213 release();
214 }
215 }
216 }
217
218 @Override
219 protected void enableCapabilities() {
220 reportStatus = isCapabilityEnabled(CAPABILITY_REPORT_STATUS);
221 usePushOptions = isCapabilityEnabled(CAPABILITY_PUSH_OPTIONS);
222 super.enableCapabilities();
223 }
224
225 @Override
226 void readPostCommands(PacketLineIn in) throws IOException {
227 if (usePushOptions) {
228 pushOptions = new ArrayList<>(4);
229 for (;;) {
230 String option = in.readString();
231 if (option == PacketLineIn.END) {
232 break;
233 }
234 pushOptions.add(option);
235 }
236 }
237 }
238
239 private void service() throws IOException {
240 if (isBiDirectionalPipe()) {
241 sendAdvertisedRefs(new PacketLineOutRefAdvertiser(pckOut));
242 pckOut.flush();
243 } else
244 getAdvertisedOrDefaultRefs();
245 if (hasError())
246 return;
247 recvCommands();
248 if (hasCommands()) {
249 Throwable unpackError = null;
250 if (needPack()) {
251 try {
252 receivePackAndCheckConnectivity();
253 } catch (IOException | RuntimeException | Error err) {
254 unpackError = err;
255 }
256 }
257
258 if (unpackError == null) {
259 boolean atomic = isCapabilityEnabled(CAPABILITY_ATOMIC);
260 setAtomic(atomic);
261
262 validateCommands();
263 if (atomic && anyRejects())
264 failPendingCommands();
265
266 preReceive.onPreReceive(this, filterCommands(Result.NOT_ATTEMPTED));
267 if (atomic && anyRejects())
268 failPendingCommands();
269 executeCommands();
270 }
271 unlockPack();
272
273 if (reportStatus) {
274 if (echoCommandFailures && msgOut != null) {
275 sendStatusReport(false, unpackError, new Reporter() {
276 @Override
277 void sendString(final String s) throws IOException {
278 msgOut.write(Constants.encode(s + "\n"));
279 }
280 });
281 msgOut.flush();
282 try {
283 Thread.sleep(500);
284 } catch (InterruptedException wakeUp) {
285
286 }
287 }
288 sendStatusReport(true, unpackError, new Reporter() {
289 @Override
290 void sendString(final String s) throws IOException {
291 pckOut.writeString(s + "\n");
292 }
293 });
294 pckOut.end();
295 } else if (msgOut != null) {
296 sendStatusReport(false, unpackError, new Reporter() {
297 @Override
298 void sendString(final String s) throws IOException {
299 msgOut.write(Constants.encode(s + "\n"));
300 }
301 });
302 }
303
304 if (unpackError != null) {
305
306
307 try {
308 postReceive.onPostReceive(this, filterCommands(Result.OK));
309 } catch (Throwable e) {
310
311 }
312 throw new UnpackException(unpackError);
313 }
314 postReceive.onPostReceive(this, filterCommands(Result.OK));
315 autoGc();
316 }
317 }
318
319 private void autoGc() {
320 Repository repo = getRepository();
321 if (!repo.getConfig().getBoolean(ConfigConstants.CONFIG_RECEIVE_SECTION,
322 ConfigConstants.CONFIG_KEY_AUTOGC, true)) {
323 return;
324 }
325 repo.autoGC(NullProgressMonitor.INSTANCE);
326 }
327
328 @Override
329 protected String getLockMessageProcessName() {
330 return "jgit receive-pack";
331 }
332 }