Commit fd8126e4c605e749ed6ab1e31ac32366adc8cc8f

Carlos Martín Nieto 2014-09-30T08:54:52

describe: implement describing the workdir When we describe the workdir, we perform a describe on HEAD and then check to see if the worktree is dirty. If it is and we have a suffix string, we append that to the buffer.

diff --git a/include/git2/describe.h b/include/git2/describe.h
index 6007b00..8b80e18 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 0c77f15..40092d0 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(&current_id, repo, GIT_HEAD_FILE)) < 0)
+		return error;
+
+	if ((error = git_object_lookup(&commit, repo, &current_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 d975ddf..230e1bd 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 a666b46..6f79358 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 39489f3..2ac59a6 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,