Blame examples/describe.c

Packit Service 20376f
/*
Packit Service 20376f
 * libgit2 "describe" example - shows how to describe commits
Packit Service 20376f
 *
Packit Service 20376f
 * Written by the libgit2 contributors
Packit Service 20376f
 *
Packit Service 20376f
 * To the extent possible under law, the author(s) have dedicated all copyright
Packit Service 20376f
 * and related and neighboring rights to this software to the public domain
Packit Service 20376f
 * worldwide. This software is distributed without any warranty.
Packit Service 20376f
 *
Packit Service 20376f
 * You should have received a copy of the CC0 Public Domain Dedication along
Packit Service 20376f
 * with this software. If not, see
Packit Service 20376f
 * <http://creativecommons.org/publicdomain/zero/1.0/>.
Packit Service 20376f
 */
Packit Service 20376f
Packit Service 20376f
#include "common.h"
Packit Service 20376f
#include <assert.h>
Packit Service 20376f
Packit Service 20376f
/**
Packit Service 20376f
 * The following example partially reimplements the `git describe` command
Packit Service 20376f
 * and some of its options.
Packit Service 20376f
 *
Packit Service 20376f
 * These commands should work:
Packit Service 20376f
Packit Service 20376f
 * - Describe HEAD with default options (`describe`)
Packit Service 20376f
 * - Describe specified revision (`describe master~2`)
Packit Service 20376f
 * - Describe specified revisions (`describe master~2 HEAD~3`)
Packit Service 20376f
 * - Describe HEAD with dirty state suffix (`describe --dirty=*`)
Packit Service 20376f
 * - Describe consider all refs (`describe --all master`)
Packit Service 20376f
 * - Describe consider lightweight tags (`describe --tags temp-tag`)
Packit Service 20376f
 * - Describe show non-default abbreviated size (`describe --abbrev=10`)
Packit Service 20376f
 * - Describe always output the long format if matches a tag (`describe --long v1.0`)
Packit Service 20376f
 * - Describe consider only tags of specified pattern (`describe --match v*-release`)
Packit Service 20376f
 * - Describe show the fallback result (`describe --always`)
Packit Service 20376f
 * - Describe follow only the first parent commit (`describe --first-parent`)
Packit Service 20376f
 *
Packit Service 20376f
 * The command line parsing logic is simplified and doesn't handle
Packit Service 20376f
 * all of the use cases.
Packit Service 20376f
 */
Packit Service 20376f
Packit Service 20376f
/** describe_options represents the parsed command line options */
Packit Service 20376f
typedef struct {
Packit Service 20376f
	const char **commits;
Packit Service 20376f
	size_t commit_count;
Packit Service 20376f
	git_describe_options describe_options;
Packit Service 20376f
	git_describe_format_options format_options;
Packit Service 20376f
} describe_options;
Packit Service 20376f
Packit Service 20376f
typedef struct args_info args_info;
Packit Service 20376f
Packit Service 20376f
static void *xrealloc(void *oldp, size_t newsz)
Packit Service 20376f
{
Packit Service 20376f
	void *p = realloc(oldp, newsz);
Packit Service 20376f
	if (p == NULL) {
Packit Service 20376f
		fprintf(stderr, "Cannot allocate memory, exiting.\n");
Packit Service 20376f
		exit(1);
Packit Service 20376f
	}
Packit Service 20376f
	return p;
Packit Service 20376f
}
Packit Service 20376f
Packit Service 20376f
static void opts_add_commit(describe_options *opts, const char *commit)
Packit Service 20376f
{
Packit Service 20376f
	size_t sz;
Packit Service 20376f
Packit Service 20376f
	assert(opts != NULL);
Packit Service 20376f
Packit Service 20376f
	sz = ++opts->commit_count * sizeof(opts->commits[0]);
Packit Service 20376f
	opts->commits = xrealloc(opts->commits, sz);
Packit Service 20376f
	opts->commits[opts->commit_count - 1] = commit;
Packit Service 20376f
}
Packit Service 20376f
Packit Service 20376f
static void do_describe_single(git_repository *repo, describe_options *opts, const char *rev)
Packit Service 20376f
{
Packit Service 20376f
	git_object *commit;
Packit Service 20376f
	git_describe_result *describe_result;
Packit Service 20376f
	git_buf buf = { 0 };
Packit Service 20376f
	
Packit Service 20376f
	if (rev) {
Packit Service 20376f
		check_lg2(git_revparse_single(&commit, repo, rev),
Packit Service 20376f
			"Failed to lookup rev", rev);
Packit Service 20376f
Packit Service 20376f
		check_lg2(git_describe_commit(&describe_result, commit, &opts->describe_options),
Packit Service 20376f
			"Failed to describe rev", rev);
Packit Service 20376f
	}
Packit Service 20376f
	else
Packit Service 20376f
		check_lg2(git_describe_workdir(&describe_result, repo, &opts->describe_options),
Packit Service 20376f
			"Failed to describe workdir", NULL);
Packit Service 20376f
Packit Service 20376f
	check_lg2(git_describe_format(&buf, describe_result, &opts->format_options),
Packit Service 20376f
			"Failed to format describe rev", rev);
Packit Service 20376f
Packit Service 20376f
	printf("%s\n", buf.ptr);
Packit Service 20376f
}
Packit Service 20376f
Packit Service 20376f
static void do_describe(git_repository *repo, describe_options *opts)
Packit Service 20376f
{
Packit Service 20376f
	if (opts->commit_count == 0)
Packit Service 20376f
		do_describe_single(repo, opts, NULL);
Packit Service 20376f
	else
Packit Service 20376f
	{
Packit Service 20376f
		size_t i;
Packit Service 20376f
		for (i = 0; i < opts->commit_count; i++)
Packit Service 20376f
			do_describe_single(repo, opts, opts->commits[i]);
Packit Service 20376f
	}
Packit Service 20376f
}
Packit Service 20376f
Packit Service 20376f
static void print_usage(void)
Packit Service 20376f
{
Packit Service 20376f
	fprintf(stderr, "usage: see `git help describe`\n");
Packit Service 20376f
	exit(1);
Packit Service 20376f
}
Packit Service 20376f
Packit Service 20376f
/** Parse command line arguments */
Packit Service 20376f
static void parse_options(describe_options *opts, int argc, char **argv)
Packit Service 20376f
{
Packit Service 20376f
	args_info args = ARGS_INFO_INIT;
Packit Service 20376f
Packit Service 20376f
	for (args.pos = 1; args.pos < argc; ++args.pos) {
Packit Service 20376f
		const char *curr = argv[args.pos];
Packit Service 20376f
Packit Service 20376f
		if (curr[0] != '-') {
Packit Service 20376f
			opts_add_commit(opts, curr);
Packit Service 20376f
		} else if (!strcmp(curr, "--all")) {
Packit Service 20376f
			opts->describe_options.describe_strategy = GIT_DESCRIBE_ALL;
Packit Service 20376f
		} else if (!strcmp(curr, "--tags")) {
Packit Service 20376f
			opts->describe_options.describe_strategy = GIT_DESCRIBE_TAGS;
Packit Service 20376f
		} else if (!strcmp(curr, "--exact-match")) {
Packit Service 20376f
			opts->describe_options.max_candidates_tags = 0;
Packit Service 20376f
		} else if (!strcmp(curr, "--long")) {
Packit Service 20376f
			opts->format_options.always_use_long_format = 1;
Packit Service 20376f
		} else if (!strcmp(curr, "--always")) {
Packit Service 20376f
			opts->describe_options.show_commit_oid_as_fallback = 1;
Packit Service 20376f
		} else if (!strcmp(curr, "--first-parent")) {
Packit Service 20376f
			opts->describe_options.only_follow_first_parent = 1;
Packit Service 20376f
		} else if (optional_str_arg(&opts->format_options.dirty_suffix, &args, "--dirty", "-dirty")) {
Packit Service 20376f
		} else if (match_int_arg((int *)&opts->format_options.abbreviated_size, &args, "--abbrev", 0)) {
Packit Service 20376f
		} else if (match_int_arg((int *)&opts->describe_options.max_candidates_tags, &args, "--candidates", 0)) {
Packit Service 20376f
		} else if (match_str_arg(&opts->describe_options.pattern, &args, "--match")) {
Packit Service 20376f
		} else {
Packit Service 20376f
			print_usage();
Packit Service 20376f
		}
Packit Service 20376f
	}
Packit Service 20376f
Packit Service 20376f
	if (opts->commit_count > 0) {
Packit Service 20376f
		if (opts->format_options.dirty_suffix)
Packit Service 20376f
			fatal("--dirty is incompatible with commit-ishes", NULL);
Packit Service 20376f
	}
Packit Service 20376f
	else {
Packit Service 20376f
		if (!opts->format_options.dirty_suffix || !opts->format_options.dirty_suffix[0]) {
Packit Service 20376f
			opts_add_commit(opts, "HEAD");
Packit Service 20376f
		}
Packit Service 20376f
	}
Packit Service 20376f
}
Packit Service 20376f
Packit Service 20376f
/** Initialize describe_options struct */
Packit Service 20376f
static void describe_options_init(describe_options *opts)
Packit Service 20376f
{
Packit Service 20376f
	memset(opts, 0, sizeof(*opts));
Packit Service 20376f
Packit Service 20376f
	opts->commits = NULL;
Packit Service 20376f
	opts->commit_count = 0;
Packit Service 20376f
	git_describe_init_options(&opts->describe_options, GIT_DESCRIBE_OPTIONS_VERSION);
Packit Service 20376f
	git_describe_init_format_options(&opts->format_options, GIT_DESCRIBE_FORMAT_OPTIONS_VERSION);
Packit Service 20376f
}
Packit Service 20376f
Packit Service 20376f
int main(int argc, char **argv)
Packit Service 20376f
{
Packit Service 20376f
	git_repository *repo;
Packit Service 20376f
	describe_options opts;
Packit Service 20376f
Packit Service 20376f
	git_libgit2_init();
Packit Service 20376f
Packit Service 20376f
	check_lg2(git_repository_open_ext(&repo, ".", 0, NULL),
Packit Service 20376f
			"Could not open repository", NULL);
Packit Service 20376f
Packit Service 20376f
	describe_options_init(&opts);
Packit Service 20376f
	parse_options(&opts, argc, argv);
Packit Service 20376f
Packit Service 20376f
	do_describe(repo, &opts);
Packit Service 20376f
Packit Service 20376f
	git_repository_free(repo);
Packit Service 20376f
	git_libgit2_shutdown();
Packit Service 20376f
Packit Service 20376f
	return 0;
Packit Service 20376f
}