summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCarlos Martín Nieto <cmn@elego.de>2011-05-16 22:07:08 +0200
committerCarlos Martín Nieto <carlos@cmartin.tk>2011-06-26 18:18:11 +0200
commit8f866daee5a0a43702f349c7fa46d3274542650c (patch)
treeb9988e5566c79f5ec9b6a064ddb1d7706a51e109
parentc5b2622d6810eed5a4b90123ab0e7fc6d4583831 (diff)
downloadlibgit2-8f866daee5a0a43702f349c7fa46d3274542650c.tar.gz
Lay down the fundations for the network code
Signed-off-by: Carlos Martín Nieto <carlos@cmartin.tk>
-rw-r--r--include/git2/net.h33
-rw-r--r--include/git2/transport.h56
-rw-r--r--include/git2/types.h11
-rw-r--r--src/transport.c77
-rw-r--r--src/transport.h79
-rw-r--r--src/transport_local.c41
6 files changed, 297 insertions, 0 deletions
diff --git a/include/git2/net.h b/include/git2/net.h
new file mode 100644
index 000000000..869309f9d
--- /dev/null
+++ b/include/git2/net.h
@@ -0,0 +1,33 @@
+#ifndef INCLUDE_net_h__
+#define INCLUDE_net_h__
+
+#include "common.h"
+#include "oid.h"
+#include "types.h"
+
+/*
+ * We need this because we need to know whether we should call
+ * git-upload-pack or git-receive-pack on the remote end when get_refs
+ * gets called.
+ */
+
+enum git_net_direction {
+ INTENT_PUSH,
+ INTENT_PULL
+};
+
+/*
+ * This is what we give out on ->ls()
+ */
+
+struct git_remote_head {
+ git_oid oid;
+ char *name;
+};
+
+struct git_headarray {
+ unsigned int len;
+ struct git_remote_head *heads;
+};
+
+#endif
diff --git a/include/git2/transport.h b/include/git2/transport.h
new file mode 100644
index 000000000..dfbc1a84c
--- /dev/null
+++ b/include/git2/transport.h
@@ -0,0 +1,56 @@
+/*
+ * This file is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, version 2,
+ * as published by the Free Software Foundation.
+ *
+ * In addition to the permissions in the GNU General Public License,
+ * the authors give you unlimited permission to link the compiled
+ * version of this file into combinations with other programs,
+ * and to distribute those combinations without any restriction
+ * coming from the use of this file. (The General Public License
+ * restrictions do apply in other respects; for example, they cover
+ * modification of the file, and distribution when not linked into
+ * a combined executable.)
+ *
+ * This file is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; see the file COPYING. If not, write to
+ * the Free Software Foundation, 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+#ifndef INCLUDE_git_transport_h__
+#define INCLUDE_git_transport_h__
+
+#include "common.h"
+#include "types.h"
+#include "net.h"
+
+/**
+ * @file git2/transport.h
+ * @brief Git protocol transport abstraction
+ * @defgroup git_transport Git protocol transport abstraction
+ * @ingroup Git
+ * @{
+ */
+GIT_BEGIN_DECL
+
+/**
+ * Get the appropriate transport for an URL.
+ * @param tranport the transport for the url
+ * @param url the url of the repo
+ */
+GIT_EXTERN(int) git_transport_get(git_transport *transport, const char *url);
+
+GIT_EXTERN(int) git_transport_connect(git_transport *transport, git_net_direction direction);
+/*
+GIT_EXTERN(const git_vector *) git_transport_get_refs(git_transport *transport);
+*/
+GIT_EXTERN(int) git_transport_add(git_transport *transport, const char *prefix);
+
+/** @} */
+GIT_END_DECL
+#endif
diff --git a/include/git2/types.h b/include/git2/types.h
index 963156f85..69aa28955 100644
--- a/include/git2/types.h
+++ b/include/git2/types.h
@@ -167,9 +167,20 @@ typedef enum {
GIT_REF_LISTALL = GIT_REF_OID|GIT_REF_SYMBOLIC|GIT_REF_PACKED,
} git_rtype;
+
typedef struct git_refspec git_refspec;
typedef struct git_remote git_remote;
+/** A transport to use */
+typedef struct git_transport git_transport;
+
+/** Whether to push or pull */
+typedef enum git_net_direction git_net_direction;
+
+typedef int (*git_transport_cb)(git_transport *transport);
+
+typedef struct git_headarray git_headarray;
+
/** @} */
GIT_END_DECL
diff --git a/src/transport.c b/src/transport.c
new file mode 100644
index 000000000..c08345968
--- /dev/null
+++ b/src/transport.c
@@ -0,0 +1,77 @@
+#include "common.h"
+#include "git2/types.h"
+#include "git2/transport.h"
+#include "git2/net.h"
+#include "transport.h"
+
+struct {
+ char *prefix;
+ git_transport_cb fn;
+} transports[] = {
+ {"git://", git_transport_dummy},
+ {"http://", git_transport_dummy},
+ {"https://", git_transport_dummy},
+ {"file://", git_transport_local},
+ {"git+ssh://", git_transport_dummy},
+ {"ssh+git://", git_transport_dummy},
+ {NULL, 0}
+};
+
+static git_transport_cb transport_fill_fn(const char *url)
+{
+ int i = 0;
+
+ while (1) {
+ if (transports[i].prefix == NULL)
+ break;
+
+ if (!strncasecmp(url, transports[i].prefix, strlen(transports[i].prefix)))
+ return transports[i].fn;
+
+ ++i;
+ }
+
+ /*
+ * If we still haven't found the transport, we assume we mean a
+ * local file.
+ * TODO: Parse "example.com:project.git" as an SSH URL
+ */
+ return git_transport_local;
+}
+
+/**************
+ * Public API *
+ **************/
+
+int git_transport_dummy(git_transport *GIT_UNUSED(transport))
+{
+ GIT_UNUSED_ARG(transport);
+ return git__throw(GIT_ENOTIMPLEMENTED, "This protocol isn't implemented. Sorry");
+}
+
+int git_transport_new(git_transport **out, git_repository *repo, const char *url)
+{
+ git_transport_cb fn;
+ git_transport *transport;
+ int error;
+
+ fn = transport_fill_fn(url);
+
+ transport = git__malloc(sizeof(git_transport));
+ if (transport == NULL)
+ return GIT_ENOMEM;
+
+ transport->url = git__strdup(url);
+ if (transport->url == NULL)
+ return GIT_ENOMEM;
+
+ transport->repo = repo;
+
+ error = fn(transport);
+ if (error < GIT_SUCCESS)
+ return git__rethrow(error, "Failed to create new transport");
+
+ *out = transport;
+
+ return GIT_SUCCESS;
+}
diff --git a/src/transport.h b/src/transport.h
new file mode 100644
index 000000000..8585b00f7
--- /dev/null
+++ b/src/transport.h
@@ -0,0 +1,79 @@
+#ifndef INCLUDE_transport_h__
+#define INCLUDE_transport_h__
+
+#include "git2/transport.h"
+#include "git2/net.h"
+#include "vector.h"
+
+/*
+ * A day in the life of a network operation
+ * ========================================
+ *
+ * The library gets told to ls-remote/push/fetch on/to/from some
+ * remote. We look at the URL of the remote and fill the function
+ * table with whatever is appropriate (the remote may be git over git,
+ * ssh or http(s). It may even be an hg or svn repository, the library
+ * at this level doesn't care, it just calls the helpers.
+ *
+ * The first call is to ->connect() which connects to the remote,
+ * making use of the direction if necessary. This function must also
+ * store the remote heads and any other information it needs.
+ *
+ * If we just want to execute ls-remote, ->ls() gets
+ * called. Otherwise, the have/want/need list needs to be built via
+ * ->wanthaveneed(). We can then ->push() or ->pull(). When we're
+ * done, we call ->close() to close the connection. ->free() takes
+ * care of freeing all the resources.
+ */
+
+struct git_transport {
+ /**
+ * Where the repo lives
+ */
+ char *url;
+ /**
+ * Where each transport stores its private/instance data
+ */
+ void *private;
+ /**
+ * The repo we want to act on
+ */
+ git_repository *repo;
+ /**
+ * Whether we want to push or fetch
+ */
+ git_net_direction direction;
+ /**
+ * Connect and store the remote heads
+ */
+ int (*connect)(struct git_transport *transport, git_net_direction intent);
+ /**
+ * Give a list of references, useful for ls-remote
+ */
+ int (*ls)(struct git_transport *transport, git_headarray *headarray);
+ /**
+ * Calculate want/have/need. May not even be needed.
+ */
+ int (*wanthaveneed)(struct git_transport *transport, void *something);
+ /**
+ * Build the pack
+ */
+ int (*build_pack)(struct git_transport *transport);
+ /**
+ * Push the changes over
+ */
+ int (*push)(struct git_transport *transport);
+ /**
+ * Fetch the changes
+ */
+ int (*fetch)(struct git_transport *transport);
+ /**
+ * Close the connection
+ */
+ int (*close)(struct git_transport *transport);
+};
+
+int git_transport_local(struct git_transport *transport);
+int git_transport_dummy(struct git_transport *transport);
+
+#endif
diff --git a/src/transport_local.c b/src/transport_local.c
new file mode 100644
index 000000000..f492a875f
--- /dev/null
+++ b/src/transport_local.c
@@ -0,0 +1,41 @@
+#include "common.h"
+#include "git2/types.h"
+#include "git2/transport.h"
+#include "git2/net.h"
+#include "git2/repository.h"
+#include "transport.h"
+
+/*
+ * Try to open the url as a git directory. The direction doesn't
+ * matter in this case because we're calulating the heads ourselves.
+ */
+static int local_connect(git_transport *transport, git_net_direction GIT_UNUSED(dir))
+{
+ git_repository *repo;
+ int error;
+
+ error = git_repository_open(&repo, transport->url);
+ if (error < GIT_SUCCESS)
+ return git__rethrow(error, "Can't open remote");
+
+ transport->private = repo;
+
+ return GIT_SUCCESS;
+}
+
+static int local_ls(git_transport *transport, git_headarray *array)
+{
+ return GIT_SUCCESS;
+}
+
+/**************
+ * Public API *
+ **************/
+
+int git_transport_local(git_transport *transport)
+{
+ transport->connect = local_connect;
+ transport->ls = local_ls;
+
+ return GIT_SUCCESS;
+}