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(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
135
136
137
138 public PreReceiveHook getPreReceiveHook() {
139 return preReceive;
140 }
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157 public void setPreReceiveHook(PreReceiveHook h) {
158 preReceive = h != null ? h : PreReceiveHook.NULL;
159 }
160
161
162
163
164
165
166 public PostReceiveHook getPostReceiveHook() {
167 return postReceive;
168 }
169
170
171
172
173
174
175
176
177
178
179
180
181 public void setPostReceiveHook(PostReceiveHook h) {
182 postReceive = h != null ? h : PostReceiveHook.NULL;
183 }
184
185
186
187
188
189
190
191
192
193
194
195 public void setEchoCommandFailures(boolean echo) {
196 echoCommandFailures = echo;
197 }
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217 public void receive(final InputStream input, final OutputStream output,
218 final OutputStream messages) throws IOException {
219 init(input, output, messages);
220 try {
221 service();
222 } finally {
223 try {
224 close();
225 } finally {
226 release();
227 }
228 }
229 }
230
231
232 @Override
233 protected void enableCapabilities() {
234 reportStatus = isCapabilityEnabled(CAPABILITY_REPORT_STATUS);
235 usePushOptions = isCapabilityEnabled(CAPABILITY_PUSH_OPTIONS);
236 super.enableCapabilities();
237 }
238
239 @Override
240 void readPostCommands(PacketLineIn in) throws IOException {
241 if (usePushOptions) {
242 pushOptions = new ArrayList<>(4);
243 for (;;) {
244 String option = in.readString();
245 if (option == PacketLineIn.END) {
246 break;
247 }
248 pushOptions.add(option);
249 }
250 }
251 }
252
253 private void service() throws IOException {
254 if (isBiDirectionalPipe()) {
255 sendAdvertisedRefs(new PacketLineOutRefAdvertiser(pckOut));
256 pckOut.flush();
257 } else
258 getAdvertisedOrDefaultRefs();
259 if (hasError())
260 return;
261 recvCommands();
262 if (hasCommands()) {
263 Throwable unpackError = null;
264 if (needPack()) {
265 try {
266 receivePackAndCheckConnectivity();
267 } catch (IOException | RuntimeException | Error err) {
268 unpackError = err;
269 }
270 }
271
272 if (unpackError == null) {
273 boolean atomic = isCapabilityEnabled(CAPABILITY_ATOMIC);
274 setAtomic(atomic);
275
276 validateCommands();
277 if (atomic && anyRejects())
278 failPendingCommands();
279
280 preReceive.onPreReceive(this, filterCommands(Result.NOT_ATTEMPTED));
281 if (atomic && anyRejects())
282 failPendingCommands();
283 executeCommands();
284 }
285 unlockPack();
286
287 if (reportStatus) {
288 if (echoCommandFailures && msgOut != null) {
289 sendStatusReport(false, unpackError, new Reporter() {
290 @Override
291 void sendString(String s) throws IOException {
292 msgOut.write(Constants.encode(s + "\n"));
293 }
294 });
295 msgOut.flush();
296 try {
297 Thread.sleep(500);
298 } catch (InterruptedException wakeUp) {
299
300 }
301 }
302 sendStatusReport(true, unpackError, new Reporter() {
303 @Override
304 void sendString(String s) throws IOException {
305 pckOut.writeString(s + "\n");
306 }
307 });
308 pckOut.end();
309 } else if (msgOut != null) {
310 sendStatusReport(false, unpackError, new Reporter() {
311 @Override
312 void sendString(String s) throws IOException {
313 msgOut.write(Constants.encode(s + "\n"));
314 }
315 });
316 }
317
318 if (unpackError != null) {
319
320
321 try {
322 postReceive.onPostReceive(this, filterCommands(Result.OK));
323 } catch (Throwable e) {
324
325 }
326 throw new UnpackException(unpackError);
327 }
328 postReceive.onPostReceive(this, filterCommands(Result.OK));
329 autoGc();
330 }
331 }
332
333 private void autoGc() {
334 Repository repo = getRepository();
335 if (!repo.getConfig().getBoolean(ConfigConstants.CONFIG_RECEIVE_SECTION,
336 ConfigConstants.CONFIG_KEY_AUTOGC, true)) {
337 return;
338 }
339 repo.autoGC(NullProgressMonitor.INSTANCE);
340 }
341
342
343 @Override
344 protected String getLockMessageProcessName() {
345 return "jgit receive-pack";
346 }
347 }