Commit 24012627 by Carlos Martín Nieto

examples: add ls-remote, fetch and index-pack examples

Signed-off-by: Carlos Martín Nieto <carlos@cmartin.tk>
parent cd19ca95
default: all
# If you've installed libgit2 to a non-standard location, you can use
# these lines to make pkg-config find it.
#LIBGIT2_PATH ?= $(HOME)/staging/libgit2/lib DEPS =
#$(shell PKG_CONFIG_PATH=$(LIBGIT2_PATH)/pkgconfig pkg-config --cflags
#--libs libgit2)
DEPS = $(shell pkg-config --cflags --libs libgit2)
CC = gcc
CFLAGS += -g
CFLAGS += $(DEPS)
OBJECTS = \
git2.o \
ls-remote.o \
fetch.o \
index-pack.o
all: $(OBJECTS)
$(CC) $(CFLAGS) -o git2 $(OBJECTS)
#ifndef __COMMON_H__
#define __COMMON_H__
#include <git2.h>
typedef int (*git_cb)(git_repository *, int , char **);
int ls_remote(git_repository *repo, int argc, char **argv);
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);
#endif /* __COMMON_H__ */
#include "common.h"
#include <git2.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
static void show_refs(git_headarray *refs)
{
int i;
git_remote_head *head;
if(refs->len == 0)
puts("Everything up-to-date");
for(i = 0; i < refs->len; ++i){
char oid[GIT_OID_HEXSZ + 1] = {0};
char *havewant;
head = refs->heads[i];
git_oid_fmt(oid, &head->oid);
printf("%s\t%s\n", oid, head->name);
}
}
static int rename_packfile(char *packname, git_indexer *idx)
{
char path[GIT_PATH_MAX], oid[GIT_OID_HEXSZ + 1], *slash;
int ret;
strcpy(path, packname);
slash = strrchr(path, '/');
if (!slash)
return GIT_EINVALIDARGS;
memset(oid, 0x0, sizeof(oid));
// The name of the packfile is given by it's hash which you can get
// with git_indexer_hash after the index has been written out to
// disk. Rename the packfile to its "real" name in the same
// directory as it was originally (libgit2 stores it in the folder
// where the packs go, so a rename in place is the right thing to do here
git_oid_fmt(oid, git_indexer_hash(idx));
ret = sprintf(slash + 1, "pack-%s.pack", oid);
if(ret < 0)
return GIT_EOSERR;
printf("Renaming pack to %s\n", path);
return rename(packname, path);
}
int fetch(git_repository *repo, int argc, char **argv)
{
git_remote *remote = NULL;
git_config *cfg = NULL;
git_indexer *idx = NULL;
git_indexer_stats stats;
int error;
char *packname = NULL;
// Load the repository's configuration
error = git_repository_config(&cfg, repo, NULL, NULL);
if (error < GIT_SUCCESS)
return error;
// Get the remote and connect to it
printf("Fetching %s\n", argv[1]);
error = git_remote_get(&remote, cfg, argv[1]);
if (error < GIT_SUCCESS)
return error;
error = git_remote_connect(remote, GIT_DIR_FETCH);
if (error < GIT_SUCCESS)
return error;
// Perform the packfile negotiation. This is where the two ends
// figure out the minimal amount of data that should be transmitted
// to bring the repository up-to-date
error = git_remote_negotiate(remote);
if (error < GIT_SUCCESS)
return error;
// Download the packfile from the server. As we don't know its hash
// yet, it will get a temporary filename
error = git_remote_download(&packname, remote);
if (error < GIT_SUCCESS)
return error;
// No error and a NULL packname means no packfile was needed
if (packname != NULL) {
printf("The packname is %s\n", packname);
// Create a new instance indexer
error = git_indexer_new(&idx, packname);
if (error < GIT_SUCCESS)
return error;
// This should be run in paralel, but it'd be too complicated for the example
error = git_indexer_run(idx, &stats);
if (error < GIT_SUCCESS)
return error;
printf("Received %d objects\n", stats.total);
// Write the index file. The index will be stored with the
// correct filename
error = git_indexer_write(idx);
if (error < GIT_SUCCESS)
return error;
error = rename_packfile(packname, idx);
if (error < GIT_SUCCESS)
return error;
}
// 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.
error = git_remote_update_tips(remote);
if (error < GIT_SUCCESS)
return error;
free(packname);
git_indexer_free(idx);
git_remote_free(remote);
return GIT_SUCCESS;
}
#include <stdlib.h>
#include <stdio.h>
#include "common.h"
// This part is not strictly libgit2-dependent, but you can use this
// as a starting point for a git-like tool
struct {
char *name;
git_cb fn;
} commands[] = {
{"ls-remote", ls_remote},
{"fetch", fetch},
{"index-pack", index_pack},
{ NULL, NULL}
};
int run_command(git_cb fn, int argc, char **argv)
{
int error;
git_repository *repo;
// Before running the actual command, create an instance of the local
// repository and pass it to the function.
error = git_repository_open(&repo, ".git");
if (error < GIT_SUCCESS)
repo = NULL;
// Run the command. If something goes wrong, print the error message to stderr
error = fn(repo, argc, argv);
if (error < GIT_SUCCESS)
fprintf(stderr, "Bad news:\n %s\n", git_lasterror());
if(repo)
git_repository_free(repo);
return !!error;
}
int main(int argc, char **argv)
{
int i, error;
if (argc < 2) {
fprintf(stderr, "usage: %s <cmd> [repo]", argv[0]);
}
for (i = 0; commands[i].name != NULL; ++i) {
if (!strcmp(argv[1], commands[i].name))
return run_command(commands[i].fn, --argc, ++argv);
}
fprintf(stderr, "Command not found: %s\n", argv[1]);
}
#include <git2.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#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)
{
printf("\rProcessing %d of %d", stats->processed, stats->total);
}
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 < GIT_SUCCESS)
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 < GIT_SUCCESS)
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 GIT_SUCCESS;
}
#include <git2.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "common.h"
static void show_refs(git_headarray *refs)
{
int i;
git_remote_head *head;
// Take each head that the remote has advertised, store the string
// representation of the OID in a buffer and print it
for(i = 0; i < refs->len; ++i){
char oid[GIT_OID_HEXSZ + 1] = {0};
head = refs->heads[i];
git_oid_fmt(oid, &head->oid);
printf("%s\t%s\n", oid, head->name);
}
}
int use_unnamed(git_repository *repo, const char *url)
{
git_remote *remote = NULL;
git_headarray refs;
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, url);
if (error < GIT_SUCCESS)
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);
if (error < GIT_SUCCESS)
goto cleanup;
// With git_remote_ls we can retrieve the advertised heads
error = git_remote_ls(remote, &refs);
if (error < GIT_SUCCESS)
goto cleanup;
show_refs(&refs);
cleanup:
git_remote_free(remote);
return error;
}
int use_remote(git_repository *repo, char *name)
{
git_remote *remote = NULL;
git_config *cfg = NULL;
git_headarray refs;
int error;
// Load the local configuration for the repository
error = git_repository_config(&cfg, repo, NULL, NULL);
if (error < GIT_SUCCESS)
return error;
// Find the remote by name
error = git_remote_get(&remote, cfg, name);
if (error < GIT_SUCCESS)
goto cleanup;
error = git_remote_connect(remote, GIT_DIR_FETCH);
if (error < GIT_SUCCESS)
goto cleanup;
error = git_remote_ls(remote, &refs);
if (error < GIT_SUCCESS)
goto cleanup;
show_refs(&refs);
cleanup:
git_remote_free(remote);
return error;
}
// This gets called to do the work. The remote can be given either as
// the name of a configured remote or an URL.
int ls_remote(git_repository *repo, int argc, char **argv)
{
git_headarray heads;
git_remote_head *head;
int error, i;
/* If there's a ':' in the name, assume it's an URL */
if (strchr(argv[1], ':') != NULL) {
error = use_unnamed(repo, argv[1]);
} else {
error = use_remote(repo, argv[1]);
}
return error;
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment