Add support for Repository.describe(...). by impl · Pull Request #585 · libgit2/pygit2 · GitHub
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions docs/repository.rst
41 changes: 41 additions & 0 deletions pygit2/decl.h
Original file line number Diff line number Diff line change
Expand Up @@ -756,6 +756,47 @@ int git_merge_trees(git_index **out, git_repository *repo, const git_tree *ances
int git_merge_file_from_index(git_merge_file_result *out, git_repository *repo, const git_index_entry *ancestor, const git_index_entry *ours, const git_index_entry *theirs, const git_merge_file_options *opts);
void git_merge_file_result_free(git_merge_file_result *result);

/*
* Describe
*/

typedef enum {
GIT_DESCRIBE_DEFAULT,
GIT_DESCRIBE_TAGS,
GIT_DESCRIBE_ALL,
} git_describe_strategy_t;

typedef struct git_describe_options {
unsigned int version;
unsigned int max_candidates_tags;
unsigned int describe_strategy;
const char *pattern;
int only_follow_first_parent;
int show_commit_oid_as_fallback;
} git_describe_options;

#define GIT_DESCRIBE_OPTIONS_VERSION ...

int git_describe_init_options(git_describe_options *opts, unsigned int version);

typedef struct {
unsigned int version;
unsigned int abbreviated_size;
int always_use_long_format;
const char *dirty_suffix;
} git_describe_format_options;

#define GIT_DESCRIBE_FORMAT_OPTIONS_VERSION ...

int git_describe_init_format_options(git_describe_format_options *opts, unsigned int version);

typedef ... git_describe_result;

int git_describe_commit(git_describe_result **result, git_object *committish, git_describe_options *opts);
int git_describe_workdir(git_describe_result **out, git_repository *repo, git_describe_options *opts);
int git_describe_format(git_buf *out, const git_describe_result *result, const git_describe_format_options *opts);
void git_describe_result_free(git_describe_result *result);

#define GIT_ATTR_CHECK_FILE_THEN_INDEX ...
#define GIT_ATTR_CHECK_INDEX_THEN_FILE ...
#define GIT_ATTR_CHECK_INDEX_ONLY ...
Expand Down
94 changes: 94 additions & 0 deletions pygit2/repository.py
Original file line number Diff line number Diff line change
Expand Up @@ -637,6 +637,100 @@ def merge_trees(self, ancestor, ours, theirs, favor='normal'):

return Index.from_c(self, cindex)

#
# Describe
#
def describe(self, committish=None, max_candidates_tags=None,
describe_strategy=None, pattern=None,
only_follow_first_parent=None,
show_commit_oid_as_fallback=None, abbreviated_size=None,
always_use_long_format=None, dirty_suffix=None):
"""Describe a commit-ish or the current working tree.

:param committish: Commit-ish object or object name to describe, or
`None` to describe the current working tree.
:type committish: `str`, :class:`~.Reference`, or :class:`~.Commit`

:param int max_candidates_tags: The number of candidate tags to
consider. Increasing above 10 will take slightly longer but may
produce a more accurate result. A value of 0 will cause only exact
matches to be output.
:param int describe_strategy: A GIT_DESCRIBE_* constant.
:param str pattern: Only consider tags matching the given `glob(7)`
pattern, excluding the "refs/tags/" prefix.
:param bool only_follow_first_parent: Follow only the first parent
commit upon seeing a merge commit.
:param bool show_commit_oid_as_fallback: Show uniquely abbreviated
commit object as fallback.
:param int abbreviated_size: The minimum number of hexadecimal digits
to show for abbreviated object names. A value of 0 will suppress
long format, only showing the closest tag.
:param bool always_use_long_format: Always output the long format (the
nearest tag, the number of commits, and the abbrevated commit name)
even when the committish matches a tag.
:param str dirty_suffix: A string to append if the working tree is
dirty.

:returns: The description.
:rtype: `str`

Example::

repo.describe(pattern='public/*', dirty_suffix='-dirty')
"""

options = ffi.new('git_describe_options *')
C.git_describe_init_options(options, C.GIT_DESCRIBE_OPTIONS_VERSION)

if max_candidates_tags is not None:
options.max_candidates_tags = max_candidates_tags
if describe_strategy is not None:
options.describe_strategy = describe_strategy
if pattern:
options.pattern = ffi.new('char[]', to_bytes(pattern))
if only_follow_first_parent is not None:
options.only_follow_first_parent = only_follow_first_parent
if show_commit_oid_as_fallback is not None:
options.show_commit_oid_as_fallback = show_commit_oid_as_fallback

result = ffi.new('git_describe_result **')
if committish:
if is_string(committish):
committish = self.revparse_single(committish)

commit = committish.peel(Commit)

cptr = ffi.new('git_object **')
ffi.buffer(cptr)[:] = commit._pointer[:]

err = C.git_describe_commit(result, cptr[0], options)
else:
err = C.git_describe_workdir(result, self._repo, options)
check_error(err)

try:
format_options = ffi.new('git_describe_format_options *')
C.git_describe_init_format_options(format_options, C.GIT_DESCRIBE_FORMAT_OPTIONS_VERSION)

if abbreviated_size is not None:
format_options.abbreviated_size = abbreviated_size
if always_use_long_format is not None:
format_options.always_use_long_format = always_use_long_format
if dirty_suffix:
format_options.dirty_suffix = ffi.new('char[]', to_bytes(dirty_suffix))

buf = ffi.new('git_buf *', (ffi.NULL, 0))

err = C.git_describe_format(buf, result[0], format_options)
check_error(err)

try:
return ffi.string(buf.ptr).decode('utf-8')
finally:
C.git_buf_free(buf)
finally:
C.git_describe_result_free(result[0])

#
# Utility for writing a tree into an archive
#
Expand Down
5 changes: 5 additions & 0 deletions src/pygit2.c
Original file line number Diff line number Diff line change
Expand Up @@ -381,6 +381,11 @@ moduleinit(PyObject* m)
ADD_CONSTANT_INT(m, GIT_MERGE_ANALYSIS_FASTFORWARD)
ADD_CONSTANT_INT(m, GIT_MERGE_ANALYSIS_UNBORN)

/* Describe */
ADD_CONSTANT_INT(m, GIT_DESCRIBE_DEFAULT);
ADD_CONSTANT_INT(m, GIT_DESCRIBE_TAGS);
ADD_CONSTANT_INT(m, GIT_DESCRIBE_ALL);

/* Global initialization of libgit2 */
git_libgit2_init();

Expand Down
106 changes: 106 additions & 0 deletions test/test_describe.py