diff options
Diffstat (limited to 'examples/network/clone.c')
-rw-r--r-- | examples/network/clone.c | 122 |
1 files changed, 122 insertions, 0 deletions
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; +} |