diff --git a/include/git2/describe.h b/include/git2/describe.h index 6007b004e..8b80e1806 100644 --- a/include/git2/describe.h +++ b/include/git2/describe.h @@ -75,6 +75,11 @@ GIT_EXTERN(int) git_describe_commit( git_object *committish, git_describe_opts *opts); +GIT_EXTERN(int) git_describe_workdir( + git_describe_result **out, + git_repository *repo, + git_describe_opts *opts); + GIT_EXTERN(int) git_describe_format(git_buf *out, const git_describe_result *result, const git_describe_format_options *opts); GIT_EXTERN(void) git_describe_result_free(git_describe_result *result); diff --git a/src/describe.c b/src/describe.c index 0c77f1537..40092d003 100644 --- a/src/describe.c +++ b/src/describe.c @@ -5,6 +5,9 @@ * a Linking Exception. For full terms see the included COPYING file. */ #include "git2/describe.h" +#include "git2/strarray.h" +#include "git2/diff.h" +#include "git2/status.h" #include "common.h" #include "commit.h" @@ -385,7 +388,6 @@ static int show_suffix( git_buf_printf(buf, "-%d-g", depth); git_buf_put(buf, hex_oid, size); - git_buf_putc(buf, '\0'); return git_buf_oom(buf) ? -1 : 0; } @@ -699,6 +701,47 @@ cleanup: return error; } +int git_describe_workdir( + git_describe_result **out, + git_repository *repo, + git_describe_opts *opts) +{ + int error; + git_oid current_id; + git_status_list *status = NULL; + git_status_options status_opts = GIT_STATUS_OPTIONS_INIT; + git_describe_result *result; + git_object *commit; + + if ((error = git_reference_name_to_id(¤t_id, repo, GIT_HEAD_FILE)) < 0) + return error; + + if ((error = git_object_lookup(&commit, repo, ¤t_id, GIT_OBJ_COMMIT)) < 0) + return error; + + /* The first step is to perform a describe of HEAD, so we can leverage this */ + if ((error = git_describe_commit(&result, commit, opts)) < 0) + goto out; + + if ((error = git_status_list_new(&status, repo, &status_opts)) < 0) + goto out; + + + if (git_status_list_entrycount(status) > 0) + result->dirty = 1; + +out: + git_object_free(commit); + git_status_list_free(status); + + if (error < 0) + git_describe_result_free(result); + else + *out = result; + + return error; +} + int git_describe_format(git_buf *out, const git_describe_result *result, const git_describe_format_options *opts) { int error; @@ -744,13 +787,13 @@ int git_describe_format(git_buf *out, const git_describe_result *result, const g char hex_oid[GIT_OID_HEXSZ + 1] = {0}; int size; if ((error = find_unique_abbrev_size( - &size, &result->commit_id, opts->abbreviated_size)) < 0) + &size, repo, &result->commit_id, opts->abbreviated_size)) < 0) return -1; git_oid_fmt(hex_oid, &result->commit_id); git_buf_put(out, hex_oid, size); - if (opts->dirty_suffix) + if (result->dirty && opts->dirty_suffix) git_buf_puts(out, opts->dirty_suffix); return git_buf_oom(out) ? -1 : 0; @@ -765,12 +808,12 @@ int git_describe_format(git_buf *out, const git_describe_result *result, const g if (opts->abbreviated_size) { if ((error = show_suffix(out, result->tag->depth, &result->commit_id, opts->abbreviated_size)) < 0) - return -1; + return error; } - if (opts->dirty_suffix) + if (result->dirty && opts->dirty_suffix) { git_buf_puts(out, opts->dirty_suffix); - + } return git_buf_oom(out) ? -1 : 0; } diff --git a/tests/describe/describe_helpers.c b/tests/describe/describe_helpers.c index d975ddf4b..230e1bd15 100644 --- a/tests/describe/describe_helpers.c +++ b/tests/describe/describe_helpers.c @@ -26,3 +26,29 @@ void assert_describe( git_object_free(object); git_buf_free(&label); } + +void assert_describe_workdir( + const char *expected_output, + const char *expected_suffix, + git_repository *repo, + git_describe_opts *opts, + git_describe_format_options *fmt_opts, + bool is_prefix_match) +{ + git_buf label = GIT_BUF_INIT; + git_describe_result *result; + + cl_git_pass(git_describe_workdir(&result, repo, opts)); + cl_git_pass(git_describe_format(&label, result, fmt_opts)); + + if (is_prefix_match) + cl_assert_equal_i(0, git__prefixcmp(git_buf_cstr(&label), expected_output)); + else + cl_assert_equal_s(expected_output, label); + + if (expected_suffix) + cl_assert_equal_i(0, git__suffixcmp(git_buf_cstr(&label), expected_suffix)); + + git_describe_result_free(result); + git_buf_free(&label); +} diff --git a/tests/describe/describe_helpers.h b/tests/describe/describe_helpers.h index a666b46cf..6f793582c 100644 --- a/tests/describe/describe_helpers.h +++ b/tests/describe/describe_helpers.h @@ -8,3 +8,11 @@ extern void assert_describe( git_describe_opts *opts, git_describe_format_options *fmt_opts, bool is_prefix_match); + +extern void assert_describe_workdir( + const char *expected_output, + const char *expected_suffix, + git_repository *repo, + git_describe_opts *opts, + git_describe_format_options *fmt_opts, + bool is_prefix_match); diff --git a/tests/describe/t6120.c b/tests/describe/t6120.c index 39489f3c5..2ac59a6bc 100644 --- a/tests/describe/t6120.c +++ b/tests/describe/t6120.c @@ -77,6 +77,20 @@ void test_describe_t6120__firstparent(void) assert_describe("e-3-", "HEAD", repo, &opts, &fmt_opts, true); } +void test_describe_t6120__workdir(void) +{ + git_describe_opts opts = GIT_DESCRIBE_OPTIONS_INIT; + git_describe_format_options fmt_opts = GIT_DESCRIBE_FORMAT_OPTIONS_INIT; + + assert_describe_workdir("A-", NULL, repo, &opts, &fmt_opts, true); + cl_git_mkfile("describe/file", "something different"); + + fmt_opts.dirty_suffix = "-dirty"; + assert_describe_workdir("A-", "-dirty", repo, &opts, &fmt_opts, true); + fmt_opts.dirty_suffix = ".mod"; + assert_describe_workdir("A-", ".mod", repo, &opts, &fmt_opts, true); +} + static void commit_and_tag( git_time_t *time, const char *commit_msg,