summaryrefslogtreecommitdiff
path: root/examples/network
diff options
context:
space:
mode:
Diffstat (limited to 'examples/network')
-rw-r--r--examples/network/Makefile11
-rw-r--r--examples/network/clone.c122
-rw-r--r--examples/network/common.h10
-rw-r--r--examples/network/fetch.c150
-rw-r--r--examples/network/git2.c6
-rw-r--r--examples/network/index-pack.c162
-rw-r--r--examples/network/ls-remote.c19
7 files changed, 324 insertions, 156 deletions
diff --git a/examples/network/Makefile b/examples/network/Makefile
index c21869ac9..810eb705b 100644
--- a/examples/network/Makefile
+++ b/examples/network/Makefile
@@ -2,13 +2,20 @@ default: all
CC = gcc
CFLAGS += -g
-CFLAGS += -I../../include -L../../ -lgit2 -lpthread
+CFLAGS += -I../../include
+LDFLAGS += -L../../build -L../..
+LIBRARIES += -lgit2 -lpthread
OBJECTS = \
git2.o \
ls-remote.o \
fetch.o \
+ clone.o \
index-pack.o
all: $(OBJECTS)
- $(CC) $(CFLAGS) -o git2 $(OBJECTS)
+ $(CC) $(CFLAGS) $(LDFLAGS) -o git2 $(OBJECTS) $(LIBRARIES)
+
+clean:
+ $(RM) $(OBJECTS)
+ $(RM) git2
diff --git a/examples/network/clone.c b/examples/network/clone.c
new file mode 100644
index 000000000..00c25c1ae
--- /dev/null
+++ b/examples/network/clone.c
@@ -0,0 +1,122 @@
+#include "common.h"
+#include <git2.h>
+#include <git2/clone.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#ifndef _WIN32
+# include <pthread.h>
+# include <unistd.h>
+#endif
+
+/* Shamelessly borrowed from http://stackoverflow.com/questions/3417837/
+ * with permission of the original author, Martin Pool.
+ * http://sourcefrog.net/weblog/software/languages/C/unused.html
+ */
+#ifdef UNUSED
+#elif defined(__GNUC__)
+# define UNUSED(x) UNUSED_ ## x __attribute__((unused))
+#elif defined(__LCLINT__)
+# define UNUSED(x) /*@unused@*/ x
+#else
+# define UNUSED(x) x
+#endif
+
+typedef struct progress_data {
+ git_transfer_progress fetch_progress;
+ size_t completed_steps;
+ size_t total_steps;
+ const char *path;
+} progress_data;
+
+static void print_progress(const progress_data *pd)
+{
+ int network_percent = (100*pd->fetch_progress.received_objects) / pd->fetch_progress.total_objects;
+ int index_percent = (100*pd->fetch_progress.indexed_objects) / pd->fetch_progress.total_objects;
+ int checkout_percent = pd->total_steps > 0
+ ? (100 * pd->completed_steps) / pd->total_steps
+ : 0.f;
+ int kbytes = pd->fetch_progress.received_bytes / 1024;
+
+ printf("net %3d%% (%4d kb, %5d/%5d) / idx %3d%% (%5d/%5d) / chk %3d%% (%4" PRIuZ "/%4" PRIuZ ") %s\n",
+ network_percent, kbytes,
+ pd->fetch_progress.received_objects, pd->fetch_progress.total_objects,
+ index_percent, pd->fetch_progress.indexed_objects, pd->fetch_progress.total_objects,
+ checkout_percent,
+ pd->completed_steps, pd->total_steps,
+ pd->path);
+}
+
+static int fetch_progress(const git_transfer_progress *stats, void *payload)
+{
+ progress_data *pd = (progress_data*)payload;
+ pd->fetch_progress = *stats;
+ print_progress(pd);
+ return 0;
+}
+static void checkout_progress(const char *path, size_t cur, size_t tot, void *payload)
+{
+ progress_data *pd = (progress_data*)payload;
+ pd->completed_steps = cur;
+ pd->total_steps = tot;
+ pd->path = path;
+ print_progress(pd);
+}
+
+static int cred_acquire(git_cred **out,
+ const char * UNUSED(url),
+ const char * UNUSED(username_from_url),
+ unsigned int UNUSED(allowed_types),
+ void * UNUSED(payload))
+{
+ char username[128] = {0};
+ char password[128] = {0};
+
+ printf("Username: ");
+ scanf("%s", username);
+
+ /* Yup. Right there on your terminal. Careful where you copy/paste output. */
+ printf("Password: ");
+ scanf("%s", password);
+
+ return git_cred_userpass_plaintext_new(out, username, password);
+}
+
+int do_clone(git_repository *repo, int argc, char **argv)
+{
+ progress_data pd = {{0}};
+ git_repository *cloned_repo = NULL;
+ git_clone_options clone_opts = GIT_CLONE_OPTIONS_INIT;
+ git_checkout_opts checkout_opts = GIT_CHECKOUT_OPTS_INIT;
+ const char *url = argv[1];
+ const char *path = argv[2];
+ int error;
+
+ (void)repo; // unused
+
+ // Validate args
+ if (argc < 3) {
+ printf ("USAGE: %s <url> <path>\n", argv[0]);
+ return -1;
+ }
+
+ // Set up options
+ checkout_opts.checkout_strategy = GIT_CHECKOUT_SAFE_CREATE;
+ checkout_opts.progress_cb = checkout_progress;
+ checkout_opts.progress_payload = &pd;
+ clone_opts.checkout_opts = checkout_opts;
+ clone_opts.fetch_progress_cb = &fetch_progress;
+ clone_opts.fetch_progress_payload = &pd;
+ clone_opts.cred_acquire_cb = cred_acquire;
+
+ // Do the clone
+ error = git_clone(&cloned_repo, url, path, &clone_opts);
+ printf("\n");
+ if (error != 0) {
+ const git_error *err = giterr_last();
+ if (err) printf("ERROR %d: %s\n", err->klass, err->message);
+ else printf("ERROR %d: no detailed info\n", error);
+ }
+ else if (cloned_repo) git_repository_free(cloned_repo);
+ return error;
+}
diff --git a/examples/network/common.h b/examples/network/common.h
index 29460bb36..a4cfa1a7e 100644
--- a/examples/network/common.h
+++ b/examples/network/common.h
@@ -10,5 +10,15 @@ int parse_pkt_line(git_repository *repo, int argc, char **argv);
int show_remote(git_repository *repo, int argc, char **argv);
int fetch(git_repository *repo, int argc, char **argv);
int index_pack(git_repository *repo, int argc, char **argv);
+int do_clone(git_repository *repo, int argc, char **argv);
+
+#ifndef PRIuZ
+/* Define the printf format specifer to use for size_t output */
+#if defined(_MSC_VER) || defined(__MINGW32__)
+# define PRIuZ "Iu"
+#else
+# define PRIuZ "zu"
+#endif
+#endif
#endif /* __COMMON_H__ */
diff --git a/examples/network/fetch.c b/examples/network/fetch.c
index f4a044984..6020ec6ec 100644
--- a/examples/network/fetch.c
+++ b/examples/network/fetch.c
@@ -3,23 +3,31 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
-#include <pthread.h>
+#ifndef _WIN32
+# include <pthread.h>
+# include <unistd.h>
+#endif
struct dl_data {
git_remote *remote;
- git_off_t *bytes;
- git_indexer_stats *stats;
int ret;
int finished;
};
+static void progress_cb(const char *str, int len, void *data)
+{
+ (void)data;
+ printf("remote: %.*s", len, str);
+ fflush(stdout); /* We don't have the \n to force the flush */
+}
+
static void *download(void *ptr)
{
struct dl_data *data = (struct dl_data *)ptr;
// Connect to the remote end specifying that we want to fetch
// information from it.
- if (git_remote_connect(data->remote, GIT_DIR_FETCH) < 0) {
+ if (git_remote_connect(data->remote, GIT_DIRECTION_FETCH) < 0) {
data->ret = -1;
goto exit;
}
@@ -27,7 +35,7 @@ static void *download(void *ptr)
// Download the packfile and index it. This function updates the
// amount of received data and the indexer stats which lets you
// inform the user about progress.
- if (git_remote_download(data->remote, data->bytes, data->stats) < 0) {
+ if (git_remote_download(data->remote, NULL, NULL) < 0) {
data->ret = -1;
goto exit;
}
@@ -36,13 +44,13 @@ static void *download(void *ptr)
exit:
data->finished = 1;
- pthread_exit(&data->ret);
+ return &data->ret;
}
-int update_cb(const char *refname, const git_oid *a, const git_oid *b)
+static int update_cb(const char *refname, const git_oid *a, const git_oid *b, void *data)
{
- const char *action;
char a_str[GIT_OID_HEXSZ+1], b_str[GIT_OID_HEXSZ+1];
+ (void)data;
git_oid_fmt(b_str, b);
b_str[GIT_OID_HEXSZ] = '\0';
@@ -60,54 +68,80 @@ int update_cb(const char *refname, const git_oid *a, const git_oid *b)
int fetch(git_repository *repo, int argc, char **argv)
{
- git_remote *remote = NULL;
- git_off_t bytes = 0;
- git_indexer_stats stats;
- pthread_t worker;
- struct dl_data data;
-
- // Figure out whether it's a named remote or a URL
- printf("Fetching %s\n", argv[1]);
- if (git_remote_load(&remote, repo, argv[1]) < 0) {
- if (git_remote_new(&remote, repo, NULL, argv[1], NULL) < 0)
- return -1;
- }
-
- // Set up the information for the background worker thread
- data.remote = remote;
- data.bytes = &bytes;
- data.stats = &stats;
- data.ret = 0;
- data.finished = 0;
- memset(&stats, 0, sizeof(stats));
-
- pthread_create(&worker, NULL, download, &data);
-
- // Loop while the worker thread is still running. Here we show processed
- // and total objects in the pack and the amount of received
- // data. Most frontends will probably want to show a percentage and
- // the download rate.
- do {
- usleep(10000);
- printf("\rReceived %d/%d objects in %d bytes", stats.processed, stats.total, bytes);
- } while (!data.finished);
- printf("\rReceived %d/%d objects in %d bytes\n", stats.processed, stats.total, bytes);
-
- // Disconnect the underlying connection to prevent from idling.
- git_remote_disconnect(remote);
-
- // Update the references in the remote's namespace to point to the
- // right commits. This may be needed even if there was no packfile
- // to download, which can happen e.g. when the branches have been
- // changed but all the neede objects are available locally.
- if (git_remote_update_tips(remote, update_cb) < 0)
- return -1;
-
- git_remote_free(remote);
-
- return 0;
-
-on_error:
- git_remote_free(remote);
- return -1;
+ git_remote *remote = NULL;
+ const git_transfer_progress *stats;
+ struct dl_data data;
+ git_remote_callbacks callbacks = GIT_REMOTE_CALLBACKS_INIT;
+#ifndef _WIN32
+ pthread_t worker;
+#endif
+
+ if (argc < 2) {
+ fprintf(stderr, "usage: %s fetch <repo>\n", argv[-1]);
+ return EXIT_FAILURE;
+ }
+
+ // Figure out whether it's a named remote or a URL
+ printf("Fetching %s for repo %p\n", argv[1], repo);
+ if (git_remote_load(&remote, repo, argv[1]) < 0) {
+ if (git_remote_create_inmemory(&remote, repo, NULL, argv[1]) < 0)
+ return -1;
+ }
+
+ // Set up the callbacks (only update_tips for now)
+ callbacks.update_tips = &update_cb;
+ callbacks.progress = &progress_cb;
+ git_remote_set_callbacks(remote, &callbacks);
+
+ // Set up the information for the background worker thread
+ data.remote = remote;
+ data.ret = 0;
+ data.finished = 0;
+
+ stats = git_remote_stats(remote);
+
+#ifdef _WIN32
+ download(&data);
+#else
+ pthread_create(&worker, NULL, download, &data);
+
+ // Loop while the worker thread is still running. Here we show processed
+ // and total objects in the pack and the amount of received
+ // data. Most frontends will probably want to show a percentage and
+ // the download rate.
+ do {
+ usleep(10000);
+
+ if (stats->total_objects > 0)
+ printf("Received %d/%d objects (%d) in %" PRIuZ " bytes\r",
+ stats->received_objects, stats->total_objects,
+ stats->indexed_objects, stats->received_bytes);
+ } while (!data.finished);
+
+ if (data.ret < 0)
+ goto on_error;
+
+ pthread_join(worker, NULL);
+#endif
+
+ printf("\rReceived %d/%d objects in %zu bytes\n",
+ stats->indexed_objects, stats->total_objects, stats->received_bytes);
+
+ // Disconnect the underlying connection to prevent from idling.
+ git_remote_disconnect(remote);
+
+ // Update the references in the remote's namespace to point to the
+ // right commits. This may be needed even if there was no packfile
+ // to download, which can happen e.g. when the branches have been
+ // changed but all the neede objects are available locally.
+ if (git_remote_update_tips(remote) < 0)
+ return -1;
+
+ git_remote_free(remote);
+
+ return 0;
+
+ on_error:
+ git_remote_free(remote);
+ return -1;
}
diff --git a/examples/network/git2.c b/examples/network/git2.c
index 7c02305c4..ecb16630b 100644
--- a/examples/network/git2.c
+++ b/examples/network/git2.c
@@ -1,5 +1,6 @@
#include <stdlib.h>
#include <stdio.h>
+#include <string.h>
#include "common.h"
@@ -12,11 +13,12 @@ struct {
} commands[] = {
{"ls-remote", ls_remote},
{"fetch", fetch},
+ {"clone", do_clone},
{"index-pack", index_pack},
{ NULL, NULL}
};
-int run_command(git_cb fn, int argc, char **argv)
+static int run_command(git_cb fn, int argc, char **argv)
{
int error;
git_repository *repo;
@@ -45,7 +47,7 @@ int run_command(git_cb fn, int argc, char **argv)
int main(int argc, char **argv)
{
- int i, error;
+ int i;
if (argc < 2) {
fprintf(stderr, "usage: %s <cmd> [repo]\n", argv[0]);
diff --git a/examples/network/index-pack.c b/examples/network/index-pack.c
index 03f3ae37e..889305da8 100644
--- a/examples/network/index-pack.c
+++ b/examples/network/index-pack.c
@@ -2,101 +2,87 @@
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#ifdef _WIN32
+# include <io.h>
+# include <Windows.h>
+
+# define open _open
+# define read _read
+# define close _close
+
+#define ssize_t unsigned int
+#else
+# include <unistd.h>
+#endif
#include "common.h"
// This could be run in the main loop whilst the application waits for
// the indexing to finish in a worker thread
-int index_cb(const git_indexer_stats *stats, void *data)
+static int index_cb(const git_transfer_progress *stats, void *data)
{
- printf("\rProcessing %d of %d", stats->processed, stats->total);
-}
+ (void)data;
+ printf("\rProcessing %d of %d", stats->indexed_objects, stats->total_objects);
-int index_pack(git_repository *repo, int argc, char **argv)
-{
- git_indexer_stream *idx;
- git_indexer_stats stats = {0, 0};
- int error, fd;
- char hash[GIT_OID_HEXSZ + 1] = {0};
- ssize_t read_bytes;
- char buf[512];
-
- if (argc < 2) {
- fprintf(stderr, "I need a packfile\n");
- return EXIT_FAILURE;
- }
-
- if (git_indexer_stream_new(&idx, ".git") < 0) {
- puts("bad idx");
- return -1;
- }
-
- if ((fd = open(argv[1], 0)) < 0) {
- perror("open");
- return -1;
- }
-
- do {
- read_bytes = read(fd, buf, sizeof(buf));
- if (read_bytes < 0)
- break;
-
- if ((error = git_indexer_stream_add(idx, buf, read_bytes, &stats)) < 0)
- goto cleanup;
-
- printf("\rIndexing %d of %d", stats.processed, stats.total);
- } while (read_bytes > 0);
-
- if (read_bytes < 0) {
- error = -1;
- perror("failed reading");
- goto cleanup;
- }
-
- if ((error = git_indexer_stream_finalize(idx, &stats)) < 0)
- goto cleanup;
-
- printf("\rIndexing %d of %d\n", stats.processed, stats.total);
-
- git_oid_fmt(hash, git_indexer_stream_hash(idx));
- puts(hash);
-
-cleanup:
- close(fd);
- git_indexer_stream_free(idx);
- return error;
+ return 0;
}
-int index_pack_old(git_repository *repo, int argc, char **argv)
+int index_pack(git_repository *repo, int argc, char **argv)
{
- git_indexer *indexer;
- git_indexer_stats stats;
- int error;
- char hash[GIT_OID_HEXSZ + 1] = {0};
-
- if (argc < 2) {
- fprintf(stderr, "I need a packfile\n");
- return EXIT_FAILURE;
- }
-
- // Create a new indexer
- error = git_indexer_new(&indexer, argv[1]);
- if (error < 0)
- return error;
-
- // Index the packfile. This function can take a very long time and
- // should be run in a worker thread.
- error = git_indexer_run(indexer, &stats);
- if (error < 0)
- return error;
-
- // Write the information out to an index file
- error = git_indexer_write(indexer);
-
- // Get the packfile's hash (which should become it's filename)
- git_oid_fmt(hash, git_indexer_hash(indexer));
- puts(hash);
-
- git_indexer_free(indexer);
-
- return 0;
+ git_indexer_stream *idx;
+ git_transfer_progress stats = {0, 0};
+ int error;
+ char hash[GIT_OID_HEXSZ + 1] = {0};
+ int fd;
+ ssize_t read_bytes;
+ char buf[512];
+
+ (void)repo;
+
+ if (argc < 2) {
+ fprintf(stderr, "usage: %s index-pack <packfile>\n", argv[-1]);
+ return EXIT_FAILURE;
+ }
+
+ if (git_indexer_stream_new(&idx, ".", NULL, NULL) < 0) {
+ puts("bad idx");
+ return -1;
+ }
+
+ if ((fd = open(argv[1], 0)) < 0) {
+ perror("open");
+ return -1;
+ }
+
+ do {
+ read_bytes = read(fd, buf, sizeof(buf));
+ if (read_bytes < 0)
+ break;
+
+ if ((error = git_indexer_stream_add(idx, buf, read_bytes, &stats)) < 0)
+ goto cleanup;
+
+ index_cb(&stats, NULL);
+ } while (read_bytes > 0);
+
+ if (read_bytes < 0) {
+ error = -1;
+ perror("failed reading");
+ goto cleanup;
+ }
+
+ if ((error = git_indexer_stream_finalize(idx, &stats)) < 0)
+ goto cleanup;
+
+ printf("\rIndexing %d of %d\n", stats.indexed_objects, stats.total_objects);
+
+ git_oid_fmt(hash, git_indexer_stream_hash(idx));
+ puts(hash);
+
+ cleanup:
+ close(fd);
+ git_indexer_stream_free(idx);
+ return error;
}
diff --git a/examples/network/ls-remote.c b/examples/network/ls-remote.c
index 39cc64725..252011828 100644
--- a/examples/network/ls-remote.c
+++ b/examples/network/ls-remote.c
@@ -7,25 +7,27 @@
static int show_ref__cb(git_remote_head *head, void *payload)
{
char oid[GIT_OID_HEXSZ + 1] = {0};
+
+ (void)payload;
git_oid_fmt(oid, &head->oid);
printf("%s\t%s\n", oid, head->name);
return 0;
}
-int use_unnamed(git_repository *repo, const char *url)
+static int use_unnamed(git_repository *repo, const char *url)
{
git_remote *remote = NULL;
int error;
// Create an instance of a remote from the URL. The transport to use
// is detected from the URL
- error = git_remote_new(&remote, repo, NULL, url, NULL);
+ error = git_remote_create_inmemory(&remote, repo, NULL, url);
if (error < 0)
goto cleanup;
// When connecting, the underlying code needs to know wether we
// want to push or fetch
- error = git_remote_connect(remote, GIT_DIR_FETCH);
+ error = git_remote_connect(remote, GIT_DIRECTION_FETCH);
if (error < 0)
goto cleanup;
@@ -37,7 +39,7 @@ cleanup:
return error;
}
-int use_remote(git_repository *repo, char *name)
+static int use_remote(git_repository *repo, char *name)
{
git_remote *remote = NULL;
int error;
@@ -47,7 +49,7 @@ int use_remote(git_repository *repo, char *name)
if (error < 0)
goto cleanup;
- error = git_remote_connect(remote, GIT_DIR_FETCH);
+ error = git_remote_connect(remote, GIT_DIRECTION_FETCH);
if (error < 0)
goto cleanup;
@@ -63,7 +65,12 @@ cleanup:
int ls_remote(git_repository *repo, int argc, char **argv)
{
- int error, i;
+ int error;
+
+ if (argc < 2) {
+ fprintf(stderr, "usage: %s ls-remote <remote>\n", argv[-1]);
+ return EXIT_FAILURE;
+ }
/* If there's a ':' in the name, assume it's an URL */
if (strchr(argv[1], ':') != NULL) {