mirror of
https://git.proxmox.com/git/libgit2
synced 2025-05-29 00:30:27 +00:00
Merge pull request #2617 from linquize/describe-example
describe: add example
This commit is contained in:
commit
943fde7f8c
@ -53,6 +53,33 @@ size_t is_prefixed(const char *str, const char *pfx)
|
||||
return strncmp(str, pfx, len) ? 0 : len;
|
||||
}
|
||||
|
||||
int optional_str_arg(
|
||||
const char **out, struct args_info *args, const char *opt, const char *def)
|
||||
{
|
||||
const char *found = args->argv[args->pos];
|
||||
size_t len = is_prefixed(found, opt);
|
||||
|
||||
if (!len)
|
||||
return 0;
|
||||
|
||||
if (!found[len]) {
|
||||
if (args->pos + 1 == args->argc) {
|
||||
*out = def;
|
||||
return 1;
|
||||
}
|
||||
args->pos += 1;
|
||||
*out = args->argv[args->pos];
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (found[len] == '=') {
|
||||
*out = found + len + 1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int match_str_arg(
|
||||
const char **out, struct args_info *args, const char *opt)
|
||||
{
|
||||
|
@ -46,6 +46,15 @@ struct args_info {
|
||||
};
|
||||
#define ARGS_INFO_INIT { argc, argv, 0 }
|
||||
|
||||
/**
|
||||
* Check current `args` entry against `opt` string. If it matches
|
||||
* exactly, take the next arg as a string; if it matches as a prefix with
|
||||
* an equal sign, take the remainder as a string; if value not supplied,
|
||||
* default value `def` will be given. otherwise return 0.
|
||||
*/
|
||||
extern int optional_str_arg(
|
||||
const char **out, struct args_info *args, const char *opt, const char *def);
|
||||
|
||||
/**
|
||||
* Check current `args` entry against `opt` string. If it matches
|
||||
* exactly, take the next arg as a string; if it matches as a prefix with
|
||||
|
162
examples/describe.c
Normal file
162
examples/describe.c
Normal file
@ -0,0 +1,162 @@
|
||||
/*
|
||||
* libgit2 "describe" example - shows how to describe commits
|
||||
*
|
||||
* 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"
|
||||
|
||||
/**
|
||||
* The following example partially reimplements the `git describe` command
|
||||
* and some of its options.
|
||||
*
|
||||
* These commands should work:
|
||||
|
||||
* - Describe HEAD with default options (`describe`)
|
||||
* - Describe specified revision (`describe master~2`)
|
||||
* - Describe specified revisions (`describe master~2 HEAD~3`)
|
||||
* - Describe HEAD with dirty state suffix (`describe --dirty=*`)
|
||||
* - Describe consider all refs (`describe --all master`)
|
||||
* - Describe consider lightweight tags (`describe --tags temp-tag`)
|
||||
* - Describe show non-default abbreviated size (`describe --abbrev=10`)
|
||||
* - Describe always output the long format if matches a tag (`describe --long v1.0`)
|
||||
* - Describe consider only tags of specified pattern (`describe --match v*-release`)
|
||||
* - Describe show the fallback result (`describe --always`)
|
||||
* - Describe follow only the first parent commit (`describe --first-parent`)
|
||||
*
|
||||
* The command line parsing logic is simplified and doesn't handle
|
||||
* all of the use cases.
|
||||
*/
|
||||
|
||||
/** describe_options represents the parsed command line options */
|
||||
typedef struct {
|
||||
const char **commits;
|
||||
size_t commit_count;
|
||||
git_describe_options describe_options;
|
||||
git_describe_format_options format_options;
|
||||
} describe_options;
|
||||
|
||||
typedef struct args_info args_info;
|
||||
|
||||
static void do_describe_single(git_repository *repo, describe_options *opts, const char *rev)
|
||||
{
|
||||
git_object *commit;
|
||||
git_describe_result *describe_result;
|
||||
git_buf buf = { 0 };
|
||||
|
||||
if (rev) {
|
||||
check_lg2(git_revparse_single(&commit, repo, rev),
|
||||
"Failed to lookup rev", rev);
|
||||
|
||||
check_lg2(git_describe_commit(&describe_result, commit, &opts->describe_options),
|
||||
"Failed to describe rev", rev);
|
||||
}
|
||||
else
|
||||
check_lg2(git_describe_workdir(&describe_result, repo, &opts->describe_options),
|
||||
"Failed to describe workdir", NULL);
|
||||
|
||||
check_lg2(git_describe_format(&buf, describe_result, &opts->format_options),
|
||||
"Failed to format describe rev", rev);
|
||||
|
||||
printf("%s\n", buf.ptr);
|
||||
}
|
||||
|
||||
static void do_describe(git_repository *repo, describe_options *opts)
|
||||
{
|
||||
if (opts->commit_count == 0)
|
||||
do_describe_single(repo, opts, NULL);
|
||||
else
|
||||
{
|
||||
size_t i;
|
||||
for (i = 0; i < opts->commit_count; i++)
|
||||
do_describe_single(repo, opts, opts->commits[i]);
|
||||
}
|
||||
}
|
||||
|
||||
static void print_usage(void)
|
||||
{
|
||||
fprintf(stderr, "usage: see `git help describe`\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/** Parse command line arguments */
|
||||
static void parse_options(describe_options *opts, int argc, char **argv)
|
||||
{
|
||||
args_info args = ARGS_INFO_INIT;
|
||||
|
||||
for (args.pos = 1; args.pos < argc; ++args.pos) {
|
||||
const char *curr = argv[args.pos];
|
||||
|
||||
if (curr[0] != '-') {
|
||||
opts->commits = (const char **)realloc((void *)opts->commits, ++opts->commit_count);
|
||||
opts->commits[opts->commit_count - 1] = curr;
|
||||
} else if (!strcmp(curr, "--all")) {
|
||||
opts->describe_options.describe_strategy = GIT_DESCRIBE_ALL;
|
||||
} else if (!strcmp(curr, "--tags")) {
|
||||
opts->describe_options.describe_strategy = GIT_DESCRIBE_TAGS;
|
||||
} else if (!strcmp(curr, "--exact-match")) {
|
||||
opts->describe_options.max_candidates_tags = 0;
|
||||
} else if (!strcmp(curr, "--long")) {
|
||||
opts->format_options.always_use_long_format = 1;
|
||||
} else if (!strcmp(curr, "--always")) {
|
||||
opts->describe_options.show_commit_oid_as_fallback = 1;
|
||||
} else if (!strcmp(curr, "--first-parent")) {
|
||||
opts->describe_options.only_follow_first_parent = 1;
|
||||
} else if (optional_str_arg(&opts->format_options.dirty_suffix, &args, "--dirty", "-dirty")) {
|
||||
} else if (match_int_arg((int *)&opts->format_options.abbreviated_size, &args, "--abbrev", 0)) {
|
||||
} else if (match_int_arg((int *)&opts->describe_options.max_candidates_tags, &args, "--candidates", 0)) {
|
||||
} else if (match_str_arg(&opts->describe_options.pattern, &args, "--match")) {
|
||||
}
|
||||
}
|
||||
|
||||
if (opts->commit_count > 0) {
|
||||
if (opts->format_options.dirty_suffix)
|
||||
fatal("--dirty is incompatible with commit-ishes", NULL);
|
||||
}
|
||||
else {
|
||||
if (!opts->format_options.dirty_suffix || !opts->format_options.dirty_suffix[0]) {
|
||||
opts->commits = (const char **)malloc(++opts->commit_count);
|
||||
opts->commits[0] = "HEAD";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Initialize describe_options struct */
|
||||
static void describe_options_init(describe_options *opts)
|
||||
{
|
||||
memset(opts, 0, sizeof(*opts));
|
||||
|
||||
opts->commits = NULL;
|
||||
opts->commit_count = 0;
|
||||
git_describe_init_options(&opts->describe_options, GIT_DESCRIBE_OPTIONS_VERSION);
|
||||
git_describe_init_format_options(&opts->format_options, GIT_DESCRIBE_FORMAT_OPTIONS_VERSION);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
git_repository *repo;
|
||||
describe_options opts;
|
||||
|
||||
git_threads_init();
|
||||
|
||||
check_lg2(git_repository_open_ext(&repo, ".", 0, NULL),
|
||||
"Could not open repository", NULL);
|
||||
|
||||
describe_options_init(&opts);
|
||||
parse_options(&opts, argc, argv);
|
||||
|
||||
do_describe(repo, &opts);
|
||||
|
||||
git_repository_free(repo);
|
||||
git_threads_shutdown();
|
||||
|
||||
return 0;
|
||||
}
|
Loading…
Reference in New Issue
Block a user