diff options
Diffstat (limited to 'examples/network')
| -rw-r--r-- | examples/network/Makefile | 11 | ||||
| -rw-r--r-- | examples/network/clone.c | 122 | ||||
| -rw-r--r-- | examples/network/common.h | 10 | ||||
| -rw-r--r-- | examples/network/fetch.c | 150 | ||||
| -rw-r--r-- | examples/network/git2.c | 6 | ||||
| -rw-r--r-- | examples/network/index-pack.c | 162 | ||||
| -rw-r--r-- | examples/network/ls-remote.c | 19 |
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) { |
