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