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.lib.Constants.HEAD;
47 import static org.eclipse.jgit.transport.GitProtocolConstants.CAPABILITY_ATOMIC;
48 import static org.eclipse.jgit.transport.GitProtocolConstants.CAPABILITY_PUSH_OPTIONS;
49 import static org.eclipse.jgit.transport.GitProtocolConstants.CAPABILITY_REPORT_STATUS;
50
51 import java.io.IOException;
52 import java.io.InputStream;
53 import java.io.OutputStream;
54 import java.util.ArrayList;
55 import java.util.Collections;
56 import java.util.List;
57 import java.util.Map;
58 import java.util.Set;
59
60 import org.eclipse.jgit.annotations.Nullable;
61 import org.eclipse.jgit.errors.UnpackException;
62 import org.eclipse.jgit.lib.ConfigConstants;
63 import org.eclipse.jgit.lib.Constants;
64 import org.eclipse.jgit.lib.NullProgressMonitor;
65 import org.eclipse.jgit.lib.ObjectId;
66 import org.eclipse.jgit.lib.Ref;
67 import org.eclipse.jgit.lib.Repository;
68 import org.eclipse.jgit.revwalk.RevWalk;
69 import org.eclipse.jgit.transport.ReceiveCommand.Result;
70 import org.eclipse.jgit.transport.RefAdvertiser.PacketLineOutRefAdvertiser;
71
72
73
74
75 public class ReceivePack extends BaseReceivePack {
76
77 private PreReceiveHook preReceive;
78
79
80 private PostReceiveHook postReceive;
81
82
83 private boolean reportStatus;
84
85
86 private boolean usePushOptions;
87 private List<String> pushOptions;
88
89
90
91
92
93
94
95 public ReceivePack(Repository into) {
96 super(into);
97 preReceive = PreReceiveHook.NULL;
98 postReceive = PostReceiveHook.NULL;
99 }
100
101
102
103
104
105
106 @Override
107 public final Repository getRepository() {
108 return db;
109 }
110
111
112
113
114
115
116 @Override
117 public final RevWalk getRevWalk() {
118 return walk;
119 }
120
121
122
123
124
125
126
127 @Override
128 public final Map<String, Ref> getAdvertisedRefs() {
129 return refs;
130 }
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149 @Override
150 public void setAdvertisedRefs(Map<String, Ref> allRefs, Set<ObjectId> additionalHaves) {
151 refs = allRefs != null ? allRefs : db.getAllRefs();
152 refs = refFilter.filter(refs);
153 advertisedHaves.clear();
154
155 Ref head = refs.get(HEAD);
156 if (head != null && head.isSymbolic()) {
157 refs.remove(HEAD);
158 }
159
160 for (Ref ref : refs.values()) {
161 if (ref.getObjectId() != null) {
162 advertisedHaves.add(ref.getObjectId());
163 }
164 }
165 if (additionalHaves != null) {
166 advertisedHaves.addAll(additionalHaves);
167 } else {
168 advertisedHaves.addAll(db.getAdditionalHaves());
169 }
170 }
171
172
173
174
175
176
177
178
179
180
181 @Override
182 public PushCertificate getPushCertificate() {
183 return pushCert;
184 }
185
186
187
188
189
190
191
192
193
194
195
196 @Override
197 public void setPushCertificate(PushCertificate cert) {
198 pushCert = cert;
199 }
200
201
202
203
204
205
206
207 @Nullable
208 public List<String> getPushOptions() {
209 if (isAllowPushOptions() && usePushOptions) {
210 return Collections.unmodifiableList(pushOptions);
211 }
212
213
214
215
216 return null;
217 }
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232 public void setPushOptions(@Nullable List<String> options) {
233 usePushOptions = options != null;
234 pushOptions = options;
235 }
236
237
238
239
240
241
242 public PreReceiveHook getPreReceiveHook() {
243 return preReceive;
244 }
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261 public void setPreReceiveHook(PreReceiveHook h) {
262 preReceive = h != null ? h : PreReceiveHook.NULL;
263 }
264
265
266
267
268
269
270 public PostReceiveHook getPostReceiveHook() {
271 return postReceive;
272 }
273
274
275
276
277
278
279
280
281
282
283
284
285 public void setPostReceiveHook(PostReceiveHook h) {
286 postReceive = h != null ? h : PostReceiveHook.NULL;
287 }
288
289
290
291
292
293
294
295
296
297
298
299
300 @Deprecated
301 public void setEchoCommandFailures(boolean echo) {
302
303 }
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323 public void receive(final InputStream input, final OutputStream output,
324 final OutputStream messages) throws IOException {
325 init(input, output, messages);
326 try {
327 service();
328 } finally {
329 try {
330 close();
331 } finally {
332 release();
333 }
334 }
335 }
336
337
338 @Override
339 protected void enableCapabilities() {
340 reportStatus = isCapabilityEnabled(CAPABILITY_REPORT_STATUS);
341 usePushOptions = isCapabilityEnabled(CAPABILITY_PUSH_OPTIONS);
342 super.enableCapabilities();
343 }
344
345 @Override
346 void readPostCommands(PacketLineIn in) throws IOException {
347 if (usePushOptions) {
348 pushOptions = new ArrayList<>(4);
349 for (;;) {
350 String option = in.readString();
351 if (option == PacketLineIn.END) {
352 break;
353 }
354 pushOptions.add(option);
355 }
356 }
357 }
358
359 private void service() throws IOException {
360 if (isBiDirectionalPipe()) {
361 sendAdvertisedRefs(new PacketLineOutRefAdvertiser(pckOut));
362 pckOut.flush();
363 } else
364 getAdvertisedOrDefaultRefs();
365 if (hasError())
366 return;
367 recvCommands();
368 if (hasCommands()) {
369 Throwable unpackError = null;
370 if (needPack()) {
371 try {
372 receivePackAndCheckConnectivity();
373 } catch (IOException | RuntimeException | Error err) {
374 unpackError = err;
375 }
376 }
377
378 try {
379 if (unpackError == null) {
380 boolean atomic = isCapabilityEnabled(CAPABILITY_ATOMIC);
381 setAtomic(atomic);
382
383 validateCommands();
384 if (atomic && anyRejects()) {
385 failPendingCommands();
386 }
387
388 preReceive.onPreReceive(
389 this, filterCommands(Result.NOT_ATTEMPTED));
390 if (atomic && anyRejects()) {
391 failPendingCommands();
392 }
393 executeCommands();
394 }
395 } finally {
396 unlockPack();
397 }
398
399 if (reportStatus) {
400 sendStatusReport(true, unpackError, new Reporter() {
401 @Override
402 void sendString(String s) throws IOException {
403 pckOut.writeString(s + "\n");
404 }
405 });
406 pckOut.end();
407 } else if (msgOut != null) {
408 sendStatusReport(false, unpackError, new Reporter() {
409 @Override
410 void sendString(String s) throws IOException {
411 msgOut.write(Constants.encode(s + "\n"));
412 }
413 });
414 }
415
416 if (unpackError != null) {
417
418
419 try {
420 postReceive.onPostReceive(this, filterCommands(Result.OK));
421 } catch (Throwable e) {
422
423 }
424 throw new UnpackException(unpackError);
425 }
426 postReceive.onPostReceive(this, filterCommands(Result.OK));
427 autoGc();
428 }
429 }
430
431 private void autoGc() {
432 Repository repo = getRepository();
433 if (!repo.getConfig().getBoolean(ConfigConstants.CONFIG_RECEIVE_SECTION,
434 ConfigConstants.CONFIG_KEY_AUTOGC, true)) {
435 return;
436 }
437 repo.autoGC(NullProgressMonitor.INSTANCE);
438 }
439
440
441 @Override
442 protected String getLockMessageProcessName() {
443 return "jgit receive-pack";
444 }
445 }