| #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; |
| } |