@Test
public void testFilterHidesPrivate() throws Exception {
Map<String, Ref> refs;
- TransportLocal t = new TransportLocal(src, uriOf(dst)) {
+ TransportLocal t = new TransportLocal(src, uriOf(dst), dst.getDirectory()) {
@Override
ReceivePack createReceivePack(final Repository db) {
db.close();
// Push this new content to the remote, doing strict validation.
//
- TransportLocal t = new TransportLocal(src, uriOf(dst)) {
+ TransportLocal t = new TransportLocal(src, uriOf(dst), dst.getDirectory()) {
@Override
ReceivePack createReceivePack(final Repository db) {
db.close();
public void testMissingPort() throws URISyntaxException {
final String incorrectSshUrl = "ssh://some-host:/path/to/repository.git";
URIish u = new URIish(incorrectSshUrl);
- assertFalse(TransportGitSsh.canHandle(u));
+ assertFalse(TransportGitSsh.PROTO_SSH.canHandle(null, u, null));
}
}
transportExceptionInvalid=Invalid {0} {1}:{2}
transportExceptionMissingAssumed=Missing assumed {0}
transportExceptionReadRef=read {0}
+transportProtoAmazonS3=Amazon S3
+transportProtoBundleFile=Git Bundle File
+transportProtoGitAnon=Anonymous Git
+transportProtoFTP=FTP
+transportProtoHTTP=HTTP
+transportProtoLocal=Local Git Repository
+transportProtoSFTP=SFTP
+transportProtoSSH=SSH
treeEntryAlreadyExists=Tree entry "{0}" already exists.
treeIteratorDoesNotSupportRemove=TreeIterator does not support remove()
truncatedHunkLinesMissingForAncestor=Truncated hunk, at least {0} lines missing for ancestor {1}
/***/ public String transportExceptionInvalid;
/***/ public String transportExceptionMissingAssumed;
/***/ public String transportExceptionReadRef;
+ /***/ public String transportProtoAmazonS3;
+ /***/ public String transportProtoBundleFile;
+ /***/ public String transportProtoFTP;
+ /***/ public String transportProtoGitAnon;
+ /***/ public String transportProtoHTTP;
+ /***/ public String transportProtoLocal;
+ /***/ public String transportProtoSFTP;
+ /***/ public String transportProtoSSH;
/***/ public String treeEntryAlreadyExists;
/***/ public String treeIteratorDoesNotSupportRemove;
/***/ public String truncatedHunkLinesMissingForAncestor;
import org.eclipse.jgit.JGitText;
import org.eclipse.jgit.api.errors.InvalidRemoteException;
import org.eclipse.jgit.api.errors.JGitInternalException;
+import org.eclipse.jgit.errors.NoRemoteRepositoryException;
import org.eclipse.jgit.errors.NotSupportedException;
import org.eclipse.jgit.errors.TransportException;
import org.eclipse.jgit.lib.Constants;
try {
Transport transport = Transport.open(repo, remote);
- transport.setCheckFetchedObjects(checkFetchedObjects);
- transport.setRemoveDeletedRefs(removeDeletedRefs);
- transport.setTimeout(timeout);
- transport.setDryRun(dryRun);
- if (tagOption != null)
- transport.setTagOpt(tagOption);
- transport.setFetchThin(thin);
- if (credentialsProvider != null)
- transport.setCredentialsProvider(credentialsProvider);
-
try {
+ transport.setCheckFetchedObjects(checkFetchedObjects);
+ transport.setRemoveDeletedRefs(removeDeletedRefs);
+ transport.setTimeout(timeout);
+ transport.setDryRun(dryRun);
+ if (tagOption != null)
+ transport.setTagOpt(tagOption);
+ transport.setFetchThin(thin);
+ if (credentialsProvider != null)
+ transport.setCredentialsProvider(credentialsProvider);
+
FetchResult result = transport.fetch(monitor, refSpecs);
return result;
-
- } catch (TransportException e) {
- throw new JGitInternalException(
- JGitText.get().exceptionCaughtDuringExecutionOfFetchCommand,
- e);
} finally {
transport.close();
}
+ } catch (NoRemoteRepositoryException e) {
+ throw new InvalidRemoteException(MessageFormat.format(
+ JGitText.get().invalidRemote, remote), e);
+ } catch (TransportException e) {
+ throw new JGitInternalException(
+ JGitText.get().exceptionCaughtDuringExecutionOfFetchCommand,
+ e);
} catch (URISyntaxException e) {
throw new InvalidRemoteException(MessageFormat.format(
JGitText.get().invalidRemote, remote));
private static final long serialVersionUID = 1L;
/**
- * @param msg
+ * @param msg message describing the invalid remote.
*/
public InvalidRemoteException(String msg) {
super(msg);
}
+
+ /**
+ * @param msg message describing the invalid remote.
+ * @param cause why the remote is invalid.
+ */
+ public InvalidRemoteException(String msg, Throwable cause) {
+ super(msg, cause);
+ }
}
package org.eclipse.jgit.transport;
import java.io.IOException;
+import java.lang.ref.WeakReference;
import java.net.URISyntaxException;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
+import java.util.concurrent.CopyOnWriteArrayList;
import org.eclipse.jgit.JGitText;
import org.eclipse.jgit.errors.NotSupportedException;
import org.eclipse.jgit.lib.Ref;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.storage.pack.PackConfig;
-import org.eclipse.jgit.util.FS;
/**
* Connects two Git repositories together and copies objects between them.
PUSH;
}
+ private static final List<WeakReference<TransportProtocol>> protocols =
+ new CopyOnWriteArrayList<WeakReference<TransportProtocol>>();
+
+ static {
+ // Registration goes backwards in order of priority.
+ register(TransportLocal.PROTO_LOCAL);
+ register(TransportBundleFile.PROTO_BUNDLE);
+ register(TransportAmazonS3.PROTO_S3);
+ register(TransportGitAnon.PROTO_GIT);
+ register(TransportSftp.PROTO_SFTP);
+ register(TransportHttp.PROTO_FTP);
+ register(TransportHttp.PROTO_HTTP);
+ register(TransportGitSsh.PROTO_SSH);
+ }
+
+ /**
+ * Register a TransportProtocol instance for use during open.
+ * <p>
+ * Protocol definitions are held by WeakReference, allowing them to be
+ * garbage collected when the calling application drops all strongly held
+ * references to the TransportProtocol. Therefore applications should use a
+ * singleton pattern as described in {@link TransportProtocol}'s class
+ * documentation to ensure their protocol does not get disabled by garbage
+ * collection earlier than expected.
+ * <p>
+ * The new protocol is registered in front of all earlier protocols, giving
+ * it higher priority than the built-in protocol definitions.
+ *
+ * @param proto
+ * the protocol definition. Must not be null.
+ */
+ public static void register(TransportProtocol proto) {
+ protocols.add(0, new WeakReference<TransportProtocol>(proto));
+ }
+
+ /**
+ * Unregister a TransportProtocol instance.
+ * <p>
+ * Unregistering a protocol usually isn't necessary, as protocols are held
+ * by weak references and will automatically clear when they are garbage
+ * collected by the JVM. Matching is handled by reference equality, so the
+ * exact reference given to {@link #register(TransportProtocol)} must be
+ * used.
+ *
+ * @param proto
+ * the exact object previously given to register.
+ */
+ public static void unregister(TransportProtocol proto) {
+ for (WeakReference<TransportProtocol> ref : protocols) {
+ TransportProtocol refProto = ref.get();
+ if (refProto == null || refProto == proto)
+ protocols.remove(ref);
+ }
+ }
+
+ /**
+ * Obtain a copy of the registered protocols.
+ *
+ * @return an immutable copy of the currently registered protocols.
+ */
+ public static List<TransportProtocol> getTransportProtocols() {
+ int cnt = protocols.size();
+ List<TransportProtocol> res = new ArrayList<TransportProtocol>(cnt);
+ for (WeakReference<TransportProtocol> ref : protocols) {
+ TransportProtocol proto = ref.get();
+ if (proto != null)
+ res.add(proto);
+ else
+ protocols.remove(ref);
+ }
+ return Collections.unmodifiableList(res);
+ }
+
/**
* Open a new transport instance to connect two repositories.
* <p>
* file and is not a well-formed URL.
* @throws NotSupportedException
* the protocol specified is not supported.
+ * @throws TransportException
+ * the transport cannot open this URI.
*/
public static Transport open(final Repository local, final String remote)
- throws NotSupportedException, URISyntaxException {
+ throws NotSupportedException, URISyntaxException,
+ TransportException {
return open(local, remote, Operation.FETCH);
}
* file and is not a well-formed URL.
* @throws NotSupportedException
* the protocol specified is not supported.
+ * @throws TransportException
+ * the transport cannot open this URI.
*/
public static Transport open(final Repository local, final String remote,
final Operation op) throws NotSupportedException,
- URISyntaxException {
+ URISyntaxException, TransportException {
final RemoteConfig cfg = new RemoteConfig(local.getConfig(), remote);
if (doesNotExist(cfg))
- return open(local, new URIish(remote));
+ return open(local, new URIish(remote), null);
return open(local, cfg, op);
}
* file and is not a well-formed URL.
* @throws NotSupportedException
* the protocol specified is not supported.
+ * @throws TransportException
+ * the transport cannot open this URI.
*/
public static List<Transport> openAll(final Repository local,
final String remote) throws NotSupportedException,
- URISyntaxException {
+ URISyntaxException, TransportException {
return openAll(local, remote, Operation.FETCH);
}
* file and is not a well-formed URL.
* @throws NotSupportedException
* the protocol specified is not supported.
+ * @throws TransportException
+ * the transport cannot open this URI.
*/
public static List<Transport> openAll(final Repository local,
final String remote, final Operation op)
- throws NotSupportedException, URISyntaxException {
+ throws NotSupportedException, URISyntaxException,
+ TransportException {
final RemoteConfig cfg = new RemoteConfig(local.getConfig(), remote);
if (doesNotExist(cfg)) {
final ArrayList<Transport> transports = new ArrayList<Transport>(1);
- transports.add(open(local, new URIish(remote)));
+ transports.add(open(local, new URIish(remote), null));
return transports;
}
return openAll(local, cfg, op);
* in remote configuration, only the first is chosen.
* @throws NotSupportedException
* the protocol specified is not supported.
+ * @throws TransportException
+ * the transport cannot open this URI.
* @throws IllegalArgumentException
* if provided remote configuration doesn't have any URI
* associated.
*/
public static Transport open(final Repository local, final RemoteConfig cfg)
- throws NotSupportedException {
+ throws NotSupportedException, TransportException {
return open(local, cfg, Operation.FETCH);
}
* in remote configuration, only the first is chosen.
* @throws NotSupportedException
* the protocol specified is not supported.
+ * @throws TransportException
+ * the transport cannot open this URI.
* @throws IllegalArgumentException
* if provided remote configuration doesn't have any URI
* associated.
*/
public static Transport open(final Repository local,
final RemoteConfig cfg, final Operation op)
- throws NotSupportedException {
+ throws NotSupportedException, TransportException {
final List<URIish> uris = getURIs(cfg, op);
if (uris.isEmpty())
throw new IllegalArgumentException(MessageFormat.format(
JGitText.get().remoteConfigHasNoURIAssociated, cfg.getName()));
- final Transport tn = open(local, uris.get(0));
+ final Transport tn = open(local, uris.get(0), cfg.getName());
tn.applyConfig(cfg);
return tn;
}
* configuration.
* @throws NotSupportedException
* the protocol specified is not supported.
+ * @throws TransportException
+ * the transport cannot open this URI.
*/
public static List<Transport> openAll(final Repository local,
- final RemoteConfig cfg) throws NotSupportedException {
+ final RemoteConfig cfg) throws NotSupportedException,
+ TransportException {
return openAll(local, cfg, Operation.FETCH);
}
* configuration.
* @throws NotSupportedException
* the protocol specified is not supported.
+ * @throws TransportException
+ * the transport cannot open this URI.
*/
public static List<Transport> openAll(final Repository local,
final RemoteConfig cfg, final Operation op)
- throws NotSupportedException {
+ throws NotSupportedException, TransportException {
final List<URIish> uris = getURIs(cfg, op);
final List<Transport> transports = new ArrayList<Transport>(uris.size());
for (final URIish uri : uris) {
- final Transport tn = open(local, uri);
+ final Transport tn = open(local, uri, cfg.getName());
tn.applyConfig(cfg);
transports.add(tn);
}
}
/**
- * Determines whether the transport can handle the given URIish.
+ * Open a new transport instance to connect two repositories.
*
- * @param remote
+ * @param local
+ * existing local repository.
+ * @param uri
* location of the remote repository.
- * @param fs
- * type of filesystem the local repository is stored on.
- * @return true if the protocol is supported.
+ * @return the new transport instance. Never null.
+ * @throws NotSupportedException
+ * the protocol specified is not supported.
+ * @throws TransportException
+ * the transport cannot open this URI.
*/
- public static boolean canHandleProtocol(final URIish remote, final FS fs) {
- if (TransportGitSsh.canHandle(remote))
- return true;
-
- else if (TransportHttp.canHandle(remote))
- return true;
-
- else if (TransportSftp.canHandle(remote))
- return true;
-
- else if (TransportGitAnon.canHandle(remote))
- return true;
-
- else if (TransportAmazonS3.canHandle(remote))
- return true;
-
- else if (TransportBundleFile.canHandle(remote, fs))
- return true;
-
- else if (TransportLocal.canHandle(remote, fs))
- return true;
-
- return false;
+ public static Transport open(final Repository local, final URIish uri)
+ throws NotSupportedException, TransportException {
+ return open(local, uri, null);
}
/**
*
* @param local
* existing local repository.
- * @param remote
+ * @param uri
* location of the remote repository.
+ * @param remoteName
+ * name of the remote, if the remote as configured in
+ * {@code local}; otherwise null.
* @return the new transport instance. Never null.
* @throws NotSupportedException
* the protocol specified is not supported.
+ * @throws TransportException
+ * the transport cannot open this URI.
*/
- public static Transport open(final Repository local, final URIish remote)
- throws NotSupportedException {
- if (TransportGitSsh.canHandle(remote))
- return new TransportGitSsh(local, remote);
-
- else if (TransportHttp.canHandle(remote))
- return new TransportHttp(local, remote);
-
- else if (TransportSftp.canHandle(remote))
- return new TransportSftp(local, remote);
-
- else if (TransportGitAnon.canHandle(remote))
- return new TransportGitAnon(local, remote);
-
- else if (TransportAmazonS3.canHandle(remote))
- return new TransportAmazonS3(local, remote);
-
- else if (TransportBundleFile.canHandle(remote, local.getFS()))
- return new TransportBundleFile(local, remote);
+ public static Transport open(Repository local, URIish uri, String remoteName)
+ throws NotSupportedException, TransportException {
+ for (WeakReference<TransportProtocol> ref : protocols) {
+ TransportProtocol proto = ref.get();
+ if (proto == null) {
+ protocols.remove(ref);
+ continue;
+ }
- else if (TransportLocal.canHandle(remote, local.getFS()))
- return new TransportLocal(local, remote);
+ if (proto.canHandle(local, uri, remoteName))
+ return proto.open(local, uri, remoteName);
+ }
- throw new NotSupportedException(MessageFormat.format(JGitText.get().URINotSupported, remote));
+ throw new NotSupportedException(MessageFormat.format(JGitText.get().URINotSupported, uri));
}
/**
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Collection;
+import java.util.Collections;
+import java.util.EnumSet;
import java.util.HashSet;
import java.util.Map;
import java.util.Properties;
+import java.util.Set;
import java.util.TreeMap;
import org.eclipse.jgit.JGitText;
import org.eclipse.jgit.lib.ObjectIdRef;
import org.eclipse.jgit.lib.ProgressMonitor;
import org.eclipse.jgit.lib.Ref;
+import org.eclipse.jgit.lib.Ref.Storage;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.lib.SymbolicRef;
-import org.eclipse.jgit.lib.Ref.Storage;
/**
* Transport over the non-Git aware Amazon S3 protocol.
public class TransportAmazonS3 extends HttpTransport implements WalkTransport {
static final String S3_SCHEME = "amazon-s3";
- static boolean canHandle(final URIish uri) {
- if (!uri.isRemote())
- return false;
- return S3_SCHEME.equals(uri.getScheme());
- }
+ static final TransportProtocol PROTO_S3 = new TransportProtocol() {
+ public String getName() {
+ return "Amazon S3";
+ }
+
+ public Set<String> getSchemes() {
+ return Collections.singleton(S3_SCHEME);
+ }
+
+ public Set<URIishField> getRequiredFields() {
+ return Collections.unmodifiableSet(EnumSet.of(URIishField.USER,
+ URIishField.HOST, URIishField.PATH));
+ }
+
+ public Set<URIishField> getOptionalFields() {
+ return Collections.unmodifiableSet(EnumSet.of(URIishField.PASS));
+ }
+
+ public Transport open(Repository local, URIish uri, String remoteName)
+ throws NotSupportedException {
+ return new TransportAmazonS3(local, uri);
+ }
+ };
/** User information necessary to connect to S3. */
private final AmazonS3 s3;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.InputStream;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.LinkedHashSet;
+import java.util.Set;
import org.eclipse.jgit.JGitText;
import org.eclipse.jgit.errors.NotSupportedException;
import org.eclipse.jgit.errors.TransportException;
import org.eclipse.jgit.lib.Repository;
-import org.eclipse.jgit.util.FS;
class TransportBundleFile extends Transport implements TransportBundle {
- static boolean canHandle(final URIish uri, FS fs) {
- if (uri.getHost() != null || uri.getPort() > 0 || uri.getUser() != null
- || uri.getPass() != null || uri.getPath() == null)
- return false;
-
- if ("file".equals(uri.getScheme()) || uri.getScheme() == null) {
- final File f = fs.resolve(new File("."), uri.getPath());
- return f.isFile() || f.getName().endsWith(".bundle");
+ static final TransportProtocol PROTO_BUNDLE = new TransportProtocol() {
+ private final String[] schemeNames = { "bundle", "file" }; //$NON-NLS-1$ //$NON-NLS-2$
+
+ private final Set<String> schemeSet = Collections
+ .unmodifiableSet(new LinkedHashSet<String>(Arrays
+ .asList(schemeNames)));
+
+ @Override
+ public String getName() {
+ return JGitText.get().transportProtoBundleFile;
}
- return false;
- }
+ public Set<String> getSchemes() {
+ return schemeSet;
+ }
+
+ @Override
+ public boolean canHandle(Repository local, URIish uri, String remoteName) {
+ if (uri.getPath() == null
+ || uri.getPort() > 0
+ || uri.getUser() != null
+ || uri.getPass() != null
+ || uri.getHost() != null
+ || (uri.getScheme() != null && !getSchemes().contains(uri.getScheme())))
+ return false;
+ return true;
+ }
+
+ @Override
+ public Transport open(Repository local, URIish uri, String remoteName)
+ throws NotSupportedException, TransportException {
+ if ("bundle".equals(uri.getScheme())) {
+ File path = local.getFS().resolve(new File("."), uri.getPath());
+ return new TransportBundleFile(local, uri, path);
+ }
+
+ // This is an ambiguous reference, it could be a bundle file
+ // or it could be a Git repository. Allow TransportLocal to
+ // resolve the path and figure out which type it is by testing
+ // the target.
+ //
+ return TransportLocal.PROTO_LOCAL.open(local, uri, remoteName);
+ }
+ };
private final File bundle;
- TransportBundleFile(final Repository local, final URIish uri) {
+ TransportBundleFile(Repository local, URIish uri, File bundlePath) {
super(local, uri);
- bundle = local.getFS().resolve(new File("."), uri.getPath()).getAbsoluteFile();
+ bundle = bundlePath;
}
@Override
import java.net.InetSocketAddress;
import java.net.Socket;
import java.net.UnknownHostException;
+import java.util.Collections;
+import java.util.EnumSet;
+import java.util.Set;
import org.eclipse.jgit.JGitText;
+import org.eclipse.jgit.errors.NotSupportedException;
import org.eclipse.jgit.errors.TransportException;
import org.eclipse.jgit.lib.Repository;
class TransportGitAnon extends TcpTransport implements PackTransport {
static final int GIT_PORT = Daemon.DEFAULT_PORT;
- static boolean canHandle(final URIish uri) {
- return "git".equals(uri.getScheme());
- }
+ static final TransportProtocol PROTO_GIT = new TransportProtocol() {
+ public String getName() {
+ return JGitText.get().transportProtoGitAnon;
+ }
+
+ public Set<String> getSchemes() {
+ return Collections.singleton("git"); //$NON-NLS-1$
+ }
+
+ public Set<URIishField> getRequiredFields() {
+ return Collections.unmodifiableSet(EnumSet.of(URIishField.HOST,
+ URIishField.PATH));
+ }
+
+ public Set<URIishField> getOptionalFields() {
+ return Collections.unmodifiableSet(EnumSet.of(URIishField.PORT));
+ }
+
+ public int getDefaultPort() {
+ return GIT_PORT;
+ }
+
+ public Transport open(Repository local, URIish uri, String remoteName)
+ throws NotSupportedException {
+ return new TransportGitAnon(local, uri);
+ }
+ };
TransportGitAnon(final Repository local, final URIish uri) {
super(local, uri);
import java.io.PipedOutputStream;
import java.text.MessageFormat;
import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.EnumSet;
+import java.util.LinkedHashSet;
import java.util.List;
+import java.util.Set;
import org.eclipse.jgit.JGitText;
import org.eclipse.jgit.errors.NoRemoteRepositoryException;
+import org.eclipse.jgit.errors.NotSupportedException;
import org.eclipse.jgit.errors.TransportException;
import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.lib.Repository;
* enumeration, save file modification and hook execution.
*/
public class TransportGitSsh extends SshTransport implements PackTransport {
- static boolean canHandle(final URIish uri) {
- if (!uri.isRemote())
- return false;
- final String scheme = uri.getScheme();
- if ("ssh".equals(scheme))
- return true;
- if ("ssh+git".equals(scheme))
- return true;
- if ("git+ssh".equals(scheme))
- return true;
- if (scheme == null && uri.getHost() != null && uri.getPath() != null)
- return true;
- return false;
- }
+ static final TransportProtocol PROTO_SSH = new TransportProtocol() {
+ private final String[] schemeNames = { "ssh", "ssh+git", "git+ssh" }; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+
+ private final Set<String> schemeSet = Collections
+ .unmodifiableSet(new LinkedHashSet<String>(Arrays
+ .asList(schemeNames)));
+
+ public String getName() {
+ return JGitText.get().transportProtoSSH;
+ }
+
+ public Set<String> getSchemes() {
+ return schemeSet;
+ }
+
+ public Set<URIishField> getRequiredFields() {
+ return Collections.unmodifiableSet(EnumSet.of(URIishField.HOST,
+ URIishField.PATH));
+ }
+
+ public Set<URIishField> getOptionalFields() {
+ return Collections.unmodifiableSet(EnumSet.of(URIishField.USER,
+ URIishField.PASS, URIishField.PORT));
+ }
+
+ public int getDefaultPort() {
+ return 22;
+ }
+
+ @Override
+ public boolean canHandle(Repository local, URIish uri, String remoteName) {
+ if (uri.getScheme() == null) {
+ // scp-style URI "host:path" does not have scheme.
+ return uri.getHost() != null
+ && uri.getPath() != null
+ && uri.getHost().length() != 0
+ && uri.getPath().length() != 0;
+ }
+ return super.canHandle(local, uri, remoteName);
+ }
+
+ public Transport open(Repository local, URIish uri, String remoteName)
+ throws NotSupportedException {
+ return new TransportGitSsh(local, uri);
+ }
+ };
TransportGitSsh(final Repository local, final URIish uri) {
super(local, uri);
import java.security.cert.X509Certificate;
import java.text.MessageFormat;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Collection;
+import java.util.Collections;
+import java.util.EnumSet;
+import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
private static final String userAgent = computeUserAgent();
- static boolean canHandle(final URIish uri) {
- if (!uri.isRemote())
- return false;
- final String s = uri.getScheme();
- return "http".equals(s) || "https".equals(s) || "ftp".equals(s); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
- }
+ static final TransportProtocol PROTO_HTTP = new TransportProtocol() {
+ private final String[] schemeNames = { "http", "https" }; //$NON-NLS-1$ //$NON-NLS-2$
+
+ private final Set<String> schemeSet = Collections
+ .unmodifiableSet(new LinkedHashSet<String>(Arrays
+ .asList(schemeNames)));
+
+ public String getName() {
+ return JGitText.get().transportProtoHTTP;
+ }
+
+ public Set<String> getSchemes() {
+ return schemeSet;
+ }
+
+ public Set<URIishField> getRequiredFields() {
+ return Collections.unmodifiableSet(EnumSet.of(URIishField.HOST,
+ URIishField.PATH));
+ }
+
+ public Set<URIishField> getOptionalFields() {
+ return Collections.unmodifiableSet(EnumSet.of(URIishField.USER,
+ URIishField.PASS, URIishField.PORT));
+ }
+
+ public int getDefaultPort() {
+ return 80;
+ }
+
+ public Transport open(Repository local, URIish uri, String remoteName)
+ throws NotSupportedException {
+ return new TransportHttp(local, uri);
+ }
+ };
+
+ static final TransportProtocol PROTO_FTP = new TransportProtocol() {
+ public String getName() {
+ return JGitText.get().transportProtoFTP;
+ }
+
+ public Set<String> getSchemes() {
+ return Collections.singleton("ftp"); //$NON-NLS-1$
+ }
+
+ public Set<URIishField> getRequiredFields() {
+ return Collections.unmodifiableSet(EnumSet.of(URIishField.HOST,
+ URIishField.PATH));
+ }
+
+ public Set<URIishField> getOptionalFields() {
+ return Collections.unmodifiableSet(EnumSet.of(URIishField.USER,
+ URIishField.PASS, URIishField.PORT));
+ }
+
+ public int getDefaultPort() {
+ return 21;
+ }
+
+ public Transport open(Repository local, URIish uri, String remoteName)
+ throws NotSupportedException {
+ return new TransportHttp(local, uri);
+ }
+ };
private static String computeUserAgent() {
String version;
import java.io.OutputStream;
import java.io.PipedInputStream;
import java.io.PipedOutputStream;
+import java.util.Collections;
import java.util.Map;
+import java.util.Set;
import org.eclipse.jgit.JGitText;
+import org.eclipse.jgit.errors.NoRemoteRepositoryException;
import org.eclipse.jgit.errors.NotSupportedException;
import org.eclipse.jgit.errors.TransportException;
-import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.lib.Repository;
+import org.eclipse.jgit.lib.RepositoryCache;
import org.eclipse.jgit.storage.file.FileRepository;
-import org.eclipse.jgit.util.FS;
import org.eclipse.jgit.util.io.MessageWriter;
import org.eclipse.jgit.util.io.StreamCopyThread;
* system pipe to transfer data.
*/
class TransportLocal extends Transport implements PackTransport {
- private static final String PWD = ".";
+ static final TransportProtocol PROTO_LOCAL = new TransportProtocol() {
+ @Override
+ public String getName() {
+ return JGitText.get().transportProtoLocal;
+ }
- static boolean canHandle(final URIish uri, FS fs) {
- if (uri.getHost() != null || uri.getPort() > 0 || uri.getUser() != null
- || uri.getPass() != null || uri.getPath() == null)
- return false;
+ public Set<String> getSchemes() {
+ return Collections.singleton("file"); //$NON-NLS-1$
+ }
- if ("file".equals(uri.getScheme()) || uri.getScheme() == null)
- return fs.resolve(new File(PWD), uri.getPath()).isDirectory();
- return false;
- }
+ @Override
+ public boolean canHandle(Repository local, URIish uri, String remoteName) {
+ if (uri.getPath() == null
+ || uri.getPort() > 0
+ || uri.getUser() != null
+ || uri.getPass() != null
+ || uri.getHost() != null
+ || (uri.getScheme() != null && !getSchemes().contains(uri.getScheme())))
+ return false;
+ return true;
+ }
+
+ @Override
+ public Transport open(Repository local, URIish uri, String remoteName)
+ throws NoRemoteRepositoryException {
+ // If the reference is to a local file, C Git behavior says
+ // assume this is a bundle, since repositories are directories.
+ //
+ File path = local.getFS().resolve(new File("."), uri.getPath());
+ if (path.isFile())
+ return new TransportBundleFile(local, uri, path);
+
+ File gitDir = RepositoryCache.FileKey.resolve(path, local.getFS());
+ if (gitDir == null)
+ throw new NoRemoteRepositoryException(uri, JGitText.get().notFound);
+ return new TransportLocal(local, uri, gitDir);
+ }
+ };
private final File remoteGitDir;
- TransportLocal(final Repository local, final URIish uri) {
+ TransportLocal(Repository local, URIish uri, File gitDir) {
super(local, uri);
-
- File d = local.getFS().resolve(new File(PWD), uri.getPath()).getAbsoluteFile();
- if (new File(d, Constants.DOT_GIT).isDirectory())
- d = new File(d, Constants.DOT_GIT);
- remoteGitDir = d;
+ remoteGitDir = gitDir;
}
UploadPack createUploadPack(final Repository dst) {
--- /dev/null
+/*
+ * Copyright (C) 2011, Google Inc.
+ * and other copyright owners as documented in the project's IP log.
+ *
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Distribution License v1.0 which
+ * accompanies this distribution, is reproduced below, and is
+ * available at http://www.eclipse.org/org/documents/edl-v10.php
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the
+ * names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.eclipse.jgit.transport;
+
+import java.util.Collections;
+import java.util.EnumSet;
+import java.util.Set;
+
+import org.eclipse.jgit.errors.NotSupportedException;
+import org.eclipse.jgit.errors.TransportException;
+import org.eclipse.jgit.lib.Repository;
+
+/**
+ * Describes a way to connect to another Git repository.
+ * <p>
+ * Implementations of this class are typically immutable singletons held by
+ * static class members, for example:
+ *
+ * <pre>
+ * class MyTransport extends Transport {
+ * static final TransportProtocol PROTO = new TransportProtocol() {
+ * public String getName() {
+ * return "My Protocol";
+ * }
+ * };
+ * }
+ * </pre>
+ *
+ * Applications may register additional protocols for use by JGit by calling
+ * {@link Transport#register(TransportProtocol)}. Because that API holds onto
+ * the protocol object by a WeakReference, applications must ensure their own
+ * ClassLoader retains the TransportProtocol for the life of the application.
+ * Using a static singleton pattern as above will ensure the protocol is valid
+ * so long as the ClassLoader that defines it remains valid.
+ */
+public abstract class TransportProtocol {
+ /** Fields within a {@link URIish} that a transport uses. */
+ public static enum URIishField {
+ /** the user field */
+ USER,
+ /** the pass (aka password) field */
+ PASS,
+ /** the host field */
+ HOST,
+ /** the port field */
+ PORT,
+ /** the path field */
+ PATH,
+ }
+
+ /** @return text name of the protocol suitable for display to a user. */
+ public abstract String getName();
+
+ /** @return immutable set of schemes supported by this protocol. */
+ public Set<String> getSchemes() {
+ return Collections.emptySet();
+ }
+
+ /** @return immutable set of URIishFields that must be filled in. */
+ public Set<URIishField> getRequiredFields() {
+ return Collections.unmodifiableSet(EnumSet.of(URIishField.PATH));
+ }
+
+ /** @return immutable set of URIishFields that may be filled in. */
+ public Set<URIishField> getOptionalFields() {
+ return Collections.emptySet();
+ }
+
+ /** @return if a port is supported, the default port, else -1. */
+ public int getDefaultPort() {
+ return -1;
+ }
+
+ /**
+ * Determine if this protocol can handle a particular URI.
+ * <p>
+ * Implementations should try to avoid looking at the local filesystem, but
+ * may look at implementation specific configuration options in the remote
+ * block of {@code local.getConfig()} using {@code remoteName} if the name
+ * is non-null.
+ * <p>
+ * The default implementation of this method matches the scheme against
+ * {@link #getSchemes()}, required fields against
+ * {@link #getRequiredFields()}, and optional fields against
+ * {@link #getOptionalFields()}, returning true only if all of the fields
+ * match the specification.
+ *
+ * @param local
+ * the local repository that will communicate with the other Git
+ * repository.
+ * @param uri
+ * address of the Git repository; never null.
+ * @param remoteName
+ * name of the remote, if the remote as configured in
+ * {@code local}; otherwise null.
+ * @return true if this protocol can handle this URI; false otherwise.
+ */
+ public boolean canHandle(Repository local, URIish uri, String remoteName) {
+ if (!getSchemes().isEmpty() && !getSchemes().contains(uri.getScheme()))
+ return false;
+
+ for (URIishField field : getRequiredFields()) {
+ switch (field) {
+ case USER:
+ if (uri.getUser() == null || uri.getUser().length() == 0)
+ return false;
+ break;
+
+ case PASS:
+ if (uri.getPass() == null || uri.getPass().length() == 0)
+ return false;
+ break;
+
+ case HOST:
+ if (uri.getHost() == null || uri.getHost().length() == 0)
+ return false;
+ break;
+
+ case PORT:
+ if (uri.getPort() <= 0)
+ return false;
+ break;
+
+ case PATH:
+ if (uri.getPath() == null || uri.getPath().length() == 0)
+ return false;
+ break;
+
+ default:
+ return false;
+ }
+ }
+
+ Set<URIishField> canHave = EnumSet.copyOf(getRequiredFields());
+ canHave.addAll(getOptionalFields());
+
+ if (uri.getUser() != null && !canHave.contains(URIishField.USER))
+ return false;
+ if (uri.getPass() != null && !canHave.contains(URIishField.PASS))
+ return false;
+ if (uri.getHost() != null && !canHave.contains(URIishField.HOST))
+ return false;
+ if (uri.getPort() > 0 && !canHave.contains(URIishField.PORT))
+ return false;
+ if (uri.getPath() != null && !canHave.contains(URIishField.PATH))
+ return false;
+
+ return true;
+ }
+
+ /**
+ * Open a Transport instance to the other repository.
+ * <p>
+ * Implementations should avoid making remote connections until an operation
+ * on the returned Transport is invoked, however they may fail fast here if
+ * they know a connection is impossible, such as when using the local
+ * filesystem and the target path does not exist.
+ * <p>
+ * Implementations may access implementation-specific configuration options
+ * within {@code local.getConfig()} using the remote block named by the
+ * {@code remoteName}, if the name is non-null.
+ *
+ * @param local
+ * the local repository that will communicate with the other Git
+ * repository.
+ * @param uri
+ * address of the Git repository.
+ * @param remoteName
+ * name of the remote, if the remote as configured in
+ * {@code local}; otherwise null.
+ * @return the transport.
+ * @throws NotSupportedException
+ * this protocol does not support the URI.
+ * @throws TransportException
+ * the transport cannot open this URI.
+ */
+ public abstract Transport open(Repository local, URIish uri,
+ String remoteName)
+ throws NotSupportedException, TransportException;
+}
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
+import java.util.EnumSet;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
+import java.util.Set;
import java.util.TreeMap;
+import org.eclipse.jgit.JGitText;
+import org.eclipse.jgit.errors.NotSupportedException;
import org.eclipse.jgit.errors.TransportException;
import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.ObjectIdRef;
import org.eclipse.jgit.lib.ProgressMonitor;
import org.eclipse.jgit.lib.Ref;
+import org.eclipse.jgit.lib.Ref.Storage;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.lib.SymbolicRef;
-import org.eclipse.jgit.lib.Ref.Storage;
import com.jcraft.jsch.Channel;
import com.jcraft.jsch.ChannelSftp;
* @see WalkFetchConnection
*/
public class TransportSftp extends SshTransport implements WalkTransport {
- static boolean canHandle(final URIish uri) {
- return uri.isRemote() && "sftp".equals(uri.getScheme());
- }
+ static final TransportProtocol PROTO_SFTP = new TransportProtocol() {
+ public String getName() {
+ return JGitText.get().transportProtoSFTP;
+ }
+
+ public Set<String> getSchemes() {
+ return Collections.singleton("sftp"); //$NON-NLS-1$
+ }
+
+ public Set<URIishField> getRequiredFields() {
+ return Collections.unmodifiableSet(EnumSet.of(URIishField.HOST,
+ URIishField.PATH));
+ }
+
+ public Set<URIishField> getOptionalFields() {
+ return Collections.unmodifiableSet(EnumSet.of(URIishField.USER,
+ URIishField.PASS, URIishField.PORT));
+ }
+
+ public int getDefaultPort() {
+ return 22;
+ }
+
+ public Transport open(Repository local, URIish uri, String remoteName)
+ throws NotSupportedException {
+ return new TransportSftp(local, uri);
+ }
+ };
TransportSftp(final Repository local, final URIish uri) {
super(local, uri);