1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 package org.eclipse.jgit.transport;
16
17 import java.io.BufferedInputStream;
18 import java.io.BufferedOutputStream;
19 import java.io.File;
20 import java.io.IOException;
21 import java.io.InputStream;
22 import java.io.OutputStream;
23 import java.util.Collection;
24 import java.util.Collections;
25 import java.util.Map;
26 import java.util.Set;
27
28 import org.eclipse.jgit.errors.NoRemoteRepositoryException;
29 import org.eclipse.jgit.errors.NotSupportedException;
30 import org.eclipse.jgit.errors.TransportException;
31 import org.eclipse.jgit.internal.JGitText;
32 import org.eclipse.jgit.lib.Repository;
33 import org.eclipse.jgit.lib.RepositoryBuilder;
34 import org.eclipse.jgit.lib.RepositoryCache;
35 import org.eclipse.jgit.transport.resolver.ReceivePackFactory;
36 import org.eclipse.jgit.transport.resolver.UploadPackFactory;
37 import org.eclipse.jgit.util.FS;
38 import org.eclipse.jgit.util.io.MessageWriter;
39 import org.eclipse.jgit.util.io.StreamCopyThread;
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64 class TransportLocal extends Transport implements PackTransport {
65 static final TransportProtocol PROTO_LOCAL = new TransportProtocol() {
66 @Override
67 public String getName() {
68 return JGitText.get().transportProtoLocal;
69 }
70
71 @Override
72 public Set<String> getSchemes() {
73 return Collections.singleton("file");
74 }
75
76 @Override
77 public boolean canHandle(URIish uri, Repository local, String remoteName) {
78 if (uri.getPath() == null
79 || uri.getPort() > 0
80 || uri.getUser() != null
81 || uri.getPass() != null
82 || uri.getHost() != null
83 || (uri.getScheme() != null && !getSchemes().contains(uri.getScheme())))
84 return false;
85 return true;
86 }
87
88 @Override
89 public Transport open(URIish uri, Repository local, String remoteName)
90 throws NoRemoteRepositoryException {
91 File localPath = local.isBare() ? local.getDirectory() : local.getWorkTree();
92 File path = local.getFS().resolve(localPath, uri.getPath());
93
94
95 if (path.isFile())
96 return new TransportBundleFile(local, uri, path);
97
98 File gitDir = RepositoryCache.FileKey.resolve(path, local.getFS());
99 if (gitDir == null)
100 throw new NoRemoteRepositoryException(uri, JGitText.get().notFound);
101 return new TransportLocal(local, uri, gitDir);
102 }
103
104 @Override
105 public Transport open(URIish uri) throws NotSupportedException,
106 TransportException {
107 File path = FS.DETECTED.resolve(new File("."), uri.getPath());
108
109
110 if (path.isFile())
111 return new TransportBundleFile(uri, path);
112
113 File gitDir = RepositoryCache.FileKey.resolve(path, FS.DETECTED);
114 if (gitDir == null)
115 throw new NoRemoteRepositoryException(uri,
116 JGitText.get().notFound);
117 return new TransportLocal(uri, gitDir);
118 }
119 };
120
121 private final File remoteGitDir;
122
123 TransportLocal(Repository local, URIish uri, File gitDir) {
124 super(local, uri);
125 remoteGitDir = gitDir;
126 }
127
128 TransportLocal(URIish uri, File gitDir) {
129 super(uri);
130 remoteGitDir = gitDir;
131 }
132
133 UploadPack createUploadPack(Repository dst) {
134 return new UploadPack(dst);
135 }
136
137 ReceivePack createReceivePack(Repository dst) {
138 return new ReceivePack(dst);
139 }
140
141 private Repository openRepo() throws TransportException {
142 try {
143 return new RepositoryBuilder()
144 .setFS(local != null ? local.getFS() : FS.DETECTED)
145 .setGitDir(remoteGitDir).build();
146 } catch (IOException err) {
147 TransportException te = new TransportException(uri,
148 JGitText.get().notAGitDirectory);
149 te.initCause(err);
150 throw te;
151 }
152 }
153
154
155 @Override
156 public FetchConnection openFetch() throws TransportException {
157 return openFetch(Collections.emptyList());
158 }
159
160 @Override
161 public FetchConnection openFetch(Collection<RefSpec> refSpecs,
162 String... additionalPatterns) throws TransportException {
163 final String up = getOptionUploadPack();
164 if (!"git-upload-pack".equals(up)
165 && !"git upload-pack".equals(up)) {
166 return new ForkLocalFetchConnection(refSpecs, additionalPatterns);
167 }
168 UploadPackFactory<Void> upf = (Void req,
169 Repository db) -> createUploadPack(db);
170 return new InternalFetchConnection<>(this, upf, null, openRepo());
171 }
172
173
174 @Override
175 public PushConnection openPush() throws TransportException {
176 final String rp = getOptionReceivePack();
177 if (!"git-receive-pack".equals(rp)
178 && !"git receive-pack".equals(rp))
179 return new ForkLocalPushConnection();
180
181 ReceivePackFactory<Void> rpf = (Void req,
182 Repository db) -> createReceivePack(db);
183 return new InternalPushConnection<>(this, rpf, null, openRepo());
184 }
185
186
187 @Override
188 public void close() {
189
190 }
191
192
193
194
195
196
197
198
199
200
201 protected Process spawn(String cmd)
202 throws TransportException {
203 return spawn(cmd, null);
204 }
205
206
207
208
209
210
211
212
213
214
215
216
217 private Process spawn(String cmd,
218 TransferConfig.ProtocolVersion protocolVersion)
219 throws TransportException {
220 try {
221 String[] args = { "." };
222 ProcessBuilder proc = local.getFS().runInShell(cmd, args);
223 proc.directory(remoteGitDir);
224
225
226 Map<String, String> env = proc.environment();
227 env.remove("GIT_ALTERNATE_OBJECT_DIRECTORIES");
228 env.remove("GIT_CONFIG");
229 env.remove("GIT_CONFIG_PARAMETERS");
230 env.remove("GIT_DIR");
231 env.remove("GIT_WORK_TREE");
232 env.remove("GIT_GRAFT_FILE");
233 env.remove("GIT_INDEX_FILE");
234 env.remove("GIT_NO_REPLACE_OBJECTS");
235 if (TransferConfig.ProtocolVersion.V2.equals(protocolVersion)) {
236 env.put(GitProtocolConstants.PROTOCOL_ENVIRONMENT_VARIABLE,
237 GitProtocolConstants.VERSION_2_REQUEST);
238 }
239 return proc.start();
240 } catch (IOException err) {
241 throw new TransportException(uri, err.getMessage(), err);
242 }
243 }
244
245 class ForkLocalFetchConnection extends BasePackFetchConnection {
246 private Process uploadPack;
247
248 private Thread errorReaderThread;
249
250 ForkLocalFetchConnection() throws TransportException {
251 this(Collections.emptyList());
252 }
253
254 ForkLocalFetchConnection(Collection<RefSpec> refSpecs,
255 String... additionalPatterns) throws TransportException {
256 super(TransportLocal.this);
257
258 final MessageWriter msg = new MessageWriter();
259 setMessageWriter(msg);
260
261 TransferConfig.ProtocolVersion gitProtocol = protocol;
262 if (gitProtocol == null) {
263 gitProtocol = TransferConfig.ProtocolVersion.V2;
264 }
265 uploadPack = spawn(getOptionUploadPack(), gitProtocol);
266
267 final InputStream upErr = uploadPack.getErrorStream();
268 errorReaderThread = new StreamCopyThread(upErr, msg.getRawStream());
269 errorReaderThread.start();
270
271 InputStream upIn = uploadPack.getInputStream();
272 OutputStream upOut = uploadPack.getOutputStream();
273
274 upIn = new BufferedInputStream(upIn);
275 upOut = new BufferedOutputStream(upOut);
276
277 init(upIn, upOut);
278 if (!readAdvertisedRefs()) {
279 lsRefs(refSpecs, additionalPatterns);
280 }
281 }
282
283 @Override
284 public void close() {
285 super.close();
286
287 if (uploadPack != null) {
288 try {
289 uploadPack.waitFor();
290 } catch (InterruptedException ie) {
291
292 } finally {
293 uploadPack = null;
294 }
295 }
296
297 if (errorReaderThread != null) {
298 try {
299 errorReaderThread.join();
300 } catch (InterruptedException e) {
301
302 } finally {
303 errorReaderThread = null;
304 }
305 }
306 }
307 }
308
309 class ForkLocalPushConnection extends BasePackPushConnection {
310 private Process receivePack;
311
312 private Thread errorReaderThread;
313
314 ForkLocalPushConnection() throws TransportException {
315 super(TransportLocal.this);
316
317 final MessageWriter msg = new MessageWriter();
318 setMessageWriter(msg);
319
320 receivePack = spawn(getOptionReceivePack());
321
322 final InputStream rpErr = receivePack.getErrorStream();
323 errorReaderThread = new StreamCopyThread(rpErr, msg.getRawStream());
324 errorReaderThread.start();
325
326 InputStream rpIn = receivePack.getInputStream();
327 OutputStream rpOut = receivePack.getOutputStream();
328
329 rpIn = new BufferedInputStream(rpIn);
330 rpOut = new BufferedOutputStream(rpOut);
331
332 init(rpIn, rpOut);
333 readAdvertisedRefs();
334 }
335
336 @Override
337 public void close() {
338 super.close();
339
340 if (receivePack != null) {
341 try {
342 receivePack.waitFor();
343 } catch (InterruptedException ie) {
344
345 } finally {
346 receivePack = null;
347 }
348 }
349
350 if (errorReaderThread != null) {
351 try {
352 errorReaderThread.join();
353 } catch (InterruptedException e) {
354
355 } finally {
356 errorReaderThread = null;
357 }
358 }
359 }
360 }
361 }