diff options
Diffstat (limited to 'examples/cat-file.c')
-rw-r--r-- | examples/cat-file.c | 239 |
1 files changed, 239 insertions, 0 deletions
diff --git a/examples/cat-file.c b/examples/cat-file.c new file mode 100644 index 0000000..741edb4 --- /dev/null +++ b/examples/cat-file.c @@ -0,0 +1,239 @@ +/* + * libgit2 "cat-file" example - shows how to print data from the ODB + * + * Written by the libgit2 contributors + * + * To the extent possible under law, the author(s) have dedicated all copyright + * and related and neighboring rights to this software to the public domain + * worldwide. This software is distributed without any warranty. + * + * You should have received a copy of the CC0 Public Domain Dedication along + * with this software. If not, see + * <http://creativecommons.org/publicdomain/zero/1.0/>. + */ + +#include "common.h" + +static void print_signature(const char *header, const git_signature *sig) +{ + char sign; + int offset, hours, minutes; + + if (!sig) + return; + + offset = sig->when.offset; + if (offset < 0) { + sign = '-'; + offset = -offset; + } else { + sign = '+'; + } + + hours = offset / 60; + minutes = offset % 60; + + printf("%s %s <%s> %ld %c%02d%02d\n", + header, sig->name, sig->email, (long)sig->when.time, + sign, hours, minutes); +} + +/** Printing out a blob is simple, get the contents and print */ +static void show_blob(const git_blob *blob) +{ + /* ? Does this need crlf filtering? */ + fwrite(git_blob_rawcontent(blob), (size_t)git_blob_rawsize(blob), 1, stdout); +} + +/** Show each entry with its type, id and attributes */ +static void show_tree(const git_tree *tree) +{ + size_t i, max_i = (int)git_tree_entrycount(tree); + char oidstr[GIT_OID_SHA1_HEXSIZE + 1]; + const git_tree_entry *te; + + for (i = 0; i < max_i; ++i) { + te = git_tree_entry_byindex(tree, i); + + git_oid_tostr(oidstr, sizeof(oidstr), git_tree_entry_id(te)); + + printf("%06o %s %s\t%s\n", + git_tree_entry_filemode(te), + git_object_type2string(git_tree_entry_type(te)), + oidstr, git_tree_entry_name(te)); + } +} + +/** + * Commits and tags have a few interesting fields in their header. + */ +static void show_commit(const git_commit *commit) +{ + unsigned int i, max_i; + char oidstr[GIT_OID_SHA1_HEXSIZE + 1]; + + git_oid_tostr(oidstr, sizeof(oidstr), git_commit_tree_id(commit)); + printf("tree %s\n", oidstr); + + max_i = (unsigned int)git_commit_parentcount(commit); + for (i = 0; i < max_i; ++i) { + git_oid_tostr(oidstr, sizeof(oidstr), git_commit_parent_id(commit, i)); + printf("parent %s\n", oidstr); + } + + print_signature("author", git_commit_author(commit)); + print_signature("committer", git_commit_committer(commit)); + + if (git_commit_message(commit)) + printf("\n%s\n", git_commit_message(commit)); +} + +static void show_tag(const git_tag *tag) +{ + char oidstr[GIT_OID_SHA1_HEXSIZE + 1]; + + git_oid_tostr(oidstr, sizeof(oidstr), git_tag_target_id(tag));; + printf("object %s\n", oidstr); + printf("type %s\n", git_object_type2string(git_tag_target_type(tag))); + printf("tag %s\n", git_tag_name(tag)); + print_signature("tagger", git_tag_tagger(tag)); + + if (git_tag_message(tag)) + printf("\n%s\n", git_tag_message(tag)); +} + +typedef enum { + SHOW_TYPE = 1, + SHOW_SIZE = 2, + SHOW_NONE = 3, + SHOW_PRETTY = 4 +} catfile_mode; + +/* Forward declarations for option-parsing helper */ +struct catfile_options { + const char *dir; + const char *rev; + catfile_mode action; + int verbose; +}; + +static void parse_opts(struct catfile_options *o, int argc, char *argv[]); + + +/** Entry point for this command */ +int lg2_cat_file(git_repository *repo, int argc, char *argv[]) +{ + struct catfile_options o = { ".", NULL, 0, 0 }; + git_object *obj = NULL; + char oidstr[GIT_OID_SHA1_HEXSIZE + 1]; + + parse_opts(&o, argc, argv); + + check_lg2(git_revparse_single(&obj, repo, o.rev), + "Could not resolve", o.rev); + + if (o.verbose) { + char oidstr[GIT_OID_SHA1_HEXSIZE + 1]; + git_oid_tostr(oidstr, sizeof(oidstr), git_object_id(obj)); + + printf("%s %s\n--\n", + git_object_type2string(git_object_type(obj)), oidstr); + } + + switch (o.action) { + case SHOW_TYPE: + printf("%s\n", git_object_type2string(git_object_type(obj))); + break; + case SHOW_SIZE: { + git_odb *odb; + git_odb_object *odbobj; + + check_lg2(git_repository_odb(&odb, repo), "Could not open ODB", NULL); + check_lg2(git_odb_read(&odbobj, odb, git_object_id(obj)), + "Could not find obj", NULL); + + printf("%ld\n", (long)git_odb_object_size(odbobj)); + + git_odb_object_free(odbobj); + git_odb_free(odb); + } + break; + case SHOW_NONE: + /* just want return result */ + break; + case SHOW_PRETTY: + + switch (git_object_type(obj)) { + case GIT_OBJECT_BLOB: + show_blob((const git_blob *)obj); + break; + case GIT_OBJECT_COMMIT: + show_commit((const git_commit *)obj); + break; + case GIT_OBJECT_TREE: + show_tree((const git_tree *)obj); + break; + case GIT_OBJECT_TAG: + show_tag((const git_tag *)obj); + break; + default: + printf("unknown %s\n", oidstr); + break; + } + break; + } + + git_object_free(obj); + + return 0; +} + +/** Print out usage information */ +static void usage(const char *message, const char *arg) +{ + if (message && arg) + fprintf(stderr, "%s: %s\n", message, arg); + else if (message) + fprintf(stderr, "%s\n", message); + fprintf(stderr, + "usage: cat-file (-t | -s | -e | -p) [-v] [-q] " + "[-h|--help] [--git-dir=<dir>] <object>\n"); + exit(1); +} + +/** Parse the command-line options taken from git */ +static void parse_opts(struct catfile_options *o, int argc, char *argv[]) +{ + struct args_info args = ARGS_INFO_INIT; + + for (args.pos = 1; args.pos < argc; ++args.pos) { + char *a = argv[args.pos]; + + if (a[0] != '-') { + if (o->rev != NULL) + usage("Only one rev should be provided", NULL); + else + o->rev = a; + } + else if (!strcmp(a, "-t")) + o->action = SHOW_TYPE; + else if (!strcmp(a, "-s")) + o->action = SHOW_SIZE; + else if (!strcmp(a, "-e")) + o->action = SHOW_NONE; + else if (!strcmp(a, "-p")) + o->action = SHOW_PRETTY; + else if (!strcmp(a, "-q")) + o->verbose = 0; + else if (!strcmp(a, "-v")) + o->verbose = 1; + else if (!strcmp(a, "--help") || !strcmp(a, "-h")) + usage(NULL, NULL); + else if (!match_str_arg(&o->dir, &args, "--git-dir")) + usage("Unknown option", a); + } + + if (!o->action || !o->rev) + usage(NULL, NULL); + +} |