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