#include "common.h" #include #include #include #include #include #include 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) { data = 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) { data->ret = -1; goto exit; } // 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) { data->ret = -1; goto exit; } data->ret = 0; exit: data->finished = 1; pthread_exit(&data->ret); } static int update_cb(const char *refname, const git_oid *a, const git_oid *b, void *data) { char a_str[GIT_OID_HEXSZ+1], b_str[GIT_OID_HEXSZ+1]; data = data; git_oid_fmt(b_str, b); b_str[GIT_OID_HEXSZ] = '\0'; if (git_oid_iszero(a)) { printf("[new] %.20s %s\n", b_str, refname); } else { git_oid_fmt(a_str, a); a_str[GIT_OID_HEXSZ] = '\0'; printf("[updated] %.10s..%.10s %s\n", a_str, b_str, refname); } return 0; } 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; git_remote_callbacks callbacks; argc = argc; // 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 callbacks (only update_tips for now) memset(&callbacks, 0, sizeof(callbacks)); 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.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); if (stats.total > 0) printf("Received %d/%d objects (%d) in %d bytes\r", stats.received, stats.total, stats.processed, bytes); } while (!data.finished); if (data.ret < 0) goto on_error; pthread_join(worker, NULL); printf("\rReceived %d/%d objects in %zu 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) < 0) return -1; git_remote_free(remote); return 0; on_error: git_remote_free(remote); return -1; }