diff --git a/docs/diff.rst b/docs/diff.rst index 09fc9da21..dc7bf4dc0 100644 --- a/docs/diff.rst +++ b/docs/diff.rst @@ -50,8 +50,8 @@ Attributes: .. autoattribute:: pygit2.Patch.old_file_path .. autoattribute:: pygit2.Patch.new_file_path -.. autoattribute:: pygit2.Patch.old_oid -.. autoattribute:: pygit2.Patch.new_oid +.. autoattribute:: pygit2.Patch.old_id +.. autoattribute:: pygit2.Patch.new_id .. autoattribute:: pygit2.Patch.status .. autoattribute:: pygit2.Patch.similarity .. autoattribute:: pygit2.Patch.hunks diff --git a/docs/merge.rst b/docs/merge.rst index 4d98590aa..47984a868 100644 --- a/docs/merge.rst +++ b/docs/merge.rst @@ -22,8 +22,8 @@ merge with the default ones defined in GIT_MERGE_OPTS_INIT libgit2 constant. Example:: >>> branch_head_hex = '5ebeeebb320790caf276b9fc8b24546d63316533' - >>> branch_oid = self.repo.get(branch_head_hex).id - >>> merge_result = self.repo.merge(branch_oid) + >>> branch_id = self.repo.get(branch_head_hex).id + >>> merge_result = self.repo.merge(branch_id) The MergeResult object ====================== @@ -33,5 +33,5 @@ Represents the result of a merge and contains these fields: - is_uptodate: bool, if there wasn't any merge because the repo was already up to date - is_fastforward: bool, whether the merge was fastforward or not -- fastforward_oid: Oid, in the case it was a fastforward, this is the - forwarded Oid. +- fastforward_id: Oid, in the case it was a fastforward, this is the + forwarded id. diff --git a/docs/objects.rst b/docs/objects.rst index 3583c17ec..b9d038bbc 100644 --- a/docs/objects.rst +++ b/docs/objects.rst @@ -14,14 +14,14 @@ type. Object lookup ================= -In the previous chapter we learnt about Object IDs. With an oid we can ask the +In the previous chapter we learnt about Object IDs. With an Oid we can ask the repository to get the associated object. To do that the ``Repository`` class implementes a subset of the mapping interface. .. automethod:: pygit2.Repository.get - Return the Git object for the given *oid*, returns the *default* value if - there's no object in the repository with that oid. The oid can be an Oid + Return the Git object for the given *id*, returns the *default* value if + there's no object in the repository with that id. The id can be an Oid object, or an hexadecimal string. Example:: @@ -32,16 +32,16 @@ implementes a subset of the mapping interface. >>> obj <_pygit2.Commit object at 0x7ff27a6b60f0> -.. method:: Repository.__getitem__(oid) +.. method:: Repository.__getitem__(id) - Return the Git object for the given oid, raise ``KeyError`` if there's no - object in the repository with that oid. The oid can be an Oid object, or + Return the Git object for the given id, raise ``KeyError`` if there's no + object in the repository with that id. The id can be an Oid object, or an hexadecimal string. -.. method:: Repository.__contains__(oid) +.. method:: Repository.__contains__(id) - Returns True if there is an object in the Repository with that oid, False - if there is not. The oid can be an Oid object, or an hexadecimal string. + Returns True if there is an object in the Repository with that id, False + if there is not. The id can be an Oid object, or an hexadecimal string. The Object base type @@ -125,15 +125,15 @@ them to the Git object database: Example: - >>> oid = repo.create_blob('foo bar') # Creates blob from bytes string - >>> blob = repo[oid] + >>> id = repo.create_blob('foo bar') # Creates blob from bytes string + >>> blob = repo[id] >>> blob.data 'foo bar' .. automethod:: pygit2.Repository.create_blob_fromworkdir .. automethod:: pygit2.Repository.create_blob_fromdisk -There are also some functions to calculate the oid for a byte string without +There are also some functions to calculate the id for a byte string without creating the blob object: .. autofunction:: pygit2.hash diff --git a/docs/references.rst b/docs/references.rst index 363e3eebe..049fa8122 100644 --- a/docs/references.rst +++ b/docs/references.rst @@ -92,8 +92,8 @@ Example:: >>> for entry in head.log(): ... print(entry.message) -.. autoattribute:: pygit2.RefLogEntry.oid_new -.. autoattribute:: pygit2.RefLogEntry.oid_old +.. autoattribute:: pygit2.RefLogEntry.id_new +.. autoattribute:: pygit2.RefLogEntry.id_old .. autoattribute:: pygit2.RefLogEntry.message .. autoattribute:: pygit2.RefLogEntry.committer @@ -109,6 +109,6 @@ The Note type -------------------- .. autoattribute:: pygit2.Note.annotated_id -.. autoattribute:: pygit2.Note.oid +.. autoattribute:: pygit2.Note.id .. autoattribute:: pygit2.Note.message .. automethod:: pygit2.Note.remove diff --git a/docs/working-copy.rst b/docs/working-copy.rst index 88762b706..15962033b 100644 --- a/docs/working-copy.rst +++ b/docs/working-copy.rst @@ -8,8 +8,8 @@ Index read:: >>> index = repo.index >>> index.read() - >>> oid = index['path/to/file'].id # from path to object id - >>> blob = repo[oid] # from object id to object + >>> id = index['path/to/file'].id # from path to object id + >>> blob = repo[id] # from object id to object Iterate over all entries of the index:: @@ -51,7 +51,7 @@ The Index type The IndexEntry type -------------------- -.. autoattribute:: pygit2.IndexEntry.oid +.. autoattribute:: pygit2.IndexEntry.id .. autoattribute:: pygit2.IndexEntry.hex .. autoattribute:: pygit2.IndexEntry.path .. autoattribute:: pygit2.IndexEntry.mode diff --git a/pygit2/__init__.py b/pygit2/__init__.py index eed50c81a..b4faa031b 100644 --- a/pygit2/__init__.py +++ b/pygit2/__init__.py @@ -189,7 +189,7 @@ def clone_into(repo, remote, branch=None): and calling this function. """ - err = C.git_clone_into(repo._repo, remote._remote, ffi.NULL, to_str(branch)) + err = C.git_clone_into(repo._repo, remote._remote, ffi.NULL, to_str(branch), ffi.NULL) if remote._stored_exception: raise remote._stored_exception diff --git a/pygit2/config.py b/pygit2/config.py index 80f38dc43..a757b9713 100644 --- a/pygit2/config.py +++ b/pygit2/config.py @@ -223,6 +223,19 @@ def add_file(self, path, level=0, force=0): err = C.git_config_add_file_ondisk(self._config, to_str(path), level, force) check_error(err) + def snapshot(self): + """Create a snapshot from this Config object + + This means that looking up multiple values will use the same version + of the configuration files + """ + + ccfg = ffi.new('git_config **') + err = C.git_config_snapshot(cfg, self._config) + check_error(err) + + return Config.from_c(self._repo, ccfg[0]) + # # Methods to parse a string according to the git-config rules # @@ -248,10 +261,13 @@ def parse_int(text): @staticmethod def _from_found_config(fn): - buf = ffi.new('char []', C.GIT_PATH_MAX) - err = fn(buf, C.GIT_PATH_MAX) + buf = ffi.new('git_buf *', (ffi.NULL, 0)) + err = fn(buf) check_error(err, True) - return Config(ffi.string(buf).decode()) + cpath = ffi.string(buf.ptr).decode() + C.git_buf_free(buf) + + return Config(cpath) @staticmethod def get_system_config(): diff --git a/pygit2/decl.h b/pygit2/decl.h index fd1c22ee5..d3b5b022d 100644 --- a/pygit2/decl.h +++ b/pygit2/decl.h @@ -5,6 +5,7 @@ typedef ... git_push; typedef ... git_cred; typedef ... git_diff_file; typedef ... git_tree; +typedef ... git_signature; #define GIT_OID_RAWSZ ... #define GIT_PATH_MAX ... @@ -13,6 +14,12 @@ typedef struct git_oid { unsigned char id[20]; } git_oid; +typedef struct { + char *ptr; + size_t asize, size; +} git_buf; +void git_buf_free(git_buf *buffer); + typedef struct git_strarray { char **strings; size_t count; @@ -79,15 +86,26 @@ typedef enum { ... } git_credtype_t; -typedef struct git_remote_callbacks { +typedef int (*git_transport_message_cb)(const char *str, int len, void *data); +typedef int (*git_cred_acquire_cb)( + git_cred **cred, + const char *url, + const char *username_from_url, + unsigned int allowed_types, + void *payload); +typedef int (*git_transfer_progress_cb)(const git_transfer_progress *stats, void *payload); + +struct git_remote_callbacks { unsigned int version; - int (*progress)(const char *str, int len, void *data); + git_transport_message_cb sideband_progress; int (*completion)(git_remote_completion_type type, void *data); - int (*credentials)(git_cred **cred, const char *url, const char *username_from_url, unsigned int allowed_types, void *data); - int (*transfer_progress)(const git_transfer_progress *stats, void *data); + git_cred_acquire_cb credentials; + git_transfer_progress_cb transfer_progress; int (*update_tips)(const char *refname, const git_oid *a, const git_oid *b, void *data); void *payload; -} git_remote_callbacks ; +}; + +typedef struct git_remote_callbacks git_remote_callbacks; int git_remote_list(git_strarray *out, git_repository *repo); int git_remote_load(git_remote **out, git_repository *repo, const char *name); @@ -98,16 +116,16 @@ int git_remote_create( const char *url); const char * git_remote_name(const git_remote *remote); -typedef int (*git_remote_rename_problem_cb)(const char *problematic_refspec, void *payload); -int git_remote_rename(git_remote *remote, - const char *new_name, - git_remote_rename_problem_cb callback, - void *payload); + +int git_remote_rename( + git_strarray *problems, + git_remote *remote, + const char *new_name); const char * git_remote_url(const git_remote *remote); int git_remote_set_url(git_remote *remote, const char* url); const char * git_remote_pushurl(const git_remote *remote); int git_remote_set_pushurl(git_remote *remote, const char* url); -int git_remote_fetch(git_remote *remote); +int git_remote_fetch(git_remote *remote, const git_signature *signature, const char *reflog_message); const git_transfer_progress * git_remote_stats(git_remote *remote); int git_remote_add_push(git_remote *remote, const char *refspec); int git_remote_add_fetch(git_remote *remote, const char *refspec); @@ -133,7 +151,10 @@ int git_push_status_foreach( int (*cb)(const char *ref, const char *msg, void *data), void *data); -int git_push_update_tips(git_push *push); +int git_push_update_tips( + git_push *push, + const git_signature *signature, + const char *reflog_message); void git_push_free(git_push *push); const char * git_refspec_src(const git_refspec *refspec); @@ -145,8 +166,8 @@ git_direction git_refspec_direction(const git_refspec *spec); int git_refspec_src_matches(const git_refspec *refspec, const char *refname); int git_refspec_dst_matches(const git_refspec *refspec, const char *refname); -int git_refspec_transform(char *out, size_t outlen, const git_refspec *spec, const char *name); -int git_refspec_rtransform(char *out, size_t outlen, const git_refspec *spec, const char *name); +int git_refspec_transform(git_buf *buf, const git_refspec *spec, const char *name); +int git_refspec_rtransform(git_buf *buf, const git_refspec *spec, const char *name); int git_cred_userpass_plaintext_new( git_cred **out, @@ -179,7 +200,7 @@ typedef void (*git_checkout_progress_cb)( size_t total_steps, void *payload); -typedef struct git_checkout_opts { +typedef struct git_checkout_options { unsigned int version; unsigned int checkout_strategy; @@ -202,10 +223,17 @@ typedef struct git_checkout_opts { const char *target_directory; + const char *ancestor_label; const char *our_label; const char *their_label; -} git_checkout_opts; +} git_checkout_options; +typedef enum { + GIT_CLONE_LOCAL_AUTO, + GIT_CLONE_LOCAL, + GIT_CLONE_NO_LOCAL, + GIT_CLONE_LOCAL_NO_LINKS, +} git_clone_local_t; /* * git_clone @@ -214,13 +242,15 @@ typedef struct git_checkout_opts { typedef struct git_clone_options { unsigned int version; - git_checkout_opts checkout_opts; + git_checkout_options checkout_opts; git_remote_callbacks remote_callbacks; int bare; int ignore_cert_errors; + git_clone_local_t local; const char *remote_name; const char* checkout_branch; + git_signature *signature; } git_clone_options; int git_clone(git_repository **out, @@ -231,8 +261,9 @@ int git_clone(git_repository **out, int git_clone_into( git_repository *repo, git_remote *remote, - const git_checkout_opts *co_opts, - const char *branch); + const git_checkout_options *co_opts, + const char *branch, + const git_signature *signature); /* * git_config @@ -257,6 +288,7 @@ typedef struct { } git_config_entry; int git_repository_config(git_config **out, git_repository *repo); +int git_repository_config_snapshot(git_config **out, git_repository *repo); void git_config_free(git_config *cfg); int git_config_get_string(const char **out, const git_config *cfg, const char *name); @@ -290,11 +322,11 @@ int git_config_set_multivar( const char *value); int git_config_new(git_config **out); +int git_config_snapshot(git_config **out, git_config *config); int git_config_open_ondisk(git_config **out, const char *path); -int git_config_find_system(char *out, size_t length); -int git_config_find_global(char *out, size_t length); -int git_config_find_xdg(char *out, size_t length); - +int git_config_find_system(git_buf *out); +int git_config_find_global(git_buf *out); +int git_config_find_xdg(git_buf *out); /* * git_repository_init diff --git a/pygit2/refspec.py b/pygit2/refspec.py index 00974495d..5a99d5231 100644 --- a/pygit2/refspec.py +++ b/pygit2/refspec.py @@ -73,38 +73,24 @@ def dst_matches(self, ref): Returns whether the given string matches the destination of this refspec""" return bool(C.git_refspec_dst_matches(self._refspec, to_str(ref))) + def _transform(self, ref, fn): + buf = ffi.new('git_buf *', (ffi.NULL, 0)) + err = fn(buf, self._refspec, to_str(ref)) + check_error(err) + + try: + return ffi.string(buf.ptr).decode() + finally: + C.git_buf_free(buf) + def transform(self, ref): """transform(str) -> str Transform a reference name according to this refspec from the lhs to the rhs.""" - alen = len(ref) - err = C.GIT_EBUFS - ptr = None - ref_str = to_str(ref) - - while err == C.GIT_EBUFS: - alen *= 2 - ptr = ffi.new('char []', alen) - - err = C.git_refspec_transform(ptr, alen, self._refspec, ref_str) - - check_error(err) - return ffi.string(ptr).decode() + return self._transform(ref, C.git_refspec_transform) def rtransform(self, ref): """transform(str) -> str Transform a reference name according to this refspec from the lhs to the rhs""" - alen = len(ref) - err = C.GIT_EBUFS - ptr = None - ref_str = to_str(ref) - - while err == C.GIT_EBUFS: - alen *= 2 - ptr = ffi.new('char []', alen) - - err = C.git_refspec_rtransform(ptr, alen, self._refspec, ref_str) - - check_error(err) - return ffi.string(ptr).decode() + return self._transform(ref, C.git_refspec_rtransform) diff --git a/pygit2/remote.py b/pygit2/remote.py index 11bc86c60..2b7f32d79 100644 --- a/pygit2/remote.py +++ b/pygit2/remote.py @@ -69,7 +69,7 @@ def __init__(self, tp): class Remote(object): - def progress(self, string): + def sideband_progress(self, string): """Progress output callback Override this function with your own progress reporting function @@ -122,7 +122,7 @@ def __init__(self, repo, ptr): # Build the callback structure callbacks = ffi.new('git_remote_callbacks *') callbacks.version = 1 - callbacks.progress = self._progress_cb + callbacks.sideband_progress = self._sideband_progress_cb callbacks.transfer_progress = self._transfer_progress_cb callbacks.update_tips = self._update_tips_cb callbacks.credentials = self._credentials_cb @@ -142,14 +142,25 @@ def name(self): return maybe_string(C.git_remote_name(self._remote)) - @name.setter - def name(self, value): - if not value: + def rename(self, new_name): + """Rename this remote + + Returns a list of fetch refspecs which were not in the standard format + and thus could not be remapped + """ + + if not new_name: raise ValueError("New remote name must be a non-empty string") - err = C.git_remote_rename(self._remote, to_str(value), ffi.NULL, ffi.NULL) + problems = ffi.new('git_strarray *') + err = C.git_remote_rename(problems, self._remote, to_str(new_name)) check_error(err) + ret = strarray_to_strings(problems) + C.git_strarray_free(problems) + + return ret + @property def url(self): """Url of the remote""" @@ -179,14 +190,19 @@ def save(self): err = C.git_remote_save(self._remote) check_error(err) - def fetch(self): - """fetch() -> TransferProgress + def fetch(self, signature=None, message=None): + """fetch(signature, message) -> TransferProgress Perform a fetch against this remote. """ + if signature: + ptr = signature._pointer[:] + else: + ptr = ffi.NULL + self._stored_exception = None - err = C.git_remote_fetch(self._remote) + err = C.git_remote_fetch(self._remote, ptr, to_str(message)) if self._stored_exception: raise self._stored_exception @@ -261,10 +277,15 @@ def _push_cb(ref, msg, data): self._bad_message = ffi.string(msg).decode() return 0 - def push(self, spec): - """push(refspec) + def push(self, spec, signature=None, message=None): + """push(refspec, signature, message) + + Push the given refspec to the remote. Raises ``GitError`` on error - Push the given refspec to the remote. Raises ``GitError`` on error""" + :param str spec: push refspec to use + :param Signature signature: signature to use when updating the tips + :param str message: message to use when updating the tips + """ cpush = ffi.new('git_push **') err = C.git_push_new(cpush, self._remote) @@ -288,7 +309,12 @@ def push(self, spec): if hasattr(self, '_bad_message'): raise GitError(self._bad_message) - err = C.git_push_update_tips(push) + if signature: + ptr = signature._pointer[:] + else: + ptr = ffi.NULL + + err = C.git_push_update_tips(push, ptr, to_str(message)) check_error(err) finally: @@ -297,7 +323,7 @@ def push(self, spec): # These functions exist to be called by the git_remote as # callbacks. They proxy the call to whatever the user set - @ffi.callback('int (*transfer_progress)(const git_transfer_progress *stats, void *data)') + @ffi.callback('git_transfer_progress_cb') def _transfer_progress_cb(stats_ptr, data): self = ffi.from_handle(data) @@ -312,8 +338,8 @@ def _transfer_progress_cb(stats_ptr, data): return 0 - @ffi.callback('int (*progress)(const char *str, int len, void *data)') - def _progress_cb(string, length, data): + @ffi.callback('git_transport_message_cb') + def _sideband_progress_cb(string, length, data): self = ffi.from_handle(data) if not hasattr(self, 'progress') or not self.progress: diff --git a/pygit2/repository.py b/pygit2/repository.py index 3f18c2c40..db047f5ee 100644 --- a/pygit2/repository.py +++ b/pygit2/repository.py @@ -128,6 +128,19 @@ def config(self): return Config.from_c(self, cconfig[0]) + @property + def config_snapshot(self): + """A snapshot for this repositiory's configuration + + This allows reads over multiple values to use the same version + of the configuration files""" + + cconfig = ffi.new('git_config **') + err = C.git_repository_config_snapshot(cconfig, self._repo) + check_error(err) + + return Config.from_c(self, cconfig[0]) + # # References # diff --git a/src/blame.c b/src/blame.c index 80b82089a..b238f050a 100644 --- a/src/blame.c +++ b/src/blame.c @@ -69,14 +69,20 @@ wrap_blame_hunk(const git_blame_hunk *hunk, Blame *blame) py_hunk->lines_in_hunk = hunk->lines_in_hunk; py_hunk->final_commit_id = git_oid_allocfmt(&hunk->final_commit_id); py_hunk->final_start_line_number = hunk->final_start_line_number; - py_hunk->final_signature = hunk->final_signature != NULL ? - git_signature_dup(hunk->final_signature) : NULL; + + py_hunk->final_signature = NULL; + if (hunk->final_signature) + git_signature_dup(&py_hunk->final_signature, hunk->final_signature); + py_hunk->orig_commit_id = git_oid_allocfmt(&hunk->orig_commit_id); py_hunk->orig_path = hunk->orig_path != NULL ? strdup(hunk->orig_path) : NULL; py_hunk->orig_start_line_number = hunk->orig_start_line_number; - py_hunk->orig_signature = hunk->orig_signature != NULL ? - git_signature_dup(hunk->orig_signature) : NULL; + + py_hunk->orig_signature = NULL; + if (hunk->orig_signature) + git_signature_dup(&py_hunk->orig_signature, hunk->orig_signature); + py_hunk->boundary = hunk->boundary; } diff --git a/src/branch.c b/src/branch.c index bcf763677..39ddd675d 100644 --- a/src/branch.c +++ b/src/branch.c @@ -101,7 +101,7 @@ Branch_rename(Branch *self, PyObject *args) if (!PyArg_ParseTuple(args, "s|i", &c_name, &force)) return NULL; - err = git_branch_move(&c_out, self->reference, c_name, force); + err = git_branch_move(&c_out, self->reference, c_name, force, NULL, NULL); if (err == GIT_OK) return wrap_branch(c_out, self->repo); else @@ -135,34 +135,19 @@ PyObject * Branch_remote_name__get__(Branch *self) { int err; + git_buf name = {NULL}; const char *branch_name; - char *c_name = NULL; PyObject *py_name; CHECK_REFERENCE(self); branch_name = git_reference_name(self->reference); - /* Get the length of the remote name */ - err = git_branch_remote_name(NULL, 0, self->repo->repo, branch_name); + err = git_branch_remote_name(&name, self->repo->repo, branch_name); if (err < GIT_OK) return Error_set(err); - /* Get the actual remote name */ - c_name = calloc(err, sizeof(char)); - if (c_name == NULL) - return PyErr_NoMemory(); - - err = git_branch_remote_name(c_name, - err * sizeof(char), - self->repo->repo, - branch_name); - if (err < GIT_OK) { - free(c_name); - return Error_set(err); - } - - py_name = to_unicode_n(c_name, err - 1, NULL, NULL); - free(c_name); + py_name = to_unicode(name.ptr, NULL, NULL); + git_buf_free(&name); return py_name; } @@ -227,34 +212,20 @@ PyObject * Branch_upstream_name__get__(Branch *self) { int err; + git_buf name = {NULL}; const char *branch_name; - char *c_name = NULL; PyObject *py_name; CHECK_REFERENCE(self); branch_name = git_reference_name(self->reference); - /* Get the length of the upstream name */ - err = git_branch_upstream_name(NULL, 0, self->repo->repo, branch_name); - if (err < GIT_OK) - return Error_set(err); - - /* Get the actual upstream name */ - c_name = calloc(err, sizeof(char)); - if (c_name == NULL) - return PyErr_NoMemory(); - err = git_branch_upstream_name(c_name, - err * sizeof(char), - self->repo->repo, - branch_name); - if (err < GIT_OK) { - free(c_name); + err = git_branch_upstream_name(&name, self->repo->repo, branch_name); + if (err < GIT_OK) return Error_set(err); - } - py_name = to_unicode_n(c_name, err - 1, NULL, NULL); - free(c_name); + py_name = to_unicode(name.ptr, NULL, NULL); + git_buf_free(&name); return py_name; } diff --git a/src/diff.c b/src/diff.c index adea3cdd8..3aeddeb85 100644 --- a/src/diff.c +++ b/src/diff.c @@ -80,8 +80,8 @@ wrap_patch(git_patch *patch) py_patch->status = git_diff_status_char(delta->status); py_patch->similarity = delta->similarity; py_patch->flags = delta->flags; - py_patch->old_oid = git_oid_allocfmt(&delta->old_file.oid); - py_patch->new_oid = git_oid_allocfmt(&delta->new_file.oid); + py_patch->old_id = git_oid_allocfmt(&delta->old_file.id); + py_patch->new_id = git_oid_allocfmt(&delta->new_file.id); git_patch_line_stats(NULL, &additions, &deletions, patch); py_patch->additions = additions; @@ -149,8 +149,8 @@ static void Patch_dealloc(Patch *self) { Py_CLEAR(self->hunks); - free(self->old_oid); - free(self->new_oid); + free(self->old_id); + free(self->new_id); /* We do not have to free old_file_path and new_file_path, they will * be freed by git_diff_list_free in Diff_dealloc */ PyObject_Del(self); @@ -159,8 +159,8 @@ Patch_dealloc(Patch *self) PyMemberDef Patch_members[] = { MEMBER(Patch, old_file_path, T_STRING, "old file path"), MEMBER(Patch, new_file_path, T_STRING, "new file path"), - MEMBER(Patch, old_oid, T_STRING, "old oid"), - MEMBER(Patch, new_oid, T_STRING, "new oid"), + MEMBER(Patch, old_id, T_STRING, "old oid"), + MEMBER(Patch, new_id, T_STRING, "new oid"), MEMBER(Patch, status, T_CHAR, "status"), MEMBER(Patch, similarity, T_INT, "similarity"), MEMBER(Patch, hunks, T_OBJECT, "hunks"), @@ -292,8 +292,7 @@ PyObject * Diff_patch__get__(Diff *self) { git_patch* patch; - char **strings = NULL; - char *buffer = NULL; + git_buf buf = {NULL}; int err = GIT_ERROR; size_t i, len, num; PyObject *py_patch = NULL; @@ -301,32 +300,25 @@ Diff_patch__get__(Diff *self) num = git_diff_num_deltas(self->list); if (num == 0) Py_RETURN_NONE; - MALLOC(strings, num * sizeof(char*), cleanup); for (i = 0, len = 1; i < num ; ++i) { err = git_patch_from_diff(&patch, self->list, i); if (err < 0) goto cleanup; - err = git_patch_to_str(&(strings[i]), patch); + /* This appends to the current buf, so we can simply keep passing it */ + err = git_patch_to_buf(&buf, patch); if (err < 0) goto cleanup; - len += strlen(strings[i]); git_patch_free(patch); } - CALLOC(buffer, (len + 1), sizeof(char), cleanup); - for (i = 0; i < num; ++i) { - strcat(buffer, strings[i]); - free(strings[i]); - } - free(strings); - - py_patch = to_unicode(buffer, NULL, NULL); - free(buffer); + py_patch = to_unicode(buf.ptr, NULL, NULL); + git_buf_free(&buf); cleanup: + git_buf_free(&buf); return (err < 0) ? Error_set(err) : py_patch; } diff --git a/src/index.c b/src/index.c index 6a855f41a..714c30872 100644 --- a/src/index.c +++ b/src/index.c @@ -649,7 +649,7 @@ IndexEntry_init(IndexEntry *self, PyObject *args, PyObject *kwds) return -1; if (id) - git_oid_cpy(&self->entry.oid, &id->oid); + git_oid_cpy(&self->entry.id, &id->oid); if (mode) self->entry.mode = mode; @@ -710,18 +710,18 @@ IndexEntry_path__set__(IndexEntry *self, PyObject *py_path) return 0; } -PyDoc_STRVAR(IndexEntry_oid__doc__, "Object id."); +PyDoc_STRVAR(IndexEntry_id__doc__, "Object id."); PyObject * -IndexEntry_oid__get__(IndexEntry *self) +IndexEntry_id__get__(IndexEntry *self) { - return git_oid_to_python(&self->entry.oid); + return git_oid_to_python(&self->entry.id); } int -IndexEntry_oid__set__(IndexEntry *self, PyObject *py_id) +IndexEntry_id__set__(IndexEntry *self, PyObject *py_id) { - if (!py_oid_to_git_oid(py_id, &self->entry.oid)) + if (!py_oid_to_git_oid(py_id, &self->entry.id)) return -1; return 0; @@ -732,13 +732,13 @@ PyDoc_STRVAR(IndexEntry_hex__doc__, "Hex id."); PyObject * IndexEntry_hex__get__(IndexEntry *self) { - return git_oid_to_py_str(&self->entry.oid); + return git_oid_to_py_str(&self->entry.id); } PyGetSetDef IndexEntry_getseters[] = { GETSET(IndexEntry, mode), GETSET(IndexEntry, path), - GETSET(IndexEntry, oid), + GETSET(IndexEntry, id), GETTER(IndexEntry, hex), {NULL}, }; diff --git a/src/mergeresult.c b/src/mergeresult.c deleted file mode 100644 index 345e56ee6..000000000 --- a/src/mergeresult.c +++ /dev/null @@ -1,145 +0,0 @@ -/* - * Copyright 2010-2014 The pygit2 contributors - * - * This file is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License, version 2, - * as published by the Free Software Foundation. - * - * In addition to the permissions in the GNU General Public License, - * the authors give you unlimited permission to link the compiled - * version of this file into combinations with other programs, - * and to distribute those combinations without any restriction - * coming from the use of this file. (The General Public License - * restrictions do apply in other respects; for example, they cover - * modification of the file, and distribution when not linked into - * a combined executable.) - * - * This file is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; see the file COPYING. If not, write to - * the Free Software Foundation, 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - */ - -#define PY_SSIZE_T_CLEAN -#include -#include "utils.h" -#include "types.h" -#include "oid.h" -#include "repository.h" -#include "mergeresult.h" - -extern PyTypeObject MergeResultType; -extern PyTypeObject IndexType; - -PyObject * -git_merge_result_to_python(git_merge_result *merge_result) -{ - MergeResult *py_merge_result; - - py_merge_result = PyObject_New(MergeResult, &MergeResultType); - if (!py_merge_result) - return NULL; - - py_merge_result->result = merge_result; - - return (PyObject*) py_merge_result; -} - -void -MergeResult_dealloc(MergeResult *self) -{ - git_merge_result_free(self->result); - PyObject_Del(self); -} - - -PyDoc_STRVAR(MergeResult_is_uptodate__doc__, "Is up to date"); - -PyObject * -MergeResult_is_uptodate__get__(MergeResult *self) -{ - if (git_merge_result_is_uptodate(self->result)) - Py_RETURN_TRUE; - else - Py_RETURN_FALSE; -} - -PyDoc_STRVAR(MergeResult_is_fastforward__doc__, "Is fastforward"); - -PyObject * -MergeResult_is_fastforward__get__(MergeResult *self) -{ - if (git_merge_result_is_fastforward(self->result)) - Py_RETURN_TRUE; - else - Py_RETURN_FALSE; -} - -PyDoc_STRVAR(MergeResult_fastforward_oid__doc__, "Fastforward Oid"); - -PyObject * -MergeResult_fastforward_oid__get__(MergeResult *self) -{ - if (git_merge_result_is_fastforward(self->result)) { - git_oid fastforward_oid; - git_merge_result_fastforward_oid(&fastforward_oid, self->result); - return git_oid_to_python((const git_oid *)&fastforward_oid); - } - else Py_RETURN_NONE; -} - -PyGetSetDef MergeResult_getseters[] = { - GETTER(MergeResult, is_uptodate), - GETTER(MergeResult, is_fastforward), - GETTER(MergeResult, fastforward_oid), - {NULL}, -}; - -PyDoc_STRVAR(MergeResult__doc__, "MergeResult object."); - -PyTypeObject MergeResultType = { - PyVarObject_HEAD_INIT(NULL, 0) - "_pygit2.MergeResult", /* tp_name */ - sizeof(MergeResult), /* tp_basicsize */ - 0, /* tp_itemsize */ - (destructor)MergeResult_dealloc, /* tp_dealloc */ - 0, /* tp_print */ - 0, /* tp_getattr */ - 0, /* tp_setattr */ - 0, /* tp_compare */ - 0, /* tp_repr */ - 0, /* tp_as_number */ - 0, /* tp_as_sequence */ - 0, /* tp_as_mapping */ - 0, /* tp_hash */ - 0, /* tp_call */ - 0, /* tp_str */ - 0, /* tp_getattro */ - 0, /* tp_setattro */ - 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT, /* tp_flags */ - MergeResult__doc__, /* tp_doc */ - 0, /* tp_traverse */ - 0, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - 0, /* tp_iter */ - 0, /* tp_iternext */ - 0, /* tp_methods */ - 0, /* tp_members */ - MergeResult_getseters, /* tp_getset */ - 0, /* tp_base */ - 0, /* tp_dict */ - 0, /* tp_descr_get */ - 0, /* tp_descr_set */ - 0, /* tp_dictoffset */ - 0, /* tp_init */ - 0, /* tp_alloc */ - 0, /* tp_new */ -}; - diff --git a/src/mergeresult.h b/src/mergeresult.h deleted file mode 100644 index 74161ea9d..000000000 --- a/src/mergeresult.h +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright 2010-2014 The pygit2 contributors - * - * This file is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License, version 2, - * as published by the Free Software Foundation. - * - * In addition to the permissions in the GNU General Public License, - * the authors give you unlimited permission to link the compiled - * version of this file into combinations with other programs, - * and to distribute those combinations without any restriction - * coming from the use of this file. (The General Public License - * restrictions do apply in other respects; for example, they cover - * modification of the file, and distribution when not linked into - * a combined executable.) - * - * This file is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; see the file COPYING. If not, write to - * the Free Software Foundation, 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - */ - -#ifndef INCLUDE_pygit2_merge_result_h -#define INCLUDE_pygit2_merge_result_h - -#define PY_SSIZE_T_CLEAN -#include -#include - -PyObject* git_merge_result_to_python(git_merge_result *merge_result); - -#endif diff --git a/src/note.c b/src/note.c index e14e30862..9762ef61e 100644 --- a/src/note.c +++ b/src/note.c @@ -66,13 +66,13 @@ Note_remove(Note *self, PyObject* args) } -PyDoc_STRVAR(Note_oid__doc__, +PyDoc_STRVAR(Note_id__doc__, "Gets the id of the blob containing the note message\n"); PyObject * -Note_oid__get__(Note *self) +Note_id__get__(Note *self) { - return git_oid_to_python(git_note_oid(self->note)); + return git_oid_to_python(git_note_id(self->note)); } @@ -108,7 +108,7 @@ PyMemberDef Note_members[] = { PyGetSetDef Note_getseters[] = { GETTER(Note, message), - GETTER(Note, oid), + GETTER(Note, id), {NULL} }; diff --git a/src/options.c b/src/options.c index 072a5ae24..1679a93d2 100644 --- a/src/options.c +++ b/src/options.c @@ -37,36 +37,16 @@ extern PyObject *GitError; static PyObject * get_search_path(long level) { - char *buf = NULL; - size_t len = 64; + git_buf buf = {NULL}; PyObject *py_path; - int error; - char *tmp; - - do { - len *= 2; - tmp = realloc(buf, len); - if (!tmp) { - free(buf); - PyErr_NoMemory(); - return NULL; - } - buf = tmp; - - error = git_libgit2_opts(GIT_OPT_GET_SEARCH_PATH, level, buf, len); - } while(error == GIT_EBUFS); + int err; - if (error < 0) { - free(buf); - Error_set(error); - return NULL; - } - - if (!buf) - return NULL; + err = git_libgit2_opts(GIT_OPT_GET_SEARCH_PATH, level, &buf); + if (err < 0) + return Error_set(err); - py_path = to_unicode(buf, NULL, NULL); - free(buf); + py_path = to_unicode(buf.ptr, NULL, NULL); + git_buf_free(&buf); if (!py_path) return NULL; diff --git a/src/pygit2.c b/src/pygit2.c index 4808f7437..ccf4a6757 100644 --- a/src/pygit2.c +++ b/src/pygit2.c @@ -28,11 +28,6 @@ #define PY_SSIZE_T_CLEAN #include -/* Pypy does not provide this header */ -#ifndef PYPY_VERSION -# include -#endif - #include #include "error.h" #include "types.h" @@ -41,11 +36,6 @@ #include "oid.h" #include "options.h" -/* FIXME: This is for pypy */ -#ifndef MAXPATHLEN -# define MAXPATHLEN 1024 -#endif - extern PyObject *GitError; extern PyTypeObject RepositoryType; @@ -78,7 +68,6 @@ extern PyTypeObject NoteIterType; extern PyTypeObject BlameType; extern PyTypeObject BlameIterType; extern PyTypeObject BlameHunkType; -extern PyTypeObject MergeResultType; @@ -90,21 +79,25 @@ PyDoc_STRVAR(discover_repository__doc__, PyObject * discover_repository(PyObject *self, PyObject *args) { + git_buf repo_path = {NULL}; const char *path; + PyObject *py_repo_path; int across_fs = 0; const char *ceiling_dirs = NULL; - char repo_path[MAXPATHLEN]; int err; if (!PyArg_ParseTuple(args, "s|Is", &path, &across_fs, &ceiling_dirs)) return NULL; - err = git_repository_discover(repo_path, sizeof(repo_path), - path, across_fs, ceiling_dirs); + memset(&repo_path, 0, sizeof(git_buf)); + err = git_repository_discover(&repo_path, path, across_fs, ceiling_dirs); if (err < 0) return Error_set_str(err, path); - return to_path(repo_path); + py_repo_path = to_path(repo_path.ptr); + git_buf_free(&repo_path); + + return py_repo_path; }; PyDoc_STRVAR(hashfile__doc__, @@ -364,8 +357,11 @@ moduleinit(PyObject* m) ADD_CONSTANT_INT(m, GIT_BLAME_TRACK_COPIES_ANY_COMMIT_COPIES) /* Merge */ - INIT_TYPE(MergeResultType, NULL, NULL) - ADD_TYPE(m, MergeResult) + ADD_CONSTANT_INT(m, GIT_MERGE_ANALYSIS_NONE) + ADD_CONSTANT_INT(m, GIT_MERGE_ANALYSIS_NORMAL) + ADD_CONSTANT_INT(m, GIT_MERGE_ANALYSIS_UP_TO_DATE) + ADD_CONSTANT_INT(m, GIT_MERGE_ANALYSIS_FASTFORWARD) + ADD_CONSTANT_INT(m, GIT_MERGE_ANALYSIS_UNBORN) /* Global initialization of libgit2 */ git_threads_init(); diff --git a/src/reference.c b/src/reference.c index e597e353a..2c5e0ff52 100644 --- a/src/reference.c +++ b/src/reference.c @@ -62,8 +62,7 @@ RefLogIter_iternext(RefLogIter *self) py_entry->oid_old = git_oid_allocfmt(git_reflog_entry_id_old(entry)); py_entry->oid_new = git_oid_allocfmt(git_reflog_entry_id_new(entry)); py_entry->message = strdup(git_reflog_entry_message(entry)); - py_entry->signature = git_signature_dup( - git_reflog_entry_committer(entry)); + git_signature_dup(&py_entry->signature, git_reflog_entry_committer(entry)); ++(self->i); @@ -160,7 +159,7 @@ Reference_rename(Reference *self, PyObject *py_name) return NULL; /* Rename */ - err = git_reference_rename(&new_reference, self->reference, c_name, 0); + err = git_reference_rename(&new_reference, self->reference, c_name, 0, NULL, NULL); git_reference_free(self->reference); free(c_name); if (err < 0) @@ -240,7 +239,7 @@ Reference_target__set__(Reference *self, PyObject *py_target) if (err < 0) return err; - err = git_reference_set_target(&new_ref, self->reference, &oid); + err = git_reference_set_target(&new_ref, self->reference, &oid, NULL, NULL); if (err < 0) goto error; @@ -254,7 +253,7 @@ Reference_target__set__(Reference *self, PyObject *py_target) if (c_name == NULL) return -1; - err = git_reference_symbolic_set_target(&new_ref, self->reference, c_name); + err = git_reference_symbolic_set_target(&new_ref, self->reference, c_name, NULL, NULL); free(c_name); if (err < 0) goto error; diff --git a/src/refspec.h b/src/refspec.h deleted file mode 100644 index 829823f94..000000000 --- a/src/refspec.h +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright 2010-2014 The pygit2 contributors - * - * This file is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License, version 2, - * as published by the Free Software Foundation. - * - * In addition to the permissions in the GNU General Public License, - * the authors give you unlimited permission to link the compiled - * version of this file into combinations with other programs, - * and to distribute those combinations without any restriction - * coming from the use of this file. (The General Public License - * restrictions do apply in other respects; for example, they cover - * modification of the file, and distribution when not linked into - * a combined executable.) - * - * This file is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; see the file COPYING. If not, write to - * the Free Software Foundation, 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - */ - -#ifndef INCLUDE_pygit2_refspec_h -#define INCLUDE_pygit2_refspec_h - -#define PY_SSIZE_T_CLEAN -#include -#include -#include - -Refspec* wrap_refspec(const Remote *owner, const git_refspec *refspec); - -#endif diff --git a/src/repository.c b/src/repository.c index 9f78480da..0b12053a4 100644 --- a/src/repository.c +++ b/src/repository.c @@ -37,7 +37,6 @@ #include "repository.h" #include "branch.h" #include "blame.h" -#include "mergeresult.h" #include "signature.h" #include @@ -190,7 +189,7 @@ Repository_head__set__(Repository *self, PyObject *py_refname) if (refname == NULL) return -1; - err = git_repository_set_head(self->repo, refname); + err = git_repository_set_head(self->repo, refname, NULL, NULL); Py_DECREF(trefname); if (err < 0) { Error_set_str(err, refname); @@ -546,46 +545,81 @@ Repository_merge_base(Repository *self, PyObject *args) return git_oid_to_python(&oid); } +PyDoc_STRVAR(Repository_merge_analysis__doc__, + "merge_analysis(id) -> (Integer, Integer)\n" + "\n" + "Analyzes the given branch and determines the opportunities for merging\n" + "them into the HEAD of the repository\n" + "\n" + "The first returned value is a mixture of the GIT_MERGE_ANALYSIS_NONE, _NORMAL,\n" + " _UP_TO_DATE, _FASTFORWARD and _UNBORN flags.\n" + "The second value is the user's preference from 'merge.ff'"); + +PyObject * +Repository_merge_analysis(Repository *self, PyObject *py_id) +{ + int err; + size_t len; + git_oid id; + git_merge_head *merge_head; + git_merge_analysis_t analysis; + git_merge_preference_t preference; + + len = py_oid_to_git_oid(py_id, &id); + if (len == 0) + return NULL; + + err = git_merge_head_from_id(&merge_head, self->repo, &id); + if (err < 0) + return Error_set(err); + + err = git_merge_analysis(&analysis, &preference, self->repo, (const git_merge_head **) &merge_head, 1); + git_merge_head_free(merge_head); + + if (err < 0) + return Error_set(err); + + return Py_BuildValue("(ii)", analysis, preference); +} + PyDoc_STRVAR(Repository_merge__doc__, - "merge(oid) -> MergeResult\n" + "merge(id)\n" "\n" - "Merges the given oid and returns the MergeResult.\n" + "Merges the given id into HEAD.\n" "\n" - "If the merge is fastforward the MergeResult will contain the new\n" - "fastforward oid.\n" - "If the branch is uptodate, nothing to merge, the MergeResult will\n" - "have the fastforward oid as None.\n" - "If the merge is not fastforward the MergeResult will have the status\n" - "produced by the merge, even if there are conflicts."); + "Merges the given commit(s) into HEAD, writing the results into the\n" + "working directory. Any changes are staged for commit and any conflicts\n" + "are written to the index. Callers should inspect the repository's\n" + "index after this completes, resolve any conflicts and prepare a\n" + "commit."); PyObject * Repository_merge(Repository *self, PyObject *py_oid) { - git_merge_result *merge_result; git_merge_head *oid_merge_head; git_oid oid; - const git_merge_opts default_opts = GIT_MERGE_OPTS_INIT; int err; size_t len; - PyObject *py_merge_result; + git_merge_options merge_opts = GIT_MERGE_OPTIONS_INIT; + git_checkout_options checkout_opts = GIT_CHECKOUT_OPTIONS_INIT; len = py_oid_to_git_oid(py_oid, &oid); if (len == 0) return NULL; - err = git_merge_head_from_oid(&oid_merge_head, self->repo, &oid); + err = git_merge_head_from_id(&oid_merge_head, self->repo, &oid); if (err < 0) return Error_set(err); - err = git_merge(&merge_result, self->repo, + err = git_merge(self->repo, (const git_merge_head **)&oid_merge_head, 1, - &default_opts); + &merge_opts, &checkout_opts); + git_merge_head_free(oid_merge_head); if (err < 0) return Error_set(err); - py_merge_result = git_merge_result_to_python(merge_result); - return py_merge_result; + Py_RETURN_NONE; } PyDoc_STRVAR(Repository_walk__doc__, @@ -888,7 +922,7 @@ Repository_create_branch(Repository *self, PyObject *args) if (!PyArg_ParseTuple(args, "sO!|i", &c_name, &CommitType, &py_commit, &force)) return NULL; - err = git_branch_create(&c_reference, self->repo, c_name, py_commit->commit, force); + err = git_branch_create(&c_reference, self->repo, c_name, py_commit->commit, force, NULL, NULL); if (err < 0) return Error_set(err); @@ -1055,7 +1089,7 @@ Repository_create_reference_direct(Repository *self, PyObject *args, if (err < 0) return NULL; - err = git_reference_create(&c_reference, self->repo, c_name, &oid, force); + err = git_reference_create(&c_reference, self->repo, c_name, &oid, force, NULL, NULL); if (err < 0) return Error_set(err); @@ -1089,7 +1123,7 @@ Repository_create_reference_symbolic(Repository *self, PyObject *args, return NULL; err = git_reference_symbolic_create(&c_reference, self->repo, c_name, - c_target, force); + c_target, force, NULL, NULL); if (err < 0) return Error_set(err); @@ -1266,7 +1300,7 @@ PyDoc_STRVAR(Repository_checkout_head__doc__, PyObject * Repository_checkout_head(Repository *self, PyObject *args) { - git_checkout_opts opts = GIT_CHECKOUT_OPTS_INIT; + git_checkout_options opts = GIT_CHECKOUT_OPTIONS_INIT; unsigned int strategy; int err; @@ -1290,7 +1324,7 @@ PyDoc_STRVAR(Repository_checkout_index__doc__, PyObject * Repository_checkout_index(Repository *self, PyObject *args) { - git_checkout_opts opts = GIT_CHECKOUT_OPTS_INIT; + git_checkout_options opts = GIT_CHECKOUT_OPTIONS_INIT; unsigned int strategy; int err; @@ -1314,7 +1348,7 @@ PyDoc_STRVAR(Repository_checkout_tree__doc__, PyObject * Repository_checkout_tree(Repository *self, PyObject *args) { - git_checkout_opts opts = GIT_CHECKOUT_OPTS_INIT; + git_checkout_options opts = GIT_CHECKOUT_OPTIONS_INIT; unsigned int strategy; Object *py_object; int err; @@ -1513,7 +1547,7 @@ Repository_reset(Repository *self, PyObject* args) err = git_object_lookup_prefix(&target, self->repo, &oid, len, GIT_OBJ_ANY); - err = err < 0 ? err : git_reset(self->repo, target, reset_type); + err = err < 0 ? err : git_reset(self->repo, target, reset_type, NULL, NULL); git_object_free(target); if (err < 0) return Error_set_oid(err, &oid, len); @@ -1529,6 +1563,7 @@ PyMethodDef Repository_methods[] = { METHOD(Repository, TreeBuilder, METH_VARARGS), METHOD(Repository, walk, METH_VARARGS), METHOD(Repository, merge_base, METH_VARARGS), + METHOD(Repository, merge_analysis, METH_O), METHOD(Repository, merge, METH_O), METHOD(Repository, read, METH_O), METHOD(Repository, write, METH_VARARGS), diff --git a/src/signature.c b/src/signature.c index 727178d9e..e3f7d7157 100644 --- a/src/signature.c +++ b/src/signature.c @@ -94,6 +94,13 @@ Signature_dealloc(Signature *self) PyObject_Del(self); } +PyDoc_STRVAR(Signature__pointer__doc__, "Get the signature's pointer. For internal use only."); +PyObject * +Signature__pointer__get__(Repository *self) +{ + /* Bytes means a raw buffer */ + return PyBytes_FromStringAndSize((char *) &self->repo, sizeof(git_repository *)); +} PyDoc_STRVAR(Signature__encoding__doc__, "Encoding."); @@ -171,6 +178,7 @@ PyGetSetDef Signature_getseters[] = { GETTER(Signature, email), GETTER(Signature, time), GETTER(Signature, offset), + GETTER(Signature, _pointer), {NULL} }; diff --git a/src/tree.c b/src/tree.c index d1968faed..b72d57858 100644 --- a/src/tree.c +++ b/src/tree.c @@ -284,20 +284,20 @@ TreeEntry * Tree_getitem_by_index(Tree *self, PyObject *py_index) { int index; - const git_tree_entry *entry; + const git_tree_entry *entry_src; + git_tree_entry *entry; index = Tree_fix_index(self, py_index); if (PyErr_Occurred()) return NULL; - entry = git_tree_entry_byindex(self->tree, index); - if (!entry) { + entry_src = git_tree_entry_byindex(self->tree, index); + if (!entry_src) { PyErr_SetObject(PyExc_IndexError, py_index); return NULL; } - entry = git_tree_entry_dup(entry); - if (entry == NULL) { + if (git_tree_entry_dup(&entry, entry_src) < 0) { PyErr_SetNone(PyExc_MemoryError); return NULL; } @@ -550,16 +550,16 @@ TreeIter_dealloc(TreeIter *self) TreeEntry * TreeIter_iternext(TreeIter *self) { - const git_tree_entry *entry; + const git_tree_entry *entry_src; + git_tree_entry *entry; - entry = git_tree_entry_byindex(self->owner->tree, self->i); - if (!entry) + entry_src = git_tree_entry_byindex(self->owner->tree, self->i); + if (!entry_src) return NULL; self->i += 1; - entry = git_tree_entry_dup(entry); - if (entry == NULL) { + if (git_tree_entry_dup(&entry, entry_src) < 0) { PyErr_SetNone(PyExc_MemoryError); return NULL; } diff --git a/src/treebuilder.c b/src/treebuilder.c index 8354b1b5e..5957040ce 100644 --- a/src/treebuilder.c +++ b/src/treebuilder.c @@ -105,19 +105,19 @@ PyObject * TreeBuilder_get(TreeBuilder *self, PyObject *py_filename) { char *filename; - const git_tree_entry *entry; + const git_tree_entry *entry_src; + git_tree_entry *entry; filename = py_path_to_c_str(py_filename); if (filename == NULL) return NULL; - entry = git_treebuilder_get(self->bld, filename); + entry_src = git_treebuilder_get(self->bld, filename); free(filename); - if (entry == NULL) + if (entry_src == NULL) Py_RETURN_NONE; - entry = git_tree_entry_dup(entry); - if (entry == NULL) { + if (git_tree_entry_dup(&entry, entry_src) < 0) { PyErr_SetNone(PyExc_MemoryError); return NULL; } diff --git a/src/types.h b/src/types.h index 15f7bfedb..e69b489eb 100644 --- a/src/types.h +++ b/src/types.h @@ -32,8 +32,8 @@ #include #include -#if !(LIBGIT2_VER_MAJOR == 0 && LIBGIT2_VER_MINOR == 20) -#error You need a compatible libgit2 version (v0.20.x) +#if !(LIBGIT2_VER_MAJOR == 0 && LIBGIT2_VER_MINOR == 21) +#error You need a compatible libgit2 version (v0.21.x) #endif /* @@ -105,8 +105,8 @@ typedef struct { PyObject* hunks; const char * old_file_path; const char * new_file_path; - char* old_oid; - char* new_oid; + char* old_id; + char* new_id; char status; unsigned similarity; unsigned additions; @@ -208,10 +208,4 @@ typedef struct { char boundary; } BlameHunk; -/* git_merge */ -typedef struct { - PyObject_HEAD - git_merge_result *result; -} MergeResult; - #endif diff --git a/test/test_blame.py b/test/test_blame.py index dbe9e6bf0..cbdba9c6a 100644 --- a/test/test_blame.py +++ b/test/test_blame.py @@ -65,11 +65,10 @@ def test_blame_index(self): self.assertEqual(HUNKS[i][0], hunk.final_commit_id) self.assertEqual(HUNKS[i][1], hunk.final_start_line_number) self.assertEqualSignature(HUNKS[i][2], hunk.final_committer) - self.assertEqual(hunk.orig_commit_id, - '0000000000000000000000000000000000000000') + self.assertEqual(HUNKS[i][0], hunk.orig_commit_id) self.assertEqual(hunk.orig_path, PATH) self.assertEqual(HUNKS[i][1], hunk.orig_start_line_number) - self.assertTrue(hunk.orig_committer is None) + self.assertEqualSignature(HUNKS[i][2], hunk.orig_committer) self.assertEqual(HUNKS[i][3], hunk.boundary) def test_blame_with_invalid_index(self): @@ -93,11 +92,10 @@ def test_blame_for_line(self): self.assertEqual(HUNKS[i][0], hunk.final_commit_id) self.assertEqual(HUNKS[i][1], hunk.final_start_line_number) self.assertEqualSignature(HUNKS[i][2], hunk.final_committer) - self.assertEqual(hunk.orig_commit_id, - '0000000000000000000000000000000000000000') + self.assertEqual(HUNKS[i][0], hunk.orig_commit_id) self.assertEqual(hunk.orig_path, PATH) self.assertEqual(HUNKS[i][1], hunk.orig_start_line_number) - self.assertTrue(hunk.orig_committer is None) + self.assertEqualSignature(HUNKS[i][2], hunk.orig_committer) self.assertEqual(HUNKS[i][3], hunk.boundary) def test_blame_with_invalid_line(self): @@ -131,11 +129,10 @@ def test_blame_newest(self): self.assertEqual(HUNKS[i][0], hunk.final_commit_id) self.assertEqual(HUNKS[i][1], hunk.final_start_line_number) self.assertEqualSignature(HUNKS[i][2], hunk.final_committer) - self.assertEqual(hunk.orig_commit_id, - '0000000000000000000000000000000000000000') + self.assertEqual(HUNKS[i][0], hunk.orig_commit_id) self.assertEqual(hunk.orig_path, PATH) self.assertEqual(HUNKS[i][1], hunk.orig_start_line_number) - self.assertTrue(hunk.orig_committer is None) + self.assertEqualSignature(HUNKS[i][2], hunk.orig_committer) self.assertEqual(HUNKS[i][3], hunk.boundary) if __name__ == '__main__': diff --git a/test/test_diff.py b/test/test_diff.py index f982d0194..2f4314d98 100644 --- a/test/test_diff.py +++ b/test/test_diff.py @@ -257,13 +257,13 @@ def test_diff_patch(self): self.assertEqual(diff.patch, PATCH) self.assertEqual(len(diff), len([patch for patch in diff])) - def test_diff_oids(self): + def test_diff_ids(self): commit_a = self.repo[COMMIT_SHA1_1] commit_b = self.repo[COMMIT_SHA1_2] patch = commit_a.tree.diff_to_tree(commit_b.tree)[0] - self.assertEqual(patch.old_oid, + self.assertEqual(patch.old_id, '7f129fd57e31e935c6d60a0c794efe4e6927664b') - self.assertEqual(patch.new_oid, + self.assertEqual(patch.new_id, 'af431f20fc541ed6d5afede3e2dc7160f6f01f16') def test_hunk_content(self): diff --git a/test/test_index.py b/test/test_index.py index eb7fa05d7..f6ec53466 100644 --- a/test/test_index.py +++ b/test/test_index.py @@ -181,13 +181,13 @@ def test_change_attributes(self): index = self.repo.index entry = index['hello.txt'] ign_entry = index['.gitignore'] - self.assertNotEqual(ign_entry.oid, entry.oid) + self.assertNotEqual(ign_entry.id, entry.id) self.assertNotEqual(entry.mode, pygit2.GIT_FILEMODE_BLOB_EXECUTABLE) entry.path = 'foo.txt' - entry.oid = ign_entry.oid + entry.id = ign_entry.id entry.mode = pygit2.GIT_FILEMODE_BLOB_EXECUTABLE self.assertEqual('foo.txt', entry.path) - self.assertEqual(ign_entry.oid, entry.oid) + self.assertEqual(ign_entry.id, entry.id) self.assertEqual(pygit2.GIT_FILEMODE_BLOB_EXECUTABLE, entry.mode) def test_write_tree_to(self): @@ -201,7 +201,7 @@ class IndexEntryTest(utils.RepoTestCase): def test_create_entry(self): index = self.repo.index hello_entry = index['hello.txt'] - entry = pygit2.IndexEntry('README.md', hello_entry.oid, hello_entry.mode) + entry = pygit2.IndexEntry('README.md', hello_entry.id, hello_entry.mode) index.add(entry) tree_id = index.write_tree() self.assertEqual('60e769e57ae1d6a2ab75d8d253139e6260e1f912', str(tree_id)) diff --git a/test/test_note.py b/test/test_note.py index 74f08940d..4fcead56e 100644 --- a/test/test_note.py +++ b/test/test_note.py @@ -58,7 +58,7 @@ def test_create_note(self): def test_lookup_note(self): annotated_id = self.repo.head.target.hex note = self.repo.lookup_note(annotated_id) - self.assertEqual(NOTES[0][0], note.oid.hex) + self.assertEqual(NOTES[0][0], note.id.hex) self.assertEqual(NOTES[0][1], note.message) def test_remove_note(self): @@ -70,7 +70,7 @@ def test_remove_note(self): def test_iterate_notes(self): for i, note in enumerate(self.repo.notes()): - entry = (note.oid.hex, note.message, note.annotated_id) + entry = (note.id.hex, note.message, note.annotated_id) self.assertEqual(NOTES[i], entry) def test_iterate_non_existing_ref(self): diff --git a/test/test_remote.py b/test/test_remote.py index 9c95f80cd..57814a386 100644 --- a/test/test_remote.py +++ b/test/test_remote.py @@ -61,11 +61,12 @@ def test_remote_rename(self): remote = self.repo.remotes[0] self.assertEqual(REMOTE_NAME, remote.name) - remote.name = 'new' + problems = remote.rename('new') + self.assertEqual([], problems) self.assertEqual('new', remote.name) - self.assertRaisesAssign(ValueError, remote, 'name', '') - self.assertRaisesAssign(ValueError, remote, 'name', None) + self.assertRaises(ValueError, remote.rename, '') + self.assertRaises(ValueError, remote.rename, None) def test_remote_set_url(self): @@ -153,7 +154,7 @@ def test_remote_list(self): def test_remote_save(self): remote = self.repo.remotes[0] - remote.name = 'new-name' + remote.rename('new-name') remote.url = 'http://example.com/test.git' remote.save() diff --git a/test/test_repository.py b/test/test_repository.py index e70fe9779..4581f4774 100644 --- a/test/test_repository.py +++ b/test/test_repository.py @@ -40,6 +40,8 @@ # Import from pygit2 from pygit2 import GIT_OBJ_ANY, GIT_OBJ_BLOB, GIT_OBJ_COMMIT +from pygit2 import GIT_MERGE_ANALYSIS_NONE, GIT_MERGE_ANALYSIS_NORMAL, GIT_MERGE_ANALYSIS_UP_TO_DATE +from pygit2 import GIT_MERGE_ANALYSIS_FASTFORWARD, GIT_MERGE_ANALYSIS_UNBORN from pygit2 import init_repository, clone_repository, clone_into, discover_repository from pygit2 import Oid, Reference, hashfile import pygit2 @@ -308,57 +310,50 @@ class RepositoryTest_III(utils.RepoTestCaseForMerging): def test_merge_none(self): self.assertRaises(TypeError, self.repo.merge, None) - def test_merge_uptodate(self): + def test_merge_analysis_uptodate(self): branch_head_hex = '5ebeeebb320790caf276b9fc8b24546d63316533' - branch_oid = self.repo.get(branch_head_hex).id - merge_result = self.repo.merge(branch_oid) - self.assertTrue(merge_result.is_uptodate) - self.assertFalse(merge_result.is_fastforward) - self.assertEqual(None, merge_result.fastforward_oid) + branch_id = self.repo.get(branch_head_hex).id + analysis, preference = self.repo.merge_analysis(branch_id) + + self.assertTrue(analysis & GIT_MERGE_ANALYSIS_UP_TO_DATE) + self.assertFalse(analysis & GIT_MERGE_ANALYSIS_FASTFORWARD) self.assertEqual({}, self.repo.status()) - def test_merge_fastforward(self): + def test_merge_analysis_fastforward(self): branch_head_hex = 'e97b4cfd5db0fb4ebabf4f203979ca4e5d1c7c87' - branch_oid = self.repo.get(branch_head_hex).id - merge_result = self.repo.merge(branch_oid) - self.assertFalse(merge_result.is_uptodate) - self.assertTrue(merge_result.is_fastforward) - # Asking twice to assure the reference counting is correct - self.assertEqual(branch_head_hex, merge_result.fastforward_oid.hex) - self.assertEqual(branch_head_hex, merge_result.fastforward_oid.hex) + branch_id = self.repo.get(branch_head_hex).id + analysis, preference = self.repo.merge_analysis(branch_id) + self.assertFalse(analysis & GIT_MERGE_ANALYSIS_UP_TO_DATE) + self.assertTrue(analysis & GIT_MERGE_ANALYSIS_FASTFORWARD) self.assertEqual({}, self.repo.status()) def test_merge_no_fastforward_no_conflicts(self): branch_head_hex = '03490f16b15a09913edb3a067a3dc67fbb8d41f1' - branch_oid = self.repo.get(branch_head_hex).id - merge_result = self.repo.merge(branch_oid) - self.assertFalse(merge_result.is_uptodate) - self.assertFalse(merge_result.is_fastforward) + branch_id = self.repo.get(branch_head_hex).id + analysis, preference = self.repo.merge_analysis(branch_id) + self.assertFalse(analysis & GIT_MERGE_ANALYSIS_UP_TO_DATE) + self.assertFalse(analysis & GIT_MERGE_ANALYSIS_FASTFORWARD) # Asking twice to assure the reference counting is correct - self.assertEqual(None, merge_result.fastforward_oid) - self.assertEqual(None, merge_result.fastforward_oid) - self.assertEqual({'bye.txt': 1}, self.repo.status()) - self.assertEqual({'bye.txt': 1}, self.repo.status()) - # Checking the index works as expected - self.repo.index.remove('bye.txt') - self.repo.index.write() - self.assertEqual({'bye.txt': 128}, self.repo.status()) + self.assertEqual({}, self.repo.status()) + self.assertEqual({}, self.repo.status()) def test_merge_no_fastforward_conflicts(self): branch_head_hex = '1b2bae55ac95a4be3f8983b86cd579226d0eb247' - branch_oid = self.repo.get(branch_head_hex).id - merge_result = self.repo.merge(branch_oid) - self.assertFalse(merge_result.is_uptodate) - self.assertFalse(merge_result.is_fastforward) + branch_id = self.repo.get(branch_head_hex).id + + analysis, preference = self.repo.merge_analysis(branch_id) + self.assertFalse(analysis & GIT_MERGE_ANALYSIS_UP_TO_DATE) + self.assertFalse(analysis & GIT_MERGE_ANALYSIS_FASTFORWARD) + + self.repo.merge(branch_id) + status = pygit2.GIT_STATUS_WT_NEW | pygit2.GIT_STATUS_INDEX_DELETED # Asking twice to assure the reference counting is correct - self.assertEqual(None, merge_result.fastforward_oid) - self.assertEqual(None, merge_result.fastforward_oid) - self.assertEqual({'.gitignore': 132}, self.repo.status()) - self.assertEqual({'.gitignore': 132}, self.repo.status()) + self.assertEqual({'.gitignore': status}, self.repo.status()) + self.assertEqual({'.gitignore': status}, self.repo.status()) # Checking the index works as expected self.repo.index.add('.gitignore') self.repo.index.write() - self.assertEqual({'.gitignore': 2}, self.repo.status()) + self.assertEqual({'.gitignore': pygit2.GIT_STATUS_INDEX_MODIFIED}, self.repo.status()) def test_merge_invalid_hex(self): branch_head_hex = '12345678'