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 java.io.IOException;
47 import java.io.OutputStream;
48 import java.text.MessageFormat;
49 import java.util.Collection;
50 import java.util.Collections;
51 import java.util.HashMap;
52 import java.util.Map;
53
54 import org.eclipse.jgit.errors.MissingObjectException;
55 import org.eclipse.jgit.errors.NotSupportedException;
56 import org.eclipse.jgit.errors.TransportException;
57 import org.eclipse.jgit.internal.JGitText;
58 import org.eclipse.jgit.lib.ObjectId;
59 import org.eclipse.jgit.lib.ProgressMonitor;
60 import org.eclipse.jgit.lib.Ref;
61 import org.eclipse.jgit.revwalk.RevCommit;
62 import org.eclipse.jgit.revwalk.RevObject;
63 import org.eclipse.jgit.revwalk.RevWalk;
64 import org.eclipse.jgit.transport.RemoteRefUpdate.Status;
65
66
67
68
69
70
71 class PushProcess {
72
73 static final String PROGRESS_OPENING_CONNECTION = JGitText.get().openingConnection;
74
75
76 private final Transport transport;
77
78
79 private PushConnection connection;
80
81
82 private final Map<String, RemoteRefUpdate> toPush;
83
84
85 private final RevWalk walker;
86
87
88 private final OutputStream out;
89
90
91
92
93
94
95
96
97
98
99
100
101 PushProcess(final Transport transport,
102 final Collection<RemoteRefUpdate> toPush) throws TransportException {
103 this(transport, toPush, null);
104 }
105
106
107
108
109
110
111
112
113
114
115
116
117
118 PushProcess(final Transport transport,
119 final Collection<RemoteRefUpdate> toPush, OutputStream out)
120 throws TransportException {
121 this.walker = new RevWalk(transport.local);
122 this.transport = transport;
123 this.toPush = new HashMap<String, RemoteRefUpdate>();
124 this.out = out;
125 for (final RemoteRefUpdate rru : toPush) {
126 if (this.toPush.put(rru.getRemoteName(), rru) != null)
127 throw new TransportException(MessageFormat.format(
128 JGitText.get().duplicateRemoteRefUpdateIsIllegal, rru.getRemoteName()));
129 }
130 }
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148 PushResult execute(final ProgressMonitor monitor)
149 throws NotSupportedException, TransportException {
150 try {
151 monitor.beginTask(PROGRESS_OPENING_CONNECTION,
152 ProgressMonitor.UNKNOWN);
153
154 final PushResult res = new PushResult();
155 connection = transport.openPush();
156 try {
157 res.setAdvertisedRefs(transport.getURI(), connection
158 .getRefsMap());
159 res.peerUserAgent = connection.getPeerUserAgent();
160 res.setRemoteUpdates(toPush);
161 monitor.endTask();
162
163 final Map<String, RemoteRefUpdate> preprocessed = prepareRemoteUpdates();
164 if (transport.isDryRun())
165 modifyUpdatesForDryRun();
166 else if (!preprocessed.isEmpty())
167 connection.push(monitor, preprocessed, out);
168 } finally {
169 connection.close();
170 res.addMessages(connection.getMessages());
171 }
172 if (!transport.isDryRun())
173 updateTrackingRefs();
174 for (final RemoteRefUpdate rru : toPush.values()) {
175 final TrackingRefUpdate tru = rru.getTrackingRefUpdate();
176 if (tru != null)
177 res.add(tru);
178 }
179 return res;
180 } finally {
181 walker.close();
182 }
183 }
184
185 private Map<String, RemoteRefUpdate> prepareRemoteUpdates()
186 throws TransportException {
187 boolean atomic = transport.isPushAtomic();
188 final Map<String, RemoteRefUpdate> result = new HashMap<String, RemoteRefUpdate>();
189 for (final RemoteRefUpdate rru : toPush.values()) {
190 final Ref advertisedRef = connection.getRef(rru.getRemoteName());
191 ObjectId advertisedOld = null;
192 if (advertisedRef != null) {
193 advertisedOld = advertisedRef.getObjectId();
194 }
195 if (advertisedOld == null) {
196 advertisedOld = ObjectId.zeroId();
197 }
198
199 if (rru.getNewObjectId().equals(advertisedOld)) {
200 if (rru.isDelete()) {
201
202 rru.setStatus(Status.NON_EXISTING);
203 } else {
204
205 rru.setStatus(Status.UP_TO_DATE);
206 }
207 continue;
208 }
209
210
211
212 if (rru.isExpectingOldObjectId()
213 && !rru.getExpectedOldObjectId().equals(advertisedOld)) {
214 rru.setStatus(Status.REJECTED_REMOTE_CHANGED);
215 if (atomic) {
216 return rejectAll();
217 }
218 continue;
219 }
220 if (!rru.isExpectingOldObjectId()) {
221 rru.setExpectedOldObjectId(advertisedOld);
222 }
223
224
225
226 if (advertisedOld.equals(ObjectId.zeroId()) || rru.isDelete()) {
227 rru.setFastForward(true);
228 result.put(rru.getRemoteName(), rru);
229 continue;
230 }
231
232
233
234
235
236 boolean fastForward = true;
237 try {
238 RevObject oldRev = walker.parseAny(advertisedOld);
239 final RevObject newRev = walker.parseAny(rru.getNewObjectId());
240 if (!(oldRev instanceof RevCommit)
241 || !(newRev instanceof RevCommit)
242 || !walker.isMergedInto((RevCommit) oldRev,
243 (RevCommit) newRev))
244 fastForward = false;
245 } catch (MissingObjectException x) {
246 fastForward = false;
247 } catch (Exception x) {
248 throw new TransportException(transport.getURI(), MessageFormat.format(
249 JGitText.get().readingObjectsFromLocalRepositoryFailed, x.getMessage()), x);
250 }
251 rru.setFastForward(fastForward);
252 if (!fastForward && !rru.isForceUpdate()) {
253 rru.setStatus(Status.REJECTED_NONFASTFORWARD);
254 if (atomic) {
255 return rejectAll();
256 }
257 } else {
258 result.put(rru.getRemoteName(), rru);
259 }
260 }
261 return result;
262 }
263
264 private Map<String, RemoteRefUpdate> rejectAll() {
265 for (RemoteRefUpdate rru : toPush.values()) {
266 if (rru.getStatus() == Status.NOT_ATTEMPTED) {
267 rru.setStatus(RemoteRefUpdate.Status.REJECTED_OTHER_REASON);
268 rru.setMessage(JGitText.get().transactionAborted);
269 }
270 }
271 return Collections.emptyMap();
272 }
273
274 private void modifyUpdatesForDryRun() {
275 for (final RemoteRefUpdate rru : toPush.values())
276 if (rru.getStatus() == Status.NOT_ATTEMPTED)
277 rru.setStatus(Status.OK);
278 }
279
280 private void updateTrackingRefs() {
281 for (final RemoteRefUpdate rru : toPush.values()) {
282 final Status status = rru.getStatus();
283 if (rru.hasTrackingRefUpdate()
284 && (status == Status.UP_TO_DATE || status == Status.OK)) {
285
286
287
288
289 try {
290 rru.updateTrackingRef(walker);
291 } catch (IOException e) {
292
293 }
294 }
295 }
296 }
297 }