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